import type { ExtensionAPI } from "@earendil-works/pi-coding-agent"; import { Type } from "typebox"; /** * The provider-side thinking value extracted from the last outgoing provider * request: a level string ("high", "xhigh", ...) or a token budget number * (budget-based thinking, e.g. older Anthropic models). `undefined` means no * recognizable thinking field was present (e.g. thinking is off, or the * provider has no thinking controls). */ let wireThinking: string | number | undefined; let wireSeen = false; function isRecord(value: unknown): value is Record { return typeof value === "object" && value !== null; } function asLevel(value: unknown): string | undefined { return typeof value === "string" && value.length > 0 ? value : undefined; } function asBudget(value: unknown): number | undefined { return typeof value === "number" && Number.isFinite(value) ? value : undefined; } /** * Extract the thinking-related field from a provider request payload. * Checked in order of specificity; a string level wins over a budget. */ function extractThinking(payload: unknown): string | number | undefined { if (!isRecord(payload)) return undefined; // OpenAI-completions style: top-level reasoning_effort const reasoningEffort = asLevel(payload.reasoning_effort); if (reasoningEffort) return reasoningEffort; // OpenAI-responses / OpenRouter style: reasoning: { effort } if (isRecord(payload.reasoning)) { const effort = asLevel(payload.reasoning.effort); if (effort) return effort; } // Anthropic adaptive thinking: output_config: { effort } if (isRecord(payload.output_config)) { const effort = asLevel(payload.output_config.effort); if (effort) return effort; } // Anthropic budget-based thinking: thinking: { budget_tokens } if (isRecord(payload.thinking)) { const budget = asBudget(payload.thinking.budget_tokens); if (budget !== undefined) return budget; } // Google: generationConfig.thinkingConfig.{ thinkingLevel | thinkingBudget } if (isRecord(payload.generationConfig) && isRecord(payload.generationConfig.thinkingConfig)) { const config = payload.generationConfig.thinkingConfig; const level = asLevel(config.thinkingLevel); if (level) return level; const budget = asBudget(config.thinkingBudget); if (budget !== undefined) return budget; } return undefined; } export default function (pi: ExtensionAPI) { pi.on("before_provider_request", (event) => { wireThinking = extractThinking(event.payload); wireSeen = true; }); pi.registerTool({ name: "whoami", label: "Whoami", description: "Report the current pi runtime identity: active provider, model, thinking level, and project directory. Takes no arguments.", parameters: Type.Object({}), async execute(_toolCallId, _params, _signal, _onUpdate, ctx) { const model = ctx.model; if (!model) { return { content: [{ type: "text", text: "No active model." }], details: { error: "no-active-model" }, isError: true, }; } // Prefer the value actually sent to the provider. Fall back to the // model's thinkingLevelMap when no request was observed yet. const level = ctx.thinkingLevel; let providerThinkingLevel: string | number | null; if (wireSeen) { providerThinkingLevel = wireThinking ?? null; } else if (level) { const mapped = model.thinkingLevelMap?.[level]; providerThinkingLevel = typeof mapped === "string" ? mapped : null; } else { providerThinkingLevel = null; } const result = { provider: model.provider, model: model.id, modelName: model.name, thinkingLevel: level ?? null, providerThinkingLevel, projectDir: ctx.cwd, }; return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], details: result, }; }, }); }