@hienlh/ppm 0.9.21 → 0.9.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## [0.9.
|
|
3
|
+
## [0.9.22] - 2026-04-05
|
|
4
4
|
|
|
5
5
|
### Fixed
|
|
6
|
-
- **SDK internal 401 retry loop stuck**: SDK retries 401 errors
|
|
6
|
+
- **SDK internal 401 retry loop stuck**: SDK retries 401 errors 10x with exponential backoff using same expired token (~2 min stuck at "Thinking..."). Now intercepts `api_retry` on first 401, refreshes token immediately, and if refresh fails (e.g. temporary account with no refresh token), switches to a different account instantly.
|
|
7
|
+
- **Auto-refresh spam for temporary accounts**: Accounts without refresh token triggered auto-refresh every 5 min, failing every time. Now skips them in the auto-refresh loop.
|
|
7
8
|
|
|
8
9
|
## [0.9.20] - 2026-04-05
|
|
9
10
|
|
package/package.json
CHANGED
|
@@ -816,6 +816,32 @@ export class ClaudeAgentSdkProvider implements AIProvider {
|
|
|
816
816
|
} catch (refreshErr) {
|
|
817
817
|
console.error(`[sdk] session=${sessionId} early OAuth refresh failed:`, refreshErr);
|
|
818
818
|
accountSelector.onAuthError(account.id);
|
|
819
|
+
// Refresh failed (e.g. temporary account with no refresh token).
|
|
820
|
+
// Abort the current query immediately and try switching to a different account.
|
|
821
|
+
const nextAcc = accountSelector.next();
|
|
822
|
+
if (nextAcc && nextAcc.id !== account.id) {
|
|
823
|
+
account = nextAcc;
|
|
824
|
+
const label = nextAcc.label ?? nextAcc.email ?? "Unknown";
|
|
825
|
+
console.log(`[sdk] session=${sessionId} refresh failed — switching to ${nextAcc.id} (${label})`);
|
|
826
|
+
yield { type: "account_retry" as const, reason: "Switching account", accountId: nextAcc.id, accountLabel: label };
|
|
827
|
+
const switchEnv = this.buildQueryEnv(meta.projectPath, nextAcc);
|
|
828
|
+
streamCtrl.done();
|
|
829
|
+
q.close();
|
|
830
|
+
const { generator: switchGen, controller: switchCtrl } = createMessageChannel();
|
|
831
|
+
const currentSdkId = getSessionMapping(sessionId);
|
|
832
|
+
const canResume = currentSdkId && currentSdkId !== sessionId;
|
|
833
|
+
if (!canResume) switchCtrl.push(firstMsg);
|
|
834
|
+
const retryOpts = { ...queryOptions, sessionId: undefined, resume: canResume ? currentSdkId : undefined, env: switchEnv };
|
|
835
|
+
const rq = query({
|
|
836
|
+
prompt: switchGen,
|
|
837
|
+
options: { ...retryOpts, ...(permissionHooks && { hooks: permissionHooks }), canUseTool } as any,
|
|
838
|
+
});
|
|
839
|
+
this.streamingSessions.set(sessionId, { meta, query: rq, controller: switchCtrl });
|
|
840
|
+
this.activeQueries.set(sessionId, rq);
|
|
841
|
+
eventSource = rq;
|
|
842
|
+
continue retryLoop;
|
|
843
|
+
}
|
|
844
|
+
// No other account available — let SDK continue and eventually emit error
|
|
819
845
|
}
|
|
820
846
|
}
|
|
821
847
|
|
|
@@ -705,6 +705,9 @@ class AccountService {
|
|
|
705
705
|
if (acc.status === "disabled") continue;
|
|
706
706
|
if (!acc.expiresAt) continue;
|
|
707
707
|
if (acc.expiresAt - nowS > REFRESH_BUFFER_S) continue;
|
|
708
|
+
// Skip temporary accounts (no refresh token) — they can't be refreshed
|
|
709
|
+
const withTokens = this.getWithTokens(acc.id);
|
|
710
|
+
if (!withTokens?.refreshToken) continue;
|
|
708
711
|
console.log(`[accounts] Auto-refreshing token for ${acc.email ?? acc.id}`);
|
|
709
712
|
try {
|
|
710
713
|
await this.refreshAccessToken(acc.id, false);
|