Skip to content

Commit c8f45c5

Browse files
committed
reorganize files and logic into cleaner structure
1 parent 2ad84af commit c8f45c5

18 files changed

Lines changed: 170 additions & 101 deletions

.sofosrc

Lines changed: 55 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,18 @@ Sofos is a terminal-based AI coding assistant powered by Anthropic's Claude API.
1414

1515
### Key Design Decisions
1616

17-
1. **Dual Session Storage Format** (src/history.rs)
17+
1. **Dual Session Storage Format** (src/session/history.rs)
1818
- `api_messages`: Anthropic API format for continuing conversations
1919
- `display_messages`: UI-friendly format for showing conversation history
2020
- This separation ensures Claude sees proper API format while users see original UI
2121

22-
2. **Tool Calling Pattern** (src/repl.rs)
22+
2. **Tool Calling Pattern** (src/repl/mod.rs)
2323
- Assistant returns content blocks (text + tool_use)
2424
- REPL executes tools and collects results
2525
- Results sent back as user message with tool_result blocks
2626
- **Loop-based handling** allows Claude to use multiple tools in sequence iteratively
2727

28-
3. **Two-Level Instructions** (src/history.rs)
28+
3. **Two-Level Instructions** (src/session/history.rs)
2929
- `.sofosrc`: Project-level, version controlled
3030
- `.sofos/instructions.md`: Personal, gitignored
3131
- Both appended to system prompt at startup
@@ -43,27 +43,47 @@ Sofos is a terminal-based AI coding assistant powered by Anthropic's Claude API.
4343

4444
```
4545
src/
46-
├── api/ # Anthropic API integration
47-
│ ├── client.rs # HTTP client for Claude API
48-
│ ├── morph.rs # Morph Apply API client (optional)
49-
│ ├── types.rs # Message types and serialization
50-
│ └── mod.rs
51-
├── tools/ # Tool implementations
52-
│ ├── filesystem.rs # File operations (read, write, list, etc)
53-
│ ├── bashexec.rs # Sandboxed bash execution
54-
│ ├── codesearch.rs # Ripgrep integration
55-
│ ├── permissions.rs # 3-tier command permission system
56-
│ ├── types.rs # Tool definitions for API
57-
│ └── mod.rs
58-
├── conversation.rs # Message history management
59-
├── diff.rs # Contextual diff generation and display
60-
├── history.rs # Session persistence + custom instructions
61-
├── repl.rs # Main REPL loop and display logic
62-
├── syntax.rs # Markdown/code syntax highlighting
63-
├── cli.rs # Command-line argument parsing
64-
├── error.rs # Error types
65-
├── session_selector.rs # TUI for session selection
66-
└── main.rs # Entry point
46+
├── main.rs # Entry point
47+
├── cli.rs # CLI argument parsing
48+
├── error.rs # Error types
49+
├── error_ext.rs # Error extensions
50+
├── config.rs # Configuration (SofosConfig, ModelConfig)
51+
52+
├── api/ # API clients
53+
│ ├── anthropic.rs # Claude API client
54+
│ ├── openai.rs # OpenAI API client
55+
│ ├── morph.rs # Morph Apply API client
56+
│ ├── types.rs # Message types and serialization
57+
│ └── utils.rs # API utilities
58+
59+
├── repl/ # REPL components
60+
│ ├── mod.rs # Main REPL loop and Repl struct
61+
│ ├── conversation.rs # Message history management
62+
│ ├── prompt.rs # Prompt rendering
63+
│ ├── request_builder.rs # API request construction
64+
│ └── response_handler.rs # Response processing
65+
66+
├── session/ # Session management
67+
│ ├── history.rs # Session persistence + custom instructions
68+
│ ├── state.rs # Runtime session state
69+
│ └── selector.rs # Session selection TUI
70+
71+
├── tools/ # Tool implementations
72+
│ ├── filesystem.rs # File operations (read, write, list, etc)
73+
│ ├── bashexec.rs # Sandboxed bash execution
74+
│ ├── codesearch.rs # Ripgrep integration
75+
│ ├── image.rs # Image handling
76+
│ ├── permissions.rs # 3-tier command permission system
77+
│ ├── types.rs # Tool definitions for API
78+
│ └── utils.rs # Tool utilities
79+
80+
├── ui/ # UI components
81+
│ ├── mod.rs # Main UI utilities and display logic
82+
│ ├── syntax.rs # Markdown/code syntax highlighting
83+
│ └── diff.rs # Contextual diff generation and display
84+
85+
└── commands/ # Built-in commands
86+
└── builtin.rs # Command implementations
6787
```
6888

6989
### Key Files
@@ -73,25 +93,28 @@ src/
7393
- Handles serialization/deserialization for Anthropic API
7494
- Supports both regular and server-side tools (like web_search)
7595

76-
**src/diff.rs**
96+
**src/ui/diff.rs**
7797
- Generate contextual diffs showing only changed code blocks
7898
- Uses `similar` crate for accurate line-by-line diffing
7999
- Formats output with colored backgrounds (red for deletions, blue for additions)
80100
- Context lines (default: 2) show unchanged code around changes
81101
- Used by morph_edit_file tool to display what changed
82102

83-
**src/history.rs**
103+
**src/session/history.rs**
84104
- SessionMetadata: Preview and timestamps for session list
85105
- Session: Dual storage (api_messages + display_messages)
86106
- DisplayMessage: Enum for user messages, assistant responses, and tool executions
87107

88-
**src/repl.rs**
108+
**src/repl/mod.rs**
89109
- Main event loop (run method)
90-
- handle_response: Recursively processes assistant responses and tool calls
91-
- display_session: Reconstructs conversation UI when resuming
92-
- Max recursion depth: 50 (prevents infinite loops)
110+
- Manages REPL state and user interaction
111+
- Coordinates conversation, tools, and UI
93112

94-
**src/conversation.rs**
113+
**src/repl/response_handler.rs**
114+
- Iteratively processes assistant responses and tool calls
115+
- Max iterations: 200 (prevents infinite loops)
116+
117+
**src/repl/conversation.rs**
95118
- Manages in-memory message history
96119
- Trims to MAX_MESSAGES (500) to prevent token overflow
97120
- Builds system prompt with features list and custom instructions
@@ -222,7 +245,7 @@ src/
222245

223246
**Problem:** Claude can make infinite tool calls if it gets stuck in a loop
224247

225-
**Solution:** (repl.rs:handle_response)
248+
**Solution:** (src/repl/response_handler.rs)
226249
- Use an **iterative loop** instead of recursion for constant stack space
227250
- Track iteration count in the loop
228251
- MAX_TOOL_ITERATIONS = 200

