Skip to content

Conversation

@pcharbon70
Copy link
Collaborator

No description provided.

Sessions can now be created without valid LLM credentials. The agent
is started on-demand when the first message is sent, providing better
UX when API keys are not yet configured.

Changes:
- Add connection_status field to Session struct (:disconnected/:connected/:error)
- Change Session.Supervisor strategy to :one_for_one (independent restarts)
- Add start_agent/1, stop_agent/1, agent_running?/1 to Session.Supervisor
- Add Connection API to AgentAPI: ensure_connected/1, disconnect/1, connected?/1
- Update TUI to lazily connect before sending messages
- Add user-friendly connection error messages
- Update tests for new lazy startup behavior
- Create Frame widget that draws visible borders around content
- Supports single, double, and rounded border character sets
- Optional title display in top border
- Apply Frame to tabs pane as proof of concept
- Set logger level to :error in dev to avoid TUI interference
Integrate TextInput widget directly into ConversationView, eliminating
the separate input area and providing a unified conversation interface.

Key changes:
- ConversationView now manages its own TextInput widget internally
- TextInput positioned at bottom of conversation with proper sizing
- Per-session UI state stored in session[:ui_state] for multi-session support
- Streaming messages accessed via Model.get_active_ui_state/1

Test fixes for lazy agent startup and supervisor strategy:
- AgentAPITest: Add start_agent calls before agent operations
- SessionPhase1/2Test: Update for :one_for_one strategy behavior
- SessionPhase4Test: Access streaming via per-session UI state
- SessionSupervisorTest: Use relative child counts
- SessionTestHelpers: Use existing registries instead of restarting

All 2766 tests passing.
Reverted ConversationView.render/2 to simple structure that works on
large terminals (132x72+). The previous TextInput integration approach
created excessive render nodes that caused rendering failures.

Changes:
- ConversationView.render/2 now returns simple structure (text or
  horizontal stack with scrollbar) instead of vertical stack with
  separator and input
- TextInput state is still managed in ConversationView for convenience
- Actual input rendering is handled separately by MainLayout
- Added get_active_input_value/1 to Model for input value access
- Updated get_active_text_input/1 to check both ui_state.text_input
  and ui_state.conversation_view.text_input
