Octopus
Browser Session Management
Each conversation session can have its own browser context — persisting cookies, localStorage, and authentication state across tool calls within the same conversation. Sessions are automatically cleaned up on expiry.
Session Lifecycle
1
First browser_navigate in a session
A new Playwright browser context is created and associated with the conversation session ID.
2
Subsequent tool calls reuse the context
Navigation history, cookies, and local storage persist. Authentication state from a login form is remembered.
3
Session idle timeout
If no browser tool is called for
MaxIdleSeconds, the browser context is closed and its resources are freed.
4
Session max duration
Sessions cannot exceed
MaxSessionDurationSeconds. Long-running sessions are closed and a new one is created on next call.
5
Conversation ends
When the conversation episode closes, the browser session is explicitly disposed along with all its pages.
BrowserSession Interface
// IBrowserSession — the abstraction injected into all tool handlers
public interface IBrowserSession
{
string SessionId { get; }
string TenantId { get; }
DateTime CreatedAt { get; }
DateTime LastActiveAt { get; }
// Get or create the active page for this session
Task<IPage> GetPageAsync(CancellationToken ct);
// Close all browser resources
Task DisposeAsync();
}
// BrowserSession — Playwright implementation
public class BrowserSession : IBrowserSession
{
private readonly IBrowserContext _context;
private IPage? _activePage;
public async Task<IPage> GetPageAsync(CancellationToken ct)
{
if (_activePage is null || _activePage.IsClosed)
{
_activePage = await _context.NewPageAsync();
_activePage.SetDefaultTimeout(_config.TimeoutMs);
}
LastActiveAt = DateTime.UtcNow;
return _activePage;
}
public async Task DisposeAsync()
{
if (_activePage is not null)
await _activePage.CloseAsync();
await _context.CloseAsync();
}
}
Session Storage in the Session Registry
// PlaywrightManager — manages session lifecycle
public class PlaywrightManager : IPlaywrightManager
{
private readonly ConcurrentDictionary<string, BrowserSession> _sessions = new();
private readonly WebDriverPluginConfig _config;
public async Task<IBrowserSession> GetOrCreateSessionAsync(
string sessionId, string tenantId, CancellationToken ct)
{
if (_sessions.TryGetValue(sessionId, out var existing))
{
// Renew idle timeout
existing.Touch();
// Check max duration
if (DateTime.UtcNow - existing.CreatedAt >
TimeSpan.FromSeconds(_config.Session.MaxSessionDurationSeconds))
{
await existing.DisposeAsync();
_sessions.TryRemove(sessionId, out _);
}
else return existing;
}
// Create new Playwright browser context
var browser = await _playwright.Chromium.LaunchAsync(new()
{
Headless = _config.Headless
});
var context = await browser.NewContextAsync(new()
{
ViewportSize = new() { Width = 1280, Height = 720 }
});
var session = new BrowserSession(sessionId, tenantId, context, _config);
_sessions[sessionId] = session;
return session;
}
}
Session Configuration
| Setting | Default | Effect |
|---|---|---|
ReuseWithinConversation | true | Session persists across tool calls in the same conversation |
MaxIdleSeconds | 120 | Session closed after 2 minutes of no browser activity |
MaxSessionDurationSeconds | 600 | Sessions cannot exceed 10 minutes regardless of activity |