Sessions

Understanding how conversations work in the Copilot SDK.

What is a Session?

A session is an independent conversation with Copilot. Think of it like opening a new chat window - each session has its own:

  • Message history
  • System prompt (optional)
  • Tool configurations
  • State (running, stopped)

Creating Sessions

// Basic session
const session = await client.createSession();

// Session with custom system prompt
const session = await client.createSession({
  systemMessage: "You are a helpful code reviewer. Be concise and direct."
});

// Session with specific tools
const session = await client.createSession({
  tools: [myWeatherTool, mySearchTool]
});

The Turn Model

Interaction happens in turns. A turn starts when you send a message and ends when Copilot finishes responding.

┌─────────────────────────────────────────────────────────────────┐
│                          ONE TURN                               │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  send()                         Events                          │
│    │                              │                             │
│    │   ┌──────────────────────────┼─────────────────────────┐  │
│    └──►│ turnStart → textDelta* → [toolCall*] → turnEnd     │  │
│        └──────────────────────────┼─────────────────────────┘  │
│                                   │                             │
│                                   ▼                             │
│                            Your handlers                        │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Events in a turn:

  1. turnStart - Copilot begins generating
  2. textDelta (repeated) - Response tokens stream in
  3. toolCall (optional) - Copilot wants to use a tool
  4. turnEnd - Generation complete

Sending Messages

Simple send (wait for completion)

const response = await session.send("Explain async/await in JavaScript");
console.log(response.text); // Full response text

Streaming (handle events as they arrive)

for await (const event of session.send("Explain async/await")) {
  switch (event.type) {
    case "textDelta":
      process.stdout.write(event.delta); // Print as it streams
      break;
    case "turnEnd":
      console.log("\n[Done]");
      break;
  }
}

With attachments

// Attach file content
const response = await session.send({
  content: "Review this code",
  attachments: [{
    type: "text",
    filename: "app.ts",
    content: "const x = 1;\nconst y = 2;"
  }]
});

// Attach image
const response = await session.send({
  content: "What's in this image?",
  attachments: [{
    type: "image",
    mediaType: "image/png",
    data: base64ImageData
  }]
});

Session Isolation

Sessions are completely independent:

const session1 = await client.createSession();
const session2 = await client.createSession();

// These don't affect each other
await session1.send("My name is Alice");
await session2.send("My name is Bob");

// session1 knows "Alice", session2 knows "Bob"
await session1.send("What's my name?"); // "Alice"
await session2.send("What's my name?"); // "Bob"

Use cases for multiple sessions:

  • Parallel task processing
  • Different system prompts for different purposes
  • Isolating user conversations in a multi-tenant app

Session Lifecycle

                  ┌───────────────┐
                  │   CREATED     │
                  └───────┬───────┘
                          │ createSession()

                  ┌───────────────┐
           ┌─────►│    ACTIVE     │◄─────┐
           │      └───────┬───────┘      │
           │              │              │
      send()              │         tool result
           │              ▼              │
           │      ┌───────────────┐      │
           └──────│  PROCESSING   │──────┘
                  └───────┬───────┘
                          │ stopSession()

                  ┌───────────────┐
                  │   STOPPED     │
                  └───────────────┘

Stopping Sessions

// Stop a specific session
await client.stopSession(session.id);

// Or close the entire client (stops all sessions)
await client.close();

When to stop sessions:

  • User conversation ends
  • Task is complete
  • Error requires session reset
  • Resource cleanup

Session Persistence

Sessions exist only in memory by default. For persistence across restarts, see the Persisting Sessions cookbook recipe.

Basic pattern:

  1. Export session state (messages, system prompt)
  2. Save to disk/database
  3. On restart, recreate session with saved state

Concurrency

Multiple sends on the same session are queued (only one turn at a time). For parallel work:

// Sequential (one at a time on same session)
await session.send("Question 1");
await session.send("Question 2");

// Parallel (different sessions)
const [r1, r2] = await Promise.all([
  session1.send("Question 1"),
  session2.send("Question 2")
]);

Common Patterns

Context window management

Copilot automatically handles context, but long conversations may lose early messages. Reset periodically for long-running apps:

// Summarize and restart
const summary = await session.send("Summarize our conversation so far");
await client.stopSession(session.id);

const newSession = await client.createSession({
  systemMessage: `Previous context: ${summary.text}`
});

Branching conversations

Create new sessions from a “checkpoint”:

const checkpoint = session.getMessages(); // If API supports this

// Branch 1
const branch1 = await client.createSession({ messages: checkpoint });
await branch1.send("What if we use React?");

// Branch 2
const branch2 = await client.createSession({ messages: checkpoint });
await branch2.send("What if we use Vue?");

Next: Tools