mirror of
https://github.com/murashit/codex-panel.git
synced 2026-07-22 17:30:31 +00:00
Handle Codex CLI 0.133.0 app-server notifications
This commit is contained in:
parent
31715f2889
commit
a8bff12df2
9 changed files with 129 additions and 0 deletions
|
|
@ -257,6 +257,10 @@ export class PanelController {
|
|||
const name = typeof params.threadName === "string" && params.threadName.trim() ? params.threadName.trim() : null;
|
||||
this.state.listedThreads = this.state.listedThreads.map((thread) => (thread.id === params.threadId ? { ...thread, name } : thread));
|
||||
this.actions.refreshThreads();
|
||||
} else if (method === "thread/settings/updated") {
|
||||
this.applyThreadSettings(params.threadSettings);
|
||||
} else if (method === "thread/goal/updated" || method === "thread/goal/cleared") {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -414,6 +418,15 @@ export class PanelController {
|
|||
if (!params?.name) return;
|
||||
this.actions.recordMcpStartupStatus(params.name, params.status, params.error ?? null);
|
||||
}
|
||||
|
||||
private applyThreadSettings(
|
||||
settings: Extract<ServerNotification, { method: "thread/settings/updated" }>["params"]["threadSettings"],
|
||||
): void {
|
||||
this.state.activeThreadCwd = settings.cwd ?? this.state.activeThreadCwd;
|
||||
this.state.activeModel = settings.model ?? null;
|
||||
this.state.activeServiceTier = settings.serviceTier ?? null;
|
||||
this.state.activeApprovalsReviewer = settings.approvalsReviewer ?? null;
|
||||
}
|
||||
}
|
||||
|
||||
function removeUnstructuredAutoReviewWarnings(items: DisplayItem[]): DisplayItem[] {
|
||||
|
|
|
|||
|
|
@ -111,6 +111,9 @@ function isThreadLifecycleNotification(notification: ServerNotification): boolea
|
|||
case "thread/archived":
|
||||
case "thread/unarchived":
|
||||
case "thread/name/updated":
|
||||
case "thread/goal/updated":
|
||||
case "thread/goal/cleared":
|
||||
case "thread/settings/updated":
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ function model(name: string, efforts: ReasoningEffort[], overrides: Partial<Mode
|
|||
supportsPersonality: false,
|
||||
additionalSpeedTiers: [],
|
||||
serviceTiers: [],
|
||||
defaultServiceTier: null,
|
||||
isDefault: false,
|
||||
...overrides,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -571,6 +571,7 @@ describe("thread item conversion preserves app-server semantics", () => {
|
|||
tool: "pull_request_read",
|
||||
status: "inProgress",
|
||||
arguments: { id: 123 },
|
||||
pluginId: null,
|
||||
result: null,
|
||||
error: null,
|
||||
durationMs: null,
|
||||
|
|
@ -599,6 +600,7 @@ describe("thread item conversion preserves app-server semantics", () => {
|
|||
tool: "pull_request_read",
|
||||
status: "failed",
|
||||
arguments: { owner: "org", repo: "project", id: 123 },
|
||||
pluginId: null,
|
||||
result: null,
|
||||
error: { message: "Not found" },
|
||||
durationMs: 10,
|
||||
|
|
|
|||
|
|
@ -190,6 +190,7 @@ function model(name: string, efforts: Model["supportedReasoningEfforts"][number]
|
|||
supportsPersonality: false,
|
||||
additionalSpeedTiers: [],
|
||||
serviceTiers: [],
|
||||
defaultServiceTier: null,
|
||||
isDefault: false,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -992,6 +992,68 @@ describe("PanelController", () => {
|
|||
expect(state.listedThreads[0]?.name).toBe("Codex Panel自動命名");
|
||||
expect(refreshThreads).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("syncs active runtime state from thread settings notifications", () => {
|
||||
const state = createPanelState();
|
||||
state.activeThreadId = "thread-active";
|
||||
const controller = controllerForState(state);
|
||||
|
||||
controller.handleNotification({
|
||||
method: "thread/settings/updated",
|
||||
params: {
|
||||
threadId: "thread-active",
|
||||
threadSettings: {
|
||||
cwd: "/workspace/active",
|
||||
approvalPolicy: "on-request",
|
||||
approvalsReviewer: "auto_review",
|
||||
sandboxPolicy: { type: "readOnly", networkAccess: false },
|
||||
activePermissionProfile: null,
|
||||
model: "gpt-5.5",
|
||||
modelProvider: "openai",
|
||||
serviceTier: "fast",
|
||||
effort: "high",
|
||||
summary: null,
|
||||
collaborationMode: {
|
||||
mode: "default",
|
||||
settings: { model: "gpt-5.5", reasoning_effort: "high", developer_instructions: null },
|
||||
},
|
||||
personality: null,
|
||||
},
|
||||
},
|
||||
} satisfies Extract<ServerNotification, { method: "thread/settings/updated" }>);
|
||||
|
||||
expect(state.activeThreadCwd).toBe("/workspace/active");
|
||||
expect(state.activeModel).toBe("gpt-5.5");
|
||||
expect(state.activeServiceTier).toBe("fast");
|
||||
expect(state.activeApprovalsReviewer).toBe("auto_review");
|
||||
expect(state.displayItems).toEqual([]);
|
||||
});
|
||||
|
||||
it("keeps goal notifications out of the message stream", () => {
|
||||
const state = createPanelState();
|
||||
state.activeThreadId = "thread-active";
|
||||
const controller = controllerForState(state);
|
||||
|
||||
controller.handleNotification({
|
||||
method: "thread/goal/updated",
|
||||
params: {
|
||||
threadId: "thread-active",
|
||||
turnId: null,
|
||||
goal: {
|
||||
threadId: "thread-active",
|
||||
objective: "Finish",
|
||||
status: "active",
|
||||
tokenBudget: null,
|
||||
tokensUsed: 0,
|
||||
timeUsedSeconds: 0,
|
||||
createdAt: 1,
|
||||
updatedAt: 1,
|
||||
},
|
||||
},
|
||||
} satisfies Extract<ServerNotification, { method: "thread/goal/updated" }>);
|
||||
|
||||
expect(state.displayItems).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("auto-review display", () => {
|
||||
|
|
|
|||
|
|
@ -66,6 +66,8 @@ describe("panel inbound routing", () => {
|
|||
expect(routeServerNotification(agentDeltaNotification(), activeScope).kind).toBe("streamUpdate");
|
||||
expect(routeServerNotification(turnStartedNotification(), activeScope).kind).toBe("turnLifecycle");
|
||||
expect(routeServerNotification(threadArchivedNotification(), activeScope).kind).toBe("threadLifecycle");
|
||||
expect(routeServerNotification(threadSettingsUpdatedNotification(), activeScope).kind).toBe("threadLifecycle");
|
||||
expect(routeServerNotification(threadGoalUpdatedNotification(), activeScope).kind).toBe("threadLifecycle");
|
||||
expect(routeServerNotification(serverRequestResolvedNotification(), activeScope).kind).toBe("requestResolved");
|
||||
expect(routeServerNotification(mcpStartupStatusNotification(), activeScope).kind).toBe("diagnosticStatus");
|
||||
expect(routeServerNotification(warningNotification(), activeScope).kind).toBe("userVisibleNotice");
|
||||
|
|
@ -165,6 +167,49 @@ function threadArchivedNotification(): ServerNotification {
|
|||
};
|
||||
}
|
||||
|
||||
function threadSettingsUpdatedNotification(): ServerNotification {
|
||||
return {
|
||||
method: "thread/settings/updated",
|
||||
params: {
|
||||
threadId: "thread-active",
|
||||
threadSettings: {
|
||||
cwd: "/vault",
|
||||
approvalPolicy: "on-request",
|
||||
approvalsReviewer: "user",
|
||||
sandboxPolicy: { type: "readOnly", networkAccess: false },
|
||||
activePermissionProfile: null,
|
||||
model: "gpt-5.5",
|
||||
modelProvider: "openai",
|
||||
serviceTier: null,
|
||||
effort: "medium",
|
||||
summary: null,
|
||||
collaborationMode: { mode: "default", settings: { model: "gpt-5.5", reasoning_effort: "medium", developer_instructions: null } },
|
||||
personality: null,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function threadGoalUpdatedNotification(): ServerNotification {
|
||||
return {
|
||||
method: "thread/goal/updated",
|
||||
params: {
|
||||
threadId: "thread-active",
|
||||
turnId: null,
|
||||
goal: {
|
||||
threadId: "thread-active",
|
||||
objective: "Finish",
|
||||
status: "active",
|
||||
tokenBudget: null,
|
||||
tokensUsed: 0,
|
||||
timeUsedSeconds: 0,
|
||||
createdAt: 1,
|
||||
updatedAt: 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function serverRequestResolvedNotification(): ServerNotification {
|
||||
return {
|
||||
method: "serverRequest/resolved",
|
||||
|
|
|
|||
|
|
@ -222,6 +222,7 @@ function model(name: string, efforts: Model["supportedReasoningEfforts"][number]
|
|||
supportsPersonality: false,
|
||||
additionalSpeedTiers: [],
|
||||
serviceTiers: [],
|
||||
defaultServiceTier: null,
|
||||
isDefault: false,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -262,6 +262,7 @@ function model(modelId: string, isDefault = false, hidden = false, efforts: Reas
|
|||
supportsPersonality: false,
|
||||
additionalSpeedTiers: [],
|
||||
serviceTiers: [],
|
||||
defaultServiceTier: null,
|
||||
} satisfies Model;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue