# Session

> Stateful multi-turn conversations with a session object.

Source: https://maincode.com/docs/agent-sdk-session
Section: Agent SDK · Matilda documentation

---

A `Session` wraps an `Agent` with auto-managed `conversationId` and accumulates turn results. The server maintains conversation history server-side using the `conversationId`, so each turn has full context.

## `createSession(agent, options?)`

```ts
import { createSession } from '@maincode-ai/matilda-agent-sdk';

const session = createSession({
  name: 'tutor',
  instructions: 'You are a patient programming tutor. Explain concepts simply.',
});

console.log('Conversation ID:', session.conversationId);

// Turn 1
const r1 = await session.run('What is a closure in JavaScript?');
console.log('Turn 1:', r1.finalOutput.slice(0, 100), '...');

// Turn 2 — the server remembers the previous exchange via conversationId
const r2 = await session.run('Can you show me a simple example?');
console.log('Turn 2:', r2.finalOutput.slice(0, 100), '...');

// The session accumulates all turn results
console.log('Total turns:', session.turns.length);
console.log('Last turn stream ID:', session.lastTurn?.streamId);
```

## `Session` class

### `session.run(input, options?)`

Runs a turn and accumulates the result in `session.turns`.

| Field | Type | Description |
| - | - | - |
| `input` | `string` | The user's message. |
| `options` | `Omit<AgentRunOptions, 'conversationId'>` | Per-turn options. Merged with session defaults. |

Returns `Promise<AgentRunResult>`.

### `session.stream(input, options?)`

Streams a turn, yielding `AgentRunEvent` as they arrive. The result is accumulated in `session.turns` when the stream completes.

```ts
for await (const event of session.stream('Explain async/await in one paragraph.')) {
  if (event.type === 'message.delta') {
    process.stdout.write(event.delta);
  }
}

console.log('\n[Turns accumulated]:', session.turns.length);
console.log('[Final output cached]:', session.lastTurn?.finalOutput.slice(0, 60), '...');
```

### `session.conversationId`

The auto-generated (or provided) conversation ID. Reused across all turns.

### `session.turns`

A readonly array of `AgentRunResult` — one per completed turn.

### `session.lastTurn`

Getter for the most recent `AgentRunResult`, or `undefined` if no turns have run.

## `SessionOptions`

Extends `Omit<AgentRunOptions, 'conversationId'>`.

| Field | Type | Description |
| - | - | - |
| `runner` | `Runner` | Custom runner instance. Defaults to defaultRunner. |
| `conversationId` | `string` | Explicit conversation ID. Auto-generated when omitted. |
| `(all AgentRunOptions fields)` | `—` | Session-level defaults applied to every turn. |

## Metadata passthrough

Metadata can be set at multiple levels: `Agent` construction, `Session` construction, or per-call. Per-call metadata merges with (and overrides) session defaults.

```ts
const session = createSession(
  {
    name: 'helper',
    instructions: ({ metadata }) =>
      `Environment: ${metadata.env ?? 'unknown'}. User: ${metadata.user ?? 'anonymous'}.`,
  },
  { metadata: { env: 'staging', user: 'demo-user' } },
);

// Session-level metadata is used by default
await session.run('Who am I?');

// Per-call metadata overrides session defaults
await session.run('Who am I now?', { metadata: { user: 'admin' } });
// → env=staging (from session), user=admin (overridden per-call)
```

## Custom runner

A `Session` can use a custom `Runner` for dependency injection in tests or isolated configuration:

```ts
import { Runner, Session } from '@maincode-ai/matilda-agent-sdk';

const myRunner = new Runner();
const session = new Session(
  { name: 'custom-runner-agent', instructions: 'Be brief.' },
  { runner: myRunner },
);

const result = await session.run('What is 2 + 2?');
```
