DeepSeek TUI Session State Management: A Complete Guide to Turn-Based Conversation

TLDR: DeepSeek TUI maintains conversation state through a centralized Session struct that persists for the entire TUI lifetime, managing turn-based message flow, context compaction via cycles, and project-aware file tracking while enforcing safety controls over tool execution.

DeepSeek TUI is a Rust-based terminal interface for interacting with DeepSeek language models. At its core lies a robust session state management system that enables persistent, turn-based conversations with automatic context compaction and tool execution capabilities. The repository Hmbown/DeepSeek-TUI implements this architecture through a centralized Session object defined in [crates/tui/src/core/session.rs](https://github.com/Hmbown/DeepSeek-TUI/blob/main/crates/tui/src/core/session.rs).

The Session Struct: Central State Container

The Session struct encapsulates the entire conversation state and configuration. Created when the TUI starts or when the dispatcher launches new execution, it persists until the session terminates.

Key fields include:

  • model – The identifier string (e.g., deepseek-v4-flash) specifying which LLM to query.
  • messages – A Vec<Message> storing the raw OpenAI-compatible chat history where every turn appends new entries.
  • reasoning_effort – Optional tier (off, low, medium, high, max) controlling DeepSeek's "thinking" mode depth.
  • workspace – The root PathBuf for resolving all relative file operations during tool execution.
  • system_prompt and compaction_summary_prompt – System-level prompts prepended to requests, with the latter storing compacted conversation summaries.
  • total_usage – Cumulative token counters (SessionUsage) updated after each turn via SessionUsage::add.
  • cycle_count, current_cycle_started, and cycle_briefings – Turn-based bookkeeping for conversation segmentation and the /cycles command.
  • allow_shell, trust_mode, auto_approve – Boolean flags controlling shell tool invocation, workspace boundary trust, and automatic safety approval.
  • working_set – A repo-aware file cache rebuilt from messages on demand, enabling the /files and /search commands.
  • project_context – Information loaded from AGENTS.md and CLAUDE.md files for context-aware tooling.
  • id – A UUID for telemetry and debugging purposes.

Turn-Based Conversation Lifecycle

Each interaction follows a strict turn-based execution model defined in [crates/tui/src/core/engine.rs](https://github.com/Hmbown/DeepSeek-TUI/blob/main/crates/tui/src/core/engine.rs). The lifecycle proceeds through five distinct phases:

1. User Input Capture

The UI creates a Message::User variant and calls Session::add_message to append the user content to the session history.

2. Engine Execution

The core engine reads session.messages, constructs the LLM request, transmits it to the DeepSeek API, and receives the response. The engine handles ContentBlock::Thinking segments by repeating reasoning blocks before final answers to comply with DeepSeek's "thinking mode" requirements.

3. Tool Call Processing

If the assistant response includes tool calls (e.g., fetch_url, web_search, apply_patch), the engine executes the appropriate handlers. Results are appended as Message::Tool entries, and the turn may replay until the model produces a final answer without tool requests.

4. Context Compaction and Cycle Handling

When the token budget approaches limits or after a configurable number of turns, the engine triggers compaction via Session::compaction_summary_prompt. The current conversation summarizes into a brief system prompt, cycle_count increments, and a CycleBriefing stores the phase summary. This bounds session size and enables the /cycles command timeline.

5. Working Set Reconstruction

Session::rebuild_working_set synchronizes the repo-aware file cache with the latest messages, ensuring subsequent /files and /search commands reference only conversation-relevant paths.

Cycle Management and Context Compaction

Long-running sessions utilize cycles to prevent unbounded token growth. A cycle represents a logical conversation segment capped by compaction events.

The CycleBriefing type, defined in [crates/tui/src/rlm/turn.rs](https://github.com/Hmbown/DeepSeek-TUI/blob/main/crates/tui/src/rlm/turn.rs), stores summaries of approximately 3,000 tokens maximum. When compaction triggers:

  1. The engine generates a summary of the current conversation context.
  2. The summary populates compaction_summary_prompt.
  3. cycle_count increments and current_cycle_started updates.
  4. A new CycleBriefing entry appends to cycle_briefings.

This design ensures the session remains serializable to disk for later resumption while maintaining manageable context windows.

Working Set and Project Awareness

The WorkingSet struct, implemented in [crates/tui/src/core/working_set.rs](https://github.com/Hmbown/DeepSeek-TUI/blob/main/crates/tui/src/core/working_set.rs), maintains a cache of files the model may reference during the conversation. Rather than scanning the entire repository each turn, the working set rebuilds incrementally from message content via rebuild_working_set.

This enables efficient "search-and-open" functionality without filesystem overhead, while project_context fields load metadata from AGENTS.md and CLAUDE.md files to provide contextual awareness of project conventions.

Safety Controls and Session Configuration

The session enforces security boundaries through three critical flags stored as struct fields:

  • allow_shell – Controls whether the model may invoke shell execution tools.
  • trust_mode – Determines if paths outside the workspace root are trusted for file operations.
  • auto_approve – When disabled, requires manual user confirmation before executing safety-sensitive actions.

These controls, alongside token accounting via SessionUsage, provide fine-grained governance over autonomous tool execution.

Practical Implementation Example

The following Rust code demonstrates session initialization and turn processing patterns:

// Creating a new session (called from the dispatcher)
let session = Session::new(
    "deepseek-v4-flash".to_string(),
    PathBuf::from("./my_project"),
    /*allow_shell=*/ false,
    /*trust_mode=*/ false,
    PathBuf::from("./notes.md"),
    PathBuf::from("./mcp_config.toml"),
);

// Adding a user message
session.add_message(Message::User {
    role: "user".into(),
    content: "Explain the Rust ownership model".into(),
});

// Run a turn – this is done by the engine; simplified here
let response = engine::run_turn(&mut session)?;

// The response is added back to the session
session.add_message(response);

// After many turns, compact the context to keep the session small
if session.total_usage.output_tokens > 10_000 {
    let summary = engine::compact_context(&session)?;
    session.compaction_summary_prompt = Some(summary);
}

Summary

  • The Session struct in crates/tui/src/core/session.rs serves as the single source of truth for conversation state, configuration, and safety controls.
  • Turn-based processing follows a five-phase lifecycle: user input → engine execution → tool handling → compaction → working set rebuild.
  • Cycles prevent context explosion by summarizing conversation segments into compact briefings stored in cycle_briefings.
  • The WorkingSet provides repo-aware file caching without full repository scans.
  • Safety flags (allow_shell, trust_mode, auto_approve) enforce execution boundaries while SessionUsage tracks cumulative token consumption.
  • All message history persists in OpenAI-compatible format, enabling serialization and session resumption.

Frequently Asked Questions

How does DeepSeek TUI handle session persistence?

The Session struct maintains all conversation state in serializable fields (messages, cycle_briefings, total_usage) that can be written to disk. The implementation stores raw message history and compaction summaries, allowing users to save and resume sessions later without losing context. The UUID field (id) aids in telemetry correlation across resumed sessions.

What triggers context compaction in a session?

Compaction triggers when total_usage.output_tokens exceeds configurable thresholds (e.g., 10,000 tokens) or after a set number of turns. The engine in crates/tui/src/core/engine.rs invokes compact_context, generating a summary that becomes the new compaction_summary_prompt. This increments cycle_count and creates a CycleBriefing entry to maintain conversation continuity while bounding memory usage.

How are tool calls integrated into the turn-based flow?

When the LLM returns tool calls, the engine executes the corresponding tools (defined in the tool registry) and appends results as Message::Tool variants to session.messages. The turn replays with the tool results included until the model provides a final assistant response without additional tool requests. This cycle may iterate multiple times per user turn depending on tool dependencies.

What is the working set and when does it rebuild?

The WorkingSet is a repo-aware cache of files referenced in the conversation, implemented in crates/tui/src/core/working_set.rs. It rebuilds via rebuild_working_set after each turn completion, scanning session.messages for file references. This enables the /files and /search commands to surface relevant project files without scanning the entire repository filesystem on every interaction.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →