Skip to content

Improve natural language install intent handling#763

Open
KingParmenides wants to merge 3 commits into
cxlinux-ai:mainfrom
KingParmenides:improve-install-intent-demo
Open

Improve natural language install intent handling#763
KingParmenides wants to merge 3 commits into
cxlinux-ai:mainfrom
KingParmenides:improve-install-intent-demo

Conversation

@KingParmenides
Copy link
Copy Markdown

@KingParmenides KingParmenides commented May 11, 2026

Summary

  • add a deterministic install intent resolver for demo-critical natural language install requests
  • show reasoning, confidence, selected apt packages, and alternatives before executing
  • handle ambiguous and unknown requests without running unsafe package commands
  • wire cx install and cx setup through the resolver before AI fallback where appropriate

Addresses cxlinux-ai/cx-distro#25.

Tests

  • rustc --test wezterm/src/cli/install_intent.rs -o /private/tmp/install_intent_tests && /private/tmp/install_intent_tests
  • cargo fmt --package cx-terminal
  • git diff --check

Note: cargo test -p cx-terminal install_intent is blocked in this environment before test execution because Cargo tries to resolve the optional private git dependency mikejmorgan-ai/hrm-ai-standalone and GitHub returns repository not found.

Summary by CodeRabbit

  • New Features
    • Install and setup commands now interpret natural-language installation requests and map them to curated package profiles.
    • Fuzzy matching tolerates typos and ambiguous wording; returns ready plans, clarification prompts, or guidance for unknown requests.
    • Generates and can run apt install commands (supports automatic yes/-y behavior) with interactive confirmation and a fallback to manual query when not handled.

Review Change Stack

@KingParmenides KingParmenides requested a review from a team as a code owner May 11, 2026 05:20
Copilot AI review requested due to automatic review settings May 11, 2026 05:20
@github-actions
Copy link
Copy Markdown
Contributor

CLA Verification Failed

The following contributors have not signed the Contributor License Agreement:

How to Sign

  1. Read the CLA document
  2. Open a CLA signature request
  3. A maintainer will add you to the signers list
  4. Comment recheck on this PR to re-run verification

This check runs automatically. Maintainers can update .github/cla-signers.json to add signers.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 11, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 96258e99-dc00-45f2-8bee-f36ed11f12ef

📥 Commits

Reviewing files that changed from the base of the PR and between 25beee6 and 0285320.

📒 Files selected for processing (2)
  • wezterm/src/cli/install_intent.rs
  • wezterm/src/cli/shortcuts.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • wezterm/src/cli/shortcuts.rs
  • wezterm/src/cli/install_intent.rs

📝 Walkthrough

Walkthrough

This PR introduces a natural-language install intent resolver that interprets user queries like "install python development tools" into concrete InstallPlan objects containing apt package names, confidence scores, and status (Ready/NeedsClarification/Unknown). The resolver tokenizes input, detects ambiguous requests, matches against five hardcoded profiles via fuzzy token matching, and integrates into CLI install/setup commands with optional confirmation and package execution.

Changes

Install Intent Resolution Core