- Updated input event handling to sync text_input in both locations
- Updated tests to match simpler render structure
Added more comprehensive terminal reset on quit:
- Disable X10 mouse mode (\e[?9l) in addition to other modes
- Exit alternate screen buffer (\e[?1049l)
- Reset terminal attributes to normal (\e[0m)

This should prevent mouse escape codes from spamming the console
after quitting the application.
Ctrl+C is intercepted by the Erlang runtime before reaching the
application. Ctrl+Q is XON (flow control) and often not passed through
by terminals. Ctrl+D (EOF) is a common quit shortcut in Unix shells
and works reliably.

This allows the app to properly disable mouse tracking and restore
terminal state on exit.
The content width was always subtracting 20% for sidebar regardless of
whether sidebar was visible. Now correctly uses actual sidebar_visible
state and sidebar_width to calculate available content width.
- Use proportional sidebar width (20%) matching MainLayout calculation
- Wrap content_stack in box with explicit width to fill available space
- Update test helper to handle new box wrapper structure
- Remove unused default values from render_single_tab/8 and build_label_with_close/4
- Fix test setup to use GenServer.whereis instead of Process.whereis for Registry names
- Apply mix format
Use Frame widget for complete border around the sessions area
instead of just top/bottom horizontal lines.
Use single multi-line text node for vertical borders instead of
individual text nodes per line. This prevents rendering issues on
large terminals caused by excessive node count.
Move the Frame widget to wrap only the content area (status bar,
conversation view, input) while keeping the tab bar outside/above
the frame border.
- Implement Option 5 connected folder tabs (╰ connects to next tab's │)
- Remove background color from active tabs (now cyan foreground only)
- Reduce sidebar header to 2 lines to match tab bar height
- Add rounded corners to content frame
- Add empty line between status bar and conversation content
- Remove unused @bottom_right module attribute
Improve code formatting consistency:
- Line breaks for long function calls and map updates
- Multi-line syntax for complex expressions
- Comment positioning fixes
Implement region-based mouse event routing to enable:
- Click on tabs to switch sessions
- Click on × button to close tabs
- Click on sidebar sessions to switch to them

Add route_mouse_event/2 for position-based routing, update handlers
for :tab_click and :sidebar_click messages, and helper functions for
session switching/closing. Includes 7 new tests.
Filter route_mouse_event to only process :click and :press actions.
Other mouse events (scroll, drag, release, move) are forwarded to
ConversationView. This prevents tabs from closing on hover.
On startup, check if a persisted session exists for the current
working directory. If found, show a confirmation dialog asking
whether to resume the previous session or start fresh.

- Add find_by_project_path/1 to Persistence module
- Add resume_dialog state and overlay rendering
- Handle Enter (resume) and Esc (new session) actions
- Add 10 tests for the new functionality
- Update status bar to show provider and model (or "none" if not set)
- Store provider/model config per-session instead of globally
- Update active session's config when provider/model is selected
- Allow nil provider/model in Session validation (not configured yet)
- Remove "unconfigured" status display, show "Idle" instead
- Use consistent status indicators (checkmark) for unconfigured state
- Replace text labels with icons: ⬢ (provider), ◆ (model), ⚙ (status)
- Add is_processing state to LLMAgent to track when streaming
- Agent now reports ready: false while processing a request
- Status bar shows "Processing" during LLM streaming, "Idle" when ready
…state

Each session now tracks its own agent_status independently, consistent
with other per-session UI state like agent_activity and awaiting_input.

- Remove agent_status from Model struct defstruct and type
- Add agent_status to session_ui_state type and default_ui_state/1
- Add helper functions: get_active_agent_status/1, get_session_agent_status/2,
  set_active_agent_status/2, set_session_agent_status/3
- Update message_handlers.ex to use Model.set_active_agent_status/2
- Update view_helpers.ex to use Model.get_active_agent_status/1
- Update tests to use new per-session pattern
Display the current agent mode (chat, chain-of-thought, react, etc.)
in a new status bar positioned below the text input.

- Add render_mode_bar/1 in view_helpers.ex
- Pass mode_bar_view through MainLayout render pipeline
- Show active thinking mode when processing, default to "chat"
- Add paste_from_clipboard/0 to clipboard module
- Add detect_paste_command/0 for platform detection
- Support pbpaste, wl-paste, xclip, xsel, powershell
- Handle Ctrl+V in TUI to trigger paste
- Insert pasted text at cursor position in TextInput
- Add selection state (start/end positions, selecting flag) to
  ConversationView widget
- Handle mouse press/drag/release for text selection
- Render selected text with highlight style (reverse video)
- Extract selected text for single/multi-line and cross-message selections
- Add Ctrl+Y handler to copy selected text to clipboard
- Refactor selection logic into smaller helper functions for better
  maintainability
- Move insert_text_at_cursor after update/2 clauses to fix grouping
  warning
Format changes applied by mix format to improve code readability.
- Trap exits to prevent ReqLLM internal cleanup tasks from crashing
  the streaming task
- Await metadata_task from ReqLLM.StreamResponse to get token usage
- Broadcast stream_end with metadata map containing usage info
- Drain EXIT messages after streaming completes
- Handle edge cases: nil streams, process cleanup race conditions
Implement complete usage tracking for LLM interactions:

Display:
- Status bar shows cumulative session usage: 🎟️ X in / Y out | $Z.ZZZZ
- Per-message usage line appears above assistant messages
- Muted styling for usage lines to avoid distraction

Tracking:
- Extract usage from stream metadata (input_tokens, output_tokens, total_cost)
- Accumulate usage per session in UI state
- Attach usage to individual assistant messages

Persistence:
- Serialize/deserialize message usage data
- Calculate and persist cumulative session usage
- Handle legacy messages/sessions without usage gracefully

Testing:
- Add message_handlers_test.exs with 19 tests for usage functions
- Add 8 persistence tests for usage serialization

Files changed:
- lib/jido_code/tui/message_handlers.ex - Usage extraction and formatting
- lib/jido_code/tui/view_helpers.ex - Status bar and message display
- lib/jido_code/tui.ex - Add usage field to session UI state
- lib/jido_code/session/persistence/* - Usage persistence
Add JidoCode.Language module for detecting and managing programming
languages in projects. Includes:

- detect/1: Auto-detects language from project marker files
  (mix.exs, package.json, Cargo.toml, pyproject.toml, etc.)
- normalize/1: Normalizes strings/atoms to valid language atoms
  with support for aliases (js, py, rb, c++, c#)
- valid?/1, all_languages/0: Language validation helpers
- display_name/1, icon/1: Human-readable names and icons
- default/0: Returns :elixir as the default language

Supports 13 languages: Elixir, JavaScript, TypeScript, Rust, Python,
Go, Ruby, Java, Kotlin, C#, PHP, C++, and C.
Wire up language detection throughout JidoCode:

Session integration:
- Add :language field to Session struct with auto-detection in new/1
- Add set_language/2 for manual language override
- Add Session.State.update_language/2 client API
- Add language to persistence serialization/deserialization
- Handle legacy sessions without language (default to :elixir)

TUI integration:
- Add /language command to show current language
- Add /language <lang> command to set language
- Add handle_language_command/2 in TUI
- Add Model.update_session/3 helper function
- Display language in status bar after project path

Test updates:
- Add :language to expected Session struct fields
- Add language to mock session state in persistence tests
- Update mode bar to show language on right side (e.g., "💧 Elixir")
- Add comprehensive tests for Language module (37 tests)
- Add tests for /language command parsing and execution (13 tests)
- Add JidoCode.TUI.Markdown module for parsing and styling markdown
- Render assistant messages with proper formatting (headers, bold,
  italic, code blocks, lists, blockquotes, links)
- Code blocks display with box-style borders and language headers
- Add language-aware system prompt to LLMAgent (uses session's
  detected language to guide code snippet generation)
- Fix truncation indicator appearing during streaming
- Add 26 tests for markdown rendering

Dependencies: MDEx ~> 0.10 (Rust-based CommonMark parser)
Only tool results should be truncated, not LLM responses or user messages.
Users can scroll to see full content of conversations.
Use Makeup library to provide semantic token-based syntax highlighting
for Elixir code in markdown code blocks. Tokens are styled with
appropriate colors (keywords: magenta, strings: green, atoms: cyan,
comments: dim gray, function names: blue, module names: yellow).
Add keyboard navigation for code blocks in conversation view:
- Tab enters interactive mode and cycles through code blocks
- Shift+Tab cycles backwards
- Enter copies focused block to clipboard
- Escape exits interactive mode

Visual feedback shows focused block with cyan border and [c] hint.
Clipboard module supports OSC 52 and platform-specific commands.
Tab key was being intercepted by main_layout for pane focus cycling,
preventing it from reaching the conversation view. Changed to Ctrl+B
for entering interactive code block mode, Enter to copy, Escape to exit.
- Up Arrow navigates to previous prompt, Down Arrow to next
- ESC clears input and exits history mode
- History persists with session save/resume
- Maximum 100 prompts per session
- Both chat prompts and commands stored
- Added save_all_sessions/1 to persist all active sessions before exit
- Prompt history and conversation state now preserved on app exit
- Updated documentation to reflect auto-save behavior
Ontology reorganization:
- Move core ontology files to lib/ontology/long-term-context/
- Add new security ontology (elixir-security.ttl, elixir-security-shapes.ttl)

New research documents:
- 1.01: LLM workflow examples and SPARQL queries
- 1.07: Two-tier memory system design
- 1.08: Credo rules semantic representation
- 1.09: Anti-pattern semantic prevention
- 1.10: Security prevention system
@pcharbon70 pcharbon70 merged commit 3838e8b into main Dec 27, 2025
1 of 6 checks passed
pcharbon70 added a commit that referenced this pull request Jan 6, 2026
Phase 7 Blocker Fix #2 - Add input validation for memory and session IDs
before they are embedded in SPARQL query strings.

## Security Improvements

- Add valid_memory_id?/1 and valid_session_id?/1 to SPARQLQueries
- Add validate_memory_id/1 and validate_session_id/1 to TripleStoreAdapter
- Validate IDs in all public API functions before query generation

## Validation Rules

- IDs must be 1-128 characters
- Only alphanumeric characters, hyphens, and underscores allowed
- Prevents SPARQL injection, path traversal, and other injection attacks

## Functions Protected

- persist/2, query_by_type/4, query_all/3, query_by_id/2
- supersede/4, delete/3, record_access/3
- query_related/5, get_stats/2, count/3

## Tests Added

- Comprehensive validation tests in triple_store_adapter_test.exs
- Tests for injection attempts, path traversal, and edge cases

## Related

- Completes Phase 7 security blocker fixes
- Addresses review concern about missing input validation
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