Portal Community

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

SettingDefaultEffect
ReuseWithinConversationtrueSession persists across tool calls in the same conversation
MaxIdleSeconds120Session closed after 2 minutes of no browser activity
MaxSessionDurationSeconds600Sessions cannot exceed 10 minutes regardless of activity