Skip to content

feat(chutes): add OAuth and API key authentication for Chutes provider#41416

Closed
Veightor wants to merge 25 commits intoopenclaw:mainfrom
chutesai:feat/chutes-provider-integration
Closed

feat(chutes): add OAuth and API key authentication for Chutes provider#41416
Veightor wants to merge 25 commits intoopenclaw:mainfrom
chutesai:feat/chutes-provider-integration

Conversation

@Veightor
Copy link
Copy Markdown

@Veightor Veightor commented Mar 9, 2026

Summary

  • Problem: Chutes.ai was only accessible via OAuth in OpenClaw, blocking users with plain API keys from connecting; the OAuth flow also failed to register provider models in the config after auth completed, leaving the model picker empty.
  • Why it matters: API key auth is the primary onboarding path for most developer users; without it, Chutes is gated behind browser OAuth. The missing model registration meant even OAuth users saw no Chutes models after setup.
  • What changed: Added a chutes-api-key auth choice alongside existing OAuth; wired both paths through a shared applyChutesConfig / applyChutesProviderConfig helper that registers the static model catalog and sets the default model. Added buildChutesProvider (dynamic model discovery) and CHUTES_OAUTH_MARKER to align with the existing implicit-provider loader pattern used by all other providers.
  • What did NOT change: No changes to Chutes OAuth login flow itself, no changes to any other provider, no gateway/routing changes.

Change Type (select all)

  • Bug fix (OAuth config not being applied after auth)
  • Feature (API key auth path)

Scope (select all touched areas)

  • Auth / tokens
  • Integrations
  • API / contracts

Linked Issue/PR

User-visible / Behavior Changes

  • New option Chutes API key appears in the auth provider list during openclaw onboard
  • After Chutes OAuth completes, the model picker now shows Chutes models pre-selected (previously models were not registered)
  • CHUTES_API_KEY environment variable is now recognized for implicit provider auto-discovery

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? YesCHUTES_API_KEY is now stored via the existing credential store, same as all other API key providers; the CHUTES_OAUTH_MARKER sentinel follows the same pattern as MINIMAX_OAUTH_MARKER / QWEN_OAUTH_MARKER
  • New/changed network calls? YesbuildChutesProvider calls https://llm.chutes.ai/v1/models for dynamic model discovery (same endpoint the existing OAuth path already calls; falls back to static catalog on failure)
  • Command/tool execution surface changed? No
  • Data access scope changed? No

Repro + Verification

Environment

  • OS: macOS 15
  • Runtime/container: Node 22 / Bun
  • Model/provider: Chutes
  • Integration/channel: any
  • Relevant config: models.providers.chutes

Steps

API key path:

  1. openclaw onboard → choose Chutes API key
  2. Paste a Chutes API key from https://chutes.ai/settings/api-keys
  3. Complete onboarding

OAuth path:

  1. openclaw onboard → choose Chutes (OAuth)
  2. Complete browser OAuth flow

Expected

  • Provider is registered with model catalog
  • Default model is set to chutes/zai-org/GLM-4.7-TEE
  • openclaw channels status --probe shows Chutes provider active

Actual

  • Same as expected (both paths verified)

Evidence

  • src/agents/chutes-models.test.ts: 139 lines of tests covering model discovery, fallback to static catalog, and model definition building
  • Lint passes clean (pnpm check: 0 errors, 0 warnings)

Human Verification (required)

  • Verified scenarios: OAuth flow registers models + sets default; API key flow stores credential and registers models
  • Edge cases checked: OAuth with setDefaultModel=false (uses applyChutesProviderConfig not applyChutesConfig); missing/expired API key falls back to static catalog
  • What you did not verify: Windows and Linux runtime; live Chutes API call with a real production key end-to-end

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? YesCHUTES_API_KEY is now auto-detected from the environment (new implicit provider behavior)
  • Migration needed? No

Failure Recovery (if this breaks)

  • How to disable/revert this change quickly: remove chutes from models.providers in ~/.openclaw/config.json; the CHUTES_API_KEY env var being absent will prevent auto-discovery
  • Files/config to restore: src/agents/chutes-models.ts, src/agents/model-auth-markers.ts, src/agents/models-config.providers.discovery.ts, src/agents/models-config.providers.ts
  • Known bad symptoms: if Chutes models don't appear after onboard, check openclaw channels status --probe for provider registration errors

Risks and Mitigations

  • Risk: Dynamic model discovery call adds a network dependency at onboarding time
    • Mitigation: buildChutesProvider falls back to the static CHUTES_MODEL_CATALOG on any fetch error — onboarding never fails due to a Chutes API outage

Veightor added 15 commits March 5, 2026 21:40
- Correct chutes-fast alias to point to a valid model (GLM-4.7-FP8)
- Align setChutesApiKey signature with other providers (accept SecretInput)
- Use maybeSetResolvedApiKey in non-interactive Chutes onboarding
- Fix test mock data to match ChutesModelEntry API shape

Made-with: Cursor
…t detections)

- Fix Feishu media download/upload type errors by removing redundant timeout parameter (handled by client)
- Add 'pragma: allowlist secret' to false-positive test tokens and translations

Made-with: Cursor
Replace complex state-mutation helper with direct applyChutesConfig call after OAuth success, matching the pattern used by the API key flow. This reliably sets the Chutes default model so the model picker shows a Chutes model as current instead of falling back to the previous anthropic default.

Made-with: Cursor
The timeout parameter was removed from the source code in a previous commit
because it was causing type errors with the SDK, but the tests were not updated.
This brings the tests in sync with the source.

Made-with: Cursor
Conflict resolutions:
- src/secrets/target-registry-pattern.ts: adopt upstream's named-variable
  style for sibling_ref check; preserve pragma allowlist comment
- extensions/feishu/src/media.test.ts: keep upstream's
  expectMediaTimeoutClientConfigured() and add PR's imageCreateMock
  assertion for image_type: "message" verification
- src/agents/models-config.providers.ts: adopt upstream's refactored
  provider-loader pattern (SIMPLE/PROFILE_IMPLICIT_PROVIDER_LOADERS);
  wire Chutes into both API-key (withApiKey) and OAuth profile
  (withProfilePresence) loader slots using buildChutesProvider from
  models-config.providers.discovery.ts

Supporting changes to integrate Chutes into the new architecture:
- src/agents/models-config.providers.discovery.ts: add buildChutesProvider
  (dynamic model discovery via discoverChutesModels with access token)
- src/agents/model-auth-markers.ts: add CHUTES_OAUTH_MARKER and register
  it in isNonSecretApiKeyMarker

Made-with: Cursor
@openclaw-barnacle openclaw-barnacle Bot added cli CLI command changes commands Command implementations agents Agent runtime and tooling channel: feishu Channel integration: feishu size: L labels Mar 9, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Mar 9, 2026

Greptile Summary

This PR adds Chutes API key authentication alongside the existing OAuth flow, and fixes a bug where Chutes OAuth didn't register provider models in the config. The new chutes-api-key auth choice, buildChutesProvider, applyChutesConfig/applyChutesProviderConfig, and CHUTES_OAUTH_MARKER follow the existing implicit-provider pattern used by MiniMax and Qwen.

Key findings:

  • Bug (logic): applyChutesConfig sets chutes/Qwen/Qwen3-32B as the imageModel fallback, but this model is declared text-only (input: ["text"]) in CHUTES_MODEL_CATALOG. If the primary image model becomes unavailable, routing to this fallback will fail at inference time.
  • Cache bypass on failure (style): discoverChutesModels only populates cachedModels on the happy path. Non-OK responses, empty API data, and caught exceptions all return the static catalog without setting the cache, so every call within the 5-minute TTL window will still attempt a network request on degraded API scenarios.
  • Widened onboarding.ts prompt condition (style): Adding || flow === "advanced" to the model-picker guard triggers the interactive promptDefaultModel prompt in the advanced flow even when authChoiceFromPrompt is false (e.g. auth supplied via CLI flag). This is out of scope for the Chutes feature and could block non-interactive advanced-flow invocations; the authChoice !== "skip" addition alone would have been sufficient to fix the stated bug.

Confidence Score: 3/5

  • Safe to merge after fixing the text-only model used as the image fallback; the other two issues are non-blocking but should be addressed.
  • The core API key and OAuth flows are well-structured and follow existing provider patterns with good test coverage. However, the imageModel fallback referencing a text-only model is a functional bug that would silently fail for vision tasks. The cache not persisting on fallback paths and the broadened onboarding prompt condition are lower-severity but represent unintended behavior changes.
  • src/commands/onboard-auth.config-core.ts (imageModel fallback) and src/wizard/onboarding.ts (widened prompt condition) need attention before merge.

Last reviewed commit: 106db9b

