mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-07-09 17:28:45 +00:00
parent
ba10b60b51
commit
e2ccdc8509
5 changed files with 55 additions and 10 deletions
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
### Fixed
|
||||
|
||||
- Fixed GitHub Copilot device-code login polling to wait before the first token poll, avoiding incorrect device-code failures for some users after browser authorization ([#6187](https://github.com/earendil-works/pi/issues/6187)).
|
||||
- Fixed OpenAI Codex user-agent construction to synchronously load Node OS metadata, avoiding a startup race that could report `pi (browser)` in Node/Bun.
|
||||
- Fixed Fireworks GLM 5.2 Fast to use the OpenAI-compatible endpoint and `thinkingLevelMap`, aligning it with GLM 5.2 ([#6195](https://github.com/earendil-works/pi/issues/6195)).
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ export type OAuthDeviceCodePollResult<T> = OAuthDeviceCodeIncompletePollResult |
|
|||
export type OAuthDeviceCodePollOptions<T> = {
|
||||
intervalSeconds?: number;
|
||||
expiresInSeconds?: number;
|
||||
waitBeforeFirstPoll?: boolean;
|
||||
poll: () => Promise<OAuthDeviceCodePollResult<T>>;
|
||||
signal?: AbortSignal;
|
||||
};
|
||||
|
|
@ -53,6 +54,13 @@ export async function pollOAuthDeviceCodeFlow<T>(options: OAuthDeviceCodePollOpt
|
|||
);
|
||||
|
||||
let slowDownResponses = 0;
|
||||
if (options.waitBeforeFirstPoll) {
|
||||
const remainingMs = deadline - Date.now();
|
||||
if (remainingMs > 0) {
|
||||
await abortableSleep(Math.min(intervalMs, remainingMs), options.signal, CANCEL_MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
while (Date.now() < deadline) {
|
||||
if (options.signal?.aborted) {
|
||||
throw new Error(CANCEL_MESSAGE);
|
||||
|
|
|
|||
|
|
@ -207,6 +207,7 @@ async function pollForGitHubAccessToken(
|
|||
return pollOAuthDeviceCodeFlow<string>({
|
||||
intervalSeconds: device.interval,
|
||||
expiresInSeconds: device.expires_in,
|
||||
waitBeforeFirstPoll: true,
|
||||
signal,
|
||||
poll: async () => {
|
||||
const raw = await fetchJson(urls.accessTokenUrl, {
|
||||
|
|
|
|||
|
|
@ -239,7 +239,7 @@ describe("GitHub Copilot OAuth device flow", () => {
|
|||
await loginPromise;
|
||||
});
|
||||
|
||||
it("polls immediately and increases the interval after slow_down", async () => {
|
||||
it("waits before polling and increases the interval after slow_down", async () => {
|
||||
vi.useFakeTimers();
|
||||
const startTime = new Date("2026-03-09T00:00:00Z");
|
||||
vi.setSystemTime(startTime);
|
||||
|
|
@ -315,6 +315,12 @@ describe("GitHub Copilot OAuth device flow", () => {
|
|||
});
|
||||
|
||||
await vi.advanceTimersByTimeAsync(0);
|
||||
expect(accessTokenPollTimes).toHaveLength(0);
|
||||
|
||||
await vi.advanceTimersByTimeAsync(4999);
|
||||
expect(accessTokenPollTimes).toHaveLength(0);
|
||||
|
||||
await vi.advanceTimersByTimeAsync(1);
|
||||
expect(accessTokenPollTimes).toHaveLength(1);
|
||||
|
||||
await vi.advanceTimersByTimeAsync(4999);
|
||||
|
|
@ -330,9 +336,9 @@ describe("GitHub Copilot OAuth device flow", () => {
|
|||
await loginPromise;
|
||||
|
||||
expect(accessTokenPollTimes).toEqual([
|
||||
startTime.getTime(),
|
||||
startTime.getTime() + 5000,
|
||||
startTime.getTime() + 15000,
|
||||
startTime.getTime() + 10000,
|
||||
startTime.getTime() + 20000,
|
||||
]);
|
||||
});
|
||||
|
||||
|
|
@ -383,18 +389,24 @@ describe("GitHub Copilot OAuth device flow", () => {
|
|||
/Device flow timed out after one or more slow_down responses/,
|
||||
);
|
||||
|
||||
await vi.advanceTimersByTimeAsync(5000);
|
||||
expect(accessTokenPollTimes).toEqual([startTime.getTime()]);
|
||||
await vi.advanceTimersByTimeAsync(4999);
|
||||
expect(accessTokenPollTimes).toEqual([]);
|
||||
|
||||
await vi.advanceTimersByTimeAsync(5000);
|
||||
expect(accessTokenPollTimes).toEqual([startTime.getTime(), startTime.getTime() + 10000]);
|
||||
await vi.advanceTimersByTimeAsync(1);
|
||||
expect(accessTokenPollTimes).toEqual([startTime.getTime() + 5000]);
|
||||
|
||||
await vi.advanceTimersByTimeAsync(14999);
|
||||
expect(accessTokenPollTimes).toEqual([startTime.getTime(), startTime.getTime() + 10000]);
|
||||
await vi.advanceTimersByTimeAsync(9999);
|
||||
expect(accessTokenPollTimes).toEqual([startTime.getTime() + 5000]);
|
||||
|
||||
await vi.advanceTimersByTimeAsync(1);
|
||||
expect(accessTokenPollTimes).toEqual([startTime.getTime() + 5000, startTime.getTime() + 15000]);
|
||||
|
||||
await vi.advanceTimersByTimeAsync(9999);
|
||||
expect(accessTokenPollTimes).toEqual([startTime.getTime() + 5000, startTime.getTime() + 15000]);
|
||||
|
||||
await vi.advanceTimersByTimeAsync(1);
|
||||
await rejection;
|
||||
|
||||
expect(accessTokenPollTimes).toEqual([startTime.getTime(), startTime.getTime() + 10000]);
|
||||
expect(accessTokenPollTimes).toEqual([startTime.getTime() + 5000, startTime.getTime() + 15000]);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -38,6 +38,29 @@ describe("OAuth device-code polling", () => {
|
|||
]);
|
||||
});
|
||||
|
||||
it("can wait before the first poll", async () => {
|
||||
vi.useFakeTimers();
|
||||
vi.setSystemTime(new Date("2026-03-09T00:00:00Z"));
|
||||
|
||||
const pollTimes: number[] = [];
|
||||
const resultPromise = pollOAuthDeviceCodeFlow({
|
||||
intervalSeconds: 2,
|
||||
expiresInSeconds: 30,
|
||||
waitBeforeFirstPoll: true,
|
||||
poll: async () => {
|
||||
pollTimes.push(Date.now());
|
||||
return { status: "complete" as const, value: "token" };
|
||||
},
|
||||
});
|
||||
|
||||
await vi.advanceTimersByTimeAsync(1999);
|
||||
expect(pollTimes).toEqual([]);
|
||||
|
||||
await vi.advanceTimersByTimeAsync(1);
|
||||
await expect(resultPromise).resolves.toBe("token");
|
||||
expect(pollTimes).toEqual([new Date("2026-03-09T00:00:02Z").getTime()]);
|
||||
});
|
||||
|
||||
it("cancels an in-flight wait", async () => {
|
||||
vi.useFakeTimers();
|
||||
const controller = new AbortController();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue