refactor: centralize gateway module and address review fixes

Move the gateway runtime files into a dedicated core/gateway module and fix follow-up issues in session deletion, history import batching, message IDs, and legacy thread parsing.

Fixes #253

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Harivansh Rathi 2026-03-07 16:53:36 -08:00
parent 753cb935f1
commit c0bba5c38f
10 changed files with 47 additions and 29 deletions

View file

@ -1,4 +1,4 @@
import type { AgentSession } from "./agent-session.js";
import type { AgentSession } from "../agent-session.js";
export function extractMessageText(message: { content: unknown }): string {
if (!Array.isArray(message.content)) {

View file

@ -0,0 +1,19 @@
export {
createGatewaySessionManager,
GatewayRuntime,
getActiveGatewayRuntime,
sanitizeSessionKey,
setActiveGatewayRuntime,
} from "./runtime.js";
export type {
ChannelStatus,
GatewayConfig,
GatewayMessageRequest,
GatewayMessageResult,
GatewayRuntimeOptions,
GatewaySessionFactory,
GatewaySessionSnapshot,
HistoryMessage,
HistoryPart,
ModelInfo,
} from "./runtime.js";

View file

@ -1,9 +1,9 @@
import type { AgentSession } from "./agent-session.js";
import type { AgentSession } from "../agent-session.js";
import type {
GatewayMessageRequest,
GatewayMessageResult,
GatewaySessionSnapshot,
} from "./gateway-runtime-types.js";
} from "./types.js";
export interface GatewayQueuedMessage {
request: GatewayMessageRequest;

View file

@ -8,18 +8,15 @@ import { rm } from "node:fs/promises";
import { join } from "node:path";
import { URL } from "node:url";
import type { AgentMessage } from "@mariozechner/pi-agent-core";
import type { AgentSession, AgentSessionEvent } from "./agent-session.js";
import {
extractMessageText,
getLastAssistantText,
} from "./gateway-runtime-helpers.js";
import type { AgentSession, AgentSessionEvent } from "../agent-session.js";
import { extractMessageText, getLastAssistantText } from "./helpers.js";
import {
type GatewayEvent,
type GatewayQueuedMessage,
HttpError,
type ManagedGatewaySession,
} from "./gateway-runtime-internal-types.js";
import { sanitizeSessionKey } from "./gateway-session-manager.js";
} from "./internal-types.js";
import { sanitizeSessionKey } from "./session-manager.js";
import type {
ChannelStatus,
GatewayConfig,
@ -31,8 +28,8 @@ import type {
HistoryMessage,
HistoryPart,
ModelInfo,
} from "./gateway-runtime-types.js";
import type { Settings } from "./settings-manager.js";
} from "./types.js";
import type { Settings } from "../settings-manager.js";
import {
createVercelStreamListener,
errorVercelStream,
@ -42,7 +39,7 @@ import {
export {
createGatewaySessionManager,
sanitizeSessionKey,
} from "./gateway-session-manager.js";
} from "./session-manager.js";
export type {
ChannelStatus,
GatewayConfig,
@ -54,7 +51,7 @@ export type {
HistoryMessage,
HistoryPart,
ModelInfo,
} from "./gateway-runtime-types.js";
} from "./types.js";
let activeGatewayRuntime: GatewayRuntime | null = null;
@ -966,7 +963,7 @@ export class GatewayRuntime {
const managed = await this.ensureSession(sessionKey);
const rawMessages = managed.session.messages;
const messages: HistoryMessage[] = [];
for (const msg of rawMessages) {
for (const [index, msg] of rawMessages.entries()) {
if (
msg.role !== "user" &&
msg.role !== "assistant" &&
@ -975,7 +972,7 @@ export class GatewayRuntime {
continue;
}
messages.push({
id: `${msg.timestamp}-${msg.role}`,
id: `${msg.timestamp}-${msg.role}-${index}`,
role: msg.role,
parts: this.messageContentToParts(msg),
timestamp: msg.timestamp,
@ -1006,14 +1003,16 @@ export class GatewayRuntime {
if (sessionKey === this.primarySessionKey) {
throw new HttpError(400, "Cannot delete primary session");
}
const managed = await this.ensureSession(sessionKey);
if (managed.processing) {
await managed.session.abort();
const managed = this.sessions.get(sessionKey);
if (managed) {
if (managed.processing) {
await managed.session.abort();
}
this.rejectQueuedMessages(managed, `Session deleted: ${sessionKey}`);
managed.unsubscribe();
managed.session.dispose();
this.sessions.delete(sessionKey);
}
this.rejectQueuedMessages(managed, `Session deleted: ${sessionKey}`);
managed.unsubscribe();
managed.session.dispose();
this.sessions.delete(sessionKey);
await rm(this.getGatewaySessionDir(sessionKey), {
recursive: true,
force: true,

View file

@ -1,5 +1,5 @@
import { join } from "node:path";
import { SessionManager } from "./session-manager.js";
import { SessionManager } from "../session-manager.js";
export function sanitizeSessionKey(sessionKey: string): string {
return sessionKey.replace(/[^a-zA-Z0-9._-]/g, "_");

View file

@ -1,5 +1,5 @@
import type { AgentSession } from "./agent-session.js";
import type { ImageContent } from "@mariozechner/pi-ai";
import type { AgentSession } from "../agent-session.js";
export interface GatewayConfig {
bind: string;

View file

@ -1,6 +1,6 @@
import { randomUUID } from "node:crypto";
import type { ServerResponse } from "node:http";
import type { AgentSessionEvent } from "./agent-session.js";
import type { AgentSessionEvent } from "../agent-session.js";
/**
* Write a single Vercel AI SDK v5+ SSE chunk to the response.

View file

@ -156,7 +156,7 @@ export {
getActiveGatewayRuntime,
sanitizeSessionKey,
setActiveGatewayRuntime,
} from "./core/gateway-runtime.js";
} from "./core/gateway/index.js";
export { convertToLlm } from "./core/messages.js";
export { ModelRegistry } from "./core/model-registry.js";
export type {

View file

@ -22,7 +22,7 @@ import { APP_NAME, getAgentDir, getModelsPath, VERSION } from "./config.js";
import { AuthStorage } from "./core/auth-storage.js";
import { exportFromFile } from "./core/export-html/index.js";
import type { LoadExtensionsResult } from "./core/extensions/index.js";
import { createGatewaySessionManager } from "./core/gateway-runtime.js";
import { createGatewaySessionManager } from "./core/gateway/index.js";
import { KeybindingsManager } from "./core/keybindings.js";
import { ModelRegistry } from "./core/model-registry.js";
import {

View file

@ -12,7 +12,7 @@ import {
GatewayRuntime,
type GatewaySessionFactory,
setActiveGatewayRuntime,
} from "../core/gateway-runtime.js";
} from "../core/gateway/index.js";
import type { GatewaySettings } from "../core/settings-manager.js";
/**