Commit Graph

180 Commits

Author SHA1 Message Date
Peter Steinberger a542f01f49 refactor: remove dead tooling and deprecated exports (#112915) 2026-07-23 01:28:11 -04:00
TUARAN 3c32f327a4 fix(anthropic): normalize unsupported inline images (#102537)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-21 11:31:24 -07:00
Peter Steinberger b4e27f8b3d refactor: move provider transports into packages/ai behind a typed host port (#111669)
* refactor(ai): invert plugin coupling behind the transport host port

* fix(ai): queue custom transport registrations until the host is configured

* refactor(ai): remove relocated transport sources from src/agents

* fix(ai): source core stream types from canonical packages and fix tarball fixtures

* fix(ai): invert plugin transport host wiring

* fix(ai): harden managed transport projection

* test(ai): register synchronous stream in transport mock

* fix(ai): lazily install transport runtime host

* fix(ai): preserve completion compat detection
2026-07-20 23:26:00 -07:00
Peter Steinberger 2bb6b870aa fix: preserve Codex-bound conversation history across session rotation (#112016)
* fix: preserve Codex conversation bindings

* test: harden Codex live gateway stress

* chore: refresh plugin SDK API baseline

* test: tighten restart recovery fixtures

* test: complete restart recovery recorder fixture

* fix: keep plugin command authorization fail closed

* fix: restore private queue source imports

* fix: keep private SDK imports inside core

* fix: keep speech core on private SDK paths

* fix: stage private SDK exports for live tests

* fix: preserve plugin-bound gateway history

* fix: block transcript writes after binding races

* test: complete live stage helper contracts

* test: align binding mocks with current types

* fix: preserve compiler OOM diagnostics

* chore: move release notes to PR context
2026-07-20 19:42:56 -07:00
Peter Steinberger cc57514e68 refactor(agents): make API registry ownership lifecycle-local (#111137)
* refactor(agents): make API registries lifecycle-owned

* refactor(agents): keep registry runtime ownership internal

* fix(agents): bind session streams to registry runtime

* refactor(agents): keep prepared runtime ownership internal

* test(agents): model lifecycle runtime fixtures

* fix(amazon-bedrock): adapt lifecycle stream types

* fix(agents): complete lifecycle runtime migration

* test(agents): satisfy lifecycle registry static gates
2026-07-18 20:55:07 -07:00
Wynne668 d5b2749fd8 fix(ai): skip blank environment credentials during provider auth (#109691)
* fix(ai): ignore blank environment API keys

* test(ai): avoid credential-shaped fixture assignments

Co-authored-by: ZengWen-DT <ceng.wen@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 22:33:54 +01:00
Peter Steinberger 6745f9a553 fix: provider usage accounting, retry/overflow classification, and output clamping (#109796)
* fix(ai): provider usage accounting, retry and overflow classification, output clamping

* ci: refresh pull-request validation

* test(ai): live-probe overflow classification and output clamping
2026-07-17 12:40:01 +01:00
Peter Steinberger 349f78776d fix(models): refresh bundled provider catalogs (#109410)
* fix(models): refresh bundled provider catalogs

* docs(models): refresh generated docs map

* fix(xiaomi): keep provider helper private

* chore(release): defer catalog release note
2026-07-16 16:47:25 -07:00
NianJiu 42ff5ec754 feat(kimi): add Kimi K3 support (#109202)
* feat(moonshot): add Kimi K3 support

* feat(kimi): add K3 subscription models

---------

Co-authored-by: NianJiuZst <180004567+NianJiuZst@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 11:41:12 -07:00
ZOOWH f83d5b8743 fix(copilot): clean up polling abort listeners (#106453) 2026-07-16 04:59:53 -07:00
Peter Steinberger 3280a0df9a test(retry): port negative matrix for provider-wrapped statuses
Ports the unique coverage from #108126 onto the parser landed via #106850:
wrapped 401/403/404 and quota-exhausted 429 stay non-retryable, an
envelope embedded in user text is ignored, and a short-window wrapped
429 retries. Credit @zhanxingxin1998.
2026-07-16 11:22:13 +01:00
wuqxuan e868a1dbd1 fix: recognize provider-wrapped HTTP status for session retry (#106850)
* fix: recognize provider-wrapped HTTP status for session retry

* fix(llm): scope wrapped status parsing to retry

Preserve the leading-status contract for rate-window and formatting callers while letting retry classification recognize built-in provider wrappers.

Co-authored-by: wuqingxuan <wu.qingxuan@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 00:40:15 -07:00
Peter Steinberger fca2e830e0 fix(auth): session refresh preserves OAuth providers (#108680)
* fix(auth): isolate OAuth provider registries

* fix(auth): remove OAuth registry back edge
2026-07-16 00:39:28 -07:00
Peter Steinberger 0393189243 chore(plugins): gate deprecation hygiene in CI and purge internal deprecated usage (#108261)
* chore(plugins): gate deprecation hygiene in CI and purge internal deprecated usage

* fix(agents): migrate auth-profiles oauth import to OAuthProviderId

* fix(whatsapp): use durability param in delivery-recovery test

* chore(scripts): declare shouldRunDeprecationHygieneChecks in check-changed types

* test(plugins): update runtime-api guard for ssrf policy rename
2026-07-15 04:15:23 -07:00
Peter Steinberger 723c2f81ad refactor(llm): privatize provider internals (#108099)
* refactor(llm): privatize provider internals

* chore(deadcode): refresh export baseline
2026-07-15 00:11:43 -07:00
Yuval Dinodia d576881390 fix(github-copilot): reject unsupported OAuth enterprise domain before refresh and model routing (#105584)
* fix(github-copilot): reject unsupported OAuth enterprise domain before refresh and model routing

Legacy github-copilot OAuth credentials can carry a non-github.com
enterpriseUrl. The token-refresh path templated it into the endpoint and
sent the bearer refresh token there with no allowlist, and the model
routing path derived a base URL from the same credential, so an unexpired
credential kept routing its access token to that origin without ever
reaching a refresh.

A persisted credential origin that is not on the Copilot host allowlist
is now rejected before any request is issued and before any model URL is
produced. Because an off-allowlist origin means the stored access token
may itself have been minted by that origin, the credential is refused as
a whole rather than coerced to github.com: modifyModels withholds the
github-copilot models so the token has no route, and its proxy-ep is
never trusted. Login rejects an unsupported host up front, so every path
that turns a domain into a bearer-bearing URL validates first.
formatAuthDoctorHint guides affected users to re-authenticate, mirroring
the qwen-portal hint. Supported hosts are unchanged: github.com and
*.ghe.com data-residency tenants still route and refresh as before.

The allowlist plus a new isSupportedGithubCopilotDomain predicate move to
a dependency-free plugin-sdk leaf so the core OAuth runtime can share them
without closing a module cycle; plugin-sdk/provider-auth re-exports
normalizeGithubCopilotDomain, so the plugin-owned GitHub Copilot provider
keeps its existing import.

Fixes #103078.

* fix(github-copilot): resolve provider auth base conflict

* fix(github-copilot): resolve provider auth base conflict

* fix(github-copilot): validate token proxy endpoint

* fix(github-copilot): remove stale helper import

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Peter Steinberger <peter@steipete.me>
2026-07-14 22:29:35 -07:00
Peter Steinberger 85e4a42fef refactor: privatize core dead exports (#107826)
* refactor(gateway): privatize Claude prompt candidate type

* refactor(music-generation): privatize runtime dependency type

* refactor(security): privatize install policy request type

* refactor(sessions): privatize state notice prefix

* refactor(skills): privatize upload concurrency limit

* refactor(agents): privatize Chutes and catalog constants

* test(commands): use Chutes endpoint contract literals

* refactor(llm): remove proxy error facade export

* refactor(infra): privatize proxy protocol error message

* refactor(proxy-capture): privatize environment keys

* chore(deadcode): shrink unused export baseline
2026-07-14 16:00:58 -07:00
Peter Steinberger f81f9d8570 chore: enforce max-lines suppression ratchet (#107315)
* ci: enforce max-lines suppression ratchet

* chore: prune stale max-lines suppression

* fix: close max-lines ratchet enforcement gaps

* fix: harden max-lines ratchet checks

* fix(ci): satisfy max-lines ratchet checks

* style: format max-lines declarations

* fix(ci): match oxlint suppression grammar

* test: isolate max-lines git fixtures

* chore: prune resolved max-lines debt

* test: skip newline path fixture on Windows

* fix: harden max-lines suppression ratchet

* chore: refresh max-lines baseline

* fix: close max-lines ratchet bypasses

* fix: derive ratchet base from PR merge tree

* fix: support older Git in staged ratchet

* fix: align max-lines declarations and baseline

* chore: refresh max-lines baseline for current main

* fix: exclude generated wizard locales from max-lines

* chore: prune resolved max-lines debt
2026-07-14 09:27:02 -07:00
Peter Steinberger eb7e32d2a2 refactor(llm): parse retry units with ms 2026-07-14 01:23:46 -07:00
Peter Steinberger e2ec8283c4 refactor(deadcode): trim mid-size src exports (#105888)
* refactor(deadcode): trim auto-reply and CLI exports

* refactor(deadcode): trim cron and task exports

* refactor(deadcode): trim fleet and process exports

* test(deadcode): exercise live task and process seams

* test(fleet): cover stream redaction through owner module

* refactor(security): trim dead internal exports

* refactor(secrets): trim dead internal exports

* refactor(deadcode): trim remaining src exports

* refactor(deadcode): remove test-only runtime exports

* refactor(deadcode): trim pairing test exports

* refactor(deadcode): reconcile refreshed baseline

* test(auto-reply): deduplicate queue state imports
2026-07-13 00:42:56 -07:00
destire-mio ca90a59370 fix(retry): avoid status code substring matches (#105258)
* fix(retry): avoid status code substring matches

* fix(retry): parse leading HTTP statuses

* style(retry): format status classifier

* test(retry): cover session retry behavior

* test(retry): emit error stream events

* fix(retry): share rate-limit window classification

Co-authored-by: destire-mio <248462155+destire-mio@users.noreply.github.com>

* docs(changelog): note session retry fix

Co-authored-by: destire-mio <248462155+destire-mio@users.noreply.github.com>

* refactor(retry): keep window type internal

Co-authored-by: destire-mio <248462155+destire-mio@users.noreply.github.com>

---------

Co-authored-by: destire-mio <248462155+destire-mio@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-12 12:12:32 -07:00
Peter Steinberger 6b95f98fe7 fix(core): make indexed access explicit across remaining src (NUIA phase 3b) (#104773)
* fix(core): make indexed access explicit in auto-reply, infra, and config

Part 1/3 of the src NUIA phase-3b burn-down (#104600): iteration and
destructuring over index reads, boundary guards on parsed input, and
named invariants. Config path walkers bind the path head once; SQLite
migration key handling is hoisted without query-shape changes.

* fix(core): make indexed access explicit in cli, gateway, commands, security, shared

Part 2/3: argv/token selection restructured, gateway event/attachment
invariants named, security parsers stay fail-closed (invariant
violations throw), edit-distance matrices access checked entries.

* fix(core): make indexed access explicit across remaining src surfaces

Part 3/3: channels, plugins, process, cron, plugin-sdk, media, logging,
tui, hooks, daemon, and small directories. Latent bug fixed: a tailnet
resolver could leak undefined through a string|null contract and now
fails with a descriptive local error.

* fix(core): keep optional boundaries optional after per-commit review

Review findings: expectDefined misused where absence is a legitimate
state. CLI --profile/route-args missing next tokens take their existing
miss paths; help normalization compares --help against the last
positional again; first-time plugin install spreads absent cfg.plugins;
denylist scan iterates manifest dependency entries instead of throwing
on omitted sections; tailnet resolver returns a guaranteed string at
the source instead of a caller-side undefined throw.

* refactor(core): closed-key provider labels and honest optional passthroughs

PROVIDER_LABELS becomes a satisfies-typed closed record (static reads
provably defined; dynamic lookups go through providerUsageLabel with
honest string|undefined). Status-scan overview passes its optional
params through unchanged instead of asserting them.

* fix(channels): make getChatChannelMeta honestly optional

The original signature claimed ChatChannelMeta while leaking undefined
on bundled channel id metadata drift; three of four callers already
handled absence. The return type now says so, and the one assuming
caller falls back to the raw channel label.

* fix(core): index-safety for post-rebase main drift

Covers the sqlite-sessions flip and auth-source-plan code that landed
mid-phase, plus the channel-validation test consuming the now honestly
optional getChatChannelMeta.

* refactor(channels): split chat-meta accessors along the SDK contract

getChatChannelMeta keeps its shipped plugin-SDK signature (defined for
bundled ids, fail-loud on impossible misses); new findChatChannelMeta
carries the drift-tolerant optional contract for core auto-enable and
formatting paths.

* fix(qa-channel): own channel metadata instead of a guaranteed-undefined catalog lookup

qa-channel spread getChatChannelMeta over an id that is never in the
bundled catalog, shipping an empty setup meta by accident; the fail-loud
SDK accessor exposed it. The channel now declares its metadata once.

* fix(gateway): heartbeat projection lookahead is optional at the transcript tail

expectDefined wrapped messages[i + 1] whose absence on the final message
is the normal case; the adjacent ternary already handled it. Restores
the plain optional read with an explicit guard in the pair condition.

* fix(plugin-sdk): channel plugin factory tolerates non-bundled channel ids again

createChannelPluginBase spreads bundled catalog meta for ANY channel id,
where absence is the normal case for external plugins; the resolver is
honestly optional again while the exported bundled-id accessor keeps the
fail-loud contract.

* fix(core): spreads of optional config sections stay optional

Fresh-setup and first-install paths (crestodian setup inference, hook
installs, agent config base, target agent models) legitimately lack the
section being rebuilt; spreading undefined is the shipped {} semantics.
Removes the remaining gratuitous assertion wraps found by tree audit.
2026-07-11 20:47:34 -07:00
Peter Steinberger 8310c565e0 feat(onboarding): add provider sign-in (#104502)
* feat(onboarding): add provider sign-in flows

* fix(oauth): keep callback compatibility

* fix(onboarding): reconcile lost auth outcomes

* fix(onboarding): lock auth cancellation at commit

* fix(onboarding): close provider auth lifecycle gaps

* fix(onboarding): make terminal auth failures dismissable

* fix(onboarding): satisfy native app checks

* fix(onboarding): reconcile absent auth sessions

* fix(onboarding): bound provider auth sessions

* fix(onboarding): open provider auth links safely

* test(onboarding): use scanner-safe auth fixtures

* revert: keep established onboarding auth fixtures

* fix(onboarding): close provider auth cancellation gaps

* fix(gateway): retain uncollected wizard results

* fix(onboarding): bind provider reconciliation attempt

* fix(i18n): avoid guessing moved string identities

* style(onboarding): normalize remote auth choices efficiently

* fix(protocol): refresh optional provider auth choices

* test(gateway): cover provider auth dispatch order

* refactor(macos): split onboarding setup support

* fix(macos): refresh merged native checks
2026-07-11 13:00:17 -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 fa77fe10d5 chore: migrate active GPT-5.5 references to GPT-5.6 (#104452)
* chore(models): migrate active GPT-5.5 references

* test(workboard): expect GPT-5.6 Sol default

* chore: keep release notes in PR body

* test(models): align picker fixtures with Sol default

* test: update PDF default model expectation

* test(qa): migrate thinking smoke to Luna

* test(gateway): align mock catalog with Sol default

* ci: retrigger exact-head PR checks

* test(gateway): document default catalog invariant
2026-07-11 06:30:57 -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
JC 59e95fe3fd feat: support GPT-5.6 Ultra across OpenClaw and Codex runtimes (#98021)
* feat: support GPT-5.6 Ultra across agent runtimes

Co-authored-by: J Cai <anyech@gmail.com>

* fix: keep harness projections discovery-free

* fix(codex): mirror V2 native subagent tasks

* chore: refresh plugin SDK surface budgets

* test: expose Ultra wire effort proof

* test(cron): avoid hoisted mock initialization race

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-10 15:23:24 +01:00
ZOOWH 6b90610cdb fix(copilot): redact OAuth error response body in fetchJson error messages (#102953)
* fix(copilot): redact OAuth error response body in fetchJson error messages

Replace raw response body text with bounded, redacted structured error detail
extracted via extractProviderErrorDetail so OAuth error responses containing
tokens, device codes, or other sensitive fields are not leaked into Error
messages and downstream logs.

* test(copilot): add device-code and non-JSON error body redaction cases

Add regression tests covering the device code flow and non-JSON error
bodies alongside the existing token refresh coverage. Also include live
proof output showing real Response object redaction via
extractProviderErrorDetail.

Ref: #102953

* fix(copilot): normalize OAuth HTTP failures

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-10 03:15:29 +01:00
Qiong ef53c20497 fix(oauth): remove base64 obfuscation from public OAuth client IDs (#96537) 2026-07-09 16:45:03 +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
Peter Steinberger 5ed8b81af7 fix(llm): project schema custom tools as functions (#101443) 2026-07-07 08:12:43 +01:00
Peter Lee 2b773a65f6 fix(anthropic): keep OAuth callback on loopback (#96917)
* fix(anthropic): restrict OAuth callback host to loopback addresses and derive redirect URI

* fix(anthropic): restore localhost as default OAuth callback host to match shipped behavior

* fix(anthropic): defer OAuth callback host validation to login path

* refactor(anthropic): bind callback host independently

Co-authored-by: xialonglee <li.xialong@xydigit.com>

* docs(changelog): note Anthropic callback fix

Co-authored-by: xialonglee <li.xialong@xydigit.com>

* fix(oauth): satisfy Anthropic callback lint

Co-authored-by: xialonglee <li.xialong@xydigit.com>

* chore: defer Anthropic OAuth changelog

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-06 02:52:15 +01:00
Peter Steinberger 1f484a8dbd test: speed up and stabilize full suite 2026-07-05 08:00:23 -04: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
Dallin Romney 6c53dfa1df refactor(infra): consolidate bounded HTTP body reads (#99744)
* refactor(infra): consolidate bounded HTTP body reads

* fix(plugin-sdk): preserve HTTP body export boundaries
2026-07-04 12:15:57 -07:00
Peter Steinberger 5ea80c8d80 fix: improve agent runtime correctness from upstream Pi (#99949)
* fix: improve agent runtime correctness

* test: track agent tool temp directories

* test: update helper routing expectation
2026-07-04 09:08:37 -04:00
Peter Steinberger 3706c2b3bd fix(anthropic): fall back to Claude Opus 4.8 when Fable 5 safety classifiers decline a request (#99906)
Claude Fable 5 requests on direct Anthropic API keys now opt into Anthropic's server-side fallback (server-side-fallback-2026-06-01): a safety-classifier decline is re-served by claude-opus-4-8 inside the same call instead of failing the turn with "LLM request failed.". Mid-stream boundaries drop the declined model's thinking/tool blocks per Anthropic's replay contract, keep the partial text as the continuation prefix, record a provider_fallback diagnostic, and cost the turn at the serving model's rates. Docs lead with the coupling: using Fable 5 means also using Opus 4.8. OAuth, proxies, Bedrock, Vertex, and Foundry requests are unchanged.

Live-verified: a benign reasoning_extraction classifier decline through the product path returns an Opus-served answer with the provider_fallback diagnostic; exact-head CI green (67 checks).

Related: #98976
2026-07-04 08:43:11 -04:00
wangmiao0668000666 f84bcdb4d7 fix(anthropic): wire buildGuardedModelFetch into the Cloudflare createClient branch (#98003)
* fix(anthropic): guard Cloudflare Anthropic fetches

Wire the Cloudflare AI Gateway Anthropic SDK client through buildGuardedModelFetch so this path gets the same SSRF and transport policy as sibling providers.

Keep the behavior proof focused on the regression: a Cloudflare Anthropic request pointed at a link-local address must fail before the SDK reaches global fetch.

* fix(anthropic): add loopback proof test to cloudflare fetch wiring

* test(anthropic-cloudflare): trim proof to SSRF-block only, remove synthetic loopback server
2026-07-03 13:17:28 +03:00
Dallin Romney 4f4e9a4c78 refactor(shared): consolidate core record guards (#99359) 2026-07-02 22:13:17 -07:00
Ayaan Zaidi a5bf55d690 refactor(agents): fold assistant string normalization into transcript ingest (#98908) 2026-07-01 22:44:02 -07:00
Onur Solmaz 530d576cc6 fix(agents): time out local streams without first event (#98525)
* fix(agents): time out streams without first event

* fix(agents): propagate first-event stream timeout

* fix(agents): abort streams on first-event timeout

* fix(agents): time out chatgpt websocket streams

* fix(agents): clamp first event stream timeouts

* fix(agents): keep first event timeout internal

* fix(agents): classify first event stream stalls as timeouts

* fix(agents): preserve provider first-event timeouts

* fix(agents): satisfy first-event timeout lint

* fix(agents): classify first-event stalls as idle timeouts

* test(tooling): include transcript store helper route
2026-07-01 23:01:46 +08:00
huangjianxiong 8abd5d4071 fix(tlon): bound error response body reads to prevent OOM (#98496)
* fix(tlon): bound error response body reads to prevent OOM

Replace bare response.text() on non-ok paths with readResponseTextLimited
capped at 16 KiB so a hostile or misconfigured Urbit ship cannot force the
gateway to buffer an arbitrary-size error body into process memory.

Affected paths:
- pokeUrbitChannel (channel-ops.ts)
- channel.runtime.ts poke path
- sendSubscription (sse-client.ts)

* fix(tlon): fix lint issues in error-body-boundary test

- Remove unused beforeEach import
- Wrap if/else bodies in braces (curly)
- Use block body for Promise executors (no-promise-executor-return)

* fix(types): resolve pre-existing TS test type errors

- Fix TS2493 tuple type errors in server-cron-notifications and
  server-cron tests by adding explicit type annotations on mock.calls
- Fix TS2322 in anthropic.test.ts by adding as const to resource
  content block type

* chore: trigger CI
2026-07-01 06:57:21 -07:00
Peter Steinberger aae1189d90 test: repair hosted CI baseline assertions (#98533) 2026-07-01 10:34:23 +01:00
snowzlmbot b63e06f68a fix(llm): preserve structured tool result replay
Preserve structured tool-result replay text across provider transports while keeping provider-facing redaction and Anthropic media ordering intact.

Thanks @snowzlmbot!
2026-06-30 23:44:02 -07:00
Peter Steinberger c52583a022 feat(openai): add GPT-5.6 series support (#98333)
* feat(openai): add GPT-5.6 series support

* docs: refresh map for GPT-5.6

* fix(openai): preserve GPT-5.6 thinking metadata

* fix(codex): sync managed app server version

* fix(codex): sync managed app server version

* fix(openai): account for GPT-5.6 cache writes

---------

Co-authored-by: Peter Steinberger <steipete@golden-gate.local>
2026-07-01 06:48:57 +01:00
sunlit-deng 70cc909eea fix(openrouter): send explicit auth headers (#98187)
* fix(openrouter): send explicit auth headers

* test(openrouter): type stream mock calls
2026-06-30 18:03:14 -07:00
solodmd b1fae752f8 fix(anthropic-oauth): bound OAuth token endpoint response reads (#96644)
postJson reads the Anthropic OAuth token endpoint response body with
an unbounded await response.text(). A compromised or hijacked OAuth
endpoint can stream an arbitrarily large body and force the runtime
to buffer the entire payload before parsing — an OOM/DoS vector.

Replace with readResponseWithLimit at 16 MiB cap + TextDecoder decode
to match the sibling bounded-read pattern (provider-http-errors.ts:308).

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-30 17:43:06 -07:00
wangmiao0668000666 ff820d3942 fix(openai-completions): bound SSE response reads via buildGuardedModelFetch
Rebased and narrowed to the current-main OpenAI completions guarded-fetch fix. Validation passed locally and GitHub checks were green before merge.
2026-06-28 21:28:27 -07:00
wangmiao0668000666 e4e4b0161f fix(mistral): bound streaming response bodies
Bounds Mistral SDK response streams at 16 MiB using the existing streaming byte guard.
2026-06-28 20:53:49 -07:00
wangmiao0668000666 66ffad1176 fix(azure-openai-responses): bound SSE response reads via buildGuardedModelFetch (#97349)
Inject buildGuardedModelFetch with resolved Azure base URL into both
SDK constructors (OpenAI and AzureOpenAI path) so Azure Responses
requests route through OpenClaw's guarded transport (SSRF policy,
timeout, retry limiting, SSE/JSON synthesis caps).

The non-OK response body cap is applied lazily inside the shared
sanitizeOpenAISdkSseResponse guard via TransformStream — closes the
unbounded response.text() OOM path for hostile 4xx/5xx responses
while preserving the OpenAI SDK's ability to cancel and retry.

- src/llm/providers/azure-openai-responses.ts: pass guardedFetch into
  both OpenAI and AzureOpenAI SDK constructors (no per-provider wrapper)
- src/agents/provider-transport-fetch.ts: add capNonOkResponseBodyLazily
  helper and wire into sanitizeOpenAISdkSseResponse for !response.ok
- src/agents/provider-transport-fetch.test.ts: 2 inline tests
  (cap fires + SDK cancel preserves source)

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-28 12:14:53 -07:00