Skip to content

EN Course 04 Session Store

lloydzhou edited this page May 29, 2026 · 1 revision

Session Store

The store layer gives each session a durable directory:

CONV_FILE="${session_dir}/conversation.jsonl"
SESSION_EVENT_FILE="${session_dir}/events.jsonl"
CONTEXT_SUMMARY_FILE="${session_dir}/summary.txt"
PLAN_FILE="${session_dir}/plan.md"
PLAN_DRAFT_FILE="${session_dir}/plan.draft"
STATS_FILE="${session_dir}/stats.json"

These files have different jobs:

File Role
conversation.jsonl model-facing message history
events.jsonl replay and stream-json event log
summary.txt compacted long-session summary
plan.md locked plan included in prompt
plan.draft draft plan that does not invalidate prompt cache
stats.json turns, token usage, cache tokens, title data

Conversation vs Events

conversation.jsonl is for the model. It stores user, assistant, and tool-result messages in the format used to build the next request.

events.jsonl is for runtime observation. It records text, thinking, tool calls, tool results, usage, errors, sub-agent events, and context updates.

This split lets the runtime replay a session without reconstructing display output from model messages.

Recent Replay

Replay reads recent events, not the full conversation:

store_event_recent_turn_lines() {
    local turns="${1:-10}" _match _from_line
    [[ -s "${SESSION_EVENT_FILE:-}" ]] || return 0
    _match=$(grep -n '"type":"user_input"' "$SESSION_EVENT_FILE" | tail -n "$turns" | head -n 1) || true
    _from_line="${_match%%:*}"
    [[ -n "$_from_line" && "$_from_line" -ge 1 ]] || _from_line=1
    tail -n +"$_from_line" "$SESSION_EVENT_FILE"
}

This keeps entering long sessions cheap.

Replay is display-oriented. It does not rebuild conversation.jsonl; it turns recent events.jsonl lines back into display messages:

events.jsonl
  -> event_replay.awk
  -> RESP-like messages
  -> display_stream

That means live execution and replay share the same display renderer.

Stats and Terminal Title

Usage events update stats.json:

agent_record_usage() {
    local kind="$1" counter_key="$2" write_event="${3:-true}"
    store_stats_update ${counter_key}=+1 \
        total_input_tokens=+${_in} \
        total_output_tokens=+${_out} \
        total_cache_read_tokens=+${_cr} \
        total_cache_creation_tokens=+${_cc}
}

Stats are not only for reporting. They drive:

  • current context token estimate
  • compaction decisions
  • cache hit visibility
  • terminal title formatting
  • runtime parity tests

The title is generated from the same stats file:

store_stats_format_title() {
    util_awk_run -v model="$1" -f "$AWK_DIR/term_title.awk" "$STATS_FILE"
}

Next

System Prompt Builder explains how stable prompt sections are assembled.

Clone this wiki locally