refactor: extract reusable AI runtime package#99059
Conversation
Dependency GuardThis PR changes dependency-related files. Maintainers should confirm these changes are intentional. Changed files:
Maintainer follow-up:
|
Dependency graph changes notedThis PR includes dependency graph changes. The dependency guard is informational because the PR author is a repository admin or a member of
Security review is still recommended before merge when the dependency graph change is intentional. |
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8b820b4886
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| "@mistralai/mistralai": "2.2.5", | ||
| "@modelcontextprotocol/sdk": "1.29.0", | ||
| "@mozilla/readability": "0.6.0", | ||
| "@openclaw/ai": "workspace:*", |
There was a problem hiding this comment.
Regenerate the root shrinkwrap for the new runtime dependency
Adding @openclaw/ai to the root package makes it part of the published OpenClaw install, but npm-shrinkwrap.json was not updated and its root dependency map still has no @openclaw/ai entry. The repo’s pnpm check path runs deps:shrinkwrap:check, so this dependency change will leave CI/release validation failing until the root shrinkwrap is regenerated and committed.
Useful? React with 👍 / 👎.
|
Codex review: needs changes before merge. Reviewed July 5, 2026, 1:42 AM ET / 05:42 UTC. Summary Reproducibility: yes. for the review findings: current-head source inspection shows the Jiti plugin loader alias map omits Review metrics: 2 noteworthy metrics.
Stored data model Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Copy recommended automerge instructionNext step before merge
Security Review findings
Review detailsBest possible solution: Keep the extraction direction, but finish the package-boundary repair so source plugin loaders resolve Do we have a high-confidence way to reproduce the issue? Yes for the review findings: current-head source inspection shows the Jiti plugin loader alias map omits Is this the best way to solve the issue? No, not yet; the extraction direction matches the linked maintainer architecture issue, but this PR still needs source-loader alias coverage and a narrower helper/transport split before it is the best merge shape. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against c29054a7dc73. Label changesLabel changes:
Label justifications:
Evidence reviewedAcceptance criteria:
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
Review history (12 earlier review cycles; latest 8 shown)
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f3da91f256
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| getEnvApiKey, | ||
| parseStreamingJson, | ||
| sanitizeSurrogates, | ||
| } from "@openclaw/ai/internal/runtime"; |
There was a problem hiding this comment.
Teach source SDK loaders about @openclaw/ai
This new SDK import is reached when a local plugin loads openclaw/plugin-sdk/llm through the source root-alias/Jiti path, but src/plugin-sdk/root-alias.cjs only aliases plugin-sdk subpaths and @openclaw/llm-core back to source. In an unbuilt source checkout, @openclaw/ai/internal/runtime falls through to the workspace package's exports target under packages/ai/dist/internal/*.mjs, which does not exist until a build, so plugin dev/test loads of this public SDK subpath fail unless the @openclaw/ai public and internal subpaths are added to the same source alias/native-resolver maps.
Useful? React with 👍 / 👎.
|
Merged via squash.
|
Closes #99040
What Problem This Solves
OpenClaw's model protocol adapters and streaming registry were embedded in the main application, so other packages could not reuse the proven Anthropic, OpenAI, Azure OpenAI, Google, Vertex, Mistral, and ChatGPT/Codex transports without taking on OpenClaw's application runtime.
Why This Change Was Made
This extracts one public package:
@openclaw/ai. It contains the provider-neutral model/message/tool contracts, validation, diagnostics, event streams, isolated runtime registry, and lazy provider adapters.packages/llm-coreremains a private implementation package and is bundled into@openclaw/ai; consumers never install or publish a second OpenClaw AI package.The package is genuinely self-contained. Pure transport helpers that previously lived in application code (tool projections and strict-schema normalization, system-prompt cache boundary, stream first-event timeout, streaming byte guard, deferred event buffer, Anthropic model contract/refusal/auth-header helpers, OpenAI reasoning-effort and responses-stream compat, reasoning-tag text partitioner, LLM request activity) moved into
packages/ai;utf16-slicemoved into@openclaw/normalization-core. Host policy stays in OpenClaw and is injected through a narrowAiTransportHostport (configureAiTransportHost): guarded model fetch (SSRF policy), secret redaction for tool-result replay, OpenAI strict-tool defaults, and diagnostics logging. Library defaults are inert;src/llm/stream.tsinstalls OpenClaw's implementations. There are no relative imports from the package back intosrc/.The public barrel is instance-first:
createApiRegistry()/createLlmRuntime()plus contracts and the host port. The process-default registry/runtime and their bound helpers moved behind@openclaw/ai/internal/*, which exists for OpenClaw itself and carries no semver guarantee (documented in the README).registerBuiltInApiProviders(registry)takes an explicit registry. Built-in provider registration is table-driven, replacing ~420 lines of per-provider boilerplate.OpenClaw consumes
@openclaw/aias a normal workspace dependency, whichpnpm packconverts to the exact release version. Runtime stream construction resolves through@openclaw/ai/event-stream, preserving oneEventStreamconstructor identity across OpenClaw, agent-core, and external consumers. The release workflow packs, verifies, and publishes@openclaw/aibefore the root package, andpackages/ainow ships its ownnpm-shrinkwrap.jsonso its transitive dependency tree stays pinned at user install time even though workspace deps are omitted from the root shrinkwrap.User Impact
Existing OpenClaw users should see no configuration, model selection, authentication, or streaming behavior change. Installing
openclawinstalls the exact@openclaw/airelease automatically, with the AI package's dependency tree pinned by its own shrinkwrap. Library consumers can depend on the one package, create isolated runtimes, and opt into the eight built-in API adapters without inheriting a mutable process-global registry.Evidence
pnpm buildpassed end to end: package declarations, root bundle, CLI/bootstrap guards, runtime postbuild, plugin SDK export check, and Control UI build.pnpm tsgoandpnpm check:test-typespass; thetsdown.config.tsdts.neverBundleoption was moved to its correctdeps.dtshome (the previous placement was a type error that brokecheck-test-typeson CI).checks-node-compact-*CI failures (Cannot find module @openclaw/ai/dist/providers.mjs) were root-caused to three Node-side alias tables that only knew@openclaw/llm-core:src/plugin-sdk/root-alias.cjs,src/plugins/plugin-sdk-native-resolver.ts, andsrc/plugins/sdk-alias.ts. All now cover the@openclaw/aiexport map (and the newnormalization-core/utf16-slicesubpath); the previously failing tests (models-config.applies-config-env-vars,model-selection) pass locally.check-dependencies(knip) is clean:packages/aideclares only its six real runtime deps (Anthropic/OpenAI/Google/Mistral SDKs, partial-json, typebox); orphaned root deps (@mistralai/mistralai,partial-json) removed; knip config knows the new package's entry points.node scripts/run-vitest.mjs: all ofpackages/ai,src/llm,packages/agent-core,packages/normalization-core, transport streams, model selection/config, custom API registry, and the host-port integration proofs (SSRF fetch-proof, redaction contract, OpenAI-compatible auth) — 869 tests, 0 failures.pnpm check:changedrun over the full branch diff.examples/ai-chatis a minimal external-consumer app that uses only the public package surface against the built dist (isolated runtime + built-in provider registration + one streamed completion). Live-verified end to end against a local Ollama server through the OpenAI-completions transport: streamed text deltas,stop=stop, token usage reported.