refactor: source thinking levels from pi and make the gauge dynamic

Depend on @earendil-works/pi-agent-core so the ThinkingLevel union has a single source of truth (re-exported via shared/thinkingLevels). Wire/data fields use string and the parser is lenient, so an unknown level from a newer pi runtime is still listed, selectable, and rendered gracefully instead of throwing. The composer gauge now derives its bar count from the levels available for the current model and fills by rank. Adds compile-time drift guards (satisfies + Exclude check) and unit tests so a changed pi level set fails fast in development.
This commit is contained in:
Federico Jaramillo Martinez
2026-06-14 13:47:44 +02:00
parent 411e61ac75
commit ca30c970a7
15 changed files with 212 additions and 51 deletions
+5 -3
View File
@@ -102,6 +102,8 @@ export function registerSessionRoutes(app: FastifyInstance, sessions: PiSessionS
app.post<{ Params: { sessionId: string }; Body: { cwd?: unknown; level?: unknown } | undefined }>(`${prefix}/sessions/:sessionId/thinking-level`, async (request, reply) => {
try {
const body = optionalRecord(request.body);
// The level string is validated against the session's live available levels
// in the service, so it stays correct if pi changes the set.
return await sessions.setThinkingLevel(sessionLookupFromBody(request.params.sessionId, body), requireThinkingLevel(body["level"]));
} catch (error) {
return reply.code(mutationErrorStatus(error)).send({ error: errorMessage(error) });
@@ -285,9 +287,9 @@ function requireString(record: Record<string, unknown>, field: string): string {
return value;
}
function requireThinkingLevel(value: unknown): "off" | "minimal" | "low" | "medium" | "high" | "xhigh" {
if (value === "off" || value === "minimal" || value === "low" || value === "medium" || value === "high" || value === "xhigh") return value;
throw new Error("level field is invalid");
function requireThinkingLevel(value: unknown): string {
if (typeof value !== "string" || value === "") throw new Error("level field is invalid");
return value;
}
function optionalField<T>(key: string, value: T | undefined): Record<string, T> | object {