feat(compaction): support SubAPI native remote compaction

- support sub-api/openai-responses through the public Responses endpoint
- preserve explicit Authorization and support header-only authentication
- retain Codex JWT requirements and native compaction failure fallback
- restore SubAPI checkpoints and preserve portable model-switching summaries
- add provider, authentication and checkpoint lifecycle regression tests
- document compatibility requirements and the Sub2API protocol reference
This commit is contained in:
云服务部-叶林立
2026-09-07 16:25:48 +08:00
parent 6e7effa792
commit ff1e7400da
9 changed files with 431 additions and 12 deletions
+7 -10
View File
@@ -14,21 +14,19 @@ import {
type SessionEntry,
} from "@earendil-works/pi-coding-agent";
import { DEFAULT_CONFIG, loadConfig } from "./src/config.js";
import { buildNativeCompactionTransport, isNativeCompactionModel } from "./src/native-provider.js";
import {
buildCodexHeaders,
buildCompactionRequestBody,
buildReplacementHistory,
buildToolPayload,
callRemoteCompaction,
findNativeCheckpoint,
isJsonObject,
isOpenAICodexModel,
mergeFeatureHeader,
messagesToResponseItems,
modelKey,
NATIVE_COMPACTION_KIND,
NATIVE_COMPACTION_VERSION,
resolveCodexResponsesUrl,
stripInputFromPayload,
type JsonObject,
type NativeCompactionDetails,
@@ -364,12 +362,12 @@ export default function piCompactionExtension(pi: ExtensionAPI): void {
});
pi.on("before_provider_headers", (event, ctx) => {
if (isOpenAICodexModel(ctx.model)) setFeatureHeader(event.headers);
if (isNativeCompactionModel(ctx.model)) setFeatureHeader(event.headers);
});
pi.on("before_provider_request", (event, ctx) => {
const model = ctx.model;
if (!model || !isOpenAICodexModel(model) || !isJsonObject(event.payload)) return undefined;
if (!model || !isNativeCompactionModel(model) || !isJsonObject(event.payload)) return undefined;
const runtime = runtimeFor(ctx);
const sessionId = ctx.sessionManager.getSessionId();
payloads.set(sessionId, { modelKey: modelKey(model), payload: stripInputFromPayload(event.payload) });
@@ -401,7 +399,7 @@ export default function piCompactionExtension(pi: ExtensionAPI): void {
const model = ctx.model;
if (!model) return undefined;
if (!runtime.config.native.enabled || !isOpenAICodexModel(model)) {
if (!runtime.config.native.enabled || !isNativeCompactionModel(model)) {
try {
const auth = await ctx.modelRegistry.getApiKeyAndHeaders(model);
if (!auth.ok) return undefined;
@@ -438,7 +436,7 @@ export default function piCompactionExtension(pi: ExtensionAPI): void {
try {
const auth = await ctx.modelRegistry.getApiKeyAndHeaders(model);
if (!auth.ok || !auth.apiKey) throw new Error(auth.ok ? "Codex authentication unavailable" : auth.error);
if (!auth.ok) throw new Error(auth.error);
const currentCheckpoint = checkpoint.status === "valid" ? checkpoint.checkpoint.details : undefined;
const input = codexInput(model, runtime, snapshot, currentCheckpoint);
const sessionId = ctx.sessionManager.getSessionId();
@@ -451,10 +449,9 @@ export default function piCompactionExtension(pi: ExtensionAPI): void {
tools: buildToolPayload(pi.getAllTools(), pi.getActiveTools()),
sessionId,
});
if (ctx.hasUI) ctx.ui.notify("pi-compaction: creating Codex native checkpoint…", "info");
if (ctx.hasUI) ctx.ui.notify(`pi-compaction: creating ${model.provider} native checkpoint...`, "info");
const remote = await callRemoteCompaction({
url: resolveCodexResponsesUrl(model.baseUrl),
headers: buildCodexHeaders({ apiKey: auth.apiKey, headers: cleanHeaders(auth.headers), sessionId }),
...buildNativeCompactionTransport({ model, apiKey: auth.apiKey, headers: cleanHeaders(auth.headers), sessionId }),
body,
signal: event.signal,
});