mirror of
https://github.com/murashit/codex-panel.git
synced 2026-07-22 06:57:10 +00:00
Detach shared app-server cache snapshots
This commit is contained in:
parent
2040883f70
commit
ec13c7daa1
2 changed files with 123 additions and 7 deletions
|
|
@ -32,34 +32,62 @@ export function createSharedAppServerState(): SharedAppServerState {
|
|||
export function applySharedThreadList(state: SharedAppServerState, threads: readonly Thread[]): SharedAppServerState {
|
||||
return {
|
||||
...state,
|
||||
threads: { kind: "loaded", data: threads },
|
||||
threads: { kind: "loaded", data: cloneThreads(threads) },
|
||||
};
|
||||
}
|
||||
|
||||
export function applySharedAppServerMetadata(state: SharedAppServerState, metadata: SharedAppServerMetadata): SharedAppServerState {
|
||||
const clonedMetadata = cloneSharedAppServerMetadata(metadata);
|
||||
return {
|
||||
...state,
|
||||
appServerMetadata: { kind: "loaded", data: metadata },
|
||||
availableModels: metadata.availableModels,
|
||||
appServerMetadata: { kind: "loaded", data: clonedMetadata },
|
||||
availableModels: cloneModels(clonedMetadata.availableModels),
|
||||
};
|
||||
}
|
||||
|
||||
export function applySharedModels(state: SharedAppServerState, models: readonly Model[]): SharedAppServerState {
|
||||
const clonedModels = cloneModels(models);
|
||||
return {
|
||||
...state,
|
||||
appServerMetadata:
|
||||
state.appServerMetadata.kind === "loaded"
|
||||
? { kind: "loaded", data: { ...state.appServerMetadata.data, availableModels: models } }
|
||||
? { kind: "loaded", data: { ...state.appServerMetadata.data, availableModels: cloneModels(clonedModels) } }
|
||||
: state.appServerMetadata,
|
||||
availableModels: models,
|
||||
availableModels: clonedModels,
|
||||
};
|
||||
}
|
||||
|
||||
export function cachedSharedThreadList(state: SharedAppServerState): readonly Thread[] | null {
|
||||
return state.threads.kind === "loaded" ? state.threads.data : null;
|
||||
return state.threads.kind === "loaded" ? cloneThreads(state.threads.data) : null;
|
||||
}
|
||||
|
||||
export function cachedSharedAppServerMetadata(state: SharedAppServerState): SharedAppServerMetadata | null {
|
||||
if (state.appServerMetadata.kind === "loaded") return state.appServerMetadata.data;
|
||||
if (state.appServerMetadata.kind === "loaded") return cloneSharedAppServerMetadata(state.appServerMetadata.data);
|
||||
return null;
|
||||
}
|
||||
|
||||
function cloneSharedAppServerMetadata(metadata: SharedAppServerMetadata): SharedAppServerMetadata {
|
||||
return {
|
||||
...metadata,
|
||||
availableModels: cloneModels(metadata.availableModels),
|
||||
availableSkills: metadata.availableSkills.map((skill) => ({ ...skill })),
|
||||
appServerDiagnostics: {
|
||||
probes: { ...metadata.appServerDiagnostics.probes },
|
||||
mcpServers: metadata.appServerDiagnostics.mcpServers.map((server) => ({ ...server })),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function cloneThreads(threads: readonly Thread[]): Thread[] {
|
||||
return threads.map((thread) => ({ ...thread, turns: [...thread.turns] }));
|
||||
}
|
||||
|
||||
function cloneModels(models: readonly Model[]): Model[] {
|
||||
return models.map((model) => ({
|
||||
...model,
|
||||
supportedReasoningEfforts: [...model.supportedReasoningEfforts],
|
||||
inputModalities: [...model.inputModalities],
|
||||
additionalSpeedTiers: [...model.additionalSpeedTiers],
|
||||
serviceTiers: [...model.serviceTiers],
|
||||
}));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import type { ConfigReadResponse } from "../../src/generated/app-server/v2/ConfigReadResponse";
|
||||
import type { Model } from "../../src/generated/app-server/v2/Model";
|
||||
import type { Thread } from "../../src/generated/app-server/v2/Thread";
|
||||
import { createAppServerDiagnostics } from "../../src/app-server/compatibility";
|
||||
import {
|
||||
compactContextLabel,
|
||||
compactModelLabel,
|
||||
|
|
@ -27,6 +30,14 @@ import {
|
|||
} from "../../src/runtime/state";
|
||||
import { readRuntimeConfig } from "../../src/runtime/config";
|
||||
import { contextSummary, effectiveConfigSections, rateLimitSummary } from "../../src/runtime/view";
|
||||
import {
|
||||
applySharedAppServerMetadata,
|
||||
applySharedModels,
|
||||
applySharedThreadList,
|
||||
cachedSharedAppServerMetadata,
|
||||
cachedSharedThreadList,
|
||||
createSharedAppServerState,
|
||||
} from "../../src/runtime/shared-app-server-state";
|
||||
|
||||
describe("runtime settings", () => {
|
||||
it("parses model overrides", () => {
|
||||
|
|
@ -35,6 +46,38 @@ describe("runtime settings", () => {
|
|||
expect(parseModelOverride("")).toBeUndefined();
|
||||
});
|
||||
|
||||
it("keeps shared app-server cache snapshots detached from caller-owned arrays", () => {
|
||||
const sourceThreads = [threadFixture("thread-1")];
|
||||
const threadState = applySharedThreadList(createSharedAppServerState(), sourceThreads);
|
||||
sourceThreads.push(threadFixture("thread-2"));
|
||||
|
||||
const cachedThreads = cachedSharedThreadList(threadState);
|
||||
expect(cachedThreads?.map((thread) => thread.id)).toEqual(["thread-1"]);
|
||||
|
||||
const mutableCachedThreads = cachedThreads as Thread[];
|
||||
mutableCachedThreads.push(threadFixture("thread-3"));
|
||||
expect(cachedSharedThreadList(threadState)?.map((thread) => thread.id)).toEqual(["thread-1"]);
|
||||
|
||||
const sourceModels = [modelFixture("gpt-5.5")];
|
||||
const modelState = applySharedModels(createSharedAppServerState(), sourceModels);
|
||||
sourceModels.push(modelFixture("gpt-5.6"));
|
||||
expect(modelState.availableModels.map((model) => model.model)).toEqual(["gpt-5.5"]);
|
||||
|
||||
const metadataState = applySharedAppServerMetadata(createSharedAppServerState(), {
|
||||
effectiveConfig: null,
|
||||
availableModels: sourceModels,
|
||||
availableSkills: [{ name: "skill", description: "", path: "/tmp/skill", scope: "repo", enabled: true }],
|
||||
rateLimit: null,
|
||||
appServerDiagnostics: {
|
||||
...createAppServerDiagnostics(),
|
||||
mcpServers: [{ name: "server", startupStatus: "ready", authStatus: null, toolCount: 1, message: null }],
|
||||
},
|
||||
});
|
||||
sourceModels.push(modelFixture("gpt-5.7"));
|
||||
const cachedMetadata = cachedSharedAppServerMetadata(metadataState);
|
||||
expect(cachedMetadata?.availableModels.map((model) => model.model)).toEqual(["gpt-5.5", "gpt-5.6"]);
|
||||
});
|
||||
|
||||
it("parses reasoning effort overrides", () => {
|
||||
expect(parseReasoningEffortOverride("high")).toBe("high");
|
||||
expect(parseReasoningEffortOverride("default")).toBeNull();
|
||||
|
|
@ -591,3 +634,48 @@ function configLayer(config: Record<string, unknown>, profile: string | null): N
|
|||
disabledReason: null,
|
||||
};
|
||||
}
|
||||
|
||||
function threadFixture(id: string): Thread {
|
||||
return {
|
||||
id,
|
||||
sessionId: "session",
|
||||
forkedFromId: null,
|
||||
preview: "",
|
||||
ephemeral: false,
|
||||
modelProvider: "openai",
|
||||
createdAt: 1,
|
||||
updatedAt: 1,
|
||||
status: { type: "idle" },
|
||||
path: null,
|
||||
cwd: "/vault",
|
||||
cliVersion: "0.0.0",
|
||||
source: "appServer",
|
||||
threadSource: null,
|
||||
agentNickname: null,
|
||||
agentRole: null,
|
||||
gitInfo: null,
|
||||
name: null,
|
||||
turns: [],
|
||||
};
|
||||
}
|
||||
|
||||
function modelFixture(model: string): Model {
|
||||
return {
|
||||
id: model,
|
||||
model,
|
||||
upgrade: null,
|
||||
upgradeInfo: null,
|
||||
availabilityNux: null,
|
||||
displayName: model,
|
||||
description: "",
|
||||
hidden: false,
|
||||
supportedReasoningEfforts: [],
|
||||
defaultReasoningEffort: "medium",
|
||||
inputModalities: [],
|
||||
supportsPersonality: false,
|
||||
additionalSpeedTiers: [],
|
||||
serviceTiers: [],
|
||||
defaultServiceTier: null,
|
||||
isDefault: false,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue