fix: show model auth in status

This commit is contained in:
Peter Steinberger
2026-01-05 15:50:14 +01:00
parent bf6aad1965
commit 7f3f73af1c
3 changed files with 63 additions and 0 deletions

View File

@@ -18,6 +18,7 @@
- Docs: clarify auth storage, migration, and OpenAI Codex OAuth onboarding.
- Sandbox: copy inbound media into sandbox workspaces so agent tools can read attachments.
- Status: show runtime (docker/direct) and move shortcuts to `/help`.
- Status: show model auth source (api-key/oauth).
### Maintenance
- Deps: bump pi-* stack, Slack SDK, discord-api-types, file-type, zod, and Biome.

View File

@@ -1,3 +1,5 @@
import fs from "node:fs";
import type { ClawdbotConfig } from "../../config/config.js";
import {
type SessionEntry,
@@ -10,6 +12,10 @@ import { resolveSendPolicy } from "../../sessions/send-policy.js";
import { normalizeE164 } from "../../utils.js";
import { resolveHeartbeatSeconds } from "../../web/reconnect.js";
import { getWebAuthAgeMs, webAuthExists } from "../../web/session.js";
import { resolveClawdbotAgentDir } from "../../agents/agent-paths.js";
import { resolveOAuthPath } from "../../config/paths.js";
import { getEnvApiKey } from "@mariozechner/pi-ai";
import { discoverAuthStorage } from "@mariozechner/pi-coding-agent";
import {
normalizeGroupActivation,
parseActivationCommand,
@@ -36,6 +42,58 @@ export type CommandContext = {
to?: string;
};
function hasOAuthCredentials(provider: string): boolean {
try {
const oauthPath = resolveOAuthPath();
if (!fs.existsSync(oauthPath)) return false;
const raw = fs.readFileSync(oauthPath, "utf8");
const parsed = JSON.parse(raw) as Record<string, unknown>;
const entry = parsed?.[provider] as
| {
refresh?: string;
refresh_token?: string;
refreshToken?: string;
access?: string;
access_token?: string;
accessToken?: string;
}
| undefined;
if (!entry) return false;
const refresh =
entry.refresh ?? entry.refresh_token ?? entry.refreshToken ?? "";
const access = entry.access ?? entry.access_token ?? entry.accessToken ?? "";
return Boolean(refresh.trim() && access.trim());
} catch {
return false;
}
}
function resolveModelAuthLabel(provider?: string): string | undefined {
const resolved = provider?.trim();
if (!resolved) return undefined;
try {
const authStorage = discoverAuthStorage(resolveClawdbotAgentDir());
const stored = authStorage.get(resolved);
if (stored?.type === "oauth") return "oauth";
if (stored?.type === "api_key") return "api-key";
} catch {
// ignore auth storage errors
}
if (resolved === "anthropic") {
const oauthEnv = process.env.ANTHROPIC_OAUTH_TOKEN;
if (oauthEnv?.trim()) return "oauth";
}
if (hasOAuthCredentials(resolved)) return "oauth";
const envKey = getEnvApiKey(resolved);
if (envKey?.trim()) return "api-key";
return "unknown";
}
export function buildCommandContext(params: {
ctx: MsgContext;
cfg: ClawdbotConfig;
@@ -314,6 +372,7 @@ export async function handleCommands(params: {
resolvedThinkLevel ?? (await resolveDefaultThinkingLevel()),
resolvedVerbose: resolvedVerboseLevel,
resolvedElevated: resolvedElevatedLevel,
modelAuth: resolveModelAuthLabel(provider),
webLinked,
webAuthAgeMs,
heartbeatSeconds,

View File

@@ -35,6 +35,7 @@ type StatusArgs = {
resolvedThink?: ThinkLevel;
resolvedVerbose?: VerboseLevel;
resolvedElevated?: ElevatedLevel;
modelAuth?: string;
now?: number;
webLinked?: boolean;
webAuthAgeMs?: number | null;
@@ -236,6 +237,7 @@ export function buildStatusMessage(args: StatusArgs): string {
const modelLabel = model ? `${provider}/${model}` : "unknown";
const agentLine = `Agent: embedded pi • ${modelLabel}`;
const authLine = args.modelAuth ? `Model auth: ${args.modelAuth}` : undefined;
const workspaceLine = args.workspaceDir
? `Workspace: ${shortenHomePath(args.workspaceDir)}`
@@ -245,6 +247,7 @@ export function buildStatusMessage(args: StatusArgs): string {
"⚙️ Status",
webLine,
agentLine,
authLine,
runtime.line,
workspaceLine,
contextLine,