Documentation
Bridge SDK
Session Registry

Session Registry

The NitySessionRegistry tracks active sessions per client, enabling multi-client support in server environments where multiple external tools (Kilo Code, Cursor, VS Code) connect simultaneously. It provides automatic cleanup on client disconnect and stale session garbage collection.

Basic Usage

import {
  createNitySession,
  NitySessionRegistry,
} from '@mariozechner/pi-coding-agent/extensions/nity/bridge';
 
const registry = new NitySessionRegistry();
 
// Create and register a session for a connected client
const session = await createNitySession({ costTier: 'free' });
registry.register('client-abc', session);
 
// Later, clean up on disconnect
await registry.cleanupClient('client-abc');

API

register

register(clientId: string, session: NitySessionHandle): void

Register a session under a client ID. A single client can own multiple sessions.


unregister

unregister(sessionId: string): Promise<void>

Close and remove a specific session by its ID. Automatically removes the session from its client's tracking and cleans up empty client entries.


cleanupClient

cleanupClient(clientId: string): Promise<number>

Close all sessions for a client. Returns the number of sessions cleaned. Call this when a client disconnects.


getClientSessions

getClientSessions(clientId: string): NitySessionHandle[]

Get all active sessions for a client. Returns an empty array if the client has no sessions.


getSession

getSession(sessionId: string): NitySessionHandle | undefined

Look up a session by its ID across all clients.


getStats

getStats(): NitySessionRegistryStats

Returns registry statistics:

interface NitySessionRegistryStats {
  totalSessions: number;
  activeClients: number;
  sessionsByClient: Record<string, number>;
}

cleanupStale

cleanupStale(): Promise<number>

Scans all sessions and removes those that are timed out or in an error state. Returns the number of sessions removed. Run this on a timer for automatic garbage collection.

Server Example

A typical multi-client server using the registry:

import {
  createNitySession,
  NitySessionRegistry,
} from '@mariozechner/pi-coding-agent/extensions/nity/bridge';
 
const registry = new NitySessionRegistry();
 
// Run stale cleanup every 60 seconds
setInterval(() => {
  registry.cleanupStale().then((count) => {
    if (count > 0) console.log(`Cleaned up ${count} stale sessions`);
  });
}, 60_000);
 
// Handle new client connections
async function onClientConnect(clientId: string) {
  const session = await createNitySession({
    costTier: 'hybrid',
    contextProvider: async () => loadClientContext(clientId),
  });
 
  registry.register(clientId, session);
  return session;
}
 
// Handle client disconnect
async function onClientDisconnect(clientId: string) {
  const cleaned = await registry.cleanupClient(clientId);
  console.log(`Client ${clientId} disconnected, cleaned ${cleaned} sessions`);
}
 
// Handle incoming tasks
async function handleTask(clientId: string, taskType: string, prompt: string) {
  const sessions = registry.getClientSessions(clientId);
 
  if (sessions.length === 0) {
    const session = await onClientConnect(clientId);
    return session.sendTask(taskType as any, prompt);
  }
 
  // Use the first available session
  const session = sessions[0];
  if (session.isRunning()) {
    throw new Error('Session is busy');
  }
 
  return session.sendTask(taskType as any, prompt);
}
 
// Monitor registry
function logStats() {
  const stats = registry.getStats();
  console.log(`Registry: ${stats.totalSessions} sessions across ${stats.activeClients} clients`);
  console.log('Per-client:', stats.sessionsByClient);
}

Session Health

Each session exposes health information through getHealth():

const sessions = registry.getClientSessions('client-abc');
for (const session of sessions) {
  const health = session.getHealth();
  console.log(`Session ${session.id}:`, {
    state: health.state,          // 'idle' | 'active' | 'completed' | 'error'
    errorCount: health.errorCount,
    isTimedOut: health.isTimedOut,
    uptime: health.uptime,        // ms since task start (0 if idle)
    lastActivity: health.lastActivity,
  });
}

Use health checks to identify unhealthy sessions before dispatching tasks:

function getHealthySession(registry: NitySessionRegistry, clientId: string) {
  const sessions = registry.getClientSessions(clientId);
 
  for (const session of sessions) {
    const health = session.getHealth();
    if (!health.isTimedOut && health.state !== 'error' && !session.isRunning()) {
      return session;
    }
  }
 
  return null;
}

Single-Client Mode

For simpler use cases with one client, the registry is optional. Just use the session handle directly:

const session = await createNitySession({ costTier: 'free' });
 
try {
  const result = await session.sendTask('analyze', 'Review the API design');
  console.log(result.output);
} finally {
  await session.close();
}

The registry becomes valuable when you have multiple clients connecting and disconnecting, and need centralized lifecycle management.

The registry does not own session creation — it only tracks sessions you register. You still create sessions with createNitySession and decide which client they belong to.

⚠️

Always pair register with cleanup (cleanupClient or cleanupStale). Without cleanup, sessions persist indefinitely and consume resources.