Skip to content

CAMEL-23978: Add AI panel slash commands to Camel TUI#24594

Merged
davsclaus merged 31 commits into
apache:mainfrom
ammachado:feature/ai-slash-commands
Jul 11, 2026
Merged

CAMEL-23978: Add AI panel slash commands to Camel TUI#24594
davsclaus merged 31 commits into
apache:mainfrom
ammachado:feature/ai-slash-commands

Conversation

@ammachado

@ammachado ammachado commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Description

Adds local slash commands to the Camel TUI AI panel so operators can control the panel and invoke Camel CLI actions without sending prompts to the configured AI provider.

Highlights

  • Built-in panel commands: /help, /provider, /model, /clear, /close, /quit (with /exit, /q, /x aliases).
  • CLI bridge commands: /run, /infra, and /send run through a TUI-safe executor with output capture and cancellation.
  • Provider switching and persisted model selection, with live command hints and TAB completion.
  • /run and /infra run launch as tracked background processes; /infra list remains in-process.
  • Fixed conversation auto-scrolling by using the exact rendered Markdown height.
  • User manual documents the supported slash commands.

Review follow-up

  • Identifies an Ollama endpoint by its root GET response (Ollama is running), so detection no longer relies on port 11434 and does not classify arbitrary reachable URLs as Ollama.
  • Serializes all in-process CLI execution used by slash commands and the AI cli_exec tool to protect the shared Camel JBang/picocli instance.
  • Keeps the AI thinking state independent from background slash-command completion, and makes agent cancellation non-blocking for the TUI event thread.
  • Blocks /provider and /model while either an AI request or background slash CLI command is active.

Tracking

https://issues.apache.org/jira/browse/CAMEL-23978

Verification

  • mvn -Dtest=LlmClientListModelsTest test in dsl/camel-jbang/camel-jbang-core
  • mvn -Dtest=AskCliToolsTest,LlmClientListModelsTest test in dsl/camel-jbang/camel-jbang-core
  • mvn -Dtest=AiPanelTest test in dsl/camel-jbang/camel-jbang-plugin-tui
  • mvn -Dtest=AiCliCommandExecutorTest,AiPanelTest test in dsl/camel-jbang/camel-jbang-plugin-tui

AI-generated by Codex on behalf of ammachado. Commits include Co-authored-by: Codex <noreply@openai.com>.

@ammachado ammachado force-pushed the feature/ai-slash-commands branch from 1a21b09 to 35c511f Compare July 10, 2026 20:53
@ammachado ammachado changed the title [CAMEL-23978] Add AI panel slash commands to Camel TUI CAMEL-23978: Add AI panel slash commands to Camel TUI Jul 10, 2026
@ammachado ammachado force-pushed the feature/ai-slash-commands branch from a39d990 to 2217053 Compare July 10, 2026 23:03
@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.

@github-actions

github-actions Bot commented Jul 10, 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

@ammachado ammachado marked this pull request as ready for review July 11, 2026 00:09
@ammachado ammachado requested review from davsclaus and gnodet July 11, 2026 00:10

@davsclaus davsclaus left a comment

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.

Review: CAMEL-23978 — AI panel slash commands

Well-structured feature PR. Clean separation of concerns (AiSlashCommandRegistry, AiSlashCommandContext, AiCliCommandExecutor), thorough test coverage (concurrency edge cases, parsing, error paths, rendering), and good documentation update.

Positive highlights:

  • Migrating ConversationEntry.role from String to the new AiRole enum catches mismatches at compile time.
  • The settings persistence integrates naturally with the existing TuiSettings/SettingsPopup pattern.
  • Architecture is independently testable per component.

Findings (inline comments below):

  1. thinkingVerb field data race — easy fix with volatile.
  2. tryExplicitUrl() behavioral change — worth noting.
  3. Minor scope: Ask.java formatter change mixed in.

This review evaluates the PR against the project's contribution rules and conventions. It does not replace specialized review tools (CodeRabbit, SonarCloud) or static analysis.

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

Claude Code on behalf of davsclaus

@gnodet gnodet left a comment

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.

Good feature addition — clean architecture, thorough test coverage, and docs updated.

One finding:

AiSlashCommandRegistryTest.java — the NoopSlashContext inner class uses java.util.concurrent.CompletableFuture as a fully qualified class name inline (2 occurrences) instead of importing it. This violates the project coding convention (no FQCNs — always use imports).

