Skip to content

CAMEL-24288: Add IBM watsonx.ai support for TUI/CLI AI prompt (F8) - #25208

Merged
gnodet merged 4 commits into
mainfrom
investigate-and-fix-camel-24288-add-ibm-watsonx
Jul 31, 2026
Merged

CAMEL-24288: Add IBM watsonx.ai support for TUI/CLI AI prompt (F8)#25208
gnodet merged 4 commits into
mainfrom
investigate-and-fix-camel-24288-add-ibm-watsonx

Conversation

@gnodet

@gnodet gnodet commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Add IBM watsonx.ai as a first-class AI provider for the Camel JBang TUI/CLI AI prompt feature (F8 key), following the patterns established by Azure OpenAI (CAMEL-24276) and Gemini/Vertex AI (CAMEL-24275).

Changes

  • LlmClient.java: Add watsonx to ApiType enum, auto-detection via WATSONX_APIKEY env var, URL normalization for the watsonx model gateway (/ml/gateway/v1/chat/completions), Bearer token auth, default model ibm/granite-4-1-8b-instruct, default URL https://us-south.ml.cloud.ibm.com
  • AiProviderSelector.java: Add watsonx to the TUI provider switch popup
  • AiPanel.java: Include WATSONX_APIKEY in the error message hint
  • Ask.java / Explain.java: Update CLI help text to document watsonx option and env var
  • LlmClientWatsonxTest.java (new): 10 unit tests for URL normalization (chat/models paths, trailing slashes, regions, full URL preservation) and OpenAI-format delegation
  • AiProviderSelectorTest.java: Updated existing tests + new watsonx de-duplication test

Design decisions

  • New ApiType.watsonx (not piggybacked on openai): gives watsonx first-class visibility in the TUI provider selector, since watsonx URLs don't look like OpenAI URLs
  • Reuses OpenAI wire format: watsonx model gateway is OpenAI-API-compatible, so generateOpenAi() / chatOpenAiFormat() are reused — no new HTTP logic
  • WATSONX_APIKEY (not WATSONX_API_KEY): follows IBM's documented naming convention, consistent with the existing camel-ibm-watsonx-ai component

Resolves: CAMEL-24288

Claude Code on behalf of Guillaume Nodet

Add watsonx as a new LlmClient.ApiType that uses the IBM watsonx.ai
model gateway (OpenAI-compatible). The implementation:

- Adds ApiType.watsonx with auto-detection via WATSONX_APIKEY and
  WATSONX_URL environment variables
- Reuses the OpenAI wire format (generate, chatWithTools) since the
  watsonx model gateway is OpenAI-API-compatible
- Adds watsonx-specific URL normalization for the /ml/gateway/v1 path
- Defaults to ibm/granite-3.1-8b-instruct model and us-south region
- Adds watsonx to the TUI AiProviderSelector and switch popup
- Updates CLI help text in Ask and Explain commands
- Includes unit tests for URL normalization and provider selection

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

🌟 Thank you for your contribution to the Apache Camel project! 🌟
🤖 CI automation will test this PR automatically.

🐫 Apache Camel Committers, please review the following items:

  • First-time contributors require MANUAL approval for the GitHub Actions to run
  • You can use the command /component-test (camel-)component-name1 (camel-)component-name2.. to request a test from the test bot although they are normally detected and executed by CI.
  • You can label PRs using skip-tests and test-dependents to fine-tune the checks executed by this PR.
  • Build and test logs are available in the summary page. Only Apache Camel committers have access to the summary.

⚠️ Be careful when sharing logs. Review their contents before sharing them publicly.

@gnodet gnodet left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Review: Looks good ✅

Clean, well-structured PR that adds IBM watsonx.ai as a new AI provider following existing patterns consistently. Tests are adequate (10 new URL normalization tests + updated provider selector tests), documentation is updated, and credentials handling is correct (Bearer auth via WATSONX_APIKEY env var). The design decision to reuse the OpenAI wire format is well-justified since the watsonx model gateway is OpenAI-API-compatible.

