2025-08-04 21:23:22 -07:00
#![ cfg(feature = " vt100-tests " ) ]
#![ expect(clippy::expect_used) ]
2025-09-26 16:35:56 -07:00
use crate ::test_backend ::VT100Backend ;
2025-08-04 21:23:22 -07:00
use ratatui ::layout ::Rect ;
2025-09-02 16:19:54 -07:00
use ratatui ::style ::Stylize ;
2025-08-04 21:23:22 -07:00
use ratatui ::text ::Line ;
// Small helper macro to assert a collection contains an item with a clearer
// failure message.
macro_rules ! assert_contains {
( $collection :expr , $item :expr $(, ) ? ) = > {
assert! (
$collection . contains ( & $item ) ,
" Expected {:?} to contain {:?} " ,
$collection ,
$item
) ;
} ;
( $collection :expr , $item :expr , $( $arg :tt ) + ) = > {
assert! ( $collection . contains ( & $item ) , $( $arg ) + ) ;
} ;
}
struct TestScenario {
feat: Complete LLMX v0.1.0 - Rebrand from Codex with LiteLLM Integration
This release represents a comprehensive transformation of the codebase from Codex to LLMX,
enhanced with LiteLLM integration to support 100+ LLM providers through a unified API.
## Major Changes
### Phase 1: Repository & Infrastructure Setup
- Established new repository structure and branching strategy
- Created comprehensive project documentation (CLAUDE.md, LITELLM-SETUP.md)
- Set up development environment and tooling configuration
### Phase 2: Rust Workspace Transformation
- Renamed all Rust crates from `codex-*` to `llmx-*` (30+ crates)
- Updated package names, binary names, and workspace members
- Renamed core modules: codex.rs → llmx.rs, codex_delegate.rs → llmx_delegate.rs
- Updated all internal references, imports, and type names
- Renamed directories: codex-rs/ → llmx-rs/, codex-backend-openapi-models/ → llmx-backend-openapi-models/
- Fixed all Rust compilation errors after mass rename
### Phase 3: LiteLLM Integration
- Integrated LiteLLM for multi-provider LLM support (Anthropic, OpenAI, Azure, Google AI, AWS Bedrock, etc.)
- Implemented OpenAI-compatible Chat Completions API support
- Added model family detection and provider-specific handling
- Updated authentication to support LiteLLM API keys
- Renamed environment variables: OPENAI_BASE_URL → LLMX_BASE_URL
- Added LLMX_API_KEY for unified authentication
- Enhanced error handling for Chat Completions API responses
- Implemented fallback mechanisms between Responses API and Chat Completions API
### Phase 4: TypeScript/Node.js Components
- Renamed npm package: @codex/codex-cli → @valknar/llmx
- Updated TypeScript SDK to use new LLMX APIs and endpoints
- Fixed all TypeScript compilation and linting errors
- Updated SDK tests to support both API backends
- Enhanced mock server to handle multiple API formats
- Updated build scripts for cross-platform packaging
### Phase 5: Configuration & Documentation
- Updated all configuration files to use LLMX naming
- Rewrote README and documentation for LLMX branding
- Updated config paths: ~/.codex/ → ~/.llmx/
- Added comprehensive LiteLLM setup guide
- Updated all user-facing strings and help text
- Created release plan and migration documentation
### Phase 6: Testing & Validation
- Fixed all Rust tests for new naming scheme
- Updated snapshot tests in TUI (36 frame files)
- Fixed authentication storage tests
- Updated Chat Completions payload and SSE tests
- Fixed SDK tests for new API endpoints
- Ensured compatibility with Claude Sonnet 4.5 model
- Fixed test environment variables (LLMX_API_KEY, LLMX_BASE_URL)
### Phase 7: Build & Release Pipeline
- Updated GitHub Actions workflows for LLMX binary names
- Fixed rust-release.yml to reference llmx-rs/ instead of codex-rs/
- Updated CI/CD pipelines for new package names
- Made Apple code signing optional in release workflow
- Enhanced npm packaging resilience for partial platform builds
- Added Windows sandbox support to workspace
- Updated dotslash configuration for new binary names
### Phase 8: Final Polish
- Renamed all assets (.github images, labels, templates)
- Updated VSCode and DevContainer configurations
- Fixed all clippy warnings and formatting issues
- Applied cargo fmt and prettier formatting across codebase
- Updated issue templates and pull request templates
- Fixed all remaining UI text references
## Technical Details
**Breaking Changes:**
- Binary name changed from `codex` to `llmx`
- Config directory changed from `~/.codex/` to `~/.llmx/`
- Environment variables renamed (CODEX_* → LLMX_*)
- npm package renamed to `@valknar/llmx`
**New Features:**
- Support for 100+ LLM providers via LiteLLM
- Unified authentication with LLMX_API_KEY
- Enhanced model provider detection and handling
- Improved error handling and fallback mechanisms
**Files Changed:**
- 578 files modified across Rust, TypeScript, and documentation
- 30+ Rust crates renamed and updated
- Complete rebrand of UI, CLI, and documentation
- All tests updated and passing
**Dependencies:**
- Updated Cargo.lock with new package names
- Updated npm dependencies in llmx-cli
- Enhanced OpenAPI models for LLMX backend
This release establishes LLMX as a standalone project with comprehensive LiteLLM
integration, maintaining full backward compatibility with existing functionality
while opening support for a wide ecosystem of LLM providers.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Sebastian Krüger <support@pivoine.art>
2025-11-12 20:40:44 +01:00
term : llmx_tui ::custom_terminal ::Terminal < VT100Backend > ,
2025-08-04 21:23:22 -07:00
}
impl TestScenario {
fn new ( width : u16 , height : u16 , viewport : Rect ) -> Self {
2025-09-26 16:35:56 -07:00
let backend = VT100Backend ::new ( width , height ) ;
feat: Complete LLMX v0.1.0 - Rebrand from Codex with LiteLLM Integration
This release represents a comprehensive transformation of the codebase from Codex to LLMX,
enhanced with LiteLLM integration to support 100+ LLM providers through a unified API.
## Major Changes
### Phase 1: Repository & Infrastructure Setup
- Established new repository structure and branching strategy
- Created comprehensive project documentation (CLAUDE.md, LITELLM-SETUP.md)
- Set up development environment and tooling configuration
### Phase 2: Rust Workspace Transformation
- Renamed all Rust crates from `codex-*` to `llmx-*` (30+ crates)
- Updated package names, binary names, and workspace members
- Renamed core modules: codex.rs → llmx.rs, codex_delegate.rs → llmx_delegate.rs
- Updated all internal references, imports, and type names
- Renamed directories: codex-rs/ → llmx-rs/, codex-backend-openapi-models/ → llmx-backend-openapi-models/
- Fixed all Rust compilation errors after mass rename
### Phase 3: LiteLLM Integration
- Integrated LiteLLM for multi-provider LLM support (Anthropic, OpenAI, Azure, Google AI, AWS Bedrock, etc.)
- Implemented OpenAI-compatible Chat Completions API support
- Added model family detection and provider-specific handling
- Updated authentication to support LiteLLM API keys
- Renamed environment variables: OPENAI_BASE_URL → LLMX_BASE_URL
- Added LLMX_API_KEY for unified authentication
- Enhanced error handling for Chat Completions API responses
- Implemented fallback mechanisms between Responses API and Chat Completions API
### Phase 4: TypeScript/Node.js Components
- Renamed npm package: @codex/codex-cli → @valknar/llmx
- Updated TypeScript SDK to use new LLMX APIs and endpoints
- Fixed all TypeScript compilation and linting errors
- Updated SDK tests to support both API backends
- Enhanced mock server to handle multiple API formats
- Updated build scripts for cross-platform packaging
### Phase 5: Configuration & Documentation
- Updated all configuration files to use LLMX naming
- Rewrote README and documentation for LLMX branding
- Updated config paths: ~/.codex/ → ~/.llmx/
- Added comprehensive LiteLLM setup guide
- Updated all user-facing strings and help text
- Created release plan and migration documentation
### Phase 6: Testing & Validation
- Fixed all Rust tests for new naming scheme
- Updated snapshot tests in TUI (36 frame files)
- Fixed authentication storage tests
- Updated Chat Completions payload and SSE tests
- Fixed SDK tests for new API endpoints
- Ensured compatibility with Claude Sonnet 4.5 model
- Fixed test environment variables (LLMX_API_KEY, LLMX_BASE_URL)
### Phase 7: Build & Release Pipeline
- Updated GitHub Actions workflows for LLMX binary names
- Fixed rust-release.yml to reference llmx-rs/ instead of codex-rs/
- Updated CI/CD pipelines for new package names
- Made Apple code signing optional in release workflow
- Enhanced npm packaging resilience for partial platform builds
- Added Windows sandbox support to workspace
- Updated dotslash configuration for new binary names
### Phase 8: Final Polish
- Renamed all assets (.github images, labels, templates)
- Updated VSCode and DevContainer configurations
- Fixed all clippy warnings and formatting issues
- Applied cargo fmt and prettier formatting across codebase
- Updated issue templates and pull request templates
- Fixed all remaining UI text references
## Technical Details
**Breaking Changes:**
- Binary name changed from `codex` to `llmx`
- Config directory changed from `~/.codex/` to `~/.llmx/`
- Environment variables renamed (CODEX_* → LLMX_*)
- npm package renamed to `@valknar/llmx`
**New Features:**
- Support for 100+ LLM providers via LiteLLM
- Unified authentication with LLMX_API_KEY
- Enhanced model provider detection and handling
- Improved error handling and fallback mechanisms
**Files Changed:**
- 578 files modified across Rust, TypeScript, and documentation
- 30+ Rust crates renamed and updated
- Complete rebrand of UI, CLI, and documentation
- All tests updated and passing
**Dependencies:**
- Updated Cargo.lock with new package names
- Updated npm dependencies in llmx-cli
- Enhanced OpenAPI models for LLMX backend
This release establishes LLMX as a standalone project with comprehensive LiteLLM
integration, maintaining full backward compatibility with existing functionality
while opening support for a wide ecosystem of LLM providers.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Sebastian Krüger <support@pivoine.art>
2025-11-12 20:40:44 +01:00
let mut term = llmx_tui ::custom_terminal ::Terminal ::with_options ( backend )
2025-08-04 21:23:22 -07:00
. expect ( " failed to construct terminal " ) ;
term . set_viewport_area ( viewport ) ;
2025-09-26 16:35:56 -07:00
Self { term }
2025-08-04 21:23:22 -07:00
}
2025-09-26 16:35:56 -07:00
fn run_insert ( & mut self , lines : Vec < Line < 'static > > ) {
feat: Complete LLMX v0.1.0 - Rebrand from Codex with LiteLLM Integration
This release represents a comprehensive transformation of the codebase from Codex to LLMX,
enhanced with LiteLLM integration to support 100+ LLM providers through a unified API.
## Major Changes
### Phase 1: Repository & Infrastructure Setup
- Established new repository structure and branching strategy
- Created comprehensive project documentation (CLAUDE.md, LITELLM-SETUP.md)
- Set up development environment and tooling configuration
### Phase 2: Rust Workspace Transformation
- Renamed all Rust crates from `codex-*` to `llmx-*` (30+ crates)
- Updated package names, binary names, and workspace members
- Renamed core modules: codex.rs → llmx.rs, codex_delegate.rs → llmx_delegate.rs
- Updated all internal references, imports, and type names
- Renamed directories: codex-rs/ → llmx-rs/, codex-backend-openapi-models/ → llmx-backend-openapi-models/
- Fixed all Rust compilation errors after mass rename
### Phase 3: LiteLLM Integration
- Integrated LiteLLM for multi-provider LLM support (Anthropic, OpenAI, Azure, Google AI, AWS Bedrock, etc.)
- Implemented OpenAI-compatible Chat Completions API support
- Added model family detection and provider-specific handling
- Updated authentication to support LiteLLM API keys
- Renamed environment variables: OPENAI_BASE_URL → LLMX_BASE_URL
- Added LLMX_API_KEY for unified authentication
- Enhanced error handling for Chat Completions API responses
- Implemented fallback mechanisms between Responses API and Chat Completions API
### Phase 4: TypeScript/Node.js Components
- Renamed npm package: @codex/codex-cli → @valknar/llmx
- Updated TypeScript SDK to use new LLMX APIs and endpoints
- Fixed all TypeScript compilation and linting errors
- Updated SDK tests to support both API backends
- Enhanced mock server to handle multiple API formats
- Updated build scripts for cross-platform packaging
### Phase 5: Configuration & Documentation
- Updated all configuration files to use LLMX naming
- Rewrote README and documentation for LLMX branding
- Updated config paths: ~/.codex/ → ~/.llmx/
- Added comprehensive LiteLLM setup guide
- Updated all user-facing strings and help text
- Created release plan and migration documentation
### Phase 6: Testing & Validation
- Fixed all Rust tests for new naming scheme
- Updated snapshot tests in TUI (36 frame files)
- Fixed authentication storage tests
- Updated Chat Completions payload and SSE tests
- Fixed SDK tests for new API endpoints
- Ensured compatibility with Claude Sonnet 4.5 model
- Fixed test environment variables (LLMX_API_KEY, LLMX_BASE_URL)
### Phase 7: Build & Release Pipeline
- Updated GitHub Actions workflows for LLMX binary names
- Fixed rust-release.yml to reference llmx-rs/ instead of codex-rs/
- Updated CI/CD pipelines for new package names
- Made Apple code signing optional in release workflow
- Enhanced npm packaging resilience for partial platform builds
- Added Windows sandbox support to workspace
- Updated dotslash configuration for new binary names
### Phase 8: Final Polish
- Renamed all assets (.github images, labels, templates)
- Updated VSCode and DevContainer configurations
- Fixed all clippy warnings and formatting issues
- Applied cargo fmt and prettier formatting across codebase
- Updated issue templates and pull request templates
- Fixed all remaining UI text references
## Technical Details
**Breaking Changes:**
- Binary name changed from `codex` to `llmx`
- Config directory changed from `~/.codex/` to `~/.llmx/`
- Environment variables renamed (CODEX_* → LLMX_*)
- npm package renamed to `@valknar/llmx`
**New Features:**
- Support for 100+ LLM providers via LiteLLM
- Unified authentication with LLMX_API_KEY
- Enhanced model provider detection and handling
- Improved error handling and fallback mechanisms
**Files Changed:**
- 578 files modified across Rust, TypeScript, and documentation
- 30+ Rust crates renamed and updated
- Complete rebrand of UI, CLI, and documentation
- All tests updated and passing
**Dependencies:**
- Updated Cargo.lock with new package names
- Updated npm dependencies in llmx-cli
- Enhanced OpenAPI models for LLMX backend
This release establishes LLMX as a standalone project with comprehensive LiteLLM
integration, maintaining full backward compatibility with existing functionality
while opening support for a wide ecosystem of LLM providers.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Sebastian Krüger <support@pivoine.art>
2025-11-12 20:40:44 +01:00
llmx_tui ::insert_history ::insert_history_lines ( & mut self . term , lines )
2025-10-30 18:07:51 -07:00
. expect ( " Failed to insert history lines in test " ) ;
2025-08-04 21:23:22 -07:00
}
}
#[ test ]
2025-08-12 17:37:28 -07:00
fn basic_insertion_no_wrap ( ) {
2025-08-04 21:23:22 -07:00
// Screen of 20x6; viewport is the last row (height=1 at y=5)
let area = Rect ::new ( 0 , 5 , 20 , 1 ) ;
let mut scenario = TestScenario ::new ( 20 , 6 , area ) ;
2025-09-02 16:19:54 -07:00
let lines = vec! [ " first " . into ( ) , " second " . into ( ) ] ;
2025-09-26 16:35:56 -07:00
scenario . run_insert ( lines ) ;
let rows = scenario . term . backend ( ) . vt100 ( ) . screen ( ) . contents ( ) ;
2025-08-04 21:23:22 -07:00
assert_contains! ( rows , String ::from ( " first " ) ) ;
assert_contains! ( rows , String ::from ( " second " ) ) ;
}
#[ test ]
2025-08-12 17:37:28 -07:00
fn long_token_wraps ( ) {
2025-08-04 21:23:22 -07:00
let area = Rect ::new ( 0 , 5 , 20 , 1 ) ;
let mut scenario = TestScenario ::new ( 20 , 6 , area ) ;
let long = " A " . repeat ( 45 ) ; // > 2 lines at width 20
2025-09-02 16:19:54 -07:00
let lines = vec! [ long . clone ( ) . into ( ) ] ;
2025-09-26 16:35:56 -07:00
scenario . run_insert ( lines ) ;
let screen = scenario . term . backend ( ) . vt100 ( ) . screen ( ) ;
2025-08-04 21:23:22 -07:00
// Count total A's on the screen
let mut count_a = 0 usize ;
for row in 0 .. 6 {
for col in 0 .. 20 {
2025-08-19 13:22:02 -07:00
if let Some ( cell ) = screen . cell ( row , col )
& & let Some ( ch ) = cell . contents ( ) . chars ( ) . next ( )
& & ch = = 'A'
{
count_a + = 1 ;
2025-08-04 21:23:22 -07:00
}
}
}
assert_eq! (
count_a ,
long . len ( ) ,
" wrapped content did not preserve all characters "
) ;
}
#[ test ]
2025-08-12 17:37:28 -07:00
fn emoji_and_cjk ( ) {
2025-08-04 21:23:22 -07:00
let area = Rect ::new ( 0 , 5 , 20 , 1 ) ;
let mut scenario = TestScenario ::new ( 20 , 6 , area ) ;
let text = String ::from ( " 😀😀😀😀😀 你好世界 " ) ;
2025-09-02 16:19:54 -07:00
let lines = vec! [ text . clone ( ) . into ( ) ] ;
2025-09-26 16:35:56 -07:00
scenario . run_insert ( lines ) ;
let rows = scenario . term . backend ( ) . vt100 ( ) . screen ( ) . contents ( ) ;
2025-08-04 21:23:22 -07:00
for ch in text . chars ( ) . filter ( | c | ! c . is_whitespace ( ) ) {
assert! (
2025-09-26 16:35:56 -07:00
rows . contains ( ch ) ,
2025-08-04 21:23:22 -07:00
" missing character {ch:?} in reconstructed screen "
) ;
}
}
#[ test ]
2025-08-12 17:37:28 -07:00
fn mixed_ansi_spans ( ) {
2025-08-04 21:23:22 -07:00
let area = Rect ::new ( 0 , 5 , 20 , 1 ) ;
let mut scenario = TestScenario ::new ( 20 , 6 , area ) ;
2025-09-02 16:19:54 -07:00
let line = vec! [ " red " . red ( ) , " +plain " . into ( ) ] . into ( ) ;
2025-09-26 16:35:56 -07:00
scenario . run_insert ( vec! [ line ] ) ;
let rows = scenario . term . backend ( ) . vt100 ( ) . screen ( ) . contents ( ) ;
2025-08-04 21:23:22 -07:00
assert_contains! ( rows , String ::from ( " red+plain " ) ) ;
}
#[ test ]
2025-08-12 17:37:28 -07:00
fn cursor_restoration ( ) {
2025-08-04 21:23:22 -07:00
let area = Rect ::new ( 0 , 5 , 20 , 1 ) ;
let mut scenario = TestScenario ::new ( 20 , 6 , area ) ;
2025-09-02 16:19:54 -07:00
let lines = vec! [ " x " . into ( ) ] ;
2025-09-26 16:35:56 -07:00
scenario . run_insert ( lines ) ;
assert_eq! ( scenario . term . last_known_cursor_pos , ( 0 , 0 ) . into ( ) ) ;
2025-08-04 21:23:22 -07:00
}
#[ test ]
2025-08-12 17:37:28 -07:00
fn word_wrap_no_mid_word_split ( ) {
// Screen of 40x10; viewport is the last row
let area = Rect ::new ( 0 , 9 , 40 , 1 ) ;
let mut scenario = TestScenario ::new ( 40 , 10 , area ) ;
let sample = " Years passed, and Willowmere thrived in peace and friendship. Mira’ s herb garden flourished with both ordinary and enchanted plants, and travelers spoke of the kindness of the woman who tended them. " ;
2025-09-26 16:35:56 -07:00
scenario . run_insert ( vec! [ sample . into ( ) ] ) ;
let joined = scenario . term . backend ( ) . vt100 ( ) . screen ( ) . contents ( ) ;
2025-08-12 17:37:28 -07:00
assert! (
! joined . contains ( " bo \n th " ) ,
" word 'both' should not be split across lines: \n {joined} "
) ;
}
#[ test ]
fn em_dash_and_space_word_wrap ( ) {
// Repro from report: ensure we break before "inside", not mid-word.
let area = Rect ::new ( 0 , 9 , 40 , 1 ) ;
let mut scenario = TestScenario ::new ( 40 , 10 , area ) ;
let sample = " Mara found an old key on the shore. Curious, she opened a tarnished box half-buried in sand—and inside lay a single, glowing seed. " ;
2025-09-26 16:35:56 -07:00
scenario . run_insert ( vec! [ sample . into ( ) ] ) ;
let joined = scenario . term . backend ( ) . vt100 ( ) . screen ( ) . contents ( ) ;
2025-08-12 17:37:28 -07:00
assert! (
! joined . contains ( " insi \n de " ) ,
" word 'inside' should not be split across lines: \n {joined} "
) ;
}