Commit Graph

44 Commits

Author SHA1 Message Date
Leon Ma
1338b0d0bc fix(ai/gemini): coerce numeric/boolean enum values to strings (#104567)
* 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>
2026-07-11 16:34:31 -07:00
VectorPeak
f8c7f67bde fix(ai): reject non-finite tool schema numbers (#104470)
* fix(ai): reject non-finite tool schema numbers

Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>

* fix(ai): catch non-finite values from tool schema serializers

Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>

Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>

* test(ai): cover nested tool schema serializers

Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>

* fix(ai): satisfy schema projection lint

Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>

* fix(ai): satisfy schema projection lint

Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>

* fix(ai): preserve empty-key schema diagnostic paths

* fix(ai): reject boxed non-finite schema numbers

* fix(ai): ignore spoofed boxed-number tags

* fix(ai): isolate boxed-number brand probes

* refactor(ai): use intrinsic boxed-number detection

---------

Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-11 14:50:54 -07:00
Peter Steinberger
4b751ce48a feat(tooling): complete packages/* noUncheckedIndexedAccess adoption (phase 2) (#104626)
* feat(tooling): extend strict-ratchet lane to all remaining leaf packages

* fix(packages): burn down indexed-access debt in ai and agent-core

All 196 noUncheckedIndexedAccess errors fixed behavior-identically
(iteration, .at()/slices, DataView byte math, guarded queue peeks) plus
cleanup finds: a sparse-tool diagnostic bug, deduplicated Responses
call/item ID parsing with an honest string|undefined splitter, and a
clearer local failure for redacted-thinking blocks missing signatures.
Removes all 17 remaining non-null assertions across ai, gateway-client,
and llm-core so the assertion ban aligns 1:1 with the ratchet lane.
speech-core joins memory-host-sdk as structurally deferred (imports
src/** via plugin-sdk path mappings).
2026-07-11 11:54:06 -07:00
Peter Steinberger
57af2bbff0 fix: clear remaining release validation blockers (#104555)
* test: align provider tool call lifecycles

* test: isolate plugin install repair migrations

* fix: accept catalog temperature compatibility

* fix: disable GPT-5.6 tool reasoning on completions

* style: avoid shadowed stream model
2026-07-11 09:32:16 -07:00
Peter Steinberger
7bf80dc2c6 chore(tooling): enforce formatting and refresh TypeScript checks (#104239)
* chore(tooling): enforce current formatter and refresh checks

* chore(tooling): keep release changelog formatter-owned

* chore(tooling): retain compatible Node type surface

* ci: enforce formatting for docs-only changes

* ci: isolate docs formatter check

* chore(tooling): apply updated lint and format rules

* chore(tooling): satisfy updated switch lint

* style(ui): apply Linux formatter layout

* test(doctor): match quiet local audio contribution

* test(doctor): assert quiet output only

* test(doctor): follow restored information contract
2026-07-11 01:09:51 -07:00
Peter Steinberger
dba64d574f chore(release): set version to 2026.7.2 2026-07-11 04:00:49 +01:00
Peter Steinberger
97bbbc2271 feat(agents): derive a provider-declared default utility model when unset (#103769)
* feat(agents): derive a provider-declared default utility model when unset

When agents.defaults.utilityModel is not set, utility tasks (titles, progress
narration) now use the primary provider's declared small model
(modelCatalog.providers.<id>.defaultUtilityModel: OpenAI -> gpt-5.6-luna,
Anthropic -> claude-haiku-4-5). Auth is inherent because derivation follows
the agent's primary provider. Setting utilityModel to an empty string
disables utility routing entirely; narration turns on automatically when a
default resolves and stays off otherwise.

Formatting/lint/tests verified on Testbox (oxfmt, oxlint, plugins:inventory,
docs:map, import-cycles, check:test-types, 4 test files).

* fix(ai): drop the temperature parameter for models that reject it

The GPT-5.6 family 400s on temperature via the Responses API (live-verified:
gpt-5.6-luna/-terra reject it; gpt-5.5 and gpt-5.4-mini/nano accept it).
supportsOpenAITemperature gates all three OpenAI payload builders, with a
catalog compat override (compat.supportsTemperature) declared for the 5.6
family in the openai manifest. Without this, utility tasks (titles,
narration) would fail once gpt-5.6-luna becomes the derived default.

Gates on Testbox: oxfmt, oxlint, plugins:inventory, import-cycles,
check:test-types, 6 test files. Live proof on Testbox: gpt-5.6-luna and
claude-haiku-4-5 one-shot completions succeed with temperature requested.

* fix(agents): carry the primary model's auth profile onto the derived utility default

A primary like openai/gpt-5.5@work previously reached utility tasks via the
profiled fallback; the derived default shares the provider, so its trailing
auth profile carries over instead of silently switching to default
credentials (Codex review). Gates on Testbox: oxfmt, check:test-types, tests.

* docs: realign the manifest provider-fields table after adding defaultUtilityModel
2026-07-10 17:40:11 +01:00
Yuval Dinodia
b7ab62c2cf fix(mattermost): preserve text-block boundaries in draft preview (#87322) (#87449)
* fix(mattermost): preserve text-block boundaries in draft preview (#87322)

* fix(mattermost): preserve block preview boundaries

* fix(mattermost): reset progress at tool boundaries

* docs(plugin-sdk): refresh API baseline

* fix(mattermost): group parallel tool previews

* fix(mattermost): stage tool previews before awaits

* fix(mattermost): satisfy tool boundary return contract

* fix(mattermost): serialize preview block generations

Co-authored-by: Yuval Dinodia <yetvald@gmail.com>

* fix(mattermost): preserve complete block previews

* test(agents): align streaming assertions

* test(telegram): align reply pipeline mock

* fix(plugin-sdk): keep reply prefix options compatible

* test(mattermost): exercise threaded final participation

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-10 14:32:11 +01:00
Peter Steinberger
ab5d143d59 feat(openai): default new setups to GPT-5.6 (#103581)
* feat(openai): default fresh setup to GPT-5.6

* test(crestodian): expect GPT-5.6 Codex defaults

* test(crestodian): expect GPT-5.6 bootstrap default
2026-07-10 10:22:58 +01:00
Peter Steinberger
461772868d fix(computer): prevent stale, replayed, and post-cancel desktop actions (#103422)
* fix(ai): preserve streamed tool-call identity

* fix(computer): bind actions to current tool authority

* fix(macos): serialize computer control lifecycle

* docs(computer): document hardened control contract

* chore: follow release-owned changelog policy

* test(agents): cover node list cancellation
2026-07-10 06:47:56 +01:00
LZY3538
939d0ef45d fix(ai): cache and case-insensitively match Azure deployment map (#103005)
* fix(ai): cache and case-insensitively match Azure deployment map

resolveAzureDeploymentNameFromMap re-parsed the deployment-map string into
a new Map on every call (a hot path: streams and lifecycle hooks) and
looked model ids up case-sensitively. A request for `GPT-4o` against a
`gpt-4o=deployment-gpt-4o` map therefore fell back to the raw model id and
404'd on Azure ("deployment not found").

Cache the parsed lookup map keyed by the raw deployment-map string (bounded
so memory stays flat) and normalize keys to lowercase so lookups are
case-insensitive. Deployment names (the values) stay verbatim because Azure
requires the exact deployment name, and the fallback still returns the
original-cased model id.

Fixes #102936

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(ai): prefer exact-case match, case-insensitive only as fallback

Addresses review: lowercasing every key regressed configs whose deployment
map distinguishes keys by case (e.g. `GPT-4o=prod-a,gpt-4o=prod-b`), where an
exact `GPT-4o` request previously resolved to `prod-a` but would now collapse
to the last lowercased entry.

Cache an exact-case lookup alongside the lowercased one and resolve exact
first, using the case-insensitive map only as a fallback. Every previously
working exact mapping is preserved; the case-insensitive path only rescues
ids that would otherwise 404. Adds a regression test for exact-case
precedence.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* test(ai): prove Azure deployment map resolves on the real provider path

Adds an integration test that drives the real streamSimpleAzureOpenAIResponses
path against a loopback server (via the AI transport host fetch) and asserts the
deployment name resolved from AZURE_OPENAI_DEPLOYMENT_NAME_MAP is what lands in
the outgoing request `model` field — the value Azure routes on, and the source
of the reported 404 when it fell back to a mixed-case model id.

Covers the mixed-case fix (GPT-4o -> deployment-gpt-4o on the wire) and the
exact-case no-regression case (GPT-4o -> prod-a).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* test(ai): use block-body promise executors to satisfy oxlint

no-promise-executor-return flagged the arrow executors around server
listen/close; use statement bodies so nothing is returned from the executor.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(ai): simplify Azure deployment lookup

* refactor(ai): simplify Azure deployment lookup

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <peter@steipete.me>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-10 06:38:39 +01:00
Ted Li
4c4609d42b fix(ai): match reasoning efforts case-insensitively without lowering provider values (#102993)
* fix(ai): match reasoning effort case-insensitively

* fix(ai): preserve mapped reasoning effort casing

* fix(ai): preserve unmapped reasoning effort casing

* fix(ai): match reasoning effort map keys by case

* fix(ai): harden reasoning effort normalization

Co-authored-by: Ted Li <tl2493@columbia.edu>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-10 04:07:57 +01:00
qingminlong
2fd0f88f62 fix: ignore invalid Retry-After HTTP dates (#102987)
* fix: ignore invalid Retry-After HTTP dates

* fix(ai): centralize strict Retry-After dates

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Peter Steinberger <peter@steipete.me>
2026-07-10 04:02:44 +01:00
Peter Steinberger
db12cb7023 fix(xai): align current model catalog and tools (#103260)
* fix(xai): align current model catalog and tools

* chore(xai): defer release note to release closeout

* docs: refresh xai documentation map
2026-07-10 03:36:14 +01:00
wm0018
50cb0d66b8 fix(ai): replace raw require(node:fs) with loadNodeBuiltinModule in getProcEnv (#102947)
* fix(ai): replace raw require(node:fs) with loadNodeBuiltinModule in getProcEnv

* test(ai): cover browser-safe env key bundle

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-10 00:14:58 +01:00
Peter Steinberger
d185f9a0b4 fix(infra): preserve characters in truncated response snippets (#103136)
* fix(infra): preserve bounded response text characters

Co-authored-by: qingminlong <34085845+qingminglong@users.noreply.github.com>

* ci(plugin-sdk): refresh API baseline

---------

Co-authored-by: qingminlong <34085845+qingminglong@users.noreply.github.com>
2026-07-09 23:43:26 +01:00
Vincent Koc
266ca5b3a2 fix(providers): publish Meta provider (#103070) 2026-07-09 12:11:56 -07:00
Hamid Shojanazeri
08a957e0ae feat(providers): add Meta Model API - muse-spark-1.1 (#102873)
* feat(providers): add Meta Model API - muse-spark-1.1

Adds meta-model-api provider via bundled extension:
- extensions/meta-model-api/ (provider, catalog, stream, thinking, onboarding)
- docs/providers/meta-model-api.md
- core wiring: env-api-keys, zod-schema, provider-display-names, dotenv, provider-env-vars

Model: meta-model-api/muse-spark-1.1 (Responses API at https://api.ai.meta.com/v1)
Auth: MODEL_API_KEY (Bearer)
Default reasoning: high, maps --thinking off -> minimal (model rejects none)

Fix: bump live test maxTokens 200->4000 (high reasoning uses ~300 tokens for reasoning alone)

Co-authored-by: Meta

* fix(meta-model-api): clean reasoning lint

* test(meta-model-api): align live proof checks

* chore(meta-model-api): bundle provider metadata

* docs: fix Meta Model API setup wording

* docs: format Meta Model API provider page

---------

Co-authored-by: Dave Morin <dave@morin.com>
Co-authored-by: Colin <colin@solvely.net>
Co-authored-by: Josh Lehman <josh@martian.engineering>
2026-07-09 10:27:09 -07:00
LiLan0125
db0f6f09dc fix(google): restore image tool results for prefixed Gemini 2 models (#102382)
* fix(google): handle prefixed Gemini 2 image fallback

* test(google): cover prefixed Gemini 3 image responses

* docs(changelog): note prefixed Gemini fallback

Co-authored-by: 李兰 0668001394 <li.lan3@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-09 15:09:05 +01:00
wuqxuan
3fd52514e3 fix: surface OpenAI chat-completions refusal as assistant text (#102344)
* fix: surface OpenAI chat-completions refusal as assistant text

* fix: cover message.refusal on packages/ai completions path
2026-07-09 06:10:03 -07:00
lsr911
3ac7729f4c fix(mistral): use truncateUtf16Safe for error text truncation (#102539)
* fix(mistral): use truncateUtf16Safe for error text truncation

Replace naive .slice(0, maxChars) with truncateUtf16Safe() in
truncateErrorText() to prevent surrogate pair splitting in
Mistral provider error messages shown to users.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(ai): keep Mistral errors UTF-16 safe

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-09 10:03:51 +01:00
Ted Li
f984209f54 fix: keep Gemini thinking disabled after clamp (#101832)
* fix: keep Gemini thinking disabled after clamp

* fix: preserve clamped Gemini thinking in wrapper

* test(ai): cover generic Gemini clamp to off

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-09 09:54:52 +01:00
Peter Steinberger
d6ec1c6cea fix(secrets): prevent capture and sentinel credential retention (#102420)
* fix(secrets): harden sentinel capture lifecycle

* chore: leave release notes to release automation
2026-07-09 05:50:28 +01:00
Peter Steinberger
4bf70be01a feat(secrets): egress-time credential injection with process-local sentinels (#102009)
* feat(secrets): resolve SecretRef model credentials at egress via process-local sentinels

SecretRef-managed model-provider credentials now travel as opaque
oc-sent-v1 sentinels through auth storage, stream options, and SDK
config; the guarded model fetch injects real values into headers and
URLs immediately before the SSRF-guarded send and fails closed on
unknown sentinels. packages/ai adapters converge on the host guarded
fetch where the SDK supports custom fetch and unwrap at construction
where it does not. Resolved values (and their percent-encoded forms)
register for exact-value log redaction. Kill switch:
OPENCLAW_SECRET_SENTINELS=off. Also fixes a pre-existing unhandled
rejection race in capNonOkResponseBodyLazily (pipeThrough writer leak).

* test(plugin-sdk): update public surface budget
2026-07-08 12:56:41 +01:00
Vincent Koc
380bc24d25 refactor(deadcode): localize AI provider declarations (#101907) 2026-07-07 16:26:22 -07:00
Vincent Koc
1b6f3e43d1 refactor(deadcode): trim private helper exports (#101886) 2026-07-07 14:43:45 -07:00
pick-cat
e72dadbb3b fix(anthropic): resolve thinking as disabled when legacy budget is below 1024 (#101415)
* fix(anthropic): resolve thinking as disabled when legacy budget is below 1024

When adjustMaxTokensForThinking collapses the thinking budget below the
Anthropic minimum (1024), option resolution now sets thinkingEnabled to
false instead of always forcing it to true. This keeps every downstream
consumer (payload, replay, temperature, tool-choice) consistent — they
all see the same disabled state instead of an enabled flag with a
missing or API-rejected thinking block.

|| → ?? in both builders is defensive: the resolution layer already
prevents invalid budgets from reaching the builder through the normal
path, but ?? preserves an explicit zero when the builder is called
directly.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(anthropic): guard raw streamAnthropic builder path against sub-minimum budgets

Add budget guards in both Anthropic payload builders so direct
streamAnthropic and bundled-plugin callers (e.g. Mantle) that bypass
option resolution also get the disabled-state rule instead of producing
API-rejected { type: "enabled", budget_tokens: < 1024 } requests.

Add proof-anthropic-thinking-budget.mts driving real production
functions with terminal output and negative control.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(anthropic): normalize legacy thinking budgets

Co-authored-by: Pick-cat <huang.ting3@xydigit.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-07 08:42:40 +01:00
snowzlmbot
53580e13a4 fix(usage): preserve provider-billed zero totals (#101177)
* fix(usage): preserve provider-billed zero totals

* fix(usage): harden provider-billed cost provenance

* fix(openrouter): retry delayed generation metadata

* fix(openrouter): satisfy retry lint

* refactor(openrouter): consume streamed billed cost

* chore: keep release notes out of contributor PR

---------

Co-authored-by: snowzlmbot <293528334+snowzlmbot@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-07 06:22:28 +01:00
Peter Steinberger
473b3cf789 fix(anthropic): keep error tool results non-empty (#101373)
Co-authored-by: Galin Iliev <5711535+galiniliev@users.noreply.github.com>
2026-07-07 06:17:27 +01:00
Peter Steinberger
c5d42593be fix(anthropic): guard SDK client transport (#101357)
Co-authored-by: wangmiao0668000666 <wang.miao86@xydigit.com>
2026-07-07 05:45:49 +01:00
Ayaan Zaidi
c718afe247 refactor(agents): thread runtime-context carrier indexes 2026-07-06 20:34:01 -07:00
Peter Lindsey
f5931f5516 fix(agents): carry current-turn inbound metadata in a tail runtime-context message for byte-stable prompt caching
The active user turn was decorated at request-build time with an inbound
metadata block (Conversation info / reply-target / sender / forwarded /
chat-history), but the session store persists the bare text and the LLM boundary
strips that block from historical replay. So a user message's serialized bytes
changed retroactively — decorated as the active turn, bare as history — on every
turn, invalidating any prefix/exact-match provider prompt cache from that point
onward, every turn. (#90811 fixed the timestamp half of this same asymmetry.)

Rework of the earlier "strip the active turn" approach (which lost model-visible
context — ClawSweeper's P1) into one that keeps the context AND recovers the
cache cost:

- Route current-turn inbound metadata out of the user prompt and into the hidden
  runtime-context custom message (the mechanism from openclaw#89428), and
  relocate that carrier to the ABSOLUTE TAIL of the wire request (after the
  active user turn and any tool-call scaffolding). The user turn stays bare and
  byte-identical in both the active and historical positions; the volatile
  carrier vanishes next turn exactly where the assistant reply begins anyway, so
  the request is an append-only prefix-extension through the active user turn.
- A durable marker (UserMessage.runtimeContextCarrier, set by convertToLlm from
  the carrier's details) lets the Anthropic SDK transport, the managed Anthropic
  transport (anthropic-transport-stream / anthropic-payload-policy), and
  OpenAI-completions skip the carrier when selecting the deepest cache_control
  breakpoint, keeping the anchor on the last stable user turn.

Storage stays BARE (invariant preserved); runtime-only turns (room events) keep
their existing inline behavior, which is byte-stable because room-event/system
context is not strip-eligible; legacy bare-stored sessions are unchanged.

Reviewed with adversarial gpt-5.5/codex sweeps (correctness, byte-identity,
compatibility, test adequacy): found + fixed the managed Anthropic transport
cache-anchor path and added the missing OpenAI-completions/managed-transport
breakpoint tests; a theoretical runtime-only mutation was verified unreachable
and pinned with a test. Final sweep clean.

Co-authored-by: openclaw#89428 (runtime-context handoff approach)
2026-07-06 20:34:01 -07:00
Peter Lindsey
3d87932541 fix(agents): send session_id affinity header to ChatGPT Responses backend
The ChatGPT backend routes requests by session_id (codex-cli sends it); without it each request lands on an arbitrary machine and the prompt cache misses. Measured on live traffic: 56.0% -> 81.8% TRUE cache hit rate (12-turn A/B, identical prompts).
2026-07-06 20:33:51 -07:00
qingminlong
d6f097b3de fix(agents): normalize surrogate cache fingerprints (#101009)
* fix(agents): normalize surrogate cache fingerprints

* fix(agents): reuse provider surrogate sanitizer

* chore(agents): keep transport imports grouped

* fix(agents): avoid runtime import for surrogate sanitizer

* fix(agents): scope surrogate cache normalization

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-07 03:06:56 +01:00
Vincent Koc
f305e707a3 feat(models): add Claude Mythos 5 support (#101238) 2026-07-06 17:19:49 -07:00
Vortex Openclaw
1f6ddb5df0 feat(models): add Claude Sonnet 5 support (#98254)
* feat(models): add Claude Sonnet 5 support

Co-authored-by: Ariel Bravy <ariel@vortexradar.com>

* fix(models): align Sonnet 5 validation baselines

* fix(models): satisfy Sonnet 5 CI contracts

* fix(models): enforce Sonnet 5 provider contracts

* docs(changelog): defer Sonnet 5 release note

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Ariel Bravy <ariel@vortexradar.com>
2026-07-07 00:05:35 +01:00
Vincent Koc
65a9cb4ed1 refactor(packages): localize internal helper types (#101041) 2026-07-06 10:30:58 -07:00
Vincent Koc
bf8626c0e9 feat(providers): add LongCat API support (#100501)
* fix(ai): honor provider reasoning compatibility

* feat(longcat): add hosted provider plugin

* chore(longcat): register package metadata

* docs(longcat): add provider setup guide

* docs(longcat): document self-hosted model routing

* refactor(longcat): externalize provider plugin

* chore(longcat): add npm release artifacts
2026-07-06 10:07:08 -07:00
Brian Bell
bacb33a909 fix: keep Bedrock live smoke on Bedrock runtime (#99607)
* fix: preserve Bedrock live API providers

* fix: derive Bedrock smoke region from AWS config

* fix: honor Bedrock discovery region in smoke

* fix: keep Bedrock live smoke on Bedrock runtime

---------

Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com>
2026-07-06 08:19:42 -07:00
Vincent Koc
709be93ca8 fix(anthropic): restore subscription OAuth billing routing 2026-07-06 06:18:52 -07:00
wm0018
e53131ea1c fix(mistral): correct model id typo in usesReasoningEffort helper (#100688)
* fix(mistral): correct model id typo in usesReasoningEffort helper

* chore: re-trigger CI

* test(mistral): cover medium reasoning effort

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-06 08:57:27 +01:00
lin-hongkuan
aca316ee16 fix(anthropic): normalize tuple tool schemas for Opus 4.8 (#100492)
* fix(anthropic): normalize tuple tool schemas

* fix(anthropic): preserve schema instance values

* test(anthropic): cover Opus tuple schemas live

---------

Co-authored-by: lin-hongkuan <lin-hongkuan@users.noreply.github.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-07-05 22:28:37 -07:00
LZY3538
e6ec74c254 fix(compaction): preserve Anthropic context usage (#99864) 2026-07-05 02:33:43 -07:00
Peter Steinberger
062f88e3e3 refactor: extract reusable AI runtime package (#99059)
* refactor: extract reusable AI runtime package

* refactor: complete AI provider relocation

* refactor: keep llm core internal

* refactor(ai): make @openclaw/ai self-contained with host policy ports

Move pure transport helpers (tool projections, strict-schema normalization,
prompt-cache boundary, stream guards, anthropic/openai compat, request
activity) from src into packages/ai; move utf16-slice into
normalization-core. Inject host policy (guarded fetch, redaction,
strict-tool defaults, diagnostics logging) through AiTransportHost with
inert library defaults installed by src/llm/stream.ts. Narrow the public
barrel to instance-scoped createApiRegistry/createLlmRuntime; the
process-default runtime moves behind internal/ and
registerBuiltInApiProviders takes an explicit registry. Delete the
src/llm/api-registry re-export facade.

* fix(ai): teach node, jiti, and vite resolvers the @openclaw/ai and utf16-slice subpaths

The workspace alias tables in root-alias.cjs, plugin-sdk-native-resolver,
sdk-alias, the shared vitest config, and the Control UI vite config only
knew @openclaw/llm-core; Node-side plugin loading resolved @openclaw/ai
through the pnpm symlink to the unbuilt dist (checks-node-compact CI
failures), and the Control UI build broke on the new
normalization-core/utf16-slice subpath.

* chore(ui): drop leftover service-worker debug logging

* build(release): ship @openclaw/ai with its own shrinkwrap and honest dependency set

packages/ai declares only its six real runtime deps (kysely, chalk, json5,
tslog, zod, fs-safe, and proxyline were never imported); orphaned root deps
removed. generate-npm-shrinkwrap now treats publishable packages/* like
publishable plugins so the AI tarball pins its transitive tree even though
workspace deps are omitted from the root shrinkwrap. knip learns the
package entry points; the tsdown dts neverBundle option moves to its
documented deps.dts home; the README documents the no-semver internal/*
contract and host ports.

* docs(ai): add minimal external-consumer example app

examples/ai-chat consumes only the public @openclaw/ai surface (built dist
via the workspace link): isolated runtime, built-in provider registration,
one streamed completion. Supports Anthropic/OpenAI via env keys and a
keyless local Ollama target; live-verified against Ollama.

* docs(ai): document the @openclaw/ai package and workspace shrinkwrap boundary

* chore(check): include examples/ in duplicate-scan targets

* fix: emit normalization package subpaths

* fix: complete AI package boundary artifacts

* fix: align AI package boundary contracts

* fix(ci): stabilize package release contracts

* test: align documentation contract checks

* test: keep cron docs guard aligned

* test: align restored docs contract guards

* test: follow upstream docs contracts

* docs: drop superseded talk wording
2026-07-05 01:56:40 -04:00