fix: restore auth fallback ordering

This commit is contained in:
Peter Steinberger
2026-01-06 01:38:09 +00:00
parent 6f541d6304
commit 87f4efda8d
5 changed files with 59 additions and 8 deletions

View File

@@ -12,6 +12,7 @@
### Fixes
- Onboarding: resolve CLI entrypoint when running via `npx` so gateway daemon install works without a build step.
- CLI: auto-migrate legacy config entries on command start (same behavior as gateway startup).
- Auth: prioritize OAuth profiles but fall back to API keys when refresh fails; stored profiles now load without explicit auth order.
- Linux: auto-attempt lingering during onboarding (try without sudo, fallback to sudo) and prompt on install/restart to keep the gateway alive after logout/idle. Thanks @tobiasbischoff for PR #237.
- TUI: migrate key handling to the updated pi-tui Key matcher API.
- Logging: redact sensitive tokens in verbose tool summaries by default (configurable patterns).

View File

@@ -30,12 +30,12 @@ describe("resolveAuthProfileOrder", () => {
},
};
it("returns empty order without explicit config", () => {
it("uses stored profiles when no config exists", () => {
const order = resolveAuthProfileOrder({
store,
provider: "anthropic",
});
expect(order).toEqual([]);
expect(order).toEqual(["anthropic:default", "anthropic:work"]);
});
it("prioritizes preferred profiles", () => {
@@ -80,4 +80,29 @@ describe("resolveAuthProfileOrder", () => {
});
expect(order).toEqual(["anthropic:work", "anthropic:default"]);
});
it("prioritizes oauth profiles when order missing", () => {
const mixedStore: AuthProfileStore = {
version: 1,
profiles: {
"anthropic:default": {
type: "api_key",
provider: "anthropic",
key: "sk-default",
},
"anthropic:oauth": {
type: "oauth",
provider: "anthropic",
access: "access-token",
refresh: "refresh-token",
expires: Date.now() + 60_000,
},
},
};
const order = resolveAuthProfileOrder({
store: mixedStore,
provider: "anthropic",
});
expect(order).toEqual(["anthropic:oauth", "anthropic:default"]);
});
});

View File

@@ -258,10 +258,16 @@ export function resolveAuthProfileOrder(params: {
.map(([profileId]) => profileId)
: [];
const lastGood = store.lastGood?.[provider];
const order =
const baseOrder =
configuredOrder ??
(explicitProfiles.length > 0 ? explicitProfiles : undefined);
if (!order) return [];
(explicitProfiles.length > 0
? explicitProfiles
: listProfilesForProvider(store, provider));
if (baseOrder.length === 0) return [];
const order =
configuredOrder && configuredOrder.length > 0
? baseOrder
: orderProfilesByMode(baseOrder, store);
const filtered = order.filter((profileId) => {
const cred = store.profiles[profileId];
@@ -288,6 +294,20 @@ export function resolveAuthProfileOrder(params: {
return deduped;
}
function orderProfilesByMode(
order: string[],
store: AuthProfileStore,
): string[] {
const scored = order.map((profileId) => {
const type = store.profiles[profileId]?.type;
const score = type === "oauth" ? 0 : type === "api_key" ? 1 : 2;
return { profileId, score };
});
return scored
.sort((a, b) => a.score - b.score)
.map((entry) => entry.profileId);
}
export async function resolveApiKeyForProfile(params: {
cfg?: ClawdbotConfig;
store: AuthProfileStore;

View File

@@ -374,8 +374,11 @@ export async function compactEmbeddedPiSession(params: {
};
}
try {
const apiKey = await getApiKeyForModel(model, authStorage);
authStorage.setRuntimeApiKey(model.provider, apiKey);
const apiKey = await getApiKeyForModel({
model,
cfg: params.config,
});
authStorage.setRuntimeApiKey(model.provider, apiKey.apiKey);
} catch (err) {
return {
ok: false,

View File

@@ -108,7 +108,9 @@ describe("sendMessageDiscord", () => {
it("adds missing permission hints on 50013", async () => {
const { rest, postMock, getMock } = makeRest();
const perms = new PermissionsBitField([PermissionsBitField.Flags.ViewChannel]);
const perms = new PermissionsBitField([
PermissionsBitField.Flags.ViewChannel,
]);
const apiError = Object.assign(new Error("Missing Permissions"), {
code: 50013,
status: 403,