copilot-api-plus 1.2.19 → 1.2.21
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/README.en.md +6 -9
- package/README.md +5 -8
- package/dist/{account-manager-BLD3jHgL.js → account-manager-hTatSbhl.js} +28 -6
- package/dist/account-manager-hTatSbhl.js.map +1 -0
- package/dist/error-BZbc7idf.js +2 -0
- package/dist/get-user-BuSGshPt.js +2 -0
- package/dist/main.js +160 -90
- package/dist/main.js.map +1 -1
- package/dist/token-DKdhI9cl.js +3 -0
- package/dist/{token-V-OSvQfl.js → token-DoqfK3CD.js} +2 -2
- package/dist/{token-V-OSvQfl.js.map → token-DoqfK3CD.js.map} +1 -1
- package/package.json +1 -1
- package/dist/account-manager-BLD3jHgL.js.map +0 -1
- package/dist/error-BDOdv5Up.js +0 -2
- package/dist/get-user-BSYESgez.js +0 -2
- package/dist/token-C9gxxgzi.js +0 -3
package/dist/main.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { C as
|
|
3
|
-
import { a as stopCopilotTokenRefresh, i as setupGitHubToken, n as refreshCopilotToken, o as pollAccessToken, r as setupCopilotToken, s as getDeviceCode, t as clearGithubToken } from "./token-
|
|
2
|
+
import { C as state, D as copilotBaseUrl, E as GITHUB_CLIENT_ID, O as copilotHeaders, S as sleep, T as GITHUB_BASE_URL, _ as cacheModels, a as getAccountDispatcher, b as isNullish, c as isProxyActive, d as resetAccountConnections, f as resetConnections, g as forwardError, h as HTTPError, k as standardHeaders, l as notifyStreamEnd, m as ensurePaths, o as initProxyFromEnv, p as PATHS, r as getCopilotUsage, s as isAccountProxied, t as accountManager, u as notifyStreamStart, v as cacheVSCodeVersion, x as rootCause, y as findModel } from "./account-manager-hTatSbhl.js";
|
|
3
|
+
import { a as stopCopilotTokenRefresh, i as setupGitHubToken, n as refreshCopilotToken, o as pollAccessToken, r as setupCopilotToken, s as getDeviceCode, t as clearGithubToken } from "./token-DoqfK3CD.js";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import { defineCommand, runMain } from "citty";
|
|
6
6
|
import consola from "consola";
|
|
@@ -1351,6 +1351,16 @@ accountRoutes.post("/", async (c) => {
|
|
|
1351
1351
|
if (!body.githubToken || !body.label) return c.json({ error: "githubToken and label are required" }, 400);
|
|
1352
1352
|
const account = await accountManager.addAccount(body.githubToken, body.label, body.accountType);
|
|
1353
1353
|
if (body.proxy) {
|
|
1354
|
+
try {
|
|
1355
|
+
const proxyUrl = new URL(body.proxy);
|
|
1356
|
+
if (![
|
|
1357
|
+
"http:",
|
|
1358
|
+
"https:",
|
|
1359
|
+
"socks5:"
|
|
1360
|
+
].includes(proxyUrl.protocol)) return c.json({ error: "proxy must use http://, https://, or socks5:// protocol" }, 400);
|
|
1361
|
+
} catch {
|
|
1362
|
+
return c.json({ error: "proxy must be a valid URL" }, 400);
|
|
1363
|
+
}
|
|
1354
1364
|
account.proxy = body.proxy;
|
|
1355
1365
|
await accountManager.saveAccounts();
|
|
1356
1366
|
}
|
|
@@ -1393,6 +1403,33 @@ accountRoutes.put("/:id/status", async (c) => {
|
|
|
1393
1403
|
return c.json({ error: "Failed to update account status" }, 500);
|
|
1394
1404
|
}
|
|
1395
1405
|
});
|
|
1406
|
+
accountRoutes.put("/:id/proxy", async (c) => {
|
|
1407
|
+
try {
|
|
1408
|
+
const id = c.req.param("id");
|
|
1409
|
+
const body = await c.req.json();
|
|
1410
|
+
const account = accountManager.getAccountById(id);
|
|
1411
|
+
if (!account) return c.json({ error: "Account not found" }, 404);
|
|
1412
|
+
if (body.proxy) {
|
|
1413
|
+
try {
|
|
1414
|
+
const proxyUrl = new URL(body.proxy);
|
|
1415
|
+
if (![
|
|
1416
|
+
"http:",
|
|
1417
|
+
"https:",
|
|
1418
|
+
"socks5:"
|
|
1419
|
+
].includes(proxyUrl.protocol)) return c.json({ error: "proxy must use http://, https://, or socks5:// protocol" }, 400);
|
|
1420
|
+
} catch {
|
|
1421
|
+
return c.json({ error: "proxy must be a valid URL" }, 400);
|
|
1422
|
+
}
|
|
1423
|
+
account.proxy = body.proxy;
|
|
1424
|
+
} else account.proxy = void 0;
|
|
1425
|
+
await accountManager.saveAccounts();
|
|
1426
|
+
return c.json({ account: sanitiseAccount(account) });
|
|
1427
|
+
} catch (error) {
|
|
1428
|
+
consola.warn(`Error updating account proxy: ${rootCause(error)}`);
|
|
1429
|
+
consola.debug("Error updating account proxy:", error);
|
|
1430
|
+
return c.json({ error: "Failed to update account proxy" }, 500);
|
|
1431
|
+
}
|
|
1432
|
+
});
|
|
1396
1433
|
accountRoutes.post("/:id/refresh", async (c) => {
|
|
1397
1434
|
try {
|
|
1398
1435
|
const id = c.req.param("id");
|
|
@@ -1630,15 +1667,6 @@ async function checkRateLimit(state) {
|
|
|
1630
1667
|
* ~120s to start streaming, so we give a generous timeout for headers.
|
|
1631
1668
|
*/
|
|
1632
1669
|
const FETCH_TIMEOUT_MS = 12e4;
|
|
1633
|
-
/**
|
|
1634
|
-
* Retry delays in ms. Empty = no retries.
|
|
1635
|
-
*
|
|
1636
|
-
* IMPORTANT: Retries are DISABLED because each attempt to Copilot consumes
|
|
1637
|
-
* a credit, and the caller (e.g. Claude Code) already retries at the
|
|
1638
|
-
* application level. Our retry + Claude Code's retry created a request
|
|
1639
|
-
* cascade that caused account bans (367 requests in 52 minutes).
|
|
1640
|
-
*/
|
|
1641
|
-
const RETRY_DELAYS = [];
|
|
1642
1670
|
/** Minimum interval (ms) between requests on the same account. */
|
|
1643
1671
|
const MIN_SAME_ACCOUNT_INTERVAL_MS = 1e3;
|
|
1644
1672
|
/** Random jitter range (ms) added when switching between accounts. */
|
|
@@ -1670,37 +1698,28 @@ async function fetchWithTimeout(url, init, { timeoutMs = FETCH_TIMEOUT_MS, accou
|
|
|
1670
1698
|
}
|
|
1671
1699
|
}
|
|
1672
1700
|
/**
|
|
1673
|
-
*
|
|
1701
|
+
* Single-attempt fetch with connection pool reset on network errors.
|
|
1674
1702
|
*
|
|
1675
|
-
*
|
|
1676
|
-
*
|
|
1703
|
+
* Retries are intentionally disabled — each Copilot request consumes a
|
|
1704
|
+
* credit, and the caller (e.g. Claude Code) already retries at the
|
|
1705
|
+
* application level. Our retry + caller retry created a request cascade
|
|
1706
|
+
* that caused account bans (367 requests in 52 minutes).
|
|
1707
|
+
*
|
|
1708
|
+
* On network failure (NOT timeout), the pooled connections are destroyed
|
|
1709
|
+
* so that the caller's next attempt gets a fresh socket instantly.
|
|
1677
1710
|
*/
|
|
1678
1711
|
async function fetchWithRetry(url, buildInit, { accountId, accountProxy } = {}) {
|
|
1679
|
-
|
|
1680
|
-
const maxAttempts = RETRY_DELAYS.length + 1;
|
|
1681
|
-
for (let attempt = 0; attempt < maxAttempts; attempt++) try {
|
|
1682
|
-
const timeout = FETCH_TIMEOUT_MS;
|
|
1712
|
+
try {
|
|
1683
1713
|
return await fetchWithTimeout(url, buildInit(), {
|
|
1684
|
-
timeoutMs:
|
|
1714
|
+
timeoutMs: FETCH_TIMEOUT_MS,
|
|
1685
1715
|
accountId,
|
|
1686
1716
|
accountProxy
|
|
1687
1717
|
});
|
|
1688
1718
|
} catch (error) {
|
|
1689
|
-
|
|
1690
|
-
const msg = error instanceof Error ? error.message : String(error);
|
|
1691
|
-
if (msg.includes("timed out")) {
|
|
1692
|
-
consola.warn(`Request timed out on attempt ${attempt + 1}/${maxAttempts} — not retrying (credit likely consumed):`, msg);
|
|
1693
|
-
break;
|
|
1694
|
-
}
|
|
1695
|
-
if (attempt === 0) if (accountId) resetAccountConnections(accountId);
|
|
1719
|
+
if (!(error instanceof Error ? error.message : String(error)).includes("timed out")) if (accountId) resetAccountConnections(accountId);
|
|
1696
1720
|
else resetConnections();
|
|
1697
|
-
|
|
1698
|
-
const delay = RETRY_DELAYS[attempt];
|
|
1699
|
-
consola.warn(`Network error on attempt ${attempt + 1}/${maxAttempts}, retrying in ${delay}ms:`, error instanceof Error ? error.message : error);
|
|
1700
|
-
await new Promise((r) => setTimeout(r, delay));
|
|
1701
|
-
}
|
|
1721
|
+
throw error;
|
|
1702
1722
|
}
|
|
1703
|
-
throw lastError instanceof Error ? lastError : /* @__PURE__ */ new Error("Network request failed");
|
|
1704
1723
|
}
|
|
1705
1724
|
/**
|
|
1706
1725
|
* Wraps an AsyncGenerator so that `releaseSlot` is called when the generator
|
|
@@ -1809,7 +1828,9 @@ const createChatCompletions = async (payload) => {
|
|
|
1809
1828
|
const result = await dispatchRequest(thinkingPayload);
|
|
1810
1829
|
if (Symbol.asyncIterator in result) {
|
|
1811
1830
|
const accountInfo = result.__accountInfo;
|
|
1812
|
-
|
|
1831
|
+
const wrapped = wrapGeneratorWithRelease(result, releaseSlot, accountInfo);
|
|
1832
|
+
wrapped.__accountInfo = accountInfo;
|
|
1833
|
+
return wrapped;
|
|
1813
1834
|
}
|
|
1814
1835
|
releaseSlot();
|
|
1815
1836
|
return result;
|
|
@@ -1819,14 +1840,14 @@ const createChatCompletions = async (payload) => {
|
|
|
1819
1840
|
if (wasInjected && errMsg.includes("Unrecognized request argument")) {
|
|
1820
1841
|
reasoningUnsupportedModels.add(resolvedModel);
|
|
1821
1842
|
consola.info(`Model "${resolvedModel}" does not support reasoning_effort — disabled for future requests`);
|
|
1822
|
-
return
|
|
1843
|
+
return retryWithModifiedPayload(routedPayload, releaseSlot);
|
|
1823
1844
|
}
|
|
1824
1845
|
if (errMsg.includes("is not supported by model")) {
|
|
1825
1846
|
const currentEffort = thinkingPayload.reasoning_effort;
|
|
1826
1847
|
if (currentEffort && currentEffort !== "medium" && currentEffort !== "low") {
|
|
1827
1848
|
reasoningEffortCap.set(resolvedModel, "medium");
|
|
1828
1849
|
consola.info(`Model "${resolvedModel}" rejected reasoning_effort="${currentEffort}" — downgrading to "medium" for future requests`);
|
|
1829
|
-
return
|
|
1850
|
+
return retryWithModifiedPayload({
|
|
1830
1851
|
...routedPayload,
|
|
1831
1852
|
reasoning_effort: "medium"
|
|
1832
1853
|
}, releaseSlot);
|
|
@@ -1838,33 +1859,18 @@ const createChatCompletions = async (payload) => {
|
|
|
1838
1859
|
}
|
|
1839
1860
|
};
|
|
1840
1861
|
/**
|
|
1841
|
-
* Retry a request
|
|
1862
|
+
* Retry a request after modifying the payload (e.g. stripping or
|
|
1863
|
+
* downgrading reasoning_effort).
|
|
1842
1864
|
* Handles slot release for both streaming and non-streaming responses.
|
|
1843
1865
|
*/
|
|
1844
|
-
async function
|
|
1845
|
-
try {
|
|
1846
|
-
const result = await dispatchRequest(payload);
|
|
1847
|
-
if (Symbol.asyncIterator in result) {
|
|
1848
|
-
const accountInfo = result.__accountInfo;
|
|
1849
|
-
return wrapGeneratorWithRelease(result, releaseSlot, accountInfo);
|
|
1850
|
-
}
|
|
1851
|
-
releaseSlot();
|
|
1852
|
-
return result;
|
|
1853
|
-
} catch (retryError) {
|
|
1854
|
-
releaseSlot();
|
|
1855
|
-
throw retryError;
|
|
1856
|
-
}
|
|
1857
|
-
}
|
|
1858
|
-
/**
|
|
1859
|
-
* Retry a request with a downgraded reasoning_effort after the model
|
|
1860
|
-
* rejected the higher value (e.g. "high" → "medium").
|
|
1861
|
-
*/
|
|
1862
|
-
async function retryWithDowngradedReasoning(payload, releaseSlot) {
|
|
1866
|
+
async function retryWithModifiedPayload(payload, releaseSlot) {
|
|
1863
1867
|
try {
|
|
1864
1868
|
const result = await dispatchRequest(payload);
|
|
1865
1869
|
if (Symbol.asyncIterator in result) {
|
|
1866
1870
|
const accountInfo = result.__accountInfo;
|
|
1867
|
-
|
|
1871
|
+
const wrapped = wrapGeneratorWithRelease(result, releaseSlot, accountInfo);
|
|
1872
|
+
wrapped.__accountInfo = accountInfo;
|
|
1873
|
+
return wrapped;
|
|
1868
1874
|
}
|
|
1869
1875
|
releaseSlot();
|
|
1870
1876
|
return result;
|
|
@@ -1881,7 +1887,7 @@ function dispatchRequest(payload) {
|
|
|
1881
1887
|
}
|
|
1882
1888
|
async function createWithSingleAccount(payload) {
|
|
1883
1889
|
if (!state.copilotToken) throw new Error("Copilot token not found");
|
|
1884
|
-
const enableVision = payload.messages.some((
|
|
1890
|
+
const enableVision = payload.messages.some((msg) => typeof msg.content !== "string" && msg.content?.some((part) => part.type === "image_url"));
|
|
1885
1891
|
const isAgentCall = payload.messages.some((msg) => ["assistant", "tool"].includes(msg.role));
|
|
1886
1892
|
const buildHeaders = () => ({
|
|
1887
1893
|
...copilotHeaders(state, enableVision),
|
|
@@ -1937,7 +1943,7 @@ async function tryRefreshAndRetry(account, payload, tokenSource) {
|
|
|
1937
1943
|
try {
|
|
1938
1944
|
await accountManager.refreshAccountToken(account);
|
|
1939
1945
|
tokenSource.copilotToken = account.copilotToken;
|
|
1940
|
-
const result = await doFetch(payload, tokenSource);
|
|
1946
|
+
const result = await doFetch(payload, tokenSource, account.id);
|
|
1941
1947
|
accountManager.markAccountSuccess(account.id);
|
|
1942
1948
|
return result;
|
|
1943
1949
|
} catch {
|
|
@@ -2040,7 +2046,7 @@ async function createWithMultiAccount(payload) {
|
|
|
2040
2046
|
* construction / retry / error‐surfacing logic in one place.
|
|
2041
2047
|
*/
|
|
2042
2048
|
async function doFetch(payload, source, accountId) {
|
|
2043
|
-
const enableVision = payload.messages.some((
|
|
2049
|
+
const enableVision = payload.messages.some((msg) => typeof msg.content !== "string" && msg.content?.some((part) => part.type === "image_url"));
|
|
2044
2050
|
const isAgentCall = payload.messages.some((msg) => ["assistant", "tool"].includes(msg.role));
|
|
2045
2051
|
const buildHeaders = () => ({
|
|
2046
2052
|
...copilotHeaders(source, enableVision),
|
|
@@ -2835,6 +2841,86 @@ function translateErrorToAnthropicErrorEvent() {
|
|
|
2835
2841
|
}
|
|
2836
2842
|
//#endregion
|
|
2837
2843
|
//#region src/routes/messages/handler.ts
|
|
2844
|
+
/** Heartbeat interval — keeps the downstream connection alive. */
|
|
2845
|
+
const HEARTBEAT_PROXIED_MS = 15e3;
|
|
2846
|
+
const HEARTBEAT_DIRECT_MS = 3e4;
|
|
2847
|
+
/**
|
|
2848
|
+
* Upstream silence timeout — if no SSE data arrives for this long,
|
|
2849
|
+
* treat the upstream as dead and close the stream with an error.
|
|
2850
|
+
*/
|
|
2851
|
+
const UPSTREAM_TIMEOUT_PROXIED_MS = 9e4;
|
|
2852
|
+
const UPSTREAM_TIMEOUT_DIRECT_MS = 3e5;
|
|
2853
|
+
/** Sentinel value returned by the sleep branch of Promise.race. */
|
|
2854
|
+
const HEARTBEAT = Symbol("heartbeat");
|
|
2855
|
+
/** Simple non-cancellable sleep that resolves to a sentinel. */
|
|
2856
|
+
function heartbeatDelay(ms) {
|
|
2857
|
+
return new Promise((resolve) => setTimeout(() => resolve(HEARTBEAT), ms));
|
|
2858
|
+
}
|
|
2859
|
+
/** Send an error event to the downstream client, ignoring write failures. */
|
|
2860
|
+
async function sendErrorEvent(stream) {
|
|
2861
|
+
try {
|
|
2862
|
+
const errorEvent = translateErrorToAnthropicErrorEvent();
|
|
2863
|
+
await stream.writeSSE({
|
|
2864
|
+
event: errorEvent.type,
|
|
2865
|
+
data: JSON.stringify(errorEvent)
|
|
2866
|
+
});
|
|
2867
|
+
} catch {}
|
|
2868
|
+
}
|
|
2869
|
+
/**
|
|
2870
|
+
* Consume the upstream SSE async iterator with heartbeat injection.
|
|
2871
|
+
*
|
|
2872
|
+
* Uses `Promise.race` between the next upstream event and a heartbeat
|
|
2873
|
+
* timer. The same `iter.next()` promise is reused across heartbeat
|
|
2874
|
+
* cycles to prevent data loss.
|
|
2875
|
+
*
|
|
2876
|
+
* No external requests are made — heartbeat pings are written to the
|
|
2877
|
+
* downstream HTTP response only.
|
|
2878
|
+
*/
|
|
2879
|
+
async function consumeStreamWithHeartbeat(response, stream, opts) {
|
|
2880
|
+
const { streamState, heartbeatMs, upstreamTimeoutMs } = opts;
|
|
2881
|
+
const iter = response[Symbol.asyncIterator]();
|
|
2882
|
+
let pendingNext = iter.next();
|
|
2883
|
+
let lastDataAt = Date.now();
|
|
2884
|
+
while (true) {
|
|
2885
|
+
const raceResult = await Promise.race([pendingNext.then((r) => ({
|
|
2886
|
+
kind: "data",
|
|
2887
|
+
result: r
|
|
2888
|
+
})), heartbeatDelay(heartbeatMs)]);
|
|
2889
|
+
if (raceResult === HEARTBEAT) {
|
|
2890
|
+
const silenceMs = Date.now() - lastDataAt;
|
|
2891
|
+
if (silenceMs >= upstreamTimeoutMs) {
|
|
2892
|
+
consola.warn(`Upstream silent for ${Math.round(silenceMs / 1e3)}s (limit ${upstreamTimeoutMs / 1e3}s), closing stream`);
|
|
2893
|
+
resetConnections();
|
|
2894
|
+
await sendErrorEvent(stream);
|
|
2895
|
+
break;
|
|
2896
|
+
}
|
|
2897
|
+
await stream.writeSSE({
|
|
2898
|
+
event: "ping",
|
|
2899
|
+
data: "{\"type\":\"ping\"}"
|
|
2900
|
+
});
|
|
2901
|
+
consola.debug(`SSE heartbeat ping sent (silent ${Math.round(silenceMs / 1e3)}s)`);
|
|
2902
|
+
continue;
|
|
2903
|
+
}
|
|
2904
|
+
const { result: iterResult } = raceResult;
|
|
2905
|
+
if (iterResult.done) break;
|
|
2906
|
+
lastDataAt = Date.now();
|
|
2907
|
+
pendingNext = iter.next();
|
|
2908
|
+
const rawEvent = iterResult.value;
|
|
2909
|
+
if (rawEvent.data === "[DONE]") break;
|
|
2910
|
+
if (!rawEvent.data) continue;
|
|
2911
|
+
let chunk;
|
|
2912
|
+
try {
|
|
2913
|
+
chunk = JSON.parse(rawEvent.data);
|
|
2914
|
+
} catch {
|
|
2915
|
+
consola.debug("Skipping malformed SSE chunk");
|
|
2916
|
+
continue;
|
|
2917
|
+
}
|
|
2918
|
+
for (const event of translateChunkToAnthropicEvents(chunk, streamState)) await stream.writeSSE({
|
|
2919
|
+
event: event.type,
|
|
2920
|
+
data: JSON.stringify(event)
|
|
2921
|
+
});
|
|
2922
|
+
}
|
|
2923
|
+
}
|
|
2838
2924
|
async function handleCompletion(c) {
|
|
2839
2925
|
await checkRateLimit(state);
|
|
2840
2926
|
const anthropicPayload = await c.req.json();
|
|
@@ -2850,10 +2936,12 @@ async function handleCompletion(c) {
|
|
|
2850
2936
|
const openAIPayload = translateToOpenAI(anthropicPayload);
|
|
2851
2937
|
if (state.manualApprove) await awaitApproval();
|
|
2852
2938
|
const response = await createChatCompletions(openAIPayload);
|
|
2853
|
-
if (isNonStreaming(response))
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2939
|
+
if (isNonStreaming(response)) return c.json(translateToAnthropic(response));
|
|
2940
|
+
const accountInfo = response.__accountInfo;
|
|
2941
|
+
const proxied = accountInfo ? isAccountProxied(accountInfo.accountProxy) : isProxyActive();
|
|
2942
|
+
const heartbeatMs = proxied ? HEARTBEAT_PROXIED_MS : HEARTBEAT_DIRECT_MS;
|
|
2943
|
+
const upstreamTimeoutMs = proxied ? UPSTREAM_TIMEOUT_PROXIED_MS : UPSTREAM_TIMEOUT_DIRECT_MS;
|
|
2944
|
+
consola.debug(`SSE stream config: proxied=${proxied}, heartbeat=${heartbeatMs / 1e3}s, timeout=${upstreamTimeoutMs / 1e3}s`);
|
|
2857
2945
|
return streamSSE(c, async (stream) => {
|
|
2858
2946
|
const streamState = {
|
|
2859
2947
|
messageStartSent: false,
|
|
@@ -2864,34 +2952,16 @@ async function handleCompletion(c) {
|
|
|
2864
2952
|
thinkingRequested: Boolean(anthropicPayload.thinking)
|
|
2865
2953
|
};
|
|
2866
2954
|
try {
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
try {
|
|
2873
|
-
chunk = JSON.parse(event.data);
|
|
2874
|
-
} catch {
|
|
2875
|
-
consola.debug("Skipping malformed SSE chunk");
|
|
2876
|
-
continue;
|
|
2877
|
-
}
|
|
2878
|
-
const events = translateChunkToAnthropicEvents(chunk, streamState);
|
|
2879
|
-
for (const event of events) await stream.writeSSE({
|
|
2880
|
-
event: event.type,
|
|
2881
|
-
data: JSON.stringify(event)
|
|
2882
|
-
});
|
|
2883
|
-
}
|
|
2955
|
+
await consumeStreamWithHeartbeat(response, stream, {
|
|
2956
|
+
streamState,
|
|
2957
|
+
heartbeatMs,
|
|
2958
|
+
upstreamTimeoutMs
|
|
2959
|
+
});
|
|
2884
2960
|
} catch (error) {
|
|
2885
2961
|
const message = error.message || String(error);
|
|
2886
2962
|
consola.warn(`SSE stream interrupted: ${message}`);
|
|
2887
2963
|
resetConnections();
|
|
2888
|
-
|
|
2889
|
-
const errorEvent = translateErrorToAnthropicErrorEvent();
|
|
2890
|
-
await stream.writeSSE({
|
|
2891
|
-
event: errorEvent.type,
|
|
2892
|
-
data: JSON.stringify(errorEvent)
|
|
2893
|
-
});
|
|
2894
|
-
} catch {}
|
|
2964
|
+
await sendErrorEvent(stream);
|
|
2895
2965
|
}
|
|
2896
2966
|
});
|
|
2897
2967
|
}
|
|
@@ -3085,7 +3155,7 @@ async function validateGitHubToken(token) {
|
|
|
3085
3155
|
state.githubToken = token;
|
|
3086
3156
|
consola.info("Using provided GitHub token");
|
|
3087
3157
|
try {
|
|
3088
|
-
const { getGitHubUser } = await import("./get-user-
|
|
3158
|
+
const { getGitHubUser } = await import("./get-user-BuSGshPt.js");
|
|
3089
3159
|
const user = await getGitHubUser();
|
|
3090
3160
|
consola.info(`Logged in as ${user.login}`);
|
|
3091
3161
|
} catch (error) {
|
|
@@ -3136,10 +3206,10 @@ async function runServer(options) {
|
|
|
3136
3206
|
try {
|
|
3137
3207
|
await setupCopilotToken();
|
|
3138
3208
|
} catch (error) {
|
|
3139
|
-
const { HTTPError } = await import("./error-
|
|
3209
|
+
const { HTTPError } = await import("./error-BZbc7idf.js");
|
|
3140
3210
|
if (error instanceof HTTPError && error.response.status === 401) {
|
|
3141
3211
|
consola.error("Failed to get Copilot token - GitHub token may be invalid or Copilot access revoked");
|
|
3142
|
-
const { clearGithubToken } = await import("./token-
|
|
3212
|
+
const { clearGithubToken } = await import("./token-DKdhI9cl.js");
|
|
3143
3213
|
await clearGithubToken();
|
|
3144
3214
|
consola.info("Please restart to re-authenticate");
|
|
3145
3215
|
}
|