Minor observations (non-blocking)

  • listWatsonxModels() auth header construction (LlmClient.java ~L422): Manually constructs auth headers instead of reusing buildOpenAiAuthHeaders(resolveApiKey()) which produces the same result. listOpenAiModels() at L397 uses the shared helper. Minor inconsistency, functionally correct.

  • JUnit vs AssertJ in AiProviderSelectorTest: The new assertions use JUnit-style (assertEquals, assertTrue) rather than AssertJ. This matches the existing style in this test file, but the new LlmClientWatsonxTest correctly uses AssertJ — nice consistency there.

  • Harden.java has its own ApiType enum (with only ollama and openai) — pre-existing limitation, not a regression from this PR, but worth tracking for future unification with LlmClient.ApiType.

  • Good design decisions throughout: first-class ApiType.watsonx (proper TUI visibility), isGenericPlaceholderModel() for clean provider switching, and proper Bearer auth flowing through applyOpenAiAuthorization().

This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.

Claude Code on behalf of Guillaume Nodet

@github-actions

github-actions Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

🧪 CI tested the following changed modules:

  • docs
  • dsl/camel-jbang/camel-jbang-core
  • dsl/camel-jbang/camel-jbang-plugin-tui

🔬 Scalpel shadow comparison — Scalpel: 8 tested, 8 compile-only — current: 6 all tested

Maveniverse Scalpel detected 16 affected modules (current approach: 6).

⚠️ Modules only in Scalpel (10)
  • camel-jbang-core
  • camel-jbang-it
  • camel-jbang-main
  • camel-jbang-plugin-edit
  • camel-jbang-plugin-generate
  • camel-jbang-plugin-kubernetes
  • camel-jbang-plugin-test
  • camel-launcher
  • coverage
  • docs

Skip-tests mode would test 8 modules (3 direct + 5 downstream), skip tests for 8 (generated code, meta-modules)

Modules Scalpel would test (8)
  • camel-jbang-core
  • camel-jbang-mcp
  • camel-jbang-plugin-mcp
  • camel-jbang-plugin-route-parser
  • camel-jbang-plugin-tui
  • camel-jbang-plugin-validate
  • camel-launcher-container
  • docs
Modules with tests skipped (8)
  • camel-jbang-it
  • camel-jbang-main
  • camel-jbang-plugin-edit
  • camel-jbang-plugin-generate
  • camel-jbang-plugin-kubernetes
  • camel-jbang-plugin-test
  • camel-launcher
  • coverage

ℹ️ Shadow mode — Scalpel observes but does not affect test execution. Learn more

⚠️ Some tests are disabled on GitHub Actions (@DisabledIfSystemProperty(named = "ci.env.name")) and require manual verification:

  • dsl/camel-jbang/camel-jbang-core: 1 test(s) disabled on GitHub Actions

💡 Manual integration tests recommended:

You modified dsl/camel-jbang/camel-jbang-core. The related integration tests in dsl/camel-jbang/camel-jbang-it are excluded from CI. Consider running them manually:

mvn verify -f dsl/camel-jbang/camel-jbang-it -Djbang-it-test
All tested modules (16 modules)
  • Camel :: Coverage
  • Camel :: Docs
  • Camel :: JBang :: Core
  • Camel :: JBang :: Integration tests
  • Camel :: JBang :: MCP
  • Camel :: JBang :: Main
  • Camel :: JBang :: Plugin :: Edit
  • Camel :: JBang :: Plugin :: Generate
  • Camel :: JBang :: Plugin :: Kubernetes
  • Camel :: JBang :: Plugin :: MCP
  • Camel :: JBang :: Plugin :: Route Parser
  • Camel :: JBang :: Plugin :: TUI
  • Camel :: JBang :: Plugin :: Testing
  • Camel :: JBang :: Plugin :: Validate
  • Camel :: Launcher
  • Camel :: Launcher :: Container

⚙️ View full build and test results

@gnodet
gnodet marked this pull request as ready for review July 29, 2026 08:45
@gnodet
gnodet requested review from ammachado and davsclaus July 29, 2026 08:45
Address review feedback: use the shared helper instead of manually
constructing Bearer auth headers, consistent with listOpenAiModels().

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

gnodet commented Jul 29, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the review! Addressed the feedback:

  • listWatsonxModels() auth headers: Switched to reuse buildOpenAiAuthHeaders(resolveApiKey()) instead of manually constructing the Bearer header — now consistent with listOpenAiModels(). ✅ (commit 4bef4d4)

The other two observations are acknowledged:

  • JUnit vs AssertJ in AiProviderSelectorTest: Agreed — the new assertions match the existing file style. Will leave as-is.
  • Harden.java separate ApiType enum: Pre-existing, tracked for future unification.

Claude Code on behalf of Guillaume Nodet

Update DEFAULT_WATSONX_MODEL from ibm/granite-3.1-8b-instruct to
ibm/granite-4-1-8b-instruct — the latest Granite generation available
on watsonx.ai with improved tool calling and instruction following.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
}
apiType = ApiType.watsonx;
apiKey = key;
String endpoint = System.getenv("WATSONX_URL");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This env var is not documented.

@gnodet gnodet left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The two follow-up commits cleanly address prior feedback (Granite 4.1 default, buildOpenAiAuthHeaders reuse). CI is green. One unresolved item remains:

Unresolved review feedback: @ammachado noted that WATSONX_URL (read in tryWatsonx() to allow endpoint override for non-US-South IBM Cloud regions like eu-de or jp-tok) is not documented anywhere — not in the --url option description, not in the .adoc docs, not in the Explain.java help text, and not in the AiPanel error message. By contrast, WATSONX_APIKEY is documented in all of those locations. Adding WATSONX_URL to the help text would aid discoverability.

For example, Explain.java line 202 could be updated:

printer().printErr("  5. camel explain my-route.yaml --api-type=watsonx    (uses WATSONX_APIKEY, WATSONX_URL)");

This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.

Claude Code on behalf of Guillaume Nodet

Add WATSONX_URL (and AZURE_OPENAI_ENDPOINT) to the --url option
description in Ask and Explain commands so users know the endpoint
can be configured via environment variable without --url flag.

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

@gnodet gnodet left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Review: Looks good ✅

Re-reviewed after new commits. The previous finding (undocumented WATSONX_URL env var) has been fully addressed in commit 81c1b20WATSONX_URL is now documented in the --url option description in Ask.java, Explain.java, both .adoc pages, the generated metadata JSON, and the Explain.java help text example.

The three follow-up commits cleanly address all prior review feedback:

  • buildOpenAiAuthHeaders reuse
  • Granite 4.1 default model upgrade
  • WATSONX_URL documentation

Code quality is good: 10 new unit tests using AssertJ, updated AiProviderSelectorTest with watsonx de-duplication test, consistent Bearer auth flow via applyOpenAiAuthorization, and proper URL normalization for the watsonx model gateway. CI is fully green.

This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.

Claude Code on behalf of Guillaume Nodet

@apupier
apupier requested review from ammachado and apupier July 31, 2026 07:23
@gnodet gnodet added the enhancement New feature or request label Jul 31, 2026
@gnodet gnodet self-assigned this Jul 31, 2026
@gnodet gnodet added this to the 4.22.0 milestone Jul 31, 2026
@gnodet
gnodet merged commit 204a047 into main Jul 31, 2026
6 checks passed
@gnodet
gnodet deleted the investigate-and-fix-camel-24288-add-ibm-watsonx branch July 31, 2026 09:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs dsl enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants