Fix boot state sharing across Next.js module boundaries
Use globalThis for all in-memory stores (credentials, models, agents, tasks) so the instrumentation hook and API route handlers share the same data. Next.js bundles these as separate chunks with independent module instances, causing boot-populated state to be invisible to API routes.
This commit is contained in:
@@ -58,7 +58,10 @@ export interface AgentConfig {
|
||||
env?: Record<string, string>; // additional env vars for the agent process
|
||||
}
|
||||
|
||||
const configs: Map<string, AgentConfig> = new Map();
|
||||
// Shared via globalThis to survive Next.js module re-bundling.
|
||||
const g = globalThis as unknown as { __harnessAgentConfigs?: Map<string, AgentConfig> };
|
||||
g.__harnessAgentConfigs ??= new Map();
|
||||
const configs = g.__harnessAgentConfigs;
|
||||
|
||||
export function getAllAgentConfigs(): AgentConfig[] {
|
||||
return Array.from(configs.values());
|
||||
|
||||
@@ -7,7 +7,8 @@ import { upsertCuratedModel, getCuratedModels } from "./model-store";
|
||||
import { upsertAgentConfig, getAllAgentConfigs, type AgentRuntime } from "./agents";
|
||||
import { fetchAllModels } from "./model-providers";
|
||||
|
||||
let booted = false;
|
||||
const gb = globalThis as unknown as { __harnessBooted?: boolean };
|
||||
|
||||
|
||||
// Well-known models with pricing (used as fallback when API discovery returns
|
||||
// models without pricing info, and to enable cost tracking from the start).
|
||||
@@ -179,8 +180,8 @@ async function discoverModelsAndAgents() {
|
||||
// ─── BOOT ───────────────────────────────────────────────────
|
||||
|
||||
export async function boot() {
|
||||
if (booted) return;
|
||||
booted = true;
|
||||
if (gb.__harnessBooted) return;
|
||||
gb.__harnessBooted = true;
|
||||
|
||||
// 1. Load credentials from mounted secrets (files take priority)
|
||||
loadClaudeCredentials();
|
||||
|
||||
@@ -13,8 +13,10 @@ export interface Credential {
|
||||
baseUrl?: string; // for self-hosted GitLab or custom endpoints
|
||||
}
|
||||
|
||||
// In-memory store. Will be replaced with encrypted persistent storage.
|
||||
const credentials: Map<string, Credential> = new Map();
|
||||
// In-memory store shared via globalThis to survive Next.js module re-bundling.
|
||||
const g = globalThis as unknown as { __harnessCredentials?: Map<string, Credential> };
|
||||
g.__harnessCredentials ??= new Map();
|
||||
const credentials = g.__harnessCredentials;
|
||||
|
||||
export function getAllCredentials(): Credential[] {
|
||||
return Array.from(credentials.values()).map(c => ({
|
||||
|
||||
@@ -32,9 +32,12 @@ export interface ModelUsageSummary {
|
||||
totalDurationMs: number;
|
||||
}
|
||||
|
||||
// In-memory stores
|
||||
const curatedModels: Map<string, CuratedModel> = new Map();
|
||||
const usageLog: ModelUsageEntry[] = [];
|
||||
// In-memory stores shared via globalThis to survive Next.js module re-bundling.
|
||||
const g = globalThis as unknown as { __harnessCuratedModels?: Map<string, CuratedModel>; __harnessUsageLog?: ModelUsageEntry[] };
|
||||
g.__harnessCuratedModels ??= new Map();
|
||||
g.__harnessUsageLog ??= [];
|
||||
const curatedModels = g.__harnessCuratedModels;
|
||||
const usageLog = g.__harnessUsageLog;
|
||||
|
||||
// ─── CURATED MODELS ─────────────────────────────────────────
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { Task } from "./types";
|
||||
|
||||
// In-memory task store. Will be replaced with persistent storage (CloudNativePG)
|
||||
// once the orchestrator loop is wired up.
|
||||
const tasks: Map<string, Task> = new Map();
|
||||
// In-memory task store shared via globalThis to survive Next.js module re-bundling.
|
||||
const g = globalThis as unknown as { __harnessTasks?: Map<string, Task> };
|
||||
g.__harnessTasks ??= new Map();
|
||||
const tasks = g.__harnessTasks;
|
||||
|
||||
export function getAllTasks(): Task[] {
|
||||
return Array.from(tasks.values());
|
||||
|
||||
Reference in New Issue
Block a user