fix: show auth in /model list
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
- macOS: Connections settings now use a custom sidebar to avoid toolbar toggle issues, with rounded styling and full-width row hit targets.
|
||||
- macOS: drop deprecated `afterMs` from agent wait params to match gateway schema.
|
||||
- Auth: add OpenAI Codex OAuth support and migrate legacy oauth.json into auth.json.
|
||||
- Model: `/model` list shows auth source (masked key or OAuth email) per provider.
|
||||
- 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`.
|
||||
|
||||
@@ -124,6 +124,13 @@ function migrateOAuthStorageToAuthStorage(
|
||||
}
|
||||
}
|
||||
|
||||
export function hydrateAuthStorage(
|
||||
authStorage: ReturnType<typeof discoverAuthStorage>,
|
||||
): void {
|
||||
ensureOAuthStorage();
|
||||
migrateOAuthStorageToAuthStorage(authStorage);
|
||||
}
|
||||
|
||||
function isOAuthProvider(provider: string): provider is OAuthProvider {
|
||||
return (
|
||||
provider === "anthropic" ||
|
||||
|
||||
@@ -578,6 +578,7 @@ describe("directive parsing", () => {
|
||||
expect(text).toContain("anthropic/claude-opus-4-5");
|
||||
expect(text).toContain("openai/gpt-4.1-mini");
|
||||
expect(text).not.toContain("claude-sonnet-4-1");
|
||||
expect(text).toContain("auth:");
|
||||
expect(runEmbeddedPiAgent).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -604,6 +605,7 @@ describe("directive parsing", () => {
|
||||
expect(text).toContain("anthropic/claude-opus-4-5");
|
||||
expect(text).toContain("openai/gpt-4.1-mini");
|
||||
expect(text).not.toContain("claude-sonnet-4-1");
|
||||
expect(text).toContain("auth:");
|
||||
expect(runEmbeddedPiAgent).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
import { getEnvApiKey } from "@mariozechner/pi-ai";
|
||||
import { discoverAuthStorage } from "@mariozechner/pi-coding-agent";
|
||||
import { resolveClawdbotAgentDir } from "../../agents/agent-paths.js";
|
||||
import { lookupContextTokens } from "../../agents/context.js";
|
||||
import {
|
||||
DEFAULT_CONTEXT_TOKENS,
|
||||
DEFAULT_MODEL,
|
||||
DEFAULT_PROVIDER,
|
||||
} from "../../agents/defaults.js";
|
||||
import { hydrateAuthStorage } from "../../agents/model-auth.js";
|
||||
import {
|
||||
buildModelAliasIndex,
|
||||
type ModelAliasIndex,
|
||||
@@ -39,6 +43,40 @@ import {
|
||||
|
||||
const SYSTEM_MARK = "⚙️";
|
||||
|
||||
const maskApiKey = (value: string): string => {
|
||||
const trimmed = value.trim();
|
||||
if (!trimmed) return "missing";
|
||||
if (trimmed.length <= 12) return trimmed;
|
||||
return `${trimmed.slice(0, 6)}...${trimmed.slice(-6)}`;
|
||||
};
|
||||
|
||||
const resolveAuthLabel = async (
|
||||
provider: string,
|
||||
authStorage: ReturnType<typeof discoverAuthStorage>,
|
||||
): Promise<string> => {
|
||||
const stored = authStorage.get(provider);
|
||||
if (stored?.type === "oauth") {
|
||||
const email = stored.email?.trim();
|
||||
return email ? `OAuth ${email}` : "OAuth (unknown)";
|
||||
}
|
||||
if (stored?.type === "api_key") {
|
||||
return maskApiKey(stored.key);
|
||||
}
|
||||
const envKey = getEnvApiKey(provider);
|
||||
if (envKey) return maskApiKey(envKey);
|
||||
if (provider === "anthropic") {
|
||||
const oauthEnv = process.env.ANTHROPIC_OAUTH_TOKEN?.trim();
|
||||
if (oauthEnv) return "OAuth (env)";
|
||||
}
|
||||
try {
|
||||
const key = await authStorage.getApiKey(provider);
|
||||
if (key) return maskApiKey(key);
|
||||
} catch {
|
||||
// ignore missing auth
|
||||
}
|
||||
return "missing";
|
||||
};
|
||||
|
||||
export type InlineDirectives = {
|
||||
cleaned: string;
|
||||
hasThinkDirective: boolean;
|
||||
@@ -202,6 +240,16 @@ export async function handleDirectiveOnly(params: {
|
||||
if (allowedModelCatalog.length === 0) {
|
||||
return { text: "No models available." };
|
||||
}
|
||||
const authStorage = discoverAuthStorage(resolveClawdbotAgentDir());
|
||||
hydrateAuthStorage(authStorage);
|
||||
const authByProvider = new Map<string, string>();
|
||||
for (const entry of allowedModelCatalog) {
|
||||
if (authByProvider.has(entry.provider)) continue;
|
||||
authByProvider.set(
|
||||
entry.provider,
|
||||
await resolveAuthLabel(entry.provider, authStorage),
|
||||
);
|
||||
}
|
||||
const current = `${params.provider}/${params.model}`;
|
||||
const defaultLabel = `${defaultProvider}/${defaultModel}`;
|
||||
const header =
|
||||
@@ -219,9 +267,11 @@ export async function handleDirectiveOnly(params: {
|
||||
aliases && aliases.length > 0
|
||||
? ` (alias: ${aliases.join(", ")})`
|
||||
: "";
|
||||
const suffix =
|
||||
const nameSuffix =
|
||||
entry.name && entry.name !== entry.id ? ` — ${entry.name}` : "";
|
||||
lines.push(`- ${label}${aliasSuffix}${suffix}`);
|
||||
const authLabel = authByProvider.get(entry.provider) ?? "missing";
|
||||
const authSuffix = ` — auth: ${authLabel}`;
|
||||
lines.push(`- ${label}${aliasSuffix}${nameSuffix}${authSuffix}`);
|
||||
}
|
||||
return { text: lines.join("\n") };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user