Skip to content

Session persistence

The assistant automatically saves the session state on exit and offers to resume on next launch. This enables continuity across sessions—the assistant knows what files existed and if they changed, allowing it to pick up where the previous session left off.

Agent Assist memory

The LLM itself does not remember the conversation. There is no server-side chat or conversation ID to preserve. The architecture is stateless from the LLM's perspective:

  • pydantic-ai + OpenAI-compatible API: The agent uses OpenAIChatModel which communicates with the OpenAI Chat Completions API through the DataRobot LLM Gateway. This API is stateless—there is no server-side conversation thread. Every request sends the full message history in the request body, and the server has no memory of prior turns.

  • message_history: This is a list[ModelMessage] maintained entirely on the client side. Each call to agent.iter(user_input, message_history=message_history) sends the full history to the LLM. When the response arrives, agent_run.all_messages() returns the updated list, including the new turn. The server doesn't track or account for a "chat or conversation ID" during this process.

This means:

  • When the process exits, the message_history list ceases to exist and the LLM doesn't remember the conversation.
  • Replaying the full raw history when the conversation resumes would be expensive and fragile due to token limits, stale tool results, etc.
  • Session continuity is achieved through compressed context injection—a summary of the conversation's actions and decisions is injected into the system prompt when the conversation resumes.

Session persistence details

Session persistence saves conversation history in compacted form: a recent-messages tail plus a summary of older turns, alongside lightweight metadata. On resume, the assistant reconstructs a trimmed message_history from this (via reconstruct_history()) and also injects a resume-context block into the system prompt. The lightweight metadata it tracks:

Artifact Purpose
Session ID and timestamps Identity and recency—"when did we last talk?".
agent_spec.md path Whether the user was designing an agent.
File manifest (SHA256 hashes) Detect if files changed while the assistant was offline. Files not in the manifest are not detected (that would require a full workspace scan).
_session_deleted Whether the session was deleted by the user.

Context injection

When the agent conversation resumes, build_resume_context() constructs a text block from the previously saved session state and injects it into the agent's system prompt using pydantic-ai's @agent.system_prompt(dynamic=True) decorator. This decorator re-evaluates on every agent run, so:

  • On resume: the agent sees session context (ID, timestamps, file changes, summary, decisions).
  • After /reset: the dynamic prompt returns "" and the agent sees nothing.
  • During normal operation: the prompt returns whatever was set at launch.

This block serves as invisible system prompt content that gives the agent awareness of prior sessions.

Session lifecycle details

When an exited session resumes, a block similar to the following is injected into the system prompt (invisible to the user):

# Resumed Session Context
This is a resumed session (ID: a1b2c3d4e5f6).
Originally started: 2026-03-30 10:15 UTC
Last active: 2026-03-31 14:22 UTC

Agent specification file: agent_spec.md

## Previous Session Summary
User designed a customer support agent with three tools. Model selection
was GPT-5 via the DataRobot model catalog. Spec was saved but not yet
implemented in code.

## Key Decisions Made
- Selected GPT-5 as the agent model for strong reasoning capability
- Chose REST API tools over SDK wrappers for portability
- Deferred authentication configuration to implementation phase

## File Changes Since Last Session
- agent_spec.md: modified

IMPORTANT: You are resuming a previous session. Review the context above
before proceeding. If the user's request seems to continue prior work,
use this context. If they start a new topic, proceed normally.

After running /reset (/new), this block disappears—the dynamic prompt returns an empty string.

Fresh launch (no prior session)

The first time the agent launches, when there is no prior session:

  1. On launch, SessionState() creates a new session with a random 12-character hex ID.
  2. The user interacts with the agent.
  3. On exit, SessionLifecycle.snapshot_and_save() captures the current file manifest, then SessionManager.save() writes the session file and active_{pid}.json pointer

Resume (existing session)

When the agent resumes a previous session:

  1. On launch, SessionManager.load() reads active_{pid}.json and loads the indicated session file.
  2. The user is prompted to resume the previous session:
    Previous session found (last active: 2026-03-31 14:22 UTC)
    Resume previous session? [Y/n]
    
  3. Yes: The existing SessionState is carried forward (same ID, same file on disk). build_resume_context() constructs the system prompt block with session info and drift detection results.
  4. No: A new SessionState() is created. The old session file remains on disk as an orphan (small, <1KB). The new session's autosave on exit updates active_{pid}.json to point to the new ID.
  5. The constructed system prompt is injected into the agent using pydantic-ai's @agent.system_prompt(dynamic=True).

Session reset

When the user runs /reset (/new):

  1. If agent_spec.md or template directory exist, the user is prompted for confirmation before deletion.
  2. Even if no files exist, /reset always:
  3. Clears in-memory conversation history (message_history = None).
  4. Creates a fresh SessionState() with a new ID.
  5. Deletes the persisted session file and active_{pid}.json pointer.
  6. Clears the dynamic resume context from the system prompt.
  7. Sets _session_deleted = True to prevent autosave resurrection on exit.
  8. If the user continues interacting after /reset, the first successful agent response re-enables autosave (_session_deleted = False) so the new session is preserved.

Session save

When the user runs /save:

  1. SessionLifecycle.explicit_save() updates agent_spec_path and rebuilds file_manifest from current workspace
  2. SessionManager.save() writes the session file and updates active_{pid}.json
  3. Re-enables autosave if it was disabled by a prior /reset

Session exit (autosave)

When the agent exits due to normal shutdown, Ctrl+C, or crash:

  1. The finally block in chat() runs on quit, Ctrl+C, or crash.
  2. If _session_deleted is True (set by /reset with no subsequent interaction), autosave is skipped
  3. Otherwise, snapshots workspace state and persists.

Session slash commands

The assistant supports the following slash commands for session management:

Command Description
/save Checkpoint the session immediately. Snapshots the current agent_spec.md state and file manifest before writing.
/reset (/new) Always clears conversation history, deletes the saved session, and removes resume context from the system prompt. If agent_spec.md or the template directory exist, prompts for confirmation before deleting them. The next agent turn starts completely clean.
/checkpoint List session checkpoints, or restore one by number (/checkpoint [number]).
/compact Compact conversation history to reduce token usage.
/resume Show the resume context currently injected into the session's system prompt.

File drift detection

On resume, the assistant compares SHA256 hashes of tracked files against the saved manifest. This detects three cases:

  • Unchanged: The hash matches; reported as a count ("1 tracked file(s) unchanged").
  • Modified: The file exists but the hash differs; listed as <file>: modified.
  • Deleted: The file was in manifest but no longer exists; listed as <file>: deleted.

File drift detection

New files not in the manifest are not detected (that would require a full workspace scan).

This allows the assistant to alert the user (or adjust its own behavior) when workspace files were changed outside the assistant between sessions.

Component map

The following components are responsible for session management:

Component Location Responsibility
SessionState session/models.py Pydantic model—schema for persisted state.
SessionManager session/manager.py CRUD operations on session JSON files.
SessionLifecycle session/lifecycle.py Owns session state, message history, resume context, and deletion flag; enforces state transition invariants; builds resume context for system prompt injection.
Filesystem helpers helpers/filesystem.py SHA256 hashing, path validation, manifest building, drift detection.
Path helpers helpers/paths.py Path-to-directory-name resolution for project settings.
Confirmation UI ui/confirm.py Destructive action confirmation dialog (isolated to break circular import).
Main loop main.py Lifecycle orchestration (resume prompt, delegates to SessionLifecycle).
Command handlers commands/handlers.py /save and /reset session operations.
CommandContext commands/base.py Carries session references to command handlers.

Storage layout

The session state is stored in the project configuration directory at ~/.config/datarobot/agent_assist/projects/<name>_<hash>/sessions/.

~/.config/datarobot/agent_assist/projects/
  my-project_a1b2c3d4/
    sessions/
      a1b2c3d4e5f6.json   # per-session state file
      active_<pid>.json    # pointer to current session (one per terminal PID)

Each session file contains the following fields:

Field Description
schema_version Schema version for forward compatibility (currently 3).
session_id 12-character hex identifier.
created_at UTC timestamp of session creation.
updated_at UTC timestamp of last save.
agent_spec_path Relative path to agent spec, or null.
file_manifest {relative_path: sha256_hex} for tracked files.
summary LLM-extracted narrative summary of the prior session, or null.
decisions Key decisions extracted from the prior session.
recent_messages Serialized recent conversation messages (the compaction tail) reconstructed on resume.
compacted_history_summary Summary of older messages compacted away, or null.
checkpoint_count Most recent checkpoint number written for the session (informational, not a live file count).
phase Current conversation phase (design / code / deploy), or null.

Security

  • Path traversal protection: All manifest paths are validated via is_safe_relative_path() (in helpers/filesystem.py) to resolve within the workspace directory before any file I/O. Tampered manifests containing ../ sequences are silently skipped.
  • Symlink rejection: build_file_manifest() and detect_file_drift() skip symlinks as defense-in-depth against time-of-check-to-time-of-use (TOCTOU) symlink attacks. A file replaced by a symlink between sessions is reported as deleted.
  • Session ID validation: Session IDs are validated against a strict ^[a-f0-9]{12}$ regex before constructing file paths, preventing path injection via crafted pointer files.
  • No secrets in session files: Session state contains only metadata (timestamps, hashes, paths). API keys, conversation content, and user input are not persisted.