import { type ChildProcessByStdio } from 'node:child_process'; import type { Readable, Writable } from 'node:stream'; import { type CliAdapter, type CliUsageSnapshot, type HarnessSpec, type ParseResult, type ResolvedEffortPreset, type TurnImage } from './cli-adapters/base.js'; import type { AwbConfig } from './rest.js'; import type { SubagentMonitor, SubagentTapHandle } from './subagent-monitor.js'; import { type RuntimeLease } from './runtime-profiles.js'; import type { RuntimeProfileSpec } from './cli-adapters/base.js'; import type { RuntimeAdapterResolver } from './runtime/composition/runtime-adapter-resolver.js'; export interface BaseSessionOptions { keyField: string; logTag: string; cfgPrefix: string; kindLabel: 'chat_session' | 'ticket_session'; adapterResolver?: RuntimeAdapterResolver; } export interface SessionDelegationConfig { enabled?: boolean; maxConcurrent?: number; ttlMinutes?: number; idleMinutes?: number; maxTurnsPerSession?: number; idleRecheckSeconds?: number; progressEscalationHours?: number; chatKeepAliveMaxMinutes?: number; claudeBin?: string; codexBin?: string; persistentChatSessions?: boolean; persistentTicketSessions?: boolean; runExecutionLock?: boolean; } export interface SessionAwareConfig extends AwbConfig { delegation: SessionDelegationConfig; } export interface MonitorMeta { ticket_id?: string; ticket_title?: string; role?: string; trigger_source?: string; } export interface SpawnOpts { onProgress?: (stage: string) => void; monitorMeta?: MonitorMeta; agentContext?: { agent_id: string; workspace_id?: string; api_key: string; cwd: string; mcp_config_path: string; cli: string; cli_home_dir: string; model?: string | null; extra_env?: Record; credential_provider?: string | null; credential_id?: string | null; runtime_config?: { permission_mode?: string | null; } | null; }; firstTurnImages?: TurnImage[]; harness?: HarnessSpec | null; runtimeProfile?: RuntimeProfileSpec | null; effortPreset?: ResolvedEffortPreset | null; envVars?: Record; chainAttempt?: number; } interface TurnState { onProgress: (stage: string) => void; stage: string | null; fired: { thinking: boolean; composing: boolean; }; heartbeatTimer: NodeJS.Timeout | null; } export interface RunSessionBinding { kind: 'qa' | 'security' | 'action'; run_id: string; workspace_id: string; } export interface SessionRecord { [key: string]: any; pid: number; cli_type: string; adapter: CliAdapter; child: ChildProcessByStdio; configPath: string | null; configPathIsTemp: boolean; pidPath: string | null; runtimeLease?: RuntimeLease | null; turnCount: number; startedAt: number; lastTouchedAt: number; idleTimer: NodeJS.Timeout | null; unrespondedTurnCount: number; unrespondedSince: number | null; unhealthyKilled: boolean; tap: SubagentTapHandle | null; usage?: CliUsageSnapshot | null; _currentTurn?: TurnState | null; onResult?: (raw: any) => void; releaseRunLock?: () => void; splitRequested?: boolean; splitReason?: string; _twinTerminated?: boolean; stopReason?: string; _effectiveApiKey?: string; _lastLivenessPostAtMs?: number; modelChain?: (string | null)[]; chainAttempt?: number; _fallbackRespawn?: (nextAttempt: number) => Promise; unhealthyRespawnCount?: number; _run?: RunSessionBinding; _orphanSweepTimer?: NodeJS.Timeout | null; taskToken?: string; _lastOutputAtMs?: number; _cliHomeDir?: string | null; _cwd?: string | null; _keepAliveUntilMs?: number | null; _keepAliveFirstDeclaredAtMs?: number | null; _keepAliveReason?: string | null; _progressEscalatedAt?: number | null; _lastBackgroundTaskCount?: number; } export interface InflightReservation { agentId?: string; ticketId?: string; roomId?: string; reservedAt?: number; nonce?: string; pid?: number; } export declare const INFLIGHT_RESERVATION_STALE_MS: number; export declare const INFLIGHT_SUPPRESS_SAFETY_VALVE = 3; export declare const INFLIGHT_SUPPRESS_SAFETY_VALVE_MIN_AGE_MS: number; export declare function isPidAlive(pid: number): boolean; export declare class BaseSessionManager { #private; protected readonly _config: SessionAwareConfig; protected _shouldRetryRuntime(runtimeId: string, cause: unknown, attempt: number): boolean; protected readonly _sessions: Map; protected readonly _inflight: Map; protected readonly _outputRings: Map; constructor(config: SessionAwareConfig, options: BaseSessionOptions); protected get _adapter(): CliAdapter; protected _adapterFor(cli: string | null | undefined): CliAdapter; setMonitor(monitor: SubagentMonitor | null): void; protected _getSession(sessionKey: string): SessionRecord | undefined; protected _isPidAlive(pid: number): boolean; protected _getLiveSession(sessionKey: string): SessionRecord | undefined; protected _onSessionReaped(_sess: SessionRecord): void; protected _onStopDrain(_sessions: SessionRecord[]): Promise; protected _ensureCapacity(): boolean; protected _spawnSession(sessionKey: string, rolePrompt: string, firstTurnText: string, opts?: SpawnOpts): Promise; protected _sendFollowUp(sess: SessionRecord, turnText: string, { checkMaxTurns, onProgress, images, }?: { checkMaxTurns?: boolean; onProgress?: (stage: string) => void; images?: TurnImage[]; }): void; protected _maybeCloseForMaxTurns(sess: SessionRecord, maxTurns: number): Promise; protected _writeTurn(sess: SessionRecord, text: string, images?: TurnImage[]): void; protected _collectOutputTail(pid: number, maxChars: number): string; protected _clearOutputBuffer(pid: number): void; protected _resetIdleTimer(sess: SessionRecord): void; protected _onIdleTimerFired(sess: SessionRecord, idleWindowMs: number): Promise; protected _onLongRunningEscalation(_sess: SessionRecord, _ageHours: string): void; protected _onSessionStatusChanged(_sess: SessionRecord): void; protected _onForcedTermination(_sess: SessionRecord, _reason: string, _info: { liveTaskCount: number; }): void; applyKeepAlive(sessionKey: string, opts: { action: 'extend' | 'release'; minutes?: number; reason?: string; }): { ok: boolean; error?: string; until?: number; ceilingMs?: number; }; protected _onStdoutParsed(_sess: SessionRecord, _parsed: ParseResult, _rawLine: string): void; protected _onStderrLine(_sess: SessionRecord, _line: string): void; protected _onChildExit(_sess: SessionRecord, _code: number | null, _signal: NodeJS.Signals | null): Promise; _trackSessionForTest(sessionKey: string, sess: SessionRecord): void; protected _maybeKillUnhealthy(sess: SessionRecord, reason: string): Promise; protected _rememberDedup(key: string): boolean; protected _forgetDedup(key: string): void; stopForAgent(agentId: string): Promise<{ count: number; inflight: Array<{ ticketId: string; role: string; }>; }>; stop(reason?: string): Promise; } export {};