README.md

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,52 @@ cargo build --release # Build release
246246
RUST_LOG=debug sofos # Debug logging
247247
```
248248
249-
**Structure:** `src/` (api, tools, commands, repl, ui, conversation, history, config, etc.), `tests/`, `assets/`, `.sofos/` (gitignored), `.sofosrc` (version controlled)
249+
**Structure:**
250+
251+
```
252+
src/
253+
├── main.rs # Entry point
254+
├── cli.rs # CLI argument parsing
255+
├── error.rs # Error types
256+
├── error_ext.rs # Error extensions
257+
├── config.rs # Configuration (SofosConfig, ModelConfig)
258+
259+
├── api/ # API clients
260+
│ ├── anthropic.rs # Claude API client
261+
│ ├── openai.rs # OpenAI API client
262+
│ ├── morph.rs # Morph Apply API client
263+
│ ├── types.rs # Message types and serialization
264+
│ └── utils.rs # API utilities
265+
266+
├── repl/ # REPL components
267+
│ ├── mod.rs # Main REPL loop
268+
│ ├── conversation.rs # Message history management
269+
│ ├── prompt.rs # Prompt rendering
270+
│ ├── request_builder.rs # API request construction
271+
│ └── response_handler.rs # Response processing
272+
273+
├── session/ # Session management
274+
│ ├── history.rs # Session persistence
275+
│ ├── state.rs # Runtime session state
276+
│ └── selector.rs # Session selection TUI
277+
278+
├── tools/ # Tool implementations
279+
│ ├── filesystem.rs # File operations
280+
│ ├── bashexec.rs # Bash execution
281+
│ ├── codesearch.rs # Code search (ripgrep)
282+
│ ├── image.rs # Image handling
283+
│ ├── permissions.rs # Permission system
284+
│ ├── types.rs # Tool definitions
285+
│ └── utils.rs # Tool utilities
286+
287+
├── ui/ # UI components
288+
│ ├── mod.rs # Main UI utilities
289+
│ ├── syntax.rs # Syntax highlighting
290+
│ └── diff.rs # Diff generation
291+
292+
└── commands/ # Built-in commands
293+
└── builtin.rs # Command implementations
294+
```
250295
251296
See `.sofosrc` for detailed conventions.
252297

src/config.rs

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,11 @@
11
/// Central configuration for Sofos
22
#[derive(Debug, Clone)]
33
pub struct SofosConfig {
4-
/// Maximum number of messages to keep in conversation history
54
pub max_messages: usize,
6-
/// Maximum context tokens to send to API (includes system prompt and messages)
7-
/// Set to 180,000 to leave buffer below API's 200,000 limit
85
pub max_context_tokens: usize,
9-
/// Maximum number of tool execution iterations to prevent infinite loops
106
pub max_tool_iterations: u32,
11-
/// Maximum file size for read operations (in bytes)
127
#[allow(dead_code)]
138
pub max_file_size: usize,
14-
/// Maximum bash command output size (in bytes)
159
#[allow(dead_code)]
1610
pub max_bash_output: usize,
1711
}
@@ -22,12 +16,41 @@ impl Default for SofosConfig {
2216
max_messages: 500,
2317
max_context_tokens: 180_000,
2418
max_tool_iterations: 200,
25-
max_file_size: 10 * 1024 * 1024, // 10MB
26-
max_bash_output: 50 * 1024 * 1024, // 50MB
19+
max_file_size: 10 * 1024 * 1024,
20+
max_bash_output: 50 * 1024 * 1024,
2721
}
2822
}
2923
}
3024

25+
/// Configuration for the language model
26+
#[derive(Clone)]
27+
pub struct ModelConfig {
28+
pub model: String,
29+
pub max_tokens: u32,
30+
pub enable_thinking: bool,
31+
pub thinking_budget: u32,
32+
}
33+
34+
impl ModelConfig {
35+
pub fn new(
36+
model: String,
37+
max_tokens: u32,
38+
enable_thinking: bool,
39+
thinking_budget: u32,
40+
) -> Self {
41+
Self {
42+
model,
43+
max_tokens,
44+
enable_thinking,
45+
thinking_budget,
46+
}
47+
}
48+
49+
pub fn set_thinking(&mut self, enabled: bool) {
50+
self.enable_thinking = enabled;
51+
}
52+
}
53+
3154
impl SofosConfig {
3255
// No need for new() since Default::default() is the idiomatic way
3356
}

src/main.rs

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,10 @@ mod api;
22
mod cli;
33
mod commands;
44
mod config;
5-
mod conversation;
6-
mod diff;
75
mod error;
86
mod error_ext;
9-
mod history;
10-
mod model_config;
11-
mod prompt;
127
mod repl;
13-
mod request_builder;
14-
mod response_handler;
15-
mod session_selector;
16-
mod session_state;
17-
mod syntax;
8+
mod session;
189
mod tools;
1910
mod ui;
2011

@@ -23,8 +14,8 @@ use clap::Parser;
2314
use cli::Cli;
2415
use colored::Colorize;
2516
use error::Result;
26-
use history::HistoryManager;
2717
use repl::{Repl, ReplConfig};
18+
use session::HistoryManager;
2819
use std::env;
2920
use ui::UI;
3021

@@ -115,7 +106,7 @@ fn main() -> Result<()> {
115106
let history_manager = HistoryManager::new(workspace)?;
116107
let sessions = history_manager.list_sessions()?;
117108

118-
if let Some(session_id) = session_selector::select_session(sessions)? {
109+
if let Some(session_id) = session::select_session(sessions)? {
119110
repl.load_session_by_id(&session_id)?;
120111
println!();
121112
}

src/model_config.rs

Lines changed: 0 additions & 28 deletions
This file was deleted.

src/repl.rs renamed to src/repl/mod.rs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
1+
pub mod conversation;
2+
mod prompt;
3+
mod request_builder;
4+
mod response_handler;
5+
6+
pub use conversation::ConversationHistory;
7+
pub use prompt::ReplPrompt;
8+
pub use request_builder::RequestBuilder;
9+
pub use response_handler::ResponseHandler;
10+
111
use crate::api::LlmClient::Anthropic;
212
use crate::api::{CreateMessageRequest, ImageSource, LlmClient, MessageContentBlock, MorphClient};
313
use crate::commands::{Command, CommandResult};
4-
use crate::config::{NORMAL_MODE_MESSAGE, SAFE_MODE_MESSAGE};
5-
use crate::conversation::ConversationHistory;
14+
use crate::config::{ModelConfig, NORMAL_MODE_MESSAGE, SAFE_MODE_MESSAGE};
615
use crate::error::{Result, SofosError};
7-
use crate::history::{DisplayMessage, HistoryManager};
8-
use crate::model_config::ModelConfig;
9-
use crate::prompt::ReplPrompt;
10-
use crate::request_builder::RequestBuilder;
11-
use crate::response_handler::ResponseHandler;
12-
use crate::session_state::SessionState;
16+
use crate::session::{DisplayMessage, HistoryManager, SessionState};
1317
use crate::tools::image::{extract_image_references, ImageLoader, ImageReference};
1418
use crate::tools::ToolExecutor;
1519
use crate::ui::{set_safe_mode_cursor_style, UI};
@@ -483,7 +487,7 @@ impl Repl {
483487
return Ok(());
484488
}
485489

486-
let selected_id = crate::session_selector::select_session(sessions)?;
490+
let selected_id = crate::session::select_session(sessions)?;
487491

488492
if let Some(session_id) = selected_id {
489493
self.load_session_by_id(&session_id)?;
File renamed without changes.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::api::LlmClient::{Anthropic, OpenAI};
22
use crate::api::{CreateMessageRequest, LlmClient, Tool};
3-
use crate::conversation::ConversationHistory;
3+
use crate::repl::conversation::ConversationHistory;
44

55
pub struct RequestBuilder<'a> {
66
client: &'a LlmClient,
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use crate::api::{ContentBlock, CreateMessageRequest, LlmClient};
22
use crate::config::SofosConfig;
3-
use crate::conversation::ConversationHistory;
43
use crate::error::{Result, SofosError};
5-
use crate::history::DisplayMessage;
6-
use crate::request_builder::RequestBuilder;
4+
use crate::repl::conversation::ConversationHistory;
5+
use crate::repl::request_builder::RequestBuilder;
6+
use crate::session::DisplayMessage;
77
use crate::tools::ToolExecutor;
88
use crate::ui::UI;
99
use colored::Colorize;

0 commit comments

Comments
 (0)