Reviewed with Claude Code on behalf of gnodet. This review was generated by an AI agent and may contain inaccuracies; please verify all suggestions before applying.

@ammachado

Copy link
Copy Markdown
Contributor Author

@gnodet Fixed in ae38606AiSlashCommandRegistryTest now imports java.util.concurrent.CompletableFuture and uses the simple name in NoopSlashContext (both occurrences), per the no-FQCN coding convention.

Claude Code on behalf of ammachado

@gnodet gnodet left a comment

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.

Claude Code review on behalf of @gnodet

Re-review after 2 new commits. Previous FQCN feedback addressed ✅. One new issue found.

Feedback addressed

  • CompletableFuture is now properly imported in AiSlashCommandRegistryTest
  • thinkingVerb marked volatile for thread safety between UI and callback threads
  • ✅ Unrelated printErr line wrap reverted

New issue: duplicate placeholder block in AiPanel.renderInput()

The placeholder rendering code is duplicated — the same block appears twice consecutively:

if (cursorPos == text.length()) {
    Optional<String> placeholder = slashCommands.placeholderFor(text);
    if (placeholder.isPresent()) {
        spans.add(Span.styled(" " + placeholder.get(), Style.EMPTY.dim()));
    }
}
if (cursorPos == text.length()) {
    Optional<String> placeholder = slashCommands.placeholderFor(text);
    if (placeholder.isPresent()) {
        spans.add(Span.styled(" " + placeholder.get(), Style.EMPTY.dim()));
    }
}

This will render the placeholder hint text twice in the input line (e.g., /run would show <files...> [--dev] [--port=8080] [...] appended twice). One of these blocks should be removed.

Slash command placeholder feature

The placeholderFor() implementation and test coverage look good — clean design with proper Optional handling.

@ammachado

Copy link
Copy Markdown
Contributor Author

@gnodet Fixed in eebbb7b — removed the duplicated placeholder block in AiPanel.renderInput(); the hint now renders once. I also strengthened commandPlaceholderRendersAfterTrailingSpace to assert the placeholder appears exactly once (the previous contains() assertion passed even with the duplicate). Verified the strengthened test fails on the duplicated code and passes after the fix.

Claude Code on behalf of ammachado

@gnodet gnodet left a comment

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.

Claude Code review on behalf of @gnodet

Duplicate placeholder fix verified ✅

  • Duplicate placeholderFor block removed from renderInput()
  • Test commandPlaceholderRendersAfterTrailingSpace now asserts the placeholder renders exactly once (via countOccurrences), guarding against regression

No remaining concerns from my reviews. LGTM.

@davsclaus davsclaus left a comment

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.

LGTM — well-executed feature addition.

Clean architecture with proper separation (AiSlashCommandRegistry, AiSlashCommandContext, AiCliCommandExecutor, AiProviderSelector), introduction of AiRole enum replacing error-prone string role identifiers, and comprehensive test coverage across all new classes.

All previous review findings from @davsclaus and @gnodet have been addressed in follow-up commits. No unresolved conversations remain.

Observations (non-blocking):

  1. Branch naming: feature/ai-slash-commands — project convention is feature/<ISSUE_ID>-<short-slug> (i.e. feature/CAMEL-23978-ai-slash-commands). Minor, for future reference.
  2. tryExplicitUrl() side-effect: Now probes /api/tags and /v1/models before bare-URL fallback, setting apiType as a side-effect. Custom proxy/gateway URLs that don't serve those sub-paths get two extra probe round-trips. Documented in commit message — worth monitoring if users report slow startup with custom AI URLs.
  3. extractStringList() unchecked cast in LlmClient.listModels(): (JsonArray) response.get(arrayField) is fail-safe (outer caller handles null returns) but silently swallows unexpected API response shapes.

Ready to merge (squash).

Claude Code on behalf of davsclaus

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

@ammachado ammachado marked this pull request as draft July 11, 2026 17:53
@davsclaus davsclaus added the enhancement New feature or request label Jul 11, 2026
@davsclaus davsclaus added this to the 4.22.0 milestone Jul 11, 2026
@ammachado

Copy link
Copy Markdown
Contributor Author

PR is back to draft since I've found a few issues testing.

@davsclaus davsclaus marked this pull request as ready for review July 11, 2026 17:54
@davsclaus

Copy link
Copy Markdown
Contributor

okay was about to, let us know when its ready next time

@davsclaus davsclaus marked this pull request as draft July 11, 2026 17:55
@ammachado ammachado marked this pull request as ready for review July 11, 2026 18:48
@ammachado ammachado requested review from davsclaus and gnodet July 11, 2026 18:48

@gnodet gnodet left a comment

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.

Claude Code review on behalf of @gnodet

Re-review: 3 new commits since last review

Commit ac20f92c — Launch /run and /infra as tracked background processes: Well-designed. /run and /infra run now go through LaunchManager (same path as F2 Actions), so they appear as tracked background processes instead of blocking the panel in-process. Key strengths:

  • LaunchSpec record with List.copyOf() for immutability
  • Infra auto-start before example launches (with findMissingInfraServices check)
  • launchDetachedQuietly() gracefully reports launch failures to the conversation
  • /infra list correctly stays in-process while /infra run detaches — isInfraRun() check is clean
  • Comprehensive test coverage: RecordingLaunchContext, LaunchSpec.forRun() / forInfra() tests

Minor: exampleCatalog volatile field has a benign data race (two threads may load the catalog simultaneously) since there's no synchronization around the read-then-write. Harmless because ExampleHelper.loadCatalog() is idempotent and reference assignment is atomic, but worth noting.

Commit 822be6d5 — Persist /model selection: Clean fix. persistModelSelection() correctly updates both TuiSettings (disk) and sessionProviderChoice (memory), so neither a restart nor a panel re-init reverts the model. Test uses @TempDir with proper finally cleanup of CommandLineHelper.useHomeDir.

Commit 427d2b3c — TAB completion and clipped output fix: Two independent improvements:

  1. TAB completion: Nice state machine — longest common prefix first, then cycle, Shift+TAB for backward, any edit resets. The completionSnapshot comparison for detecting edits is clean and avoids explicit reset logic in every key handler.
  2. Clipped output fix: Replacing character-count estimation with MarkdownView.computeHeight() is the right fix — the old approach under-counted lines for markdown block elements (headings, lists, fenced code, blockquotes) that render with surrounding blank rows. Re-measuring at the narrower width after adding the scrollbar column is a good attention to detail.

One minor nit: The longResponseAutoScrollsToShowLastLine test uses Thread.onSpinWait() in a busy-wait loop. While onSpinWait() isn't Thread.sleep(), Awaitility would be more idiomatic:

await().atMost(5, TimeUnit.SECONDS).until(() -> !panel.isAgentThreadRunningForTesting());

Approved — all three commits are well-implemented with thorough tests.

ammachado and others added 18 commits July 11, 2026 15:52
Co-authored-by: OpenAI Codex <codex@openai.com>
Pick the thinking verb with ThreadLocalRandom instead of a round-robin
counter, and pick up the formatter-driven line wrap in Ask.java from
the Task 6 verification pass.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Remove gemini/azure-openai provider choices that LlmClient.ApiType
  cannot represent, which threw IllegalArgumentException and left the
  panel permanently unusable once selected
- Report provider-switch failures instead of a false "Switched to X"
  success message
- Stop leaking a stale model string across a provider switch
- Fall back Settings' AI Provider field to "auto" instead of silently
  defaulting to "ollama" for an unrecognized stored value
- Close the provider popup when the panel closes and let it claim
  keys (including F8) while visible, so it can no longer get stuck
  open across a close/reopen cycle
- Clamp provider popup dimensions to avoid a negative-size Rect on
  small terminals
- Join the agent thread before interrupting or switching providers to
  avoid races with an in-flight request, and guard Ctrl+P/question
  submission while the agent thread is alive
- Guard against submitting a question with no LLM client configured
- Derive Settings' AI provider list from LlmClient.ApiType directly
  and add mouse support to the provider switch popup
Re-add isAgentThreadRunningForTesting() dropped during the merge with
feature/ai-slash-commands so provider-switch and interrupt tests compile.

Co-authored-by: Cursor <cursoragent@cursor.com>
Drop the task report file that was accidentally included in the branch.

Co-authored-by: Cursor <cursoragent@cursor.com>
Addresses a comprehensive review of the AI panel slash command PR:

- AiCliCommandExecutor.cancel() no longer permanently wedges the
  executor or blocks the caller for up to 30s; the cancellation
  timeout now runs on a watcher thread.
- Sub-command stderr is now captured into the CLI output shown to the
  user instead of being swallowed by picocli's default handler.
- /clear now also resets the LLM message context, not just the
  visible transcript.
- /model no longer reports success when there is no client to apply
  the switch to.
- Invalid persisted provider values now get an actionable message.
- Fixed /help's self-referential defaults() recursion, added a
  fail-fast alias-collision check, removed the dead
  Descriptor.asynchronous field, broadened slash-command dispatch
  error handling, and made the conversation list thread-safe.
- Introduced a shared AiRole enum for ConversationEntry/CommandResult
  so an unexpected role can no longer be silently dropped by the
  renderer.
- Documented the /help command aliases and the /provider,/model busy
  behavior; minor cleanup (final modifier, ProviderChoice validation,
  clearer CLI executor failure messages).

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
stopAgentThread()'s thread.join(30_000) runs on the caller (the
interactive UI thread on Esc/Ctrl+C, or destroy() during shutdown)
and can block it for up to 30s if the agent thread's LLM HTTP call
ignores the interrupt. Left blocking deliberately, unlike
AiCliCommandExecutor.cancel(), because AiPanelTest asserts synchronous
cancellation semantics; note the tradeoff for future reference.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Move the provider-choice building (env/settings ordering and
de-duplication) and provider/model/url application logic out of
AiPanel's private methods into a dedicated, independently-testable
AiProviderSelector. Previously these rules could only be exercised
through AiPanel's key-event handling and test-only escape hatches;
they now have direct unit test coverage for the choice-ordering rules
and provider-name validation.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Add LlmClient.listModels(), querying Ollama's /api/tags and the
OpenAI-compatible/Anthropic /v1/models endpoints (Vertex AI has no
listing endpoint, so it stays empty). Wire AiPanel's
PanelSlashCommandContext.availableModels() to it so /model with no
arguments shows real models instead of always an empty list.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Bring back the moving "..." suffix on the AI panel's thinking status
(dropped when the verb-based thinking text replaced the old literal
"thinking" label), keeping the new random thinking verbs. Also fix
AiProviderSelector so the provider-switch popup always offers
anthropic/openai/ollama for manual selection instead of hiding
providers whose API key isn't currently detected in the environment;
LlmClient already surfaces a clear error at request time if the
selected provider's key is missing. Also drops an unused static
import in CamelMonitor and labels assistant replies with "TUI:" in
the AI panel conversation view.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The rebase onto origin/main pulled in an upstream "Log Pin" settings
row that shifted the AI Provider row from index 3 to 4. Update
aiRowsPersistProviderModelAndUrl to navigate to the new row index;
behavior itself is unaffected, only the test's key-press count.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Append dimmed parameter hints inline when a slash command is typed
with a trailing space and no parameters yet.

Co-authored-by: Cursor <cursoragent@cursor.com>
- AiPanel: mark thinkingVerb volatile so its value is visible across the
  UI thread and the CLI completion callback thread (davsclaus).
- AiSlashCommandRegistryTest: import CompletableFuture instead of using
  the fully qualified name, per the no-FQCN coding convention (gnodet).
- Ask: revert the unrelated printErr line wrap to keep the diff focused;
  the single line is within the 128-char formatter limit (davsclaus).

Note on detection behavior (davsclaus): LlmClient.tryExplicitUrl now probes
"/api/tags" and "/v1/models" before the bare URL and sets apiType as a side
effect when a probe succeeds. Custom proxy/gateway URLs that do not serve
those sub-paths still fall through to the bare-URL reachability check, at the
cost of two extra probe round-trips.

Co-authored-by: Cursor <cursoragent@cursor.com>
The slash-command placeholder hint block in renderInput() was duplicated,
rendering the placeholder twice on the input line (e.g. "/run " showed the
argument hint appended twice). Remove the second block.

Strengthen commandPlaceholderRendersAfterTrailingSpace to assert the
placeholder renders exactly once; the previous contains() assertion passed
even when it rendered twice.

Reported-by: gnodet

Co-authored-by: Cursor <cursoragent@cursor.com>
The AI panel's /run slash command executed camel run in-process, which
blocked forever on a long-running application, locked the panel, and left
the app untracked. This diverged from the F2 Actions menu, which spawns a
detached, tracked process.

Route /run and /infra run through the same LaunchManager the F2 menu uses:
detached process, --name derived from a categorised --example,
--logging-color, infra auto-start, and process tracking. Short in-process
commands (/send, /infra list) no longer lock the panel into the thinking
state, so the user can keep typing; Esc still cancels them. Also advertise
--example in the /run placeholder.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The /model slash command only called client.withModel(...) in memory, so a
model chosen via /model was lost on the next TUI start (only the Settings
popup persisted it). Write the selection to TuiSettings and keep the
in-session provider choice in sync so re-initialising the client does not
revert it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add TAB completion for slash command names in the AI panel input. TAB
first fills in the longest common prefix of the matching commands, then
cycles forward through the matches (wrapping so every match is reachable
with TAB alone); Shift+TAB cycles backward. A single match is completed
fully with a trailing space. The cycle continues only while the buffer
still equals the text the last TAB press produced, so any other edit
transparently starts a fresh completion.

Also fix the conversation view clipping the last couple of lines of an AI
response. The scroll position was derived from a character-count line
estimate that under-counts markdown block elements (headings, lists,
fenced code, blockquotes render with surrounding blank rows the naive
per-line count ignores), so auto-scrolling to the bottom left the newest
lines hidden below the visible area. Use MarkdownView.computeHeight() for
the exact rendered height instead, re-measuring at the narrower width when
the scrollbar column is shown.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Codex <noreply@openai.com>
@ammachado ammachado force-pushed the feature/ai-slash-commands branch from 0db1778 to ba40132 Compare July 11, 2026 19:52

@gnodet gnodet left a comment

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.

Claude Code review on behalf of @gnodet

Re-review: New commit ba40132d — Harden AI model selection

Three clean changes:

  1. LlmClient.extractStringList(): Replaced unchecked cast (JsonArray) response.get(arrayField) with instanceof pattern matching. Prevents ClassCastException when a provider returns an unexpected shape (e.g., {"models":{}} instead of {"models":[]}). Good defensive fix.

  2. New test returnsEmptyListWhenModelListHasUnexpectedShape(): Covers the exact case — object instead of array. ✓

  3. AiPanel.initClient(): Removed hardcoded .withModel("llama3.2"). Correct — a hardcoded Ollama-specific default doesn't belong in a multi-provider context. The model now comes from sessionProviderChoice or the provider's own default.

LGTM — still approved.

@davsclaus davsclaus left a comment

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.

Nice work on this PR — the slash command architecture (registry, executor, context) is clean, the TAB completion is a thoughtful UX touch, and the test coverage across 7 new test files is excellent. A few observations below.

This review does not replace specialized tools such as CodeRabbit, Sourcery, or SonarCloud for deeper static analysis.

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

Claude Code on behalf of davsclaus

ammachado and others added 2 commits July 11, 2026 17:10
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
@ammachado ammachado requested review from davsclaus and gnodet July 11, 2026 21:23

@gnodet gnodet left a comment

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.

Claude Code review on behalf of @gnodet

Re-review: New commit d97d48fd — Address latest AI panel review feedback

Four well-motivated changes:

  1. Non-blocking cancellation (stopAgentThread()): Replaced the blocking t.join(30_000) on the UI thread with a daemon watcher thread. This prevents the TUI from freezing for up to 30s when an HTTP client ignores interruption. The agent thread's own finally block clears the thinking state, so removing the redundant thinking.set(false) from stopAgentThread() is correct.

  2. CLI/LLM state separation: Removed thinking.set(false) from handleCliCompletion(). Since CLI commands (like /send) no longer put the panel into thinking state (previous commit), clearing it on completion was wrong — it would accidentally kill an active LLM request's thinking indicator. The new test cliCompletionDoesNotClearLlmThinkingState is the exact regression test for this.

  3. Awaitility migration: All Thread.onSpinWait() busy-wait loops replaced with await().atMost(...) — this directly addresses the review feedback from the TAB completion commit. Awaitility dependency added to pom.xml. Five test methods updated consistently. ✓

  4. Ollama detection rework: Replaced the fragile inferApiTypeFromUrlHost() URL-pattern heuristic with isOllamaRoot(), which actually checks the server's response body for "Ollama is running". Much more reliable — the old approach guessed from URL substrings like "11434" or "ollama". New test with a real HTTP server covers non-default port detection.

LGTM — all changes are well-tested. Still approved.

@davsclaus davsclaus merged commit e0837c4 into apache:main Jul 11, 2026
6 checks passed
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