Layer / File(s) Summary
Data Contracts
wezterm/src/cli/install_intent.rs
InstallPlanStatus enum (Ready, NeedsClarification, Unknown), InstallPlan fields, and internal Candidate helper.
Public API Methods
wezterm/src/cli/install_intent.rs
InstallPlan::apt_command(auto_confirm: bool) emits sudo apt install ... for Ready plans (appends -y when auto_confirm), and InstallPlan::summary_lines() formats topic, reasoning, confidence, packages, and alternatives.
Core Resolver
wezterm/src/cli/install_intent.rs
resolve_install_intent() tokenizes queries, detects ambiguity, scores profile candidates, selects highest-confidence match, and returns Ready/NeedsClarification/Unknown based on a fixed threshold.
Profile Matchers
wezterm/src/cli/install_intent.rs
Five candidate matchers (ML, Python dev, web server, Docker+Kubernetes, Docker) with keyword checks, fuzzy-typo handling, confidence adjustments, and apt package lists/alternatives.
Clarification Builder
wezterm/src/cli/install_intent.rs
clarification_plan constructs NeedsClarification plans with empty packages and suggested alternatives.
Query Processing
wezterm/src/cli/install_intent.rs
Tokenization, membership helpers (has_all, has_any, has_token), fuzzy matching via Levenshtein with length-based limits, ambiguity heuristics, and stopword set.
Tests
wezterm/src/cli/install_intent.rs
Unit tests validating ready-plan selection, typo tolerance, ambiguous/unknown handling, and apt command/summary formatting.
Module Export
wezterm/src/cli/mod.rs
Declares install_intent as public CLI submodule.
CLI Integration
wezterm/src/cli/shortcuts.rs
Adds imports and changes InstallCommand::run and SetupCommand::run to call handle_install_intent (with fallback to AskCommand); handle_install_intent prints plans, prompts or auto-confirms, executes sudo apt install for Ready plans, and adds print_install_plan and confirm_install helpers.

Sequence Diagram(s)

sequenceDiagram
  participant User as User
  participant CLI as CLI command
  participant Resolver as resolve_install_intent
  participant Tokenizer as tokenize
  participant Matchers as ProfileMatchers
  participant Selector as CandidateSelector
  participant Shell as sudo apt

  User->>CLI: issue install/setup description
  CLI->>Resolver: call resolve_install_intent(query)
  Resolver->>Tokenizer: tokenize + normalize
  Tokenizer->>Matchers: tokens
  Matchers->>Selector: candidates with confidence
  Selector->>CLI: InstallPlan (Ready/NeedsClarification/Unknown)
  CLI->>User: print summary_lines
  alt Ready and confirmed
    CLI->>Shell: run sudo apt install <packages>
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

  • Implements the install intent resolver infrastructure requested to handle natural-language install queries with typo tolerance, confidence scoring, and ambiguity detection.

Poem

A rabbit builds profiles for Python and more,
Fuzzy tokens match typos, the heuristics explore,
Confidence decides if packages are shown,
sudo apt install when the plan is Ready and known. 🐰 📦

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.69% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Improve natural language install intent handling' directly summarizes the main change: adding a deterministic resolver for natural language install requests with confidence scoring and fallback handling.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
wezterm/src/cli/install_intent.rs (2)

293-314: 💤 Low value

Consider expanding ambiguity detection.

The ambiguity detection relies on a small stopword list and limited patterns. Consider whether additional ambiguous patterns should be caught before a demo, such as:

  • Generic tech terms without specifics ("install development tools", "install programming stuff")
  • Requests mentioning multiple unrelated categories
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@wezterm/src/cli/install_intent.rs` around lines 293 - 314,
is_ambiguous_request currently only catches a few vague tokens and a single
"server" case; extend its ambiguity heuristics by (1) adding more generic tech
terms to the stopword/ambiguous set (e.g. "development", "programming", "dev",
"libs", "packages", "tools", "stuff") — update is_stopword or create a small
is_generic_tech_token helper; (2) add pattern checks inside is_ambiguous_request
to treat tokens like "development tools", "programming", or "libraries" as
ambiguous even when alone (extend the matches! check on meaningful[0]); and (3)
detect requests mentioning multiple unrelated categories by defining small
category keyword lists (e.g. web: ["web","http","nginx","apache"], db:
["database","postgres","mysql"], infra: ["ssh","server","docker"], dev:
["development","programming","tools"]) and returning true if tokens match two or
more different categories (use has_any or a new function to count category
hits). Update references to is_stopword, is_ambiguous_request, and has_any when
implementing these changes.

99-99: ⚡ Quick win

Document the confidence threshold rationale.

The confidence thresholds (0.68 for Ready, 0.42 for clarification, 0.18 for unknown) appear to be magic numbers. Comments should explain WHY these specific values were chosen rather than WHAT they do.

📝 Example documentation
+    // Confidence threshold of 0.68 ensures high certainty before executing package installs,
+    // chosen to balance typo tolerance with safety for demo-critical operations.
     if best.confidence >= 0.68 {

Also applies to: 73-73, 66-66

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@wezterm/src/cli/install_intent.rs` at line 99, The comparisons against
best.confidence (e.g., if best.confidence >= 0.68 and the other checks at 0.42
and 0.18) use unexplained magic numbers; add brief inline comments near each
threshold in wezterm::cli::install_intent (around the checks using
best.confidence) that state the rationale — e.g., that 0.68 was chosen from
calibration/ROC analysis to balance precision/recall, 0.42 triggers a
clarification when probability is ambiguous, and 0.18 marks model uncertainty —
and include how these values were derived (data/calibration method or heuristic)
and a TODO referencing where to update them if recalibrating.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@wezterm/src/cli/shortcuts.rs`:
- Line 123: Replace the unsafe shell invocation
Command::new("sh").arg("-c").arg(&command).status()? by invoking the executable
and arguments directly: stop building a single shell string and instead call
Command::new with the concrete program (e.g., "sudo" or "apt") and pass each
argument via .arg(...) so the package name comes in as a parameter, not
interpolated into a shell; locate the call to Command::new("sh") that uses the
variable command and change it to a parameterized Command::new(...) invocation
that supplies the program and each argument separately (for example,
Command::new("sudo").arg("apt").arg("install").arg(package_name).status()),
preserving existing error handling around status().

---

Nitpick comments:
In `@wezterm/src/cli/install_intent.rs`:
- Around line 293-314: is_ambiguous_request currently only catches a few vague
tokens and a single "server" case; extend its ambiguity heuristics by (1) adding
more generic tech terms to the stopword/ambiguous set (e.g. "development",
"programming", "dev", "libs", "packages", "tools", "stuff") — update is_stopword
or create a small is_generic_tech_token helper; (2) add pattern checks inside
is_ambiguous_request to treat tokens like "development tools", "programming", or
"libraries" as ambiguous even when alone (extend the matches! check on
meaningful[0]); and (3) detect requests mentioning multiple unrelated categories
by defining small category keyword lists (e.g. web:
["web","http","nginx","apache"], db: ["database","postgres","mysql"], infra:
["ssh","server","docker"], dev: ["development","programming","tools"]) and
returning true if tokens match two or more different categories (use has_any or
a new function to count category hits). Update references to is_stopword,
is_ambiguous_request, and has_any when implementing these changes.
- Line 99: The comparisons against best.confidence (e.g., if best.confidence >=
0.68 and the other checks at 0.42 and 0.18) use unexplained magic numbers; add
brief inline comments near each threshold in wezterm::cli::install_intent
(around the checks using best.confidence) that state the rationale — e.g., that
0.68 was chosen from calibration/ROC analysis to balance precision/recall, 0.42
triggers a clarification when probability is ambiguous, and 0.18 marks model
uncertainty — and include how these values were derived (data/calibration method
or heuristic) and a TODO referencing where to update them if recalibrating.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f87e6acb-7401-469b-a975-a98252d476a0

📥 Commits

Reviewing files that changed from the base of the PR and between bf87c78 and 25beee6.

📒 Files selected for processing (3)
  • wezterm/src/cli/install_intent.rs
  • wezterm/src/cli/mod.rs
  • wezterm/src/cli/shortcuts.rs

Comment thread wezterm/src/cli/shortcuts.rs Outdated
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a deterministic natural language intent resolver to handle common installation requests offline, covering stacks like Docker, Machine Learning, and Python. It integrates this into the install and setup CLI commands as a primary check before falling back to AI-based processing. Review feedback highlights a logic error in the install command that prevents the AI fallback from being reached for unknown packages and suggests optimizing the Levenshtein distance implementation to reduce memory allocations.

Comment thread wezterm/src/cli/shortcuts.rs Outdated
let query = format!("install {}", self.description.join(" "));
let query = self.description.join(" ");

if handle_install_intent(&query, self.auto_confirm, true)? {
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.

high

The handle_unknown parameter is set to true here, which causes handle_install_intent to return Ok(true) and print a generic "I do not know a safe package set" message for any request that doesn't match the deterministic resolver. This effectively blocks the AI fallback logic on lines 51-62, making it unreachable for unknown packages (e.g., cx install vim). To allow the intended AI fallback for requests outside the demo-critical set, this should be false.

Suggested change
if handle_install_intent(&query, self.auto_confirm, true)? {
if handle_install_intent(&query, self.auto_confirm, false)? {

Comment on lines +351 to +368
fn levenshtein(left: &str, right: &str) -> usize {
let mut costs: Vec<usize> = (0..=right.len()).collect();

for (i, left_char) in left.chars().enumerate() {
let mut previous = i;
costs[0] = i + 1;

for (j, right_char) in right.chars().enumerate() {
let insert = costs[j + 1] + 1;
let delete = costs[j] + 1;
let replace = previous + usize::from(left_char != right_char);
previous = costs[j + 1];
costs[j + 1] = insert.min(delete).min(replace);
}
}

costs[right.len()]
}
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.

medium

The levenshtein function allocates a new Vec<usize> on every call. Since token_matches is called in a loop for every token against every keyword in the candidate functions, this results in many small allocations. While acceptable for a CLI tool, reusing a pre-allocated buffer or using a fixed-size array for the costs (since tokens are typically short) would improve efficiency.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds a deterministic, offline “install intent” resolver to make cx install/cx setup handle a handful of demo-critical natural-language installation requests without needing AI fallback, and to present the selected package plan (reasoning/confidence/alternatives) before running anything.

Changes:

  • Introduces install_intent module with tokenization + heuristic matching and unit tests.
  • Routes cx install and cx setup through the resolver before falling back to cx ask.
  • Adds interactive confirmation + execution for “Ready” plans.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
wezterm/src/cli/shortcuts.rs Calls the new resolver for install/setup and executes the resulting apt install plan when ready.
wezterm/src/cli/mod.rs Exposes the new install_intent module.
wezterm/src/cli/install_intent.rs Implements deterministic intent resolution, plan summaries, and adds unit tests for expected demo cases.

Comment on lines +120 to +124
println!("Command: {}", command);

if auto_confirm || confirm_install()? {
let status = Command::new("sh").arg("-c").arg(&command).status()?;

Comment thread wezterm/src/cli/install_intent.rs Outdated
Comment on lines +27 to +31
if self.status != InstallPlanStatus::Ready || self.packages.is_empty() {
return None;
}

Some(format!("sudo apt install {}", self.packages.join(" ")))
Comment thread wezterm/src/cli/install_intent.rs Outdated
.map(|alt| alt.to_string())
.collect(),
reasoning: format!(
"{} I am not confident enough to install packages without confirmation.",
@sonarqubecloud
Copy link
Copy Markdown

@KingParmenides
Copy link
Copy Markdown
Author

Pushed follow-ups for the review items:

  • let unknown cx install ... requests fall through to the AI fallback instead of being handled as a terminal Unknown plan;
  • replaced sh -c install execution with parameterized sudo apt install ... args;
  • pass -y to apt when --yes/auto_confirm is set and reflect that in the displayed command;
  • reworded the clarification reasoning so it asks for more detail instead of implying confirmation is enough.

Local verification:

  • rustfmt --check wezterm/src/cli/install_intent.rs wezterm/src/cli/shortcuts.rs
  • rustc --test wezterm/src/cli/install_intent.rs -o /private/tmp/install_intent_tests && /private/tmp/install_intent_tests --nocapture

Note: full cargo test -p wezterm --lib cli::install_intent is blocked in this sandbox because Cargo cannot write its git dependency cache (finl_unicode) under .cargo/git.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants