Skip to content

Chapter 5 · Sessions and Context Management ​

Chapter goals: Understand Flue's session model and ID addressing mechanism, master the principle of cross-conversation context retention, and learn to design reasonable session lifecycles.

5.1 Sessions Are the Agent's "Memory Unit" ​

An LLM call without a session is amnesiac: every message starts fresh. In Flue, each agent instance binds to a session (session), persisted by ID:

text
Agent function (definition)          Session instance (runtime state)
┌─────────────────┐                 ┌──────────────────────┐
│ export function │                 │ id: "ticket-1024"    │
│ Triage() {...}  │ ──────────▶     │ messages: [...history]│
│                 │   instantiated  │ state: persistent flags│
└─────────────────┘      by ID      └──────────────────────┘
  • Agent definition is a stateless function template, one global copy;
  • Session instance is a stateful runtime object, one per ID;
  • The same agent can serve thousands of sessions concurrently without interference.

5.2 Building Multi-Turn Conversations with ID ​

The semantics of ID are fully defined by your business — user ID, ticket number, GitHub issue number, random string, all work:

bash
# CLI: --id creates/resumes a named session
npx flue run src/agents/assistant.ts --id crab-owner-42 --message \
  "I want to keep a pet crab, help me name it"
npx flue run src/agents/assistant.ts --id crab-owner-42 --message \
  "Go with the first name you suggested; give me three nicknames"
# The second message picks up the first — same ID shares message history
typescript
// HTTP: the :id in POST /:id is the session identifier
// After mounting the route in src/app.ts:
//
// curl -X POST http://localhost:5173/agents/support/user-8817 \
//   -H 'content-type: application/json' \
//   -d '{"text": "My order hasn\'t arrived"}'
//
// Subsequent messages from user-8817 all land in the same session

ID design advice

Use IDs as business primary keys: user-{uid} for customer service scenarios, {repo}-{issue} for operations. This naturally achieves "one person one session, one task one session" and restores on restart via ID alone.

5.3 Context Composition and Auto-Compaction ​

The full context sent to the model consists of three parts, of which session history grows with conversation:

typescript
'use agent';
import { useModel } from '@flue/runtime';

export function LongTaskAgent() {
  useModel('anthropic/claude-sonnet-4-6', {
    // Required for long tasks: auto-compact when approaching the cap
    compaction: {
      reserveTokens: 30000,     // Trigger early: compact when used tokens exceed cap - 30000
      keepRecentTokens: 16000,  // Keep the most recent 16k tokens of messages verbatim
      model: 'anthropic/claude-haiku-4-5', // Delegate summarization to a cheaper model
    },
  });
  return `
Execute a full codebase security audit:
scan directory by directory, log findings, summarize the report.
Task is long — maintain a "current progress" summary in your replies.`;
}

How compaction works: old history folded into a summary + recent messages kept verbatim — the session continues without interruption. This lets a single session run longer than any model's context window — this is part of the Durability feature mentioned in Chapter 1.

5.4 Custom Persistent State Across Rounds ​

Beyond message history, agents have their own persistent state slots — usePersistentState:

typescript
'use agent';
import { useModel, usePersistentState, useTool } from '@flue/runtime';
import { defineTool } from '@flue/runtime';
import * as v from 'valibot';

// A tool that lets the model主动 register findings, writing to persistent state
const recordFinding = defineTool({
  name: 'record_finding',
  description: 'Record an audit finding into the session-level清单.',
  input: v.object({ severity: v.string(), detail: v.string() }),
  async run() { return { output: 'Recorded' }; }, // Simplified example
});

export function Auditor() {
  useModel('anthropic/claude-sonnet-4-6');
  useTool(recordFinding);

  // findings persist across the entire session lifetime
  const [findings] = usePersistentState<string[]>('findings', []);

  return `
You are a security auditor.
${findings.length > 0
  ? `Already ${findings.length} findings recorded; continue scanning uncovered directories.`
  : 'Begin the first full-repo scan.'}
Use record_finding after each check.`;
}

Note the combination with Chapter 3's "re-render": when findings.length changes, the next round's instructions change with it — this is the practical usage of "instructions reflect current state."

5.5 Session Lifecycle Design ​

ScenarioRecommended ID StrategyLifespan
Personal assistantuser-{uid}Long-term, follows the user
Ticket processingticket-{no}Archive when ticket closes
CI taskrun-{pipeline_id}Single pipeline run
Scheduled patrolpatrol-{date}Roll by day

Two practice advice:

  1. Prefer finer session granularity: a mega-session dilutes old context's attention on new tasks; unrelated tasks get new sessions;
  2. Rely on compaction而非 manual cleanup: rather than truncating history yourself, configure compaction and let the framework handle it.
typescript
// Type-safe session ID encapsulation suggestion — encode ID semantics into types
// Avoid format drift from hand-spliced strings everywhere
type SessionId<T extends string> = `${T}-${string}`;

const userSession = (uid: string) => `user-${uid}` as const;      // user-8817
const ticketSession = (no: number) => `ticket-${no}` as const;    // ticket-1024
const runSession = (pid: string) => `run-${pid}` as const;        // run-ci-7788

// Unified export: all business modules get session IDs from here
export const sessions = { userSession, ticketSession, runSession };

5.6 Chapter Summary ​

  • Agent definition is stateless; session instances are stateful, linked by ID;
  • ID semantics are business-defined; CLI uses --id, HTTP uses POST /:id;
  • Long sessions rely on compaction: summarize old history + keep recent verbatim;
  • usePersistentState provides业务 state persistence beyond messages;
  • Session granularity should be fine not coarse; leave compaction to the framework.

🧪 随堂测验

点击你认为正确的选项。答错时会展示正确答案与原因解析。

1. What is the relationship between session instances and Agent functions in Flue?

2. What is the HTTP route for sending a message to a specific session?

3. What happens when compaction triggers?

4. Regarding session ID design, which practice is most reasonable?

🛠️ Hands-On Exercises ​

  1. Open two sessions with different IDs for the same agent; verify their messages are invisible to each other.
  2. Configure compaction for a long-task agent and故意 run an ultra-long task; observe the摘要 replacing原文 behavior.
  3. Use usePersistentState to implement an "already-asked questions" list; verify the agent avoids重复提问.

Sessions configured. Next, learn type-safe tools with defineTool.