Comment thread src/commands/onboard-auth.config-core.ts Outdated
Comment thread src/agents/chutes-models.ts
Comment thread src/wizard/onboarding.ts Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 106db9b59e

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/agents/models-config.providers.ts Outdated
Comment thread src/agents/chutes-models.ts Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 176abe4762

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/agents/models-config.providers.ts Outdated
Comment thread src/agents/chutes-models.ts Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1d7d043b01

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/agents/models-config.providers.ts Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 268a5f5997

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +157 to +160
"chutes-api-key": {
provider: "chutes",
profileId: "chutes:default",
expectedProviders: ["chutes"],
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Map chutes token-provider alias to chutes API-key flow

The new chutes-api-key branch exists, but the apiKey alias remap table still has no chutes entry, so --auth-choice apiKey --token-provider chutes --token ... never reaches this new flow and falls through without applying Chutes auth/config. This regresses the existing token-provider alias onboarding pattern that already works for other providers in this same function.

Useful? React with 👍 / 👎.

Comment thread src/agents/models-config.providers.ts Outdated
Comment on lines +560 to +562
const oauthProfileId = listProfilesForProvider(ctx.authStore, "chutes").find(
(id) => ctx.authStore.profiles[id]?.type === "oauth",
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Select OAuth profile by configured order before discovery

This loader picks the first Chutes OAuth profile by raw store iteration order and uses its access token for model discovery, which can choose a stale or non-preferred account when multiple OAuth profiles exist. In that case, discovered models may come from the wrong account (or degrade to public-only on 401) even if a different profile is configured as preferred; this should resolve OAuth profile choice via auth ordering/eligibility rather than first match.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9d3eb3b3f5

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +168 to +171
"chutes-api-key": {
provider: "chutes",
profileId: "chutes:default",
expectedProviders: ["chutes"],
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Add chutes alias to apiKey token-provider remap

This commit adds a "chutes-api-key" flow, but --auth-choice apiKey --token-provider chutes --token ... still cannot reach it because the API_KEY_TOKEN_PROVIDER_AUTH_CHOICE remap table has no chutes entry. In that path, authChoice remains "apiKey", Anthropic handling exits early for non-Anthropic providers, and no later branch applies Chutes credentials/config, so onboarding silently skips the requested provider setup.

Useful? React with 👍 / 👎.

@Veightor Veightor requested a review from a team as a code owner March 17, 2026 14:02
@openclaw-barnacle openclaw-barnacle Bot added app: web-ui App: web-ui and removed cli CLI command changes labels Mar 17, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 033fb8b590

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@@ -0,0 +1,12 @@
{
"name": "@openclaw/chutes-provider",
"version": "2026.3.17",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep bundled plugin version in sync with root version

Set this new extension package version to the repository release base version (2026.3.14 in this commit) instead of 2026.3.17; scripts/release-check.ts validates that every extensions/*/package.json version normalizes to the root package version, so this mismatch will make pnpm release:check fail and block release publishing.

Useful? React with 👍 / 👎.

@steipete
Copy link
Copy Markdown
Contributor

Taking this over. We recently moved main over to be plugin-based, so converting this to a plugin

steipete added a commit that referenced this pull request Mar 17, 2026
* refactor: generalize bundled provider discovery seams

* feat: land chutes extension via plugin-owned auth (#41416) (thanks @Veightor)
@steipete
Copy link
Copy Markdown
Contributor

Superseded by merged #49136.

Your original branch was not maintainer-editable (maintainerCanModify: false), so I rebuilt the PR on a maintainer branch, kept the changes split into two commits, and landed that instead.

Thanks @Veightor.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 84f40eb1f2

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

* so the gateway injects the stored access token at request time.
*/
async function resolveCatalog(ctx: ProviderCatalogContext) {
const { apiKey, discoveryApiKey } = ctx.resolveProviderApiKey(PROVIDER_ID);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Prefer CHUTES_API_KEY when both Chutes env vars are set

This catalog resolver delegates auth selection to ctx.resolveProviderApiKey("chutes"), which currently follows PROVIDER_AUTH_ENV_VAR_CANDIDATES where CHUTES_OAUTH_TOKEN is checked before CHUTES_API_KEY (src/secrets/provider-env-vars.ts). In environments that keep both variables (for example, a stale OAuth token plus a valid API key after migration), the plugin will bind to the OAuth token and ignore the API key, causing authenticated Chutes calls to fail even though a valid key is present.

Useful? React with 👍 / 👎.

Comment on lines +27 to +29
models["chutes-fast"] = { alias: "chutes/zai-org/GLM-4.7-FP8" };
models["chutes-vision"] = { alias: "chutes/chutesai/Mistral-Small-3.2-24B-Instruct-2506" };
models["chutes-pro"] = { alias: "chutes/deepseek-ai/DeepSeek-V3.2-TEE" };
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve existing Chutes shortcut aliases during re-onboard

These assignments unconditionally reset chutes-fast, chutes-vision, and chutes-pro, so rerunning Chutes onboarding overwrites any user-customized aliases in agents.defaults.models. Other provider onboard helpers in this repo generally preserve existing alias values with ??; this regression makes repeated onboarding destructive for users who tuned these shortcuts.

Useful? React with 👍 / 👎.

nikolaisid pushed a commit to nikolaisid/openclaw that referenced this pull request Mar 18, 2026
* refactor: generalize bundled provider discovery seams

* feat: land chutes extension via plugin-owned auth (openclaw#41416) (thanks @Veightor)
ralyodio pushed a commit to ralyodio/openclaw that referenced this pull request Apr 3, 2026
* refactor: generalize bundled provider discovery seams

* feat: land chutes extension via plugin-owned auth (openclaw#41416) (thanks @Veightor)
juancatorr added a commit to juancatorr/openclaw that referenced this pull request Apr 8, 2026
* refactor(slack): share setup wizard base

* refactor(discord): share setup wizard base

* refactor(signal): reuse shared setup security

* refactor(imessage): reuse shared setup security

* refactor(setup): reuse patched adapters across channels

* refactor(imessage): share setup status base

* refactor(slack): share token credential setup

* refactor(setup): share env-aware patched adapters

* refactor(discord): use shared plugin base

* refactor(outbound): share base session helpers

* refactor(whatsapp): reuse login tool implementation

* refactor(providers): reuse simple api-key catalog helper

* refactor(plugins): share bundle path list helpers

* refactor(slack): reuse shared action adapter

* refactor(tts): share provider readiness checks

* refactor(plugins): share claiming hook loop

* refactor(plugins): share install target flow

* refactor(status): share scan helper state

* refactor(usage): share legacy pi auth token lookup

* refactor(device): share missing-scope helper

* refactor(config): share schema lookup helpers

* fix(plugin-sdk): restore core export boundary

* build: tighten lazy runtime boundaries

* fix(gateway): surface env override keys in exec approvals

* Agents: move bootstrap warnings out of system prompt (openclaw#48753)

Merged via squash.

Prepared head SHA: dc1d4d0
Co-authored-by: scoootscooob <167050519+scoootscooob@users.noreply.github.com>
Reviewed-by: @scoootscooob

* refactor: dedupe channel entrypoints and test bridges

* style: fix rebase formatting drift

* fix: resolve rebase type fallout in channel setup seams

* fix(macos): block canvas symlink escapes

* refactor: bundle lazy runtime surfaces

* fix: remove discord setup rebase marker

* docs(gateway): clarify URL allowlist semantics

* docs(changelog): restore 2026.2.27 heading

* fix: unblock full gate

* fix: stabilize full gate

* test: cover invalid main job store load

* build(test): ignore vitest scratch root

* refactor: dedupe bundled plugin entrypoints

* docs: add context engine documentation

Add dedicated docs page for the pluggable context engine system:
- Full lifecycle explanation (ingest, assemble, compact, afterTurn)
- Legacy engine behavior documentation
- Plugin engine authoring guide with code examples
- ContextEngine interface reference table
- ownsCompaction semantics
- Subagent lifecycle hooks (prepareSubagentSpawn, onSubagentEnded)
- systemPromptAddition mechanism
- Relationship to compaction, memory plugins, and session pruning
- Configuration reference and tips

Also:
- Add context-engine to docs nav (Agents > Fundamentals, after Context)
- Add /context-engine redirect
- Cross-link from context.md and compaction.md

* docs: add plugin installation steps to context engine page

Show the full workflow: install via openclaw plugins install,
enable in plugins.entries, then select in plugins.slots.contextEngine.
Uses lossless-claw as the concrete example.

* docs: address review feedback on context-engine page

- Rename 'Method' column to 'Member' with explicit Kind column since
  info is a property, not a callable method
- Document AssembleResult fields (estimatedTokens, systemPromptAddition)
  with types and optionality
- Add lifecycle timing notes for bootstrap, ingestBatch, and dispose
  so plugin authors know when each is invoked

* docs: fix context engine review notes

* fix: harden telegram and loader contracts

* refactor(tests): share setup wizard prompter

* refactor(telegram-tests): share native command helpers

* fix(telegram-tests): load plugin mocks before commands

* refactor(telegram-tests): share webhook settlement helper

* refactor(nextcloud-tests): share inbound authz setup

* refactor(feishu-tests): share card action event builders

* refactor(runtime-tests): share typing lease assertions

* refactor(hook-tests): share subagent hook helpers

* refactor(provider-tests): share discovery catalog helpers

* refactor(command-tests): share workspace harness

* refactor(contracts): share session binding assertions

* refactor(plugin-tests): share interactive dispatch assertions

* refactor(plugin-tests): share binding approval resolution

* refactor(usage-tests): share provider usage loader harness

* refactor(bundle-tests): share bundle mcp fixtures

* refactor(provider-tests): share codex catalog assertions

* refactor(apns-tests): share relay push params

* refactor(media-tests): share telegram redaction assertion

* refactor(heartbeat-tests): share seeded heartbeat run

* refactor(kilocode-tests): share reasoning payload capture

* refactor(kilocode-tests): share extra-params harness

* refactor(kilocode-tests): share cache retention wrapper

* refactor(attempt-tests): share wrapped stream helper

* refactor(payload-tests): share empty payload assertion

* Telegram: fix named-account DM topic session keys (openclaw#48773)

* refactor(compaction-tests): share aggregate timeout params

* refactor(compaction-tests): share snapshot assertions

* refactor(truncation-tests): share first tool result text helper

* refactor(system-prompt-tests): share session setup helper

* refactor(lanes-tests): share table-driven assertions

* refactor(google-tests): share schema tool fixture

* refactor(extension-tests): share safeguard factory setup

* refactor(openrouter-tests): share state dir helper

* refactor(thinking-tests): share assistant drop helper

* refactor(kilocode-tests): share eligibility assertions

* refactor(payload-tests): share empty payload helper

* refactor(model-tests): share template model mock helper

* refactor(image-tests): share empty prompt image assertions

* fix: restore full gate

* refactor: consolidate lazy runtime surfaces

* refactor: remove remaining extension core imports

* refactor(payload-tests): reuse empty payload helper

* refactor(image-tests): share empty ref assertions

* refactor(image-tests): share single-ref detection helper

* refactor(image-tests): share ref count assertions

* refactor(history-tests): share array content assertion

* refactor(runs-tests): share run handle factory

* refactor(skills-tests): share bundled diffs setup

* refactor(payload-tests): share single payload summary assertion

* refactor(payload-tests): table-drive recoverable tool suppressions

* refactor(payload-tests): table-drive sessions send suppressions

* refactor(history-tests): share pruned image assertions

* refactor(failover-tests): share observation base

* refactor(extension-tests): share safeguard runtime assertions

* fix(ci): quote changed extension matrix input

* refactor: split plugin testing seam from bundled extension helpers

* test: fix discord provider helper import

* Changelog: add Telegram DM topic session-key fix

* fix(ci): harden zizmor workflow diffing

* feat(image-generation): add image_generate tool

* test(image-generation): add live variant coverage

* docs(image-generation): remove nano banana stock docs

* fix(ci): restore local check suite

* chore: sync pnpm lockfile importers

* fix(ui): restore control-ui query token compatibility (openclaw#43979)

* fix(ui): restore control-ui query token imports

* chore(changelog): add entry for openclaw#43979 thanks @stim64045-spec

---------

Co-authored-by: 大禹 <dayu@dayudeMac-mini.local>
Co-authored-by: Val Alexander <bunsthedev@gmail.com>
Co-authored-by: Val Alexander <68980965+BunsDev@users.noreply.github.com>

* fix: update macOS node service to use current CLI command shape (closes openclaw#43171) (openclaw#46843)

Merged via squash.

Prepared head SHA: dbf2edd
Co-authored-by: Br1an67 <29810238+Br1an67@users.noreply.github.com>
Co-authored-by: ImLukeF <92253590+ImLukeF@users.noreply.github.com>
Reviewed-by: @ImLukeF

* fix(macos): stop relaunching the app after quit when launch-at-login is enabled (openclaw#40213)

Merged via squash.

Prepared head SHA: c702d98
Co-authored-by: stablegenius49 <259448942+stablegenius49@users.noreply.github.com>
Co-authored-by: ImLukeF <92253590+ImLukeF@users.noreply.github.com>
Reviewed-by: @ImLukeF

* tests: add missing useNoBundledPlugins() to bundle MCP loader test

The "treats bundle MCP as a supported bundle surface" test was missing
the useNoBundledPlugins() call present in all surrounding bundle plugin
tests. Without it, loadOpenClawPlugins() scanned and loaded the full
real bundled plugins directory on every call (with cache:false), causing
excessive memory pressure and an OOM crash on Linux CI, which manifested
as the test timing out at 120s.

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

* fix ssh sandbox key cp (openclaw#48924)

Signed-off-by: sallyom <somalley@redhat.com>

* tests: fix googlechat outbound partial mock

* tests(google): inject oauth credential fs stubs

* tests(feishu): mock conversation runtime seam

* tests(feishu): inject client runtime seam

* tests(contracts): fix provider catalog runtime wiring (openclaw#49040)

* fix(plugins): forward plugin subagent overrides (openclaw#48277)

Merged via squash.

Prepared head SHA: ffa4589
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman

* fix(security): block JVM, Python, and .NET env injection vectors in host exec sandbox (openclaw#49025)

Add JAVA_TOOL_OPTIONS, _JAVA_OPTIONS, JDK_JAVA_OPTIONS, PYTHONBREAKPOINT, and
DOTNET_STARTUP_HOOKS to blockedKeys in the host exec security policy.

Closes openclaw#22681

* CI: rename startup memory smoke (openclaw#49041)

* CI: guard gateway watch against duplicate runtime regressions (openclaw#49048)

* fix(hooks): pass sessionFile and sessionKey in after_compaction hook (openclaw#40781)

Merged via squash.

Prepared head SHA: 11e85f8
Co-authored-by: jarimustonen <1272053+jarimustonen@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman

* refactor: expose lazy runtime helper to plugins

* refactor: align telegram test support with plugin runtime seam

* fix(tlon): defer DM cite expansion until after auth

* fix(context-engine): preserve legacy plugin sessionKey interop (openclaw#44779)

Merged via squash.

Prepared head SHA: e04c6fb
Co-authored-by: hhhhao28 <112874572+hhhhao28@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman

* test: harden CI-sensitive test suites

* test: remove repeated update module imports

* test: inline bluebubbles action mocks

* test: reuse subagent orphan recovery imports

* test: flatten twitch send mocks

* test: stabilize pdf tool runtime mocks

* test: reuse run-node module imports

* test: reuse git commit module exports

* test: trim redundant context engine assertions

* test: merge duplicate update cli scenarios

* test: preload plugin sdk subpath imports

* test: cache provider discovery fixtures

* test: merge context lookup warmup cases

* test: trim lightweight status and capability suites

* test: merge telegram action matrix cases

* test: merge embeddings provider selection cases

* test: preload inbound contract fixtures

* test: merge message action media sandbox cases

* test: merge pid alive linux stat cases

* test: merge tts config gating cases

* test: trim signal and slack action cases

* test: harden commands test module seams

* test: merge bundle loader fixture cases

* test: merge loader cache partition cases

* test: merge loader setup entry matrix

* test: merge discord audit allowlist cases

* test: merge zalouser audit group cases

* test: merge audit auth precedence cases

* test: merge channel command audit cases

* test: merge browser control audit cases

* test: merge control ui audit cases

* test: merge feishu audit doc cases

* test: merge hooks audit risk cases

* test: merge gateway http audit cases

* test: share audit exposure severity helper

* test: merge loader provenance path cases

* test: merge loader escape path cases

* test: merge loader alias resolution cases

* test: merge install metadata audit cases

* test: merge loader duplicate registration cases

* test: merge loader http route cases

* test: merge audit extension and workspace cases

* test: merge loader single-plugin registration cases

* test: merge loader precedence cases

* test: merge audit exposure heuristic cases

* test: merge loader workspace warning cases

* test: merge audit hooks ingress cases

* test: merge audit extension allowlist severity cases

* test: merge loader provenance warning cases

* test: merge loader bundled telegram cases

* test: merge loader memory slot cases

* test: merge loader scoped load cases

* test: merge audit gateway auth presence cases

* test: merge audit browser container cases

* test: merge audit windows acl cases

* test: merge audit deny command cases

* test: merge audit code safety failure cases

* test: merge loader cache miss cases

* test: merge update cli service refresh cases

* test: merge slack action mapping cases

* test: merge command owner gating cases

* test: merge update status output cases

* test: merge command gateway config permission cases

* test: merge command approval scope cases

* test: merge command hook cases

* test: merge command config write denial cases

* test: merge command allowlist add cases

* test: merge update cli service refresh behavior

* test: merge command owner show gating cases

* test: merge discord action listing cases

* test: merge signal reaction mapping cases

* test: merge discord reaction id resolution cases

* test: merge telegram reaction id cases

* test: merge audit resolved inspection cases

* test: merge audit gateway auth guardrail cases

* test: merge audit sandbox docker danger cases

* test: merge audit discord allowlist cases

* test: merge audit sandbox docker config cases

* test: merge audit browser sandbox cases

* test: merge audit allowCommands cases

* test: merge audit install metadata cases

* test: merge audit code safety cases

* test: merge audit dangerous flag cases

* test: merge audit trust exposure cases

* test: merge audit channel command hygiene cases

* test: merge slack validation cases

* test: merge update cli dry run cases

* test: merge update cli outcome cases

* test: merge update cli validation cases

* test: merge action media root cases

* test: merge update cli restart behavior cases

* test: merge update cli channel cases

* test: stabilize full gate

* feat(agents): infer image generation defaults

* docs(image-generation): document implicit tool enablement

* refactor: dedupe plugin lazy runtime helpers

* fix(telegram): persist sticky IPv4 fallback across polling restarts (fixes openclaw#48177) (openclaw#48282)

* fix(telegram): persist sticky IPv4 fallback across polling restarts (fixes openclaw#48177)

Hoist resolveTelegramTransport() out of createTelegramBot() so the
transport (and its sticky IPv4 fallback state) persists across polling
restarts. Previously, each polling restart created a new transport with
stickyIpv4FallbackEnabled=false, causing repeated IPv6 timeouts on
hosts with unstable IPv6 connectivity.

Changes:
- bot.ts: accept optional telegramTransport in TelegramBotOptions
- monitor.ts: resolve transport once before polling loop
- polling-session.ts: pass transport through to bot creation

AI-assisted (Claude Sonnet 4). Tested: tsc --noEmit clean.

* Update extensions/telegram/src/polling-session.ts

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* style: fix oxfmt formatting in bot.ts

* test: cover telegram transport reuse across restarts

* fix: preserve telegram sticky IPv4 fallback across polling restarts (openclaw#48282) (thanks @yassinebkr)

---------

Co-authored-by: Yassine <yassinebkr@users.noreply.github.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>

* ACP: harden startup and move configured routing behind plugin seams (openclaw#48197)

* ACPX: keep plugin-local runtime installs out of dist

* Gateway: harden ACP startup and service PATH

* ACP: reinitialize error-state configured bindings

* ACP: classify pre-turn runtime failures as session init failures

* Plugins: move configured ACP routing behind channel seams

* Telegram tests: align startup probe assertions after rebase

* Discord: harden ACP configured binding recovery

* ACP: recover Discord bindings after stale runtime exits

* ACPX: replace dead sessions during ensure

* Discord: harden ACP binding recovery

* Discord: fix review follow-ups

* ACP bindings: load channel snapshots across workspaces

* ACP bindings: cache snapshot channel plugin resolution

* Experiments: add ACP pluginification holy grail plan

* Experiments: rename ACP pluginification plan doc

* Experiments: drop old ACP pluginification doc path

* ACP: move configured bindings behind plugin services

* Experiments: update bindings capability architecture plan

* Bindings: isolate configured binding routing and targets

* Discord tests: fix runtime env helper path

* Tests: fix channel binding CI regressions

* Tests: normalize ACP workspace assertion on Windows

* Bindings: isolate configured binding registry

* Bindings: finish configured binding cleanup

* Bindings: finish generic cleanup

* Bindings: align runtime approval callbacks

* ACP: delete residual bindings barrel

* Bindings: restore legacy compatibility

* Revert "Bindings: restore legacy compatibility"

This reverts commit ac2ed68fa2426ecc874d68278c71c71ad363fcfe.

* Tests: drop ACP route legacy helper names

* Discord/ACP: fix binding regressions

---------

Co-authored-by: Onur <2453968+osolmaz@users.noreply.github.com>

* feat: add bundled Chutes extension (openclaw#49136)

* refactor: generalize bundled provider discovery seams

* feat: land chutes extension via plugin-owned auth (openclaw#41416) (thanks @Veightor)

* docs(security): clarify wildcard Control UI origins

* refactor: clean extension api boundaries

* fix: remove duplicate setup helper imports

* fix(compaction): break safeguard cancel loop for sessions with no summarizable messages (openclaw#41981) (openclaw#42215)

Merged via squash.

Prepared head SHA: 7ce6bd8
Co-authored-by: lml2468 <39320777+lml2468@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman

* feat(mattermost): add retry logic and timeout handling for DM channel creation (openclaw#42398)

Merged via squash.

Prepared head SHA: 3db47be
Co-authored-by: JonathanJing <17068507+JonathanJing@users.noreply.github.com>
Co-authored-by: mukhtharcm <56378562+mukhtharcm@users.noreply.github.com>
Reviewed-by: @mukhtharcm

* docs(hooks): clarify trust model and audit guidance

* test: stabilize memory async search close

* refactor: narrow extension public seams

* chore: add gog CLI support via custom Docker image

Add Dockerfile.gog to extend openclaw:local with the gog binary
(Google Workspace CLI). Also forward OPENAI_API_KEY and GEMINI_API_KEY
env vars in docker-compose.yml for both services.

Made-with: Cursor

* chore: inject GOG_KEYRING_PASSWORD for non-interactive gog auth

The gog CLI uses a file-based keyring to store Google OAuth tokens.
In Docker/headless environments, the keyring prompts for a passphrase
interactively, which blocks the agent from running gog autonomously.

Setting GOG_KEYRING_PASSWORD as an environment variable allows gog to
unlock the keyring without user interaction, enabling the agent to
execute Gmail, Calendar, Drive, and other Google Workspace commands
directly via the gog skill.

Setup steps to enable the gog skill in Docker:
1. Build the custom image: docker build -f Dockerfile.gog -t openclaw:gog .
2. Set OPENCLAW_IMAGE=openclaw:gog in .env
3. Set GOG_KEYRING_PASSWORD= in .env (empty = no passphrase)
4. Run: gog auth keyring file (inside container)
5. Run: gog auth credentials /path/to/client_secret.json
6. Run: gog auth add you@gmail.com --manual
7. Add to openclaw.json: tools.alsoAllow = ["exec", "process"]

Made-with: Cursor

* docs: add Docker commands reference and Mac migration plan

* docs: add docker save/load alternative to migration plan

* docs: add Docker+gog env example file

* config: clear unused OPENAI_API_KEY and document LLM auth in migration guide

* chore: remove .env from git tracking (contains secrets)

Made-with: Cursor

* docs: add openai-codex auth commands to migration guide

* docs: add gog token persistence, exec tool fix, and image migration cases

- docker-compose.yml: mount ~/.openclaw/gogcli as volume so gog tokens survive container restarts
- docs/docker-commands.html: add case 10 (gog token loss diagnosis + re-auth + volume persistence)
- docs/docker-commands.html: add case 11 (exec tool not enabled — tools.alsoAllow fix + persistence explanation)
- docs/docker-commands.html: add case 08 (migrate Docker Desktop images to Colima via docker save/load) + TOC entry

* docs: add Colima disk lock fix to docker-commands

* feat(docker): add local Whisper audio transcription to gog image

* docs: update docker-commands with TTS and contact number fixes

* docs: add gog token expiry troubleshooting and publish-app fix (caso 12)

* docs: add OpenAI Codex rate limit troubleshooting (caso 13)

* docs: add model set/status commands to caso 13

* docs: add provider/model switching guide (caso 14)

* docs: replace placeholder email with herbert.cadbury.bot@gmail.com

---------

Signed-off-by: sallyom <somalley@redhat.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: scoootscooob <zhentongfan@gmail.com>
Co-authored-by: scoootscooob <167050519+scoootscooob@users.noreply.github.com>
Co-authored-by: Josh Lehman <josh@martian.engineering>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Co-authored-by: Frank Yang <frank.ekn@gmail.com>
Co-authored-by: stim64045-spec <stim64045@gmail.com>
Co-authored-by: 大禹 <dayu@dayudeMac-mini.local>
Co-authored-by: Val Alexander <bunsthedev@gmail.com>
Co-authored-by: Val Alexander <68980965+BunsDev@users.noreply.github.com>
Co-authored-by: Br1an <932039080@qq.com>
Co-authored-by: Br1an67 <29810238+Br1an67@users.noreply.github.com>
Co-authored-by: ImLukeF <92253590+ImLukeF@users.noreply.github.com>
Co-authored-by: Stable Genius <stablegenius043@gmail.com>
Co-authored-by: stablegenius49 <259448942+stablegenius49@users.noreply.github.com>
Co-authored-by: Chris Kimpton <chris@kimptoc.net>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Sally O'Malley <somalley@redhat.com>
Co-authored-by: huntharo <harold@pwrdrvr.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Co-authored-by: Andrew Demczuk <andrew.demczuk@gmail.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
Co-authored-by: Jari Mustonen <jari.mustonen@iki.fi>
Co-authored-by: jarimustonen <1272053+jarimustonen@users.noreply.github.com>
Co-authored-by: F_ool <112874572+hhhhao28@users.noreply.github.com>
Co-authored-by: Kwest OG <50209930+yassinebkr@users.noreply.github.com>
Co-authored-by: Yassine <yassinebkr@users.noreply.github.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
Co-authored-by: Bob <dutifulbob@gmail.com>
Co-authored-by: Onur <2453968+osolmaz@users.noreply.github.com>
Co-authored-by: Peter Steinberger <peter@steipete.me>
Co-authored-by: Menglin Li <limenglin5911@gmail.com>
Co-authored-by: lml2468 <39320777+lml2468@users.noreply.github.com>
Co-authored-by: Jonathan Jing <JonathanJing@users.noreply.github.com>
Co-authored-by: JonathanJing <17068507+JonathanJing@users.noreply.github.com>
Co-authored-by: mukhtharcm <56378562+mukhtharcm@users.noreply.github.com>
@steipete
Copy link
Copy Markdown
Contributor

Closing this as implemented after Codex review.

PR #41416 is already implemented on current main and was superseded by a merged maintainer PR. The Chutes provider now ships as a bundled, default-enabled plugin with both OAuth and API-key auth, dynamic model discovery, default-model/config wiring, docs, and regression coverage.

What I checked:

  • Maintainer supersede note: The PR thread says this work was superseded by merged PR feat: add bundled Chutes extension #49136, with squash merge commit a724bbce1a63ab361f5f306f747fb4c3ac08bbc4. (a724bbce1a63)
  • Bundled provider implementation: Current main registers the bundled chutes provider, exposes both Chutes (OAuth) and Chutes API key, and uses dynamic catalog discovery in the provider catalog path. (extensions/chutes/index.ts:119)
  • Default model and catalog wiring: Current main applies Chutes provider config, registers model aliases, and sets the default Chutes model plus image model fallback wiring. (extensions/chutes/onboard.ts:19)
  • Default-enabled manifest: The Chutes plugin manifest is present and marked enabledByDefault, with both OAuth and API-key auth choices declared. (extensions/chutes/openclaw.plugin.json:3)
  • Docs and changelog: The docs describe both OAuth and API-key onboarding plus discovery/default-model behavior, and the changelog explicitly records Plugins/Chutes ... (#41416) under the 2026.3.22 release section. (docs/providers/chutes.md:10)
  • Release note entry: Changelog entry tying this feature to #41416. (CHANGELOG.md:2225)

So I’m closing this as already implemented rather than keeping a duplicate issue open.

Review notes: reviewed against e94c0bf51542; fix evidence: release v2026.3.22, commit a724bbce1a63.

@steipete steipete closed this Apr 25, 2026
lovewanwan pushed a commit to lovewanwan/openclaw that referenced this pull request Apr 28, 2026
* refactor: generalize bundled provider discovery seams

* feat: land chutes extension via plugin-owned auth (openclaw#41416) (thanks @Veightor)
ogt-redknie pushed a commit to ogt-redknie/OPENX that referenced this pull request May 2, 2026
* refactor: generalize bundled provider discovery seams

* feat: land chutes extension via plugin-owned auth (openclaw#41416) (thanks @Veightor)
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 9, 2026
* refactor: generalize bundled provider discovery seams

* feat: land chutes extension via plugin-owned auth (openclaw#41416) (thanks @Veightor)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling app: web-ui App: web-ui channel: feishu Channel integration: feishu commands Command implementations size: XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants