@code-yeongyu/senpi 2026.9.8 → 2026.9.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -4
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +2 -0
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/compaction/compaction-execution.d.ts.map +1 -1
- package/dist/core/compaction/compaction-execution.js +5 -5
- package/dist/core/compaction/compaction-execution.js.map +1 -1
- package/dist/core/compaction/compaction-settings.d.ts +2 -0
- package/dist/core/compaction/compaction-settings.d.ts.map +1 -1
- package/dist/core/compaction/compaction-settings.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +3 -3
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +12 -7
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/compaction/stream-watchdog.d.ts +29 -0
- package/dist/core/compaction/stream-watchdog.d.ts.map +1 -1
- package/dist/core/compaction/stream-watchdog.js +35 -0
- package/dist/core/compaction/stream-watchdog.js.map +1 -1
- package/dist/core/compaction-settings-access.d.ts +6 -0
- package/dist/core/compaction-settings-access.d.ts.map +1 -1
- package/dist/core/compaction-settings-access.js.map +1 -1
- package/dist/core/compaction-settings-resolver.d.ts +2 -0
- package/dist/core/compaction-settings-resolver.d.ts.map +1 -1
- package/dist/core/compaction-settings-resolver.js +5 -0
- package/dist/core/compaction-settings-resolver.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/model-usability-budget.d.ts +1 -1
- package/dist/core/extensions/builtin/compaction/model-usability-budget.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/model-usability-budget.js +23 -3
- package/dist/core/extensions/builtin/compaction/model-usability-budget.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/speculative-summary.d.ts +2 -0
- package/dist/core/extensions/builtin/compaction/speculative-summary.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/speculative-summary.js +5 -2
- package/dist/core/extensions/builtin/compaction/speculative-summary.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/speculative.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/speculative.js +9 -3
- package/dist/core/extensions/builtin/compaction/speculative.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/summarization-retry.d.ts +10 -4
- package/dist/core/extensions/builtin/compaction/summarization-retry.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/summarization-retry.js +14 -5
- package/dist/core/extensions/builtin/compaction/summarization-retry.js.map +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +11 -1
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-write-reservation.d.ts +4 -0
- package/dist/core/session-write-reservation.d.ts.map +1 -0
- package/dist/core/session-write-reservation.js +12 -0
- package/dist/core/session-write-reservation.js.map +1 -0
- package/dist/main.d.ts +14 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +162 -147
- package/dist/main.js.map +1 -1
- package/dist/modes/rpc/connection-handler.d.ts +2 -0
- package/dist/modes/rpc/connection-handler.d.ts.map +1 -1
- package/dist/modes/rpc/connection-handler.js +1 -1
- package/dist/modes/rpc/connection-handler.js.map +1 -1
- package/dist/modes/rpc/multi-session-host.d.ts +2 -0
- package/dist/modes/rpc/multi-session-host.d.ts.map +1 -1
- package/dist/modes/rpc/multi-session-host.js +18 -8
- package/dist/modes/rpc/multi-session-host.js.map +1 -1
- package/dist/modes/rpc/session-binding.d.ts.map +1 -1
- package/dist/modes/rpc/session-binding.js +3 -0
- package/dist/modes/rpc/session-binding.js.map +1 -1
- package/dist/modes/rpc/session-command-router.d.ts +1 -1
- package/dist/modes/rpc/session-command-router.d.ts.map +1 -1
- package/dist/modes/rpc/session-command-router.js +57 -25
- package/dist/modes/rpc/session-command-router.js.map +1 -1
- package/dist/modes/rpc/session-event-writer.d.ts +23 -1
- package/dist/modes/rpc/session-event-writer.d.ts.map +1 -1
- package/dist/modes/rpc/session-event-writer.js +108 -1
- package/dist/modes/rpc/session-event-writer.js.map +1 -1
- package/dist/modes/rpc/session-registry.d.ts +4 -2
- package/dist/modes/rpc/session-registry.d.ts.map +1 -1
- package/dist/modes/rpc/session-registry.js +1 -1
- package/dist/modes/rpc/session-registry.js.map +1 -1
- package/dist/modes/rpc/session-worker-client.d.ts +47 -0
- package/dist/modes/rpc/session-worker-client.d.ts.map +1 -0
- package/dist/modes/rpc/session-worker-client.js +226 -0
- package/dist/modes/rpc/session-worker-client.js.map +1 -0
- package/dist/modes/rpc/session-worker-protocol.d.ts +103 -0
- package/dist/modes/rpc/session-worker-protocol.d.ts.map +1 -0
- package/dist/modes/rpc/session-worker-protocol.js +12 -0
- package/dist/modes/rpc/session-worker-protocol.js.map +1 -0
- package/dist/modes/rpc/session-worker-requests.d.ts +24 -0
- package/dist/modes/rpc/session-worker-requests.d.ts.map +1 -0
- package/dist/modes/rpc/session-worker-requests.js +71 -0
- package/dist/modes/rpc/session-worker-requests.js.map +1 -0
- package/dist/modes/rpc/session-worker.d.ts +2 -0
- package/dist/modes/rpc/session-worker.d.ts.map +1 -0
- package/dist/modes/rpc/session-worker.js +229 -0
- package/dist/modes/rpc/session-worker.js.map +1 -0
- package/dist/modes/rpc/worker-session-registry.d.ts +37 -0
- package/dist/modes/rpc/worker-session-registry.d.ts.map +1 -0
- package/dist/modes/rpc/worker-session-registry.js +207 -0
- package/dist/modes/rpc/worker-session-registry.js.map +1 -0
- package/docs/rpc.md +70 -9
- package/docs/settings.md +1 -0
- package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +12 -0
- package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
- package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
- package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js +23 -5
- package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.d.ts +30 -0
- package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js +30 -0
- package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/amazon-bedrock.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
- package/node_modules/@earendil-works/pi-ai/package.json +2 -2
- package/node_modules/@earendil-works/pi-pty/package.json +1 -1
- package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
- package/node_modules/@earendil-works/pi-tui/package.json +1 -1
- package/package.json +7 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-command-router.js","sourceRoot":"","sources":["../../../src/modes/rpc/session-command-router.ts"],"names":[],"mappings":"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","sourcesContent":["import { VERSION } from \"../../config.ts\";\nimport { buildRpcSessionState } from \"./connection-handler.ts\";\nimport { AUTO_TITLE_SESSIONS_CAPABILITY, MEDIA_PLACEHOLDERS_CAPABILITY } from \"./custom-capability.ts\";\nimport type { RpcCommand, RpcResponse } from \"./rpc-types.ts\";\nimport {\n\tRPC_ERROR_MISSING_SESSION_ID,\n\tRPC_ERROR_OPEN_FAILED,\n\tRPC_ERROR_SESSION_CLOSING,\n\tRPC_ERROR_UNKNOWN_SESSION,\n} from \"./rpc-types.ts\";\nimport { createRpcSessionBinding, type RpcSessionBinding } from \"./session-binding.ts\";\nimport type { SessionEventWriter } from \"./session-event-writer.ts\";\nimport type { OpenRpcSession, RpcSessionLaunchProfile, RpcSessionRegistry } from \"./session-registry.ts\";\nimport { RpcSessionRegistryError } from \"./session-registry.ts\";\n\nconst controls = new Set([\"get_protocol_info\", \"open_session\", \"close_session\", \"list_sessions\"]);\n\n/** Binding factory seam, injectable so host wiring is testable without a full runtime stack. */\nexport type RpcBindingFactory = typeof createRpcSessionBinding;\n\n/**\n * Occupancy policy for the shared multi-session host. All fields are opt-in:\n * a router constructed without a policy keeps today's behavior (sessions live\n * until close_session; the host never self-exits).\n */\nexport interface RpcSessionIdlePolicy {\n\t/** Injectable clock (defaults to Date.now) for deterministic tests. */\n\tnow?: () => number;\n\t/** Evict open sessions whose last routed command or session-owned work settled longer ago than this. */\n\tidleEvictionMs?: number;\n\t/** Invoke onEmptyExit once the registry has stayed empty for this long. */\n\temptyExitMs?: number;\n\t/** Host shutdown hook fired by the empty-exit window; called at most once. */\n\tonEmptyExit?: () => void;\n\t/**\n\t * Consulted every tick before the empty-exit window advances. Returning false\n\t * both blocks the exit and resets the window, so a host with a connected but\n\t * sessionless client stays up instead of exiting under its supervisor.\n\t */\n\tcanExitWhenEmpty?: () => boolean;\n}\n\nfunction error(id: string | undefined, command: string, code: string): RpcResponse {\n\treturn { id, type: \"response\", command, success: false, error: code };\n}\n\n/** Routes control messages and enforces a routing handle for every session command. */\nexport class SessionCommandRouter {\n\tprivate readonly bindings = new Map<string, RpcSessionBinding>();\n\t/** Session handles opened by each connection, with one count per attachment. */\n\tprivate readonly sessionsByConnection = new Map<string, Map<string, number>>();\n\t/** Opens currently awaiting runtime/binding setup, keyed by connection. */\n\tprivate readonly opensByConnection = new Map<string, Set<Promise<void>>>();\n\t/** Connections whose socket has already been detached. */\n\tprivate readonly releasedConnections = new Set<string>();\n\tprivate readonly registry: RpcSessionRegistry;\n\tprivate readonly writer: SessionEventWriter;\n\tprivate readonly defaults: Pick<\n\t\tRpcSessionLaunchProfile,\n\t\t\"cwd\" | \"permissionPreset\" | \"creationModel\" | \"initialThinkingLevel\"\n\t>;\n\tprivate readonly createBinding: typeof createRpcSessionBinding;\n\tprivate readonly connectionOptions: Parameters<typeof createRpcSessionBinding>[4];\n\tprivate readonly widths = new Map<string, Map<string, number>>();\n\tprivate readonly pendingCapabilities = new Map<string, string[]>();\n\tprivate readonly finalizations = new Map<string, { promise: Promise<void>; resolve: () => void }>();\n\tprivate readonly idleNow: () => number;\n\tprivate readonly idleEvictionMs: number;\n\tprivate readonly emptyExitMs: number;\n\tprivate readonly onEmptyExit?: () => void;\n\tprivate readonly canExitWhenEmpty?: () => boolean;\n\tprivate sweepTimer: ReturnType<typeof setInterval> | undefined;\n\tprivate emptySince: number | undefined;\n\n\tconstructor(\n\t\tregistry: RpcSessionRegistry,\n\t\twriter: SessionEventWriter,\n\t\tdefaults: Pick<RpcSessionLaunchProfile, \"cwd\" | \"permissionPreset\" | \"creationModel\" | \"initialThinkingLevel\">,\n\t\tcreateBinding: typeof createRpcSessionBinding = createRpcSessionBinding,\n\t\tconnectionOptions: Parameters<typeof createRpcSessionBinding>[4] = {},\n\t\tidle?: RpcSessionIdlePolicy,\n\t) {\n\t\tthis.registry = registry;\n\t\tthis.writer = writer;\n\t\tthis.defaults = defaults;\n\t\tthis.createBinding = createBinding;\n\t\tthis.connectionOptions = connectionOptions;\n\t\tthis.idleNow = idle?.now ?? Date.now;\n\t\tthis.idleEvictionMs = idle?.idleEvictionMs ?? Number.POSITIVE_INFINITY;\n\t\tthis.emptyExitMs = idle?.emptyExitMs ?? Number.POSITIVE_INFINITY;\n\t\tthis.onEmptyExit = idle?.onEmptyExit;\n\t\tthis.canExitWhenEmpty = idle?.canExitWhenEmpty;\n\t\tif (Number.isFinite(this.idleEvictionMs) || Number.isFinite(this.emptyExitMs)) {\n\t\t\t// Unref'd: occupancy hygiene must never be the reason the event loop stays open.\n\t\t\tconst tickMs = Math.max(20, Math.min(5_000, Math.min(this.idleEvictionMs, this.emptyExitMs) / 4));\n\t\t\tthis.sweepTimer = setInterval(() => this.sweepIdleSessions(), tickMs);\n\t\t\tthis.sweepTimer.unref?.();\n\t\t}\n\t}\n\n\tasync handle(command: RpcCommand): Promise<RpcResponse | undefined> {\n\t\tif (command.type === \"get_protocol_info\") {\n\t\t\tconst capabilities = new Set([\n\t\t\t\t\"multi_session\",\n\t\t\t\tAUTO_TITLE_SESSIONS_CAPABILITY,\n\t\t\t\tMEDIA_PLACEHOLDERS_CAPABILITY,\n\t\t\t\t...(this.connectionOptions?.capabilities ?? []),\n\t\t\t]);\n\t\t\treturn {\n\t\t\t\tid: command.id,\n\t\t\t\ttype: \"response\",\n\t\t\t\tcommand: \"get_protocol_info\",\n\t\t\t\tsuccess: true,\n\t\t\t\tdata: {\n\t\t\t\t\tprotocolVersion: 1,\n\t\t\t\t\tserverVersion: VERSION,\n\t\t\t\t\tcapabilities: [...capabilities],\n\t\t\t\t\tmode: \"multi\",\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\tif (command.type === \"list_sessions\")\n\t\t\treturn {\n\t\t\t\tid: command.id,\n\t\t\t\ttype: \"response\",\n\t\t\t\tcommand: \"list_sessions\",\n\t\t\t\tsuccess: true,\n\t\t\t\tdata: { sessions: this.registry.list() },\n\t\t\t};\n\t\tif (command.type === \"open_session\") return this.openWithBarrier(command);\n\t\tif (command.type === \"close_session\") return this.close(command);\n\t\tif (command.type === \"set_client_info\" && !command.sessionId) {\n\t\t\tconst connection = this.writer.currentConnection();\n\t\t\tif (connection !== undefined) {\n\t\t\t\tthis.pendingCapabilities.set(connection, command.capabilities ?? []);\n\t\t\t\tthis.writer.setConnectionCapabilities(connection, command.capabilities ?? []);\n\t\t\t}\n\t\t\treturn { id: command.id, type: \"response\", command: \"set_client_info\", success: true } as RpcResponse;\n\t\t}\n\t\tif (controls.has(command.type)) return undefined;\n\t\tif (!command.sessionId) return error(command.id, command.type, RPC_ERROR_MISSING_SESSION_ID);\n\t\ttry {\n\t\t\tthis.registry.getForCommand(command.sessionId, command.type);\n\t\t\tconst binding = this.bindings.get(command.sessionId);\n\t\t\tif (!binding) return error(command.id, command.type, RPC_ERROR_UNKNOWN_SESSION);\n\t\t\tawait binding.handle(command);\n\t\t\treturn undefined;\n\t\t} catch (cause) {\n\t\t\treturn error(command.id, command.type, this.code(cause));\n\t\t}\n\t}\n\n\tasync dispose(): Promise<void> {\n\t\tthis.stopSweep();\n\t\tawait Promise.all(\n\t\t\t[...this.bindings.entries()].map(async ([sessionId, binding]) => {\n\t\t\t\tconst claim = this.tryClaimClose(sessionId, { drainAttachments: true });\n\t\t\t\tif (!claim) return;\n\t\t\t\tif (claim.finalizer) await this.finalizeClose(sessionId, binding);\n\t\t\t\telse await this.finalizations.get(sessionId)?.promise;\n\t\t\t}),\n\t\t);\n\t\tthis.bindings.clear();\n\t}\n\n\t/**\n\t * One occupancy sweep. Evicts open sessions idle longer than idleEvictionMs,\n\t * where \"idle\" is the COMPLETE session-owned activity contract\n\t * (`AgentSession.isSessionBusy`: agent run, bash, background terminal jobs and\n\t * other published wake sources, compaction, barrier-held session work) - busy\n\t * sessions restart their idle clock instead, so work that outlives a turn is\n\t * never killed. Fires onEmptyExit once the registry has STAYED empty for\n\t * emptyExitMs with the exit permitted; any live session or connected client\n\t * resets that window. Runs on an unref'd interval and is safe to call directly.\n\t */\n\tsweepIdleSessions(): void {\n\t\tconst now = this.idleNow();\n\t\tif (Number.isFinite(this.idleEvictionMs)) {\n\t\t\tfor (const { sessionId, status } of this.registry.list()) {\n\t\t\t\tif (status !== \"open\") continue;\n\t\t\t\tconst entry = this.registry.peek(sessionId);\n\t\t\t\tif (!entry) continue;\n\t\t\t\tif (entry.runtime?.session.isSessionBusy) {\n\t\t\t\t\t// Session-owned work defers eviction; the window restarts when it settles.\n\t\t\t\t\tentry.lastCommandAt = now;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (now - entry.lastCommandAt >= this.idleEvictionMs) void this.evictIdleSession(sessionId);\n\t\t\t}\n\t\t}\n\t\tif (Number.isFinite(this.emptyExitMs)) {\n\t\t\tif (this.registry.size === 0 && (this.canExitWhenEmpty?.() ?? true)) {\n\t\t\t\tif (this.emptySince === undefined) this.emptySince = now;\n\t\t\t\telse if (now - this.emptySince >= this.emptyExitMs) {\n\t\t\t\t\tthis.stopSweep();\n\t\t\t\t\tthis.onEmptyExit?.();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.emptySince = undefined;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Idle-session eviction: the same refcounted close sequence as an explicit\n\t * close_session, draining every attachment because eviction ends the shared\n\t * session, not one client's claim. Races with concurrent lifecycle paths are\n\t * tolerated the same way releaseOwnedSession tolerates them.\n\t */\n\tprivate async evictIdleSession(sessionId: string): Promise<void> {\n\t\t// A failed claim means an explicit close raced us and owns the entry now.\n\t\tconst claim = this.tryClaimClose(sessionId, { drainAttachments: true });\n\t\tif (!claim) return;\n\t\tconst binding = this.bindings.get(sessionId);\n\t\tbinding?.cancelPendingExtensionUiRequests?.();\n\t\tthis.forgetSessionOwnership(sessionId);\n\t\tif (claim.finalizer) {\n\t\t\tawait this.finalizeClose(sessionId, binding, () =>\n\t\t\t\tthis.writer.closeSession(sessionId, {\n\t\t\t\t\ttype: \"response\",\n\t\t\t\t\tcommand: \"close_session\",\n\t\t\t\t\tsuccess: true,\n\t\t\t\t\tdata: {},\n\t\t\t\t}),\n\t\t\t);\n\t\t} else {\n\t\t\tawait this.finalizations.get(sessionId)?.promise;\n\t\t}\n\t\t// The runtime is disposed and routing handles are unique per process\n\t\t// epoch, so nothing can emit under this id again: drop the writer's\n\t\t// per-session bookkeeping instead of retaining it for the host's life.\n\t\tthis.writer.forgetSession(sessionId);\n\t}\n\n\t/** Drops per-connection records for a handle the host closed on its own. */\n\tprivate forgetSessionOwnership(sessionId: string): void {\n\t\tfor (const [connection, owned] of this.sessionsByConnection) {\n\t\t\towned.delete(sessionId);\n\t\t\tif (owned.size === 0) this.sessionsByConnection.delete(connection);\n\t\t}\n\t\tthis.widths.delete(sessionId);\n\t}\n\n\tprivate stopSweep(): void {\n\t\tif (this.sweepTimer === undefined) return;\n\t\tclearInterval(this.sweepTimer);\n\t\tthis.sweepTimer = undefined;\n\t}\n\n\tprivate openWithBarrier(command: Extract<RpcCommand, { type: \"open_session\" }>): Promise<RpcResponse | undefined> {\n\t\tconst owner = this.writer.currentConnection();\n\t\tif (owner === undefined) return this.open(command);\n\t\tlet resolveBarrier!: () => void;\n\t\tconst barrier = new Promise<void>((resolve) => {\n\t\t\tresolveBarrier = resolve;\n\t\t});\n\t\tconst opens = this.opensByConnection.get(owner) ?? new Set<Promise<void>>();\n\t\topens.add(barrier);\n\t\tthis.opensByConnection.set(owner, opens);\n\t\treturn this.open(command, owner).finally(() => {\n\t\t\tresolveBarrier();\n\t\t\topens.delete(barrier);\n\t\t\tif (opens.size === 0) this.opensByConnection.delete(owner);\n\t\t});\n\t}\n\n\tprivate async open(\n\t\tcommand: Extract<RpcCommand, { type: \"open_session\" }>,\n\t\towner?: string,\n\t): Promise<RpcResponse | undefined> {\n\t\tlet opened: OpenRpcSession | undefined;\n\t\ttry {\n\t\t\topened = await this.registry.openSession({\n\t\t\t\tcwd: command.cwd ?? this.defaults.cwd,\n\t\t\t\tsessionPath: command.sessionPath,\n\t\t\t\tpermissionPreset: command.permissionPreset ?? this.defaults.permissionPreset,\n\t\t\t\tcreationModel:\n\t\t\t\t\tcommand.provider && command.modelId\n\t\t\t\t\t\t? { provider: command.provider, modelId: command.modelId }\n\t\t\t\t\t\t: this.defaults.creationModel,\n\t\t\t\tinitialThinkingLevel: command.thinkingLevel ?? this.defaults.initialThinkingLevel,\n\t\t\t});\n\t\t\tconst openedSession = opened;\n\t\t\tconst entry = this.registry.getForCommand(openedSession.sessionId, \"open_session\");\n\t\t\tif (owner !== undefined) {\n\t\t\t\tif (!this.writer.hasRegisteredConnectionCapabilities(owner))\n\t\t\t\t\tthis.writer.setConnectionCapabilities(\n\t\t\t\t\t\towner,\n\t\t\t\t\t\tthis.pendingCapabilities.get(owner) ?? this.connectionOptions?.capabilities ?? [],\n\t\t\t\t\t);\n\t\t\t\tthis.writer.attachConnectionToSession(owner, openedSession.sessionId);\n\t\t\t}\n\t\t\t// A client that dies without close_session (terminal closed, SIGKILL, dropped\n\t\t\t// SSH) still holds this handle's attachment and its path reservation. Remember\n\t\t\t// which connection owns it so releaseConnection() can close exactly that.\n\t\t\tif (owner !== undefined) {\n\t\t\t\tconst owned = this.sessionsByConnection.get(owner) ?? new Map<string, number>();\n\t\t\t\towned.set(openedSession.sessionId, (owned.get(openedSession.sessionId) ?? 0) + 1);\n\t\t\t\tthis.sessionsByConnection.set(owner, owned);\n\t\t\t}\n\t\t\tif (!this.bindings.has(openedSession.sessionId)) {\n\t\t\t\tthis.bindings.set(\n\t\t\t\t\topenedSession.sessionId,\n\t\t\t\t\tawait this.createBinding(\n\t\t\t\t\t\topenedSession.sessionId,\n\t\t\t\t\t\tentry,\n\t\t\t\t\t\tthis.writer,\n\t\t\t\t\t\t() => void this.close({ type: \"close_session\", sessionId: openedSession.sessionId }),\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t...this.connectionOptions,\n\t\t\t\t\t\t\tcapabilities:\n\t\t\t\t\t\t\t\towner !== undefined\n\t\t\t\t\t\t\t\t\t? (this.pendingCapabilities.get(owner) ?? this.connectionOptions?.capabilities ?? [])\n\t\t\t\t\t\t\t\t\t: this.connectionOptions?.capabilities,\n\t\t\t\t\t\t\tsharedWidth: {\n\t\t\t\t\t\t\t\tgetWidth: () => {\n\t\t\t\t\t\t\t\t\tconst widths = this.widths.get(openedSession.sessionId);\n\t\t\t\t\t\t\t\t\treturn widths?.size ? Math.min(...widths.values()) : 80;\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tsetWidth: (connectionId, width) => {\n\t\t\t\t\t\t\t\t\tif (connectionId !== undefined) {\n\t\t\t\t\t\t\t\t\t\tconst widths = this.widths.get(openedSession.sessionId) ?? new Map<string, number>();\n\t\t\t\t\t\t\t\t\t\twidths.set(connectionId, width);\n\t\t\t\t\t\t\t\t\t\tthis.widths.set(openedSession.sessionId, widths);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tclearWidth: (connectionId) => {\n\t\t\t\t\t\t\t\t\tconst widths = this.widths.get(openedSession.sessionId);\n\t\t\t\t\t\t\t\t\tif (connectionId !== undefined) widths?.delete(connectionId);\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tsetCapabilities: (connectionId, capabilities) => {\n\t\t\t\t\t\t\t\t\tif (connectionId !== undefined) {\n\t\t\t\t\t\t\t\t\t\tthis.writer.setConnectionCapabilities(connectionId, capabilities);\n\t\t\t\t\t\t\t\t\t\tthis.pendingCapabilities.set(connectionId, [...capabilities]);\n\t\t\t\t\t\t\t\t\t\tfor (const binding of this.bindings.values()) binding.rerenderComponents?.();\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\thasRenderedComponents: (sessionId) => this.writer.hasCapableConnection(sessionId),\n\n\t\t\t\t\t\t\t\tconnectionId: () => this.writer.currentConnection(),\n\t\t\t\t\t\t\t\tonChange: () => {\n\t\t\t\t\t\t\t\t\tfor (const binding of this.bindings.values()) binding.rerenderComponents?.();\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (owner !== undefined && this.releasedConnections.has(owner)) {\n\t\t\t\tawait this.releaseOwnedSession(openedSession.sessionId);\n\t\t\t}\n\t\t\tconst state = entry.runtime!.session;\n\t\t\tthis.writer.enqueue(opened.sessionId, {\n\t\t\t\tid: command.id,\n\t\t\t\ttype: \"response\",\n\t\t\t\tcommand: \"open_session\",\n\t\t\t\tsuccess: true,\n\t\t\t\tdata: {\n\t\t\t\t\tsessionId: opened.sessionId,\n\t\t\t\t\tstate: buildRpcSessionState(state),\n\t\t\t\t\t...(opened.attached ? { attached: true } : {}),\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn undefined;\n\t\t} catch (cause) {\n\t\t\tif (opened) {\n\t\t\t\ttry {\n\t\t\t\t\tawait this.registry.close(opened.sessionId);\n\t\t\t\t} catch {\n\t\t\t\t\t/* The open rollback has already removed the entry. */\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn error(command.id, \"open_session\", this.code(cause));\n\t\t}\n\t}\n\n\t/**\n\t * Releases every session a dropped connection still owned. Each handle goes through\n\t * the same refcounted close as an explicit close_session, so a session another\n\t * connection is still attached to keeps running and only the last owner tears it down.\n\t */\n\tasync releaseConnection(connectionId: string): Promise<void> {\n\t\tthis.releasedConnections.add(connectionId);\n\t\tthis.writer.clearConnectionCapabilities(connectionId);\n\t\tfor (const sessionId of this.sessionsByConnection.get(connectionId)?.keys() ?? [])\n\t\t\tthis.writer.detachConnectionFromSession(connectionId, sessionId);\n\t\tfor (const widths of this.widths.values()) widths.delete(connectionId);\n\t\tfor (const binding of this.bindings.values()) binding.rerenderComponents?.();\n\t\tconst opens = this.opensByConnection.get(connectionId);\n\t\tif (opens) await Promise.all([...opens]);\n\t\tconst owned = this.sessionsByConnection.get(connectionId);\n\t\tthis.sessionsByConnection.delete(connectionId);\n\t\tif (owned === undefined) {\n\t\t\tthis.releasedConnections.delete(connectionId);\n\t\t\treturn;\n\t\t}\n\t\tfor (const [sessionId, count] of owned) {\n\t\t\tthis.bindings.get(sessionId)?.cancelPendingExtensionUiRequests?.();\n\t\t\tfor (let attachment = 0; attachment < count; attachment++) {\n\t\t\t\t// Headless completion contract: a turn survives its client's death and\n\t\t\t\t// runs to settlement (the host lifecycle keeps the process alive on\n\t\t\t\t// active turns even with zero connections). Releasing mid-turn aborts\n\t\t\t\t// the run and seals the session before agent_settled reaches the\n\t\t\t\t// lifecycle observer, leaking the busy counter so the host never\n\t\t\t\t// idle-exits. Defer - never skip - the release until the turn settles,\n\t\t\t\t// so the dropped owner's reservation still frees afterwards.\n\t\t\t\tconst live = this.registry.peek(sessionId);\n\t\t\t\tconst session = live?.state === \"open\" ? live.runtime?.session : undefined;\n\t\t\t\tif (session?.isStreaming) {\n\t\t\t\t\tlet released = false;\n\t\t\t\t\tconst unsubscribe = session.subscribe((event) => {\n\t\t\t\t\t\tif (event.type !== \"agent_settled\" && event.type !== \"agent_idle\") return;\n\t\t\t\t\t\tif (released) return;\n\t\t\t\t\t\treleased = true;\n\t\t\t\t\t\tunsubscribe();\n\t\t\t\t\t\tvoid this.releaseOwnedSession(sessionId).catch((cause) => {\n\t\t\t\t\t\t\tprocess.stderr.write(\n\t\t\t\t\t\t\t\t`senpi rpc deferred release for session ${sessionId} failed: ${String(cause)}\\n`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tawait this.releaseOwnedSession(sessionId);\n\t\t\t}\n\t\t}\n\t\tthis.releasedConnections.delete(connectionId);\n\t}\n\n\t/**\n\t * One owned handle's refcounted close: the same sequence as an explicit\n\t * close_session, tolerant of races with other lifecycle paths (an entry\n\t * already closed or claimed elsewhere is simply skipped). Disposal and\n\t * binding removal happen only when this was the LAST attachment (the entry\n\t * transitioned to \"closing\"): surviving attachments keep the shared binding\n\t * and their event stream.\n\t */\n\tprivate async releaseOwnedSession(sessionId: string): Promise<void> {\n\t\t// A failed claim means the entry is already closed or owned by another path.\n\t\tconst claim = this.tryClaimClose(sessionId, { drainAttachments: false });\n\t\tif (!claim) return;\n\t\tif (claim.finalizer) await this.finalizeClose(sessionId, this.bindings.get(sessionId));\n\t\telse await this.finalizations.get(sessionId)?.promise;\n\t}\n\n\t/**\n\t * Releases one attachment (or every attachment when draining) and reports\n\t * whether this caller became the finalizer. The join token is installed inside\n\t * the registry callback, before any await, so a close that lands between the\n\t * claim and finalizeClose() always finds a token to wait on instead of\n\t * answering ahead of the terminal records.\n\t */\n\tprivate claimClose(sessionId: string, options: { drainAttachments: boolean }): { finalizer: boolean } {\n\t\tlet finalizer = true;\n\t\tconst onRole = (isFinalizer: boolean): void => {\n\t\t\tfinalizer = isFinalizer;\n\t\t\tif (isFinalizer && !this.finalizations.has(sessionId))\n\t\t\t\tthis.finalizations.set(sessionId, this.createFinalization());\n\t\t};\n\t\tlet entry = this.registry.beginClose(sessionId, onRole);\n\t\twhile (options.drainAttachments && entry.state === \"open\") entry = this.registry.beginClose(sessionId, onRole);\n\t\treturn { finalizer: finalizer && entry.state === \"closing\" };\n\t}\n\n\t/** claimClose() for lifecycle paths that treat a lost race as \"nothing to do\". */\n\tprivate tryClaimClose(\n\t\tsessionId: string,\n\t\toptions: { drainAttachments: boolean },\n\t): { finalizer: boolean } | undefined {\n\t\ttry {\n\t\t\treturn this.claimClose(sessionId, options);\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tprivate async close(command: Extract<RpcCommand, { type: \"close_session\" }>): Promise<RpcResponse | undefined> {\n\t\t// This must be the first operation: binding.dispose() awaits teardown and\n\t\t// otherwise leaves a window where commands can enter the old handler.\n\t\tlet claim: { finalizer: boolean };\n\t\ttry {\n\t\t\tclaim = this.claimClose(command.sessionId, { drainAttachments: false });\n\t\t} catch (cause) {\n\t\t\treturn error(command.id, \"close_session\", this.code(cause));\n\t\t}\n\t\tconst response = {\n\t\t\tid: command.id,\n\t\t\ttype: \"response\" as const,\n\t\t\tcommand: \"close_session\" as const,\n\t\t\tsuccess: true as const,\n\t\t\tdata: {},\n\t\t};\n\t\tconst owner = this.writer.currentConnection();\n\t\tif (owner !== undefined) this.releaseOwnerAttachment(owner, command.sessionId);\n\t\tif (claim.finalizer) {\n\t\t\tawait this.finalizeClose(command.sessionId, this.bindings.get(command.sessionId), () =>\n\t\t\t\tthis.writer.closeSession(command.sessionId, response),\n\t\t\t);\n\t\t} else {\n\t\t\tawait this.finalizations.get(command.sessionId)?.promise;\n\t\t\tthis.writer.enqueueClosedResponse(command.sessionId, response);\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/** Detaches the closing connection's UI/width state; a rerender failure must not abort the close. */\n\tprivate releaseOwnerAttachment(owner: string, sessionId: string): void {\n\t\tthis.widths.get(sessionId)?.delete(owner);\n\t\tthis.writer.detachConnectionFromSession(owner, sessionId);\n\t\tfor (const binding of this.bindings.values()) {\n\t\t\ttry {\n\t\t\t\tbinding.rerenderComponents?.();\n\t\t\t} catch (cause) {\n\t\t\t\tprocess.stderr.write(`senpi rpc rerender after close of session ${sessionId} failed: ${String(cause)}\\n`);\n\t\t\t}\n\t\t}\n\t\tconst owned = this.sessionsByConnection.get(owner);\n\t\tconst count = owned?.get(sessionId);\n\t\tif (!owned || count === undefined) return;\n\t\tif (count === 1) owned.delete(sessionId);\n\t\telse owned.set(sessionId, count - 1);\n\t\tif (owned.size === 0) this.sessionsByConnection.delete(owner);\n\t}\n\n\t/**\n\t * Runs the finalizer side of a close for a handle whose beginClose() made this\n\t * caller the owner: dispose the binding, complete the registry teardown, emit\n\t * the terminal records, then release joiners. Every step is guarded so the join\n\t * token always resolves and a failing binding yields one logged line, never a\n\t * second response or an escaped rejection.\n\t */\n\tprivate async finalizeClose(\n\t\tsessionId: string,\n\t\tbinding: RpcSessionBinding | undefined,\n\t\tterminal?: () => void,\n\t): Promise<void> {\n\t\tconst finalization = this.finalizations.get(sessionId) ?? this.createFinalization();\n\t\tthis.finalizations.set(sessionId, finalization);\n\t\ttry {\n\t\t\ttry {\n\t\t\t\tawait binding?.dispose();\n\t\t\t} catch (cause) {\n\t\t\t\tprocess.stderr.write(`senpi rpc binding dispose for session ${sessionId} failed: ${String(cause)}\\n`);\n\t\t\t}\n\t\t\tthis.bindings.delete(sessionId);\n\t\t\ttry {\n\t\t\t\tawait this.registry.closeMarked(sessionId);\n\t\t\t} catch (cause) {\n\t\t\t\tprocess.stderr.write(`senpi rpc close for session ${sessionId} failed: ${String(cause)}\\n`);\n\t\t\t}\n\t\t\tterminal?.();\n\t\t} finally {\n\t\t\tfinalization.resolve();\n\t\t\tthis.finalizations.delete(sessionId);\n\t\t}\n\t}\n\n\tprivate createFinalization(): { promise: Promise<void>; resolve: () => void } {\n\t\tlet resolveFinalization: (() => void) | undefined;\n\t\tconst promise = new Promise<void>((resolve) => {\n\t\t\tresolveFinalization = resolve;\n\t\t});\n\t\treturn { promise, resolve: () => resolveFinalization?.() };\n\t}\n\n\tprivate code(cause: unknown): string {\n\t\tif (cause instanceof RpcSessionRegistryError) {\n\t\t\treturn cause.code === RPC_ERROR_OPEN_FAILED ? cause.message : cause.code;\n\t\t}\n\t\tif (cause instanceof Error && [RPC_ERROR_UNKNOWN_SESSION, RPC_ERROR_SESSION_CLOSING].includes(cause.message)) {\n\t\t\treturn cause.message;\n\t\t}\n\t\treturn cause instanceof Error && cause.message\n\t\t\t? `${RPC_ERROR_OPEN_FAILED}: ${cause.message}`\n\t\t\t: RPC_ERROR_UNKNOWN_SESSION;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"session-command-router.js","sourceRoot":"","sources":["../../../src/modes/rpc/session-command-router.ts"],"names":[],"mappings":"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","sourcesContent":["import { VERSION } from \"../../config.ts\";\nimport { buildRpcSessionState } from \"./connection-handler.ts\";\nimport { AUTO_TITLE_SESSIONS_CAPABILITY, MEDIA_PLACEHOLDERS_CAPABILITY } from \"./custom-capability.ts\";\nimport type { RpcCommand, RpcResponse } from \"./rpc-types.ts\";\nimport {\n\tRPC_ERROR_MISSING_SESSION_ID,\n\tRPC_ERROR_OPEN_FAILED,\n\tRPC_ERROR_SESSION_CLOSING,\n\tRPC_ERROR_UNKNOWN_SESSION,\n} from \"./rpc-types.ts\";\nimport { createRpcSessionBinding, type RpcSessionBinding } from \"./session-binding.ts\";\nimport type { SessionEventWriter } from \"./session-event-writer.ts\";\nimport type { OpenRpcSession, RpcSessionLaunchProfile, RpcSessionRegistry } from \"./session-registry.ts\";\nimport { RpcSessionRegistryError } from \"./session-registry.ts\";\n\nconst controls = new Set([\"get_protocol_info\", \"open_session\", \"close_session\", \"list_sessions\"]);\n\n/** Binding factory seam, injectable so host wiring is testable without a full runtime stack. */\nexport type RpcBindingFactory = typeof createRpcSessionBinding;\n\n/**\n * Occupancy policy for the shared multi-session host. All fields are opt-in:\n * a router constructed without a policy keeps today's behavior (sessions live\n * until close_session; the host never self-exits).\n */\nexport interface RpcSessionIdlePolicy {\n\t/** Injectable clock (defaults to Date.now) for deterministic tests. */\n\tnow?: () => number;\n\t/** Evict open sessions whose last routed command or session-owned work settled longer ago than this. */\n\tidleEvictionMs?: number;\n\t/** Invoke onEmptyExit once the registry has stayed empty for this long. */\n\temptyExitMs?: number;\n\t/** Host shutdown hook fired by the empty-exit window; called at most once. */\n\tonEmptyExit?: () => void;\n\t/**\n\t * Consulted every tick before the empty-exit window advances. Returning false\n\t * both blocks the exit and resets the window, so a host with a connected but\n\t * sessionless client stays up instead of exiting under its supervisor.\n\t */\n\tcanExitWhenEmpty?: () => boolean;\n}\n\nfunction error(id: string | undefined, command: string, code: string): RpcResponse {\n\treturn { id, type: \"response\", command, success: false, error: code };\n}\n\n/** Routes control messages and enforces a routing handle for every session command. */\nexport class SessionCommandRouter {\n\tprivate readonly bindings = new Map<string, RpcSessionBinding>();\n\t/** Session handles opened by each connection, with one count per attachment. */\n\tprivate readonly sessionsByConnection = new Map<string, Map<string, number>>();\n\t/** Opens currently awaiting runtime/binding setup, keyed by connection. */\n\tprivate readonly opensByConnection = new Map<string, Set<Promise<void>>>();\n\t/** Connections whose socket has already been detached. */\n\tprivate readonly releasedConnections = new Set<string>();\n\tprivate readonly registry: Pick<\n\t\tRpcSessionRegistry,\n\t\t\"openSession\" | \"peek\" | \"getForCommand\" | \"beginClose\" | \"close\" | \"closeMarked\" | \"list\" | \"size\"\n\t>;\n\tprivate readonly writer: SessionEventWriter;\n\tprivate readonly defaults: Pick<\n\t\tRpcSessionLaunchProfile,\n\t\t\"cwd\" | \"permissionPreset\" | \"creationModel\" | \"initialThinkingLevel\"\n\t>;\n\tprivate readonly createBinding: typeof createRpcSessionBinding;\n\tprivate readonly connectionOptions: Parameters<typeof createRpcSessionBinding>[4];\n\tprivate readonly widths = new Map<string, Map<string, number>>();\n\tprivate readonly pendingCapabilities = new Map<string, string[]>();\n\tprivate readonly finalizations = new Map<string, { promise: Promise<void>; resolve: () => void }>();\n\tprivate readonly idleNow: () => number;\n\tprivate readonly idleEvictionMs: number;\n\tprivate readonly emptyExitMs: number;\n\tprivate readonly onEmptyExit?: () => void;\n\tprivate readonly canExitWhenEmpty?: () => boolean;\n\tprivate sweepTimer: ReturnType<typeof setInterval> | undefined;\n\tprivate emptySince: number | undefined;\n\n\tconstructor(\n\t\tregistry: Pick<\n\t\t\tRpcSessionRegistry,\n\t\t\t\"openSession\" | \"peek\" | \"getForCommand\" | \"beginClose\" | \"close\" | \"closeMarked\" | \"list\" | \"size\"\n\t\t>,\n\t\twriter: SessionEventWriter,\n\t\tdefaults: Pick<RpcSessionLaunchProfile, \"cwd\" | \"permissionPreset\" | \"creationModel\" | \"initialThinkingLevel\">,\n\t\tcreateBinding: typeof createRpcSessionBinding = createRpcSessionBinding,\n\t\tconnectionOptions: Parameters<typeof createRpcSessionBinding>[4] = {},\n\t\tidle?: RpcSessionIdlePolicy,\n\t) {\n\t\tthis.registry = registry;\n\t\tthis.writer = writer;\n\t\tthis.defaults = defaults;\n\t\tthis.createBinding = createBinding;\n\t\tthis.connectionOptions = connectionOptions;\n\t\tthis.idleNow = idle?.now ?? Date.now;\n\t\tthis.idleEvictionMs = idle?.idleEvictionMs ?? Number.POSITIVE_INFINITY;\n\t\tthis.emptyExitMs = idle?.emptyExitMs ?? Number.POSITIVE_INFINITY;\n\t\tthis.onEmptyExit = idle?.onEmptyExit;\n\t\tthis.canExitWhenEmpty = idle?.canExitWhenEmpty;\n\t\tif (Number.isFinite(this.idleEvictionMs) || Number.isFinite(this.emptyExitMs)) {\n\t\t\t// Unref'd: occupancy hygiene must never be the reason the event loop stays open.\n\t\t\tconst tickMs = Math.max(20, Math.min(5_000, Math.min(this.idleEvictionMs, this.emptyExitMs) / 4));\n\t\t\tthis.sweepTimer = setInterval(() => this.sweepIdleSessions(), tickMs);\n\t\t\tthis.sweepTimer.unref?.();\n\t\t}\n\t}\n\n\tasync handle(command: RpcCommand): Promise<RpcResponse | undefined> {\n\t\tif (command.type === \"get_protocol_info\") {\n\t\t\tconst capabilities = new Set([\n\t\t\t\t\"multi_session\",\n\t\t\t\tAUTO_TITLE_SESSIONS_CAPABILITY,\n\t\t\t\tMEDIA_PLACEHOLDERS_CAPABILITY,\n\t\t\t\t...(this.connectionOptions?.capabilities ?? []),\n\t\t\t]);\n\t\t\treturn {\n\t\t\t\tid: command.id,\n\t\t\t\ttype: \"response\",\n\t\t\t\tcommand: \"get_protocol_info\",\n\t\t\t\tsuccess: true,\n\t\t\t\tdata: {\n\t\t\t\t\tprotocolVersion: 1,\n\t\t\t\t\tserverVersion: VERSION,\n\t\t\t\t\tcapabilities: [...capabilities],\n\t\t\t\t\tmode: \"multi\",\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\tif (command.type === \"list_sessions\")\n\t\t\treturn {\n\t\t\t\tid: command.id,\n\t\t\t\ttype: \"response\",\n\t\t\t\tcommand: \"list_sessions\",\n\t\t\t\tsuccess: true,\n\t\t\t\tdata: { sessions: this.registry.list() },\n\t\t\t};\n\t\tif (command.type === \"open_session\") return this.openWithBarrier(command);\n\t\tif (command.type === \"close_session\") return this.close(command);\n\t\tif (command.type === \"set_client_info\" && !command.sessionId) {\n\t\t\tconst connection = this.writer.currentConnection();\n\t\t\tif (connection !== undefined) {\n\t\t\t\tthis.pendingCapabilities.set(connection, command.capabilities ?? []);\n\t\t\t\tthis.writer.setConnectionCapabilities(connection, command.capabilities ?? []);\n\t\t\t}\n\t\t\treturn { id: command.id, type: \"response\", command: \"set_client_info\", success: true } as RpcResponse;\n\t\t}\n\t\tif (controls.has(command.type)) return undefined;\n\t\tif (!command.sessionId) return error(command.id, command.type, RPC_ERROR_MISSING_SESSION_ID);\n\t\ttry {\n\t\t\tthis.registry.getForCommand(command.sessionId, command.type);\n\t\t\tconst binding = this.bindings.get(command.sessionId);\n\t\t\tif (!binding) return error(command.id, command.type, RPC_ERROR_UNKNOWN_SESSION);\n\t\t\tawait binding.handle(command);\n\t\t\treturn undefined;\n\t\t} catch (cause) {\n\t\t\treturn error(command.id, command.type, this.code(cause));\n\t\t}\n\t}\n\n\tasync dispose(): Promise<void> {\n\t\tthis.stopSweep();\n\t\tawait Promise.all(\n\t\t\t[...this.bindings.entries()].map(async ([sessionId, binding]) => {\n\t\t\t\tconst claim = this.tryClaimClose(sessionId, { drainAttachments: true });\n\t\t\t\tif (!claim) return;\n\t\t\t\tif (claim.finalizer) await this.finalizeClose(sessionId, binding);\n\t\t\t\telse await this.finalizations.get(sessionId)?.promise;\n\t\t\t}),\n\t\t);\n\t\tthis.bindings.clear();\n\t}\n\n\t/**\n\t * One occupancy sweep. Evicts open sessions idle longer than idleEvictionMs,\n\t * where \"idle\" is the COMPLETE session-owned activity contract\n\t * (`AgentSession.isSessionBusy`: agent run, bash, background terminal jobs and\n\t * other published wake sources, compaction, barrier-held session work) - busy\n\t * sessions restart their idle clock instead, so work that outlives a turn is\n\t * never killed. Fires onEmptyExit once the registry has STAYED empty for\n\t * emptyExitMs with the exit permitted; any live session or connected client\n\t * resets that window. Runs on an unref'd interval and is safe to call directly.\n\t */\n\tsweepIdleSessions(): void {\n\t\tconst now = this.idleNow();\n\t\tif (Number.isFinite(this.idleEvictionMs)) {\n\t\t\tfor (const { sessionId, status } of this.registry.list()) {\n\t\t\t\tif (status !== \"open\") continue;\n\t\t\t\tconst entry = this.registry.peek(sessionId);\n\t\t\t\tif (!entry) continue;\n\t\t\t\tif (entry.worker?.busy || entry.runtime?.session.isSessionBusy) {\n\t\t\t\t\t// Session-owned work defers eviction; the window restarts when it settles.\n\t\t\t\t\tentry.lastCommandAt = now;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (now - entry.lastCommandAt >= this.idleEvictionMs) void this.evictIdleSession(sessionId);\n\t\t\t}\n\t\t}\n\t\tif (Number.isFinite(this.emptyExitMs)) {\n\t\t\tif (this.registry.size === 0 && (this.canExitWhenEmpty?.() ?? true)) {\n\t\t\t\tif (this.emptySince === undefined) this.emptySince = now;\n\t\t\t\telse if (now - this.emptySince >= this.emptyExitMs) {\n\t\t\t\t\tthis.stopSweep();\n\t\t\t\t\tthis.onEmptyExit?.();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.emptySince = undefined;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Idle-session eviction: the same refcounted close sequence as an explicit\n\t * close_session, draining every attachment because eviction ends the shared\n\t * session, not one client's claim. Races with concurrent lifecycle paths are\n\t * tolerated the same way releaseOwnedSession tolerates them.\n\t */\n\tprivate async evictIdleSession(sessionId: string): Promise<void> {\n\t\t// A failed claim means an explicit close raced us and owns the entry now.\n\t\tconst claim = this.tryClaimClose(sessionId, { drainAttachments: true });\n\t\tif (!claim) return;\n\t\tconst binding = this.bindings.get(sessionId);\n\t\tbinding?.cancelPendingExtensionUiRequests?.();\n\t\tthis.forgetSessionOwnership(sessionId);\n\t\tif (claim.finalizer) {\n\t\t\tawait this.finalizeClose(sessionId, binding, () =>\n\t\t\t\tthis.writer.closeSession(sessionId, {\n\t\t\t\t\ttype: \"response\",\n\t\t\t\t\tcommand: \"close_session\",\n\t\t\t\t\tsuccess: true,\n\t\t\t\t\tdata: {},\n\t\t\t\t}),\n\t\t\t);\n\t\t} else {\n\t\t\tawait this.finalizations.get(sessionId)?.promise;\n\t\t}\n\t\t// The runtime is disposed and routing handles are unique per process\n\t\t// epoch, so nothing can emit under this id again: drop the writer's\n\t\t// per-session bookkeeping instead of retaining it for the host's life.\n\t\tthis.writer.forgetSession(sessionId);\n\t}\n\n\t/** Drops per-connection records for a handle the host closed on its own. */\n\tprivate forgetSessionOwnership(sessionId: string): void {\n\t\tfor (const [connection, owned] of this.sessionsByConnection) {\n\t\t\towned.delete(sessionId);\n\t\t\tif (owned.size === 0) this.sessionsByConnection.delete(connection);\n\t\t}\n\t\tthis.widths.delete(sessionId);\n\t}\n\n\tprivate stopSweep(): void {\n\t\tif (this.sweepTimer === undefined) return;\n\t\tclearInterval(this.sweepTimer);\n\t\tthis.sweepTimer = undefined;\n\t}\n\n\tprivate openWithBarrier(command: Extract<RpcCommand, { type: \"open_session\" }>): Promise<RpcResponse | undefined> {\n\t\tconst owner = this.writer.currentConnection();\n\t\tif (owner === undefined) return this.open(command);\n\t\tlet resolveBarrier!: () => void;\n\t\tconst barrier = new Promise<void>((resolve) => {\n\t\t\tresolveBarrier = resolve;\n\t\t});\n\t\tconst opens = this.opensByConnection.get(owner) ?? new Set<Promise<void>>();\n\t\topens.add(barrier);\n\t\tthis.opensByConnection.set(owner, opens);\n\t\treturn this.open(command, owner).finally(() => {\n\t\t\tresolveBarrier();\n\t\t\topens.delete(barrier);\n\t\t\tif (opens.size === 0) this.opensByConnection.delete(owner);\n\t\t});\n\t}\n\n\tprivate async open(\n\t\tcommand: Extract<RpcCommand, { type: \"open_session\" }>,\n\t\towner?: string,\n\t): Promise<RpcResponse | undefined> {\n\t\tlet opened: OpenRpcSession | undefined;\n\t\ttry {\n\t\t\topened = await this.registry.openSession({\n\t\t\t\tcwd: command.cwd ?? this.defaults.cwd,\n\t\t\t\tsessionPath: command.sessionPath,\n\t\t\t\tpermissionPreset: command.permissionPreset ?? this.defaults.permissionPreset,\n\t\t\t\tcreationModel:\n\t\t\t\t\tcommand.provider && command.modelId\n\t\t\t\t\t\t? { provider: command.provider, modelId: command.modelId }\n\t\t\t\t\t\t: this.defaults.creationModel,\n\t\t\t\tinitialThinkingLevel: command.thinkingLevel ?? this.defaults.initialThinkingLevel,\n\t\t\t});\n\t\t\tconst openedSession = opened;\n\t\t\tconst entry = this.registry.getForCommand(openedSession.sessionId, \"open_session\");\n\t\t\tif (owner !== undefined) {\n\t\t\t\tif (!this.writer.hasRegisteredConnectionCapabilities(owner))\n\t\t\t\t\tthis.writer.setConnectionCapabilities(\n\t\t\t\t\t\towner,\n\t\t\t\t\t\tthis.pendingCapabilities.get(owner) ?? this.connectionOptions?.capabilities ?? [],\n\t\t\t\t\t);\n\t\t\t\tthis.writer.attachConnectionToSession(owner, openedSession.sessionId);\n\t\t\t}\n\t\t\t// A client that dies without close_session (terminal closed, SIGKILL, dropped\n\t\t\t// SSH) still holds this handle's attachment and its path reservation. Remember\n\t\t\t// which connection owns it so releaseConnection() can close exactly that.\n\t\t\tif (owner !== undefined) {\n\t\t\t\tconst owned = this.sessionsByConnection.get(owner) ?? new Map<string, number>();\n\t\t\t\towned.set(openedSession.sessionId, (owned.get(openedSession.sessionId) ?? 0) + 1);\n\t\t\t\tthis.sessionsByConnection.set(owner, owned);\n\t\t\t}\n\t\t\tif (!this.bindings.has(openedSession.sessionId)) {\n\t\t\t\tthis.bindings.set(\n\t\t\t\t\topenedSession.sessionId,\n\t\t\t\t\tawait this.createBinding(\n\t\t\t\t\t\topenedSession.sessionId,\n\t\t\t\t\t\tentry,\n\t\t\t\t\t\tthis.writer,\n\t\t\t\t\t\t() => void this.close({ type: \"close_session\", sessionId: openedSession.sessionId }),\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t...this.connectionOptions,\n\t\t\t\t\t\t\tcapabilities:\n\t\t\t\t\t\t\t\towner !== undefined\n\t\t\t\t\t\t\t\t\t? (this.pendingCapabilities.get(owner) ?? this.connectionOptions?.capabilities ?? [])\n\t\t\t\t\t\t\t\t\t: this.connectionOptions?.capabilities,\n\t\t\t\t\t\t\tsharedWidth: {\n\t\t\t\t\t\t\t\tgetWidth: () => {\n\t\t\t\t\t\t\t\t\tconst widths = this.widths.get(openedSession.sessionId);\n\t\t\t\t\t\t\t\t\treturn widths?.size ? Math.min(...widths.values()) : 80;\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tsetWidth: (connectionId, width) => {\n\t\t\t\t\t\t\t\t\tif (connectionId !== undefined) {\n\t\t\t\t\t\t\t\t\t\tconst widths = this.widths.get(openedSession.sessionId) ?? new Map<string, number>();\n\t\t\t\t\t\t\t\t\t\twidths.set(connectionId, width);\n\t\t\t\t\t\t\t\t\t\tthis.widths.set(openedSession.sessionId, widths);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tclearWidth: (connectionId) => {\n\t\t\t\t\t\t\t\t\tconst widths = this.widths.get(openedSession.sessionId);\n\t\t\t\t\t\t\t\t\tif (connectionId !== undefined) widths?.delete(connectionId);\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tsetCapabilities: (connectionId, capabilities) => {\n\t\t\t\t\t\t\t\t\tif (connectionId !== undefined) {\n\t\t\t\t\t\t\t\t\t\tthis.writer.setConnectionCapabilities(connectionId, capabilities);\n\t\t\t\t\t\t\t\t\t\tthis.pendingCapabilities.set(connectionId, [...capabilities]);\n\t\t\t\t\t\t\t\t\t\tfor (const binding of this.bindings.values()) binding.rerenderComponents?.();\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\thasRenderedComponents: (sessionId) => this.writer.hasCapableConnection(sessionId),\n\n\t\t\t\t\t\t\t\tconnectionId: () => this.writer.currentConnection(),\n\t\t\t\t\t\t\t\tonChange: () => {\n\t\t\t\t\t\t\t\t\tfor (const binding of this.bindings.values()) binding.rerenderComponents?.();\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t\tif (entry.worker) entry.worker.bindingReady = true;\n\t\t\t\tif (entry.worker)\n\t\t\t\t\tvoid entry.worker.exited.then(async () => {\n\t\t\t\t\t\tawait this.finalizations.get(openedSession.sessionId)?.promise;\n\t\t\t\t\t\tthis.bindings.delete(openedSession.sessionId);\n\t\t\t\t\t\tthis.forgetSessionOwnership(openedSession.sessionId);\n\t\t\t\t\t\tthis.writer.forgetSession(openedSession.sessionId);\n\t\t\t\t\t});\n\t\t\t}\n\t\t\tif (owner !== undefined && this.releasedConnections.has(owner)) {\n\t\t\t\tthis.releaseOwnerAttachment(owner, openedSession.sessionId);\n\t\t\t\tawait this.releaseOwnedSession(openedSession.sessionId);\n\t\t\t}\n\t\t\tconst state =\n\t\t\t\tentry.worker?.snapshot?.state ?? (entry.runtime ? buildRpcSessionState(entry.runtime.session) : undefined);\n\t\t\tif (!state) throw new Error(\"Session state was not created\");\n\t\t\tthis.writer.enqueue(opened.sessionId, {\n\t\t\t\tid: command.id,\n\t\t\t\ttype: \"response\",\n\t\t\t\tcommand: \"open_session\",\n\t\t\t\tsuccess: true,\n\t\t\t\tdata: {\n\t\t\t\t\tsessionId: opened.sessionId,\n\t\t\t\t\tstate,\n\t\t\t\t\t...(opened.attached ? { attached: true } : {}),\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn undefined;\n\t\t} catch (cause) {\n\t\t\tif (opened) {\n\t\t\t\ttry {\n\t\t\t\t\tawait this.registry.close(opened.sessionId);\n\t\t\t\t} catch {\n\t\t\t\t\t/* The open rollback has already removed the entry. */\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn error(command.id, \"open_session\", this.code(cause));\n\t\t}\n\t}\n\n\t/**\n\t * Releases every session a dropped connection still owned. Each handle goes through\n\t * the same refcounted close as an explicit close_session, so a session another\n\t * connection is still attached to keeps running and only the last owner tears it down.\n\t */\n\tasync releaseConnection(connectionId: string): Promise<void> {\n\t\tthis.releasedConnections.add(connectionId);\n\t\tthis.writer.clearConnectionCapabilities(connectionId);\n\t\tfor (const sessionId of this.sessionsByConnection.get(connectionId)?.keys() ?? [])\n\t\t\tthis.writer.detachConnectionFromSession(connectionId, sessionId);\n\t\tfor (const widths of this.widths.values()) widths.delete(connectionId);\n\t\tfor (const binding of this.bindings.values()) binding.rerenderComponents?.();\n\t\tconst opens = this.opensByConnection.get(connectionId);\n\t\tconst owned = this.sessionsByConnection.get(connectionId);\n\t\tthis.sessionsByConnection.delete(connectionId);\n\t\tif (owned === undefined) {\n\t\t\tif (opens) await Promise.all([...opens]);\n\t\t\tthis.releasedConnections.delete(connectionId);\n\t\t\treturn;\n\t\t}\n\t\tawait Promise.all(\n\t\t\t[...owned].map(async ([sessionId, count]) => {\n\t\t\t\tthis.bindings.get(sessionId)?.cancelPendingExtensionUiRequests?.();\n\t\t\t\tfor (let attachment = 0; attachment < count; attachment++) {\n\t\t\t\t\t// Headless completion contract: a turn survives its client's death and\n\t\t\t\t\t// runs to settlement (the host lifecycle keeps the process alive on\n\t\t\t\t\t// active turns even with zero connections). Releasing mid-turn aborts\n\t\t\t\t\t// the run and seals the session before agent_settled reaches the\n\t\t\t\t\t// lifecycle observer, leaking the busy counter so the host never\n\t\t\t\t\t// idle-exits. Defer - never skip - the release until the turn settles,\n\t\t\t\t\t// so the dropped owner's reservation still frees afterwards.\n\t\t\t\t\tconst live = this.registry.peek(sessionId);\n\t\t\t\t\tconst session = live?.state === \"open\" ? live.runtime?.session : undefined;\n\t\t\t\t\tif (live?.state === \"open\" && live.worker?.snapshot?.streaming) {\n\t\t\t\t\t\tconst unsubscribe = live.worker.subscribeSettled(() => {\n\t\t\t\t\t\t\tunsubscribe();\n\t\t\t\t\t\t\tvoid this.releaseOwnedSession(sessionId).catch((cause: unknown) => {\n\t\t\t\t\t\t\t\tprocess.stderr.write(\n\t\t\t\t\t\t\t\t\t`senpi rpc deferred worker release ${sessionId} failed: ${String(cause)}\\n`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t});\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tif (session?.isStreaming) {\n\t\t\t\t\t\tlet released = false;\n\t\t\t\t\t\tconst unsubscribe = session.subscribe((event) => {\n\t\t\t\t\t\t\tif (event.type !== \"agent_settled\" && event.type !== \"agent_idle\") return;\n\t\t\t\t\t\t\tif (released) return;\n\t\t\t\t\t\t\treleased = true;\n\t\t\t\t\t\t\tunsubscribe();\n\t\t\t\t\t\t\tvoid this.releaseOwnedSession(sessionId).catch((cause) => {\n\t\t\t\t\t\t\t\tprocess.stderr.write(\n\t\t\t\t\t\t\t\t\t`senpi rpc deferred release for session ${sessionId} failed: ${String(cause)}\\n`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t});\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tawait this.releaseOwnedSession(sessionId);\n\t\t\t\t}\n\t\t\t}),\n\t\t);\n\t\tif (opens) await Promise.all([...opens]);\n\t\tthis.releasedConnections.delete(connectionId);\n\t}\n\n\t/**\n\t * One owned handle's refcounted close: the same sequence as an explicit\n\t * close_session, tolerant of races with other lifecycle paths (an entry\n\t * already closed or claimed elsewhere is simply skipped). Disposal and\n\t * binding removal happen only when this was the LAST attachment (the entry\n\t * transitioned to \"closing\"): surviving attachments keep the shared binding\n\t * and their event stream.\n\t */\n\tprivate async releaseOwnedSession(sessionId: string): Promise<void> {\n\t\t// A failed claim means the entry is already closed or owned by another path.\n\t\tconst claim = this.tryClaimClose(sessionId, { drainAttachments: false });\n\t\tif (!claim) return;\n\t\tif (claim.finalizer) await this.finalizeClose(sessionId, this.bindings.get(sessionId));\n\t\telse await this.finalizations.get(sessionId)?.promise;\n\t}\n\n\t/**\n\t * Releases one attachment (or every attachment when draining) and reports\n\t * whether this caller became the finalizer. The join token is installed inside\n\t * the registry callback, before any await, so a close that lands between the\n\t * claim and finalizeClose() always finds a token to wait on instead of\n\t * answering ahead of the terminal records.\n\t */\n\tprivate claimClose(sessionId: string, options: { drainAttachments: boolean }): { finalizer: boolean } {\n\t\tlet finalizer = true;\n\t\tconst onRole = (isFinalizer: boolean): void => {\n\t\t\tfinalizer = isFinalizer;\n\t\t\tif (isFinalizer && !this.finalizations.has(sessionId))\n\t\t\t\tthis.finalizations.set(sessionId, this.createFinalization());\n\t\t};\n\t\tlet entry = this.registry.beginClose(sessionId, onRole);\n\t\twhile (options.drainAttachments && entry.state === \"open\") entry = this.registry.beginClose(sessionId, onRole);\n\t\treturn { finalizer: finalizer && entry.state === \"closing\" };\n\t}\n\n\t/** claimClose() for lifecycle paths that treat a lost race as \"nothing to do\". */\n\tprivate tryClaimClose(\n\t\tsessionId: string,\n\t\toptions: { drainAttachments: boolean },\n\t): { finalizer: boolean } | undefined {\n\t\ttry {\n\t\t\treturn this.claimClose(sessionId, options);\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tprivate async close(command: Extract<RpcCommand, { type: \"close_session\" }>): Promise<RpcResponse | undefined> {\n\t\tconst response = {\n\t\t\tid: command.id,\n\t\t\ttype: \"response\" as const,\n\t\t\tcommand: \"close_session\" as const,\n\t\t\tsuccess: true as const,\n\t\t\tdata: {},\n\t\t};\n\t\tconst reply = this.writer.reserveCloseResponse(command.sessionId, response);\n\t\tif (!reply) return undefined;\n\t\t// Admission and claiming are synchronous, before any teardown await. A\n\t\t// saturated requester neither releases an attachment nor joins a promise.\n\t\tlet claim: { finalizer: boolean };\n\t\ttry {\n\t\t\tclaim = this.claimClose(command.sessionId, { drainAttachments: false });\n\t\t} catch (cause) {\n\t\t\treply.release();\n\t\t\treturn error(command.id, \"close_session\", this.code(cause));\n\t\t}\n\t\ttry {\n\t\t\tconst owner = this.writer.currentConnection();\n\t\t\tif (owner !== undefined) this.releaseOwnerAttachment(owner, command.sessionId);\n\t\t\tif (claim.finalizer) {\n\t\t\t\tawait this.finalizeClose(command.sessionId, this.bindings.get(command.sessionId), () =>\n\t\t\t\t\treply.complete(true),\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tawait this.finalizations.get(command.sessionId)?.promise;\n\t\t\t\treply.complete(false);\n\t\t\t}\n\t\t\treturn undefined;\n\t\t} finally {\n\t\t\treply.release();\n\t\t}\n\t}\n\n\t/** Detaches the closing connection's UI/width state; a rerender failure must not abort the close. */\n\tprivate releaseOwnerAttachment(owner: string, sessionId: string): void {\n\t\tthis.widths.get(sessionId)?.delete(owner);\n\t\tthis.writer.detachConnectionFromSession(owner, sessionId);\n\t\tfor (const binding of this.bindings.values()) {\n\t\t\ttry {\n\t\t\t\tbinding.rerenderComponents?.();\n\t\t\t} catch (cause) {\n\t\t\t\tprocess.stderr.write(`senpi rpc rerender after close of session ${sessionId} failed: ${String(cause)}\\n`);\n\t\t\t}\n\t\t}\n\t\tconst owned = this.sessionsByConnection.get(owner);\n\t\tconst count = owned?.get(sessionId);\n\t\tif (!owned || count === undefined) return;\n\t\tif (count === 1) owned.delete(sessionId);\n\t\telse owned.set(sessionId, count - 1);\n\t\tif (owned.size === 0) this.sessionsByConnection.delete(owner);\n\t}\n\n\t/**\n\t * Runs the finalizer side of a close for a handle whose beginClose() made this\n\t * caller the owner: dispose the binding, complete the registry teardown, emit\n\t * the terminal records, then release joiners. Every step is guarded so the join\n\t * token always resolves and a failing binding yields one logged line, never a\n\t * second response or an escaped rejection.\n\t */\n\tprivate async finalizeClose(\n\t\tsessionId: string,\n\t\tbinding: RpcSessionBinding | undefined,\n\t\tterminal?: () => void,\n\t): Promise<void> {\n\t\tconst finalization = this.finalizations.get(sessionId) ?? this.createFinalization();\n\t\tthis.finalizations.set(sessionId, finalization);\n\t\ttry {\n\t\t\ttry {\n\t\t\t\tawait binding?.dispose();\n\t\t\t} catch (cause) {\n\t\t\t\tprocess.stderr.write(`senpi rpc binding dispose for session ${sessionId} failed: ${String(cause)}\\n`);\n\t\t\t}\n\t\t\tthis.bindings.delete(sessionId);\n\t\t\ttry {\n\t\t\t\tawait this.registry.closeMarked(sessionId);\n\t\t\t} catch (cause) {\n\t\t\t\tprocess.stderr.write(`senpi rpc close for session ${sessionId} failed: ${String(cause)}\\n`);\n\t\t\t}\n\t\t\tterminal?.();\n\t\t} finally {\n\t\t\tfinalization.resolve();\n\t\t\tthis.finalizations.delete(sessionId);\n\t\t}\n\t}\n\n\tprivate createFinalization(): { promise: Promise<void>; resolve: () => void } {\n\t\tlet resolveFinalization: (() => void) | undefined;\n\t\tconst promise = new Promise<void>((resolve) => {\n\t\t\tresolveFinalization = resolve;\n\t\t});\n\t\treturn { promise, resolve: () => resolveFinalization?.() };\n\t}\n\n\tprivate code(cause: unknown): string {\n\t\tif (cause instanceof RpcSessionRegistryError) {\n\t\t\treturn cause.code === RPC_ERROR_OPEN_FAILED ? cause.message : cause.code;\n\t\t}\n\t\tif (cause instanceof Error && [RPC_ERROR_UNKNOWN_SESSION, RPC_ERROR_SESSION_CLOSING].includes(cause.message)) {\n\t\t\treturn cause.message;\n\t\t}\n\t\treturn cause instanceof Error && cause.message\n\t\t\t? `${RPC_ERROR_OPEN_FAILED}: ${cause.message}`\n\t\t\t: RPC_ERROR_UNKNOWN_SESSION;\n\t}\n}\n"]}
|
|
@@ -3,6 +3,8 @@ export { RENDERED_COMPONENT_RECORD, type SessionEventWriterConnection } from "./
|
|
|
3
3
|
type RawWriter = (chunk: string) => void;
|
|
4
4
|
type BackpressureWaiter = () => Promise<void>;
|
|
5
5
|
type FlushScheduler = (flush: () => Promise<void>) => void;
|
|
6
|
+
export declare const MAX_SHARED_STDIO_QUEUE_BYTES: number;
|
|
7
|
+
export declare const MAX_SHARED_STDIO_QUEUE_RECORDS = 4096;
|
|
6
8
|
/**
|
|
7
9
|
* Process-wide stdout scheduler for multi-session RPC mode.
|
|
8
10
|
*
|
|
@@ -26,6 +28,13 @@ export declare class SessionEventWriter {
|
|
|
26
28
|
private drainPromise?;
|
|
27
29
|
private inFlight?;
|
|
28
30
|
private failure?;
|
|
31
|
+
private controlOverflowReported;
|
|
32
|
+
private closeOverflowReported;
|
|
33
|
+
private readonly closeOverflowActors;
|
|
34
|
+
private reservedCloseRecords;
|
|
35
|
+
private reservedCloseBytes;
|
|
36
|
+
get pendingCloseRecordCount(): number;
|
|
37
|
+
get pendingCloseByteLength(): number;
|
|
29
38
|
constructor(writeRaw: RawWriter, scheduleFlush?: FlushScheduler);
|
|
30
39
|
constructor(writeRaw: RawWriter, waitForBackpressure: BackpressureWaiter, scheduleFlush?: FlushScheduler);
|
|
31
40
|
get bufferedRecordCount(): number;
|
|
@@ -47,6 +56,8 @@ export declare class SessionEventWriter {
|
|
|
47
56
|
currentConnection(): string | undefined;
|
|
48
57
|
/** Queue a session record. Content events target connections attached to the session. */
|
|
49
58
|
enqueue(sessionId: string, value: object): boolean;
|
|
59
|
+
/** Return worker credit only after this session's destinations consumed their queues. */
|
|
60
|
+
waitForSessionBackpressure(sessionId: string): Promise<void>;
|
|
50
61
|
/** Queue one untagged host-control response for the current connection. */
|
|
51
62
|
enqueueControl(value: object): Promise<void>;
|
|
52
63
|
/**
|
|
@@ -55,8 +66,18 @@ export declare class SessionEventWriter {
|
|
|
55
66
|
* session's final stdout record.
|
|
56
67
|
*/
|
|
57
68
|
closeSession(sessionId: string, response: object): void;
|
|
58
|
-
/**
|
|
69
|
+
/**
|
|
70
|
+
* Admit reply debt before routing can mutate attachments or await finalization.
|
|
71
|
+
* Reserve the lifecycle as well: the claimant's role is not known yet. Rejected
|
|
72
|
+
* closes do not wait, retain their ids, or create per-request stderr output.
|
|
73
|
+
*/
|
|
74
|
+
reserveCloseResponse(sessionId: string, response: object, records?: number): {
|
|
75
|
+
release: () => void;
|
|
76
|
+
complete: (terminal: boolean) => void;
|
|
77
|
+
} | undefined;
|
|
78
|
+
/** Queue a joined close only after admitting its noncompactable reply. */
|
|
59
79
|
enqueueClosedResponse(sessionId: string, response: object): void;
|
|
80
|
+
private appendClosedResponse;
|
|
60
81
|
/**
|
|
61
82
|
* Drops per-session bookkeeping for a handle whose runtime is fully disposed.
|
|
62
83
|
* Routing handles are unique per process epoch, so nothing can legitimately
|
|
@@ -68,6 +89,7 @@ export declare class SessionEventWriter {
|
|
|
68
89
|
flush(): Promise<void>;
|
|
69
90
|
private drainUntilEmpty;
|
|
70
91
|
private drainReadyQueues;
|
|
92
|
+
private exceedsStdioCapacity;
|
|
71
93
|
private connectionQueue;
|
|
72
94
|
private appendSessionRecord;
|
|
73
95
|
private demoteAndMerge;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-event-writer.d.ts","sourceRoot":"","sources":["../../../src/modes/rpc/session-event-writer.ts"],"names":[],"mappings":"AAIA,OAAO,EAGN,KAAK,4BAA4B,EACjC,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"session-event-writer.d.ts","sourceRoot":"","sources":["../../../src/modes/rpc/session-event-writer.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,8 @@ import { serializeJsonLine } from "./jsonl.js";
|
|
|
4
4
|
import { omitInlineMedia } from "./media-placeholders.js";
|
|
5
5
|
import { RENDERED_COMPONENT_RECORD, SessionEventFanout, } from "./session-event-fanout.js";
|
|
6
6
|
export { RENDERED_COMPONENT_RECORD } from "./session-event-fanout.js";
|
|
7
|
+
export const MAX_SHARED_STDIO_QUEUE_BYTES = 64 * 1024 * 1024;
|
|
8
|
+
export const MAX_SHARED_STDIO_QUEUE_RECORDS = 4096;
|
|
7
9
|
const MESSAGE_KEY = "message";
|
|
8
10
|
const COMPACT_DELTA_TYPES = new Set(["text_delta", "thinking_delta", "toolcall_delta"]);
|
|
9
11
|
function compactDelta(value) {
|
|
@@ -45,6 +47,12 @@ function toolUpdateKey(value) {
|
|
|
45
47
|
* scheduling boundary and violate D9.
|
|
46
48
|
*/
|
|
47
49
|
export class SessionEventWriter {
|
|
50
|
+
get pendingCloseRecordCount() {
|
|
51
|
+
return this.reservedCloseRecords;
|
|
52
|
+
}
|
|
53
|
+
get pendingCloseByteLength() {
|
|
54
|
+
return this.reservedCloseBytes;
|
|
55
|
+
}
|
|
48
56
|
constructor(writeRaw, waitOrSchedule, scheduleFlush) {
|
|
49
57
|
this.queues = new Map();
|
|
50
58
|
this.fanout = new SessionEventFanout();
|
|
@@ -53,6 +61,11 @@ export class SessionEventWriter {
|
|
|
53
61
|
this.readyQueues = [];
|
|
54
62
|
this.sealedSessions = new Set();
|
|
55
63
|
this.flushScheduled = false;
|
|
64
|
+
this.controlOverflowReported = false;
|
|
65
|
+
this.closeOverflowReported = false;
|
|
66
|
+
this.closeOverflowActors = new WeakSet();
|
|
67
|
+
this.reservedCloseRecords = 0;
|
|
68
|
+
this.reservedCloseBytes = 0;
|
|
56
69
|
this.writeRaw = writeRaw;
|
|
57
70
|
if (waitOrSchedule && scheduleFlush === undefined && waitOrSchedule.length > 0) {
|
|
58
71
|
this.scheduleFlush = waitOrSchedule;
|
|
@@ -127,6 +140,15 @@ export class SessionEventWriter {
|
|
|
127
140
|
const tagged = { ...value, sessionId };
|
|
128
141
|
const { [RENDERED_COMPONENT_RECORD]: _rendered, ...wireTagged } = tagged;
|
|
129
142
|
const line = serializeJsonLine(wireTagged);
|
|
143
|
+
if (this.fanout.isEmpty() && this.exceedsStdioCapacity(line)) {
|
|
144
|
+
this.closeSession(sessionId, {
|
|
145
|
+
type: "response",
|
|
146
|
+
command: "close_session",
|
|
147
|
+
success: false,
|
|
148
|
+
error: "session_output_overflow, resync required",
|
|
149
|
+
});
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
130
152
|
const targets = this.fanout.targets(sessionId, targetId, isTargeted, record[RENDERED_COMPONENT_RECORD] === true, record.type);
|
|
131
153
|
// A record is only walked and re-serialized when a target asked for placeholders;
|
|
132
154
|
// otherwise this is byte-for-byte today's path, with serializeJsonLine called once.
|
|
@@ -150,6 +172,16 @@ export class SessionEventWriter {
|
|
|
150
172
|
this.requestFlush();
|
|
151
173
|
return true;
|
|
152
174
|
}
|
|
175
|
+
/** Return worker credit only after this session's destinations consumed their queues. */
|
|
176
|
+
waitForSessionBackpressure(sessionId) {
|
|
177
|
+
if (this.fanout.isEmpty())
|
|
178
|
+
return this.flush();
|
|
179
|
+
const targets = new Set([
|
|
180
|
+
...this.fanout.targets(sessionId, this.currentConnection(), false, false, undefined),
|
|
181
|
+
this.currentConnection(),
|
|
182
|
+
]);
|
|
183
|
+
return Promise.all([...targets].map((target) => (target === undefined ? undefined : this.fanout.get(target)?.actor.flush()))).then(() => undefined);
|
|
184
|
+
}
|
|
153
185
|
/** Queue one untagged host-control response for the current connection. */
|
|
154
186
|
enqueueControl(value) {
|
|
155
187
|
if (this.failure !== undefined)
|
|
@@ -160,6 +192,15 @@ export class SessionEventWriter {
|
|
|
160
192
|
registered.actor.enqueue(serializeJsonLine(value));
|
|
161
193
|
return Promise.resolve();
|
|
162
194
|
}
|
|
195
|
+
if (this.exceedsStdioCapacity(serializeJsonLine(value))) {
|
|
196
|
+
if (!this.controlOverflowReported) {
|
|
197
|
+
this.controlOverflowReported = true;
|
|
198
|
+
this.append(this.controlQueue, { type: "overflow", error: "rpc_control_output_overflow, resync required" });
|
|
199
|
+
this.markReady(this.controlQueue);
|
|
200
|
+
this.requestFlush();
|
|
201
|
+
}
|
|
202
|
+
return Promise.reject(new Error("rpc_control_output_overflow, resync required"));
|
|
203
|
+
}
|
|
163
204
|
const queue = targetId === undefined ? this.controlQueue : this.connectionQueue(targetId);
|
|
164
205
|
const completion = new Promise((resolve, reject) => {
|
|
165
206
|
this.append(queue, { ...value }, undefined, resolve, reject);
|
|
@@ -191,8 +232,67 @@ export class SessionEventWriter {
|
|
|
191
232
|
this.appendSessionRecord(sessionId, taggedResponse, targetId);
|
|
192
233
|
this.requestFlush();
|
|
193
234
|
}
|
|
194
|
-
/**
|
|
235
|
+
/**
|
|
236
|
+
* Admit reply debt before routing can mutate attachments or await finalization.
|
|
237
|
+
* Reserve the lifecycle as well: the claimant's role is not known yet. Rejected
|
|
238
|
+
* closes do not wait, retain their ids, or create per-request stderr output.
|
|
239
|
+
*/
|
|
240
|
+
reserveCloseResponse(sessionId, response, records = 2) {
|
|
241
|
+
const bytes = Buffer.byteLength(serializeJsonLine({ ...response, sessionId })) +
|
|
242
|
+
(records === 2 ? Buffer.byteLength(serializeJsonLine({ type: "session_closed", sessionId })) : 0);
|
|
243
|
+
if (this.bufferedRecordCount + this.reservedCloseRecords + records > MAX_SHARED_STDIO_QUEUE_RECORDS ||
|
|
244
|
+
this.bufferedByteLength + this.reservedCloseBytes + bytes > MAX_SHARED_STDIO_QUEUE_BYTES) {
|
|
245
|
+
const overflow = {
|
|
246
|
+
type: "overflow",
|
|
247
|
+
command: "close_session",
|
|
248
|
+
error: "rpc_close_output_overflow, resync required",
|
|
249
|
+
};
|
|
250
|
+
const targetId = this.currentConnection();
|
|
251
|
+
if (targetId !== undefined) {
|
|
252
|
+
const actor = this.fanout.get(targetId)?.actor;
|
|
253
|
+
if (actor && !this.closeOverflowActors.has(actor)) {
|
|
254
|
+
this.closeOverflowActors.add(actor);
|
|
255
|
+
// One outstanding notice per sink, released only on consumption.
|
|
256
|
+
// Actor identity isolates reconnects and does not retain dead sinks.
|
|
257
|
+
actor.enqueue(serializeJsonLine(overflow), undefined, () => this.closeOverflowActors.delete(actor));
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
else if (!this.closeOverflowReported) {
|
|
261
|
+
this.closeOverflowReported = true;
|
|
262
|
+
this.append(this.controlQueue, overflow);
|
|
263
|
+
this.markReady(this.controlQueue);
|
|
264
|
+
this.requestFlush();
|
|
265
|
+
}
|
|
266
|
+
return undefined;
|
|
267
|
+
}
|
|
268
|
+
this.reservedCloseRecords += records;
|
|
269
|
+
this.reservedCloseBytes += bytes;
|
|
270
|
+
let active = true;
|
|
271
|
+
const release = () => {
|
|
272
|
+
if (!active)
|
|
273
|
+
return;
|
|
274
|
+
active = false;
|
|
275
|
+
this.reservedCloseRecords -= records;
|
|
276
|
+
this.reservedCloseBytes -= bytes;
|
|
277
|
+
};
|
|
278
|
+
return {
|
|
279
|
+
release,
|
|
280
|
+
complete: (terminal) => {
|
|
281
|
+
if (!active)
|
|
282
|
+
return;
|
|
283
|
+
release();
|
|
284
|
+
if (terminal)
|
|
285
|
+
this.closeSession(sessionId, response);
|
|
286
|
+
else
|
|
287
|
+
this.appendClosedResponse(sessionId, response);
|
|
288
|
+
},
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
/** Queue a joined close only after admitting its noncompactable reply. */
|
|
195
292
|
enqueueClosedResponse(sessionId, response) {
|
|
293
|
+
this.reserveCloseResponse(sessionId, response, 1)?.complete(false);
|
|
294
|
+
}
|
|
295
|
+
appendClosedResponse(sessionId, response) {
|
|
196
296
|
const targetId = this.connectionContext.getStore();
|
|
197
297
|
const taggedResponse = { ...response, sessionId };
|
|
198
298
|
const registered = targetId === undefined ? undefined : this.fanout.get(targetId);
|
|
@@ -246,6 +346,9 @@ export class SessionEventWriter {
|
|
|
246
346
|
await this.drainReadyQueues();
|
|
247
347
|
} while (this.readyQueues.length > 0);
|
|
248
348
|
await Promise.all([...this.fanout.values()].map(({ actor }) => actor.flush()));
|
|
349
|
+
this.controlOverflowReported = false;
|
|
350
|
+
if (this.reservedCloseRecords === 0)
|
|
351
|
+
this.closeOverflowReported = false;
|
|
249
352
|
}
|
|
250
353
|
async drainReadyQueues() {
|
|
251
354
|
while (this.readyQueues.length > 0) {
|
|
@@ -290,6 +393,10 @@ export class SessionEventWriter {
|
|
|
290
393
|
}
|
|
291
394
|
}
|
|
292
395
|
}
|
|
396
|
+
exceedsStdioCapacity(line) {
|
|
397
|
+
return (this.bufferedRecordCount + this.reservedCloseRecords >= MAX_SHARED_STDIO_QUEUE_RECORDS ||
|
|
398
|
+
this.bufferedByteLength + this.reservedCloseBytes + Buffer.byteLength(line) > MAX_SHARED_STDIO_QUEUE_BYTES);
|
|
399
|
+
}
|
|
293
400
|
connectionQueue(targetId) {
|
|
294
401
|
const key = `connection:${targetId}`;
|
|
295
402
|
let queue = this.queues.get(key);
|