mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-15 07:04:45 +00:00
fix(ai, web-ui): browser compatibility for pi-ai, update tsgo for decorator support
- Update @typescript/native-preview to 7.0.0-dev.20260120.1 (supports experimentalDecorators) - Replace top-level node:fs, node:os, node:path imports with dynamic imports in stream.ts - Replace top-level node:os import with dynamic import in openai-codex-responses.ts - Replace top-level node:crypto, node:http imports with dynamic imports in openai-codex.ts - Replace Buffer.from with atob for browser-compatible base64 decoding fixes #873
This commit is contained in:
parent
d327b9c768
commit
b712d1ca43
5 changed files with 95 additions and 47 deletions
64
package-lock.json
generated
64
package-lock.json
generated
|
|
@ -20,7 +20,7 @@
|
|||
"devDependencies": {
|
||||
"@biomejs/biome": "2.3.5",
|
||||
"@types/node": "^22.10.5",
|
||||
"@typescript/native-preview": "7.0.0-dev.20251212.1",
|
||||
"@typescript/native-preview": "7.0.0-dev.20260120.1",
|
||||
"concurrently": "^9.2.1",
|
||||
"husky": "^9.1.7",
|
||||
"tsx": "^4.20.3",
|
||||
|
|
@ -3959,28 +3959,28 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript/native-preview": {
|
||||
"version": "7.0.0-dev.20251212.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview/-/native-preview-7.0.0-dev.20251212.1.tgz",
|
||||
"integrity": "sha512-uNPMu5+ElTN7AZRFJXsTPtSAQ2b7FIXMvpQbU/L0VD5PoBp5nMiQbgO1QFSvbFiIoTTma3I2TX3WSO5olIMTLQ==",
|
||||
"version": "7.0.0-dev.20260120.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview/-/native-preview-7.0.0-dev.20260120.1.tgz",
|
||||
"integrity": "sha512-nnEf37C9ue7OBRnF2zmV/OCBmV5Y7T/K4mCHa+nxgiXcF/1w8sA0cgdFl+gHQ0mysqUJ+Bu5btAMeWgpLyjrgg==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsgo": "bin/tsgo.js"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@typescript/native-preview-darwin-arm64": "7.0.0-dev.20251212.1",
|
||||
"@typescript/native-preview-darwin-x64": "7.0.0-dev.20251212.1",
|
||||
"@typescript/native-preview-linux-arm": "7.0.0-dev.20251212.1",
|
||||
"@typescript/native-preview-linux-arm64": "7.0.0-dev.20251212.1",
|
||||
"@typescript/native-preview-linux-x64": "7.0.0-dev.20251212.1",
|
||||
"@typescript/native-preview-win32-arm64": "7.0.0-dev.20251212.1",
|
||||
"@typescript/native-preview-win32-x64": "7.0.0-dev.20251212.1"
|
||||
"@typescript/native-preview-darwin-arm64": "7.0.0-dev.20260120.1",
|
||||
"@typescript/native-preview-darwin-x64": "7.0.0-dev.20260120.1",
|
||||
"@typescript/native-preview-linux-arm": "7.0.0-dev.20260120.1",
|
||||
"@typescript/native-preview-linux-arm64": "7.0.0-dev.20260120.1",
|
||||
"@typescript/native-preview-linux-x64": "7.0.0-dev.20260120.1",
|
||||
"@typescript/native-preview-win32-arm64": "7.0.0-dev.20260120.1",
|
||||
"@typescript/native-preview-win32-x64": "7.0.0-dev.20260120.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/native-preview-darwin-arm64": {
|
||||
"version": "7.0.0-dev.20251212.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-darwin-arm64/-/native-preview-darwin-arm64-7.0.0-dev.20251212.1.tgz",
|
||||
"integrity": "sha512-5tof0OT01yPQ0mcoKPeSrGMxQ9Dl//gTjSKCMKwbLr5urrIPxX5bNRWUH0hxWaB4A3mXQvDvxSSrWR5TMOl2aQ==",
|
||||
"version": "7.0.0-dev.20260120.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-darwin-arm64/-/native-preview-darwin-arm64-7.0.0-dev.20260120.1.tgz",
|
||||
"integrity": "sha512-r3pWFuR2H7mn6ScwpH5jJljKQqKto0npVuJSk6pRwFwexpTyxOGmJTZJ1V0AWiisaNxU2+CNAqWFJSJYIE/QTg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
|
@ -3992,9 +3992,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@typescript/native-preview-darwin-x64": {
|
||||
"version": "7.0.0-dev.20251212.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-darwin-x64/-/native-preview-darwin-x64-7.0.0-dev.20251212.1.tgz",
|
||||
"integrity": "sha512-zUgcCXmDfO2yo5fNZZ3wUCv8hdqc/Qbc1WZUEDYYo3ItnBUL9qp0lUtTwsLtNreL2WmHOCeTQuKWa/JQzdw89g==",
|
||||
"version": "7.0.0-dev.20260120.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-darwin-x64/-/native-preview-darwin-x64-7.0.0-dev.20260120.1.tgz",
|
||||
"integrity": "sha512-cuC1+wLbUP+Ip2UT94G134fqRdp5w3b3dhcCO6/FQ4yXxvRNyv/WK+upHBUFDaeSOeHgDTyO9/QFYUWwC4If1A==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -4006,9 +4006,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@typescript/native-preview-linux-arm": {
|
||||
"version": "7.0.0-dev.20251212.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm/-/native-preview-linux-arm-7.0.0-dev.20251212.1.tgz",
|
||||
"integrity": "sha512-peQCeG2+XqMqs6/Sg6nbQPI3Kae91Esi5Qh1VyDETO4wjMbKeAzVjw8t3Qz5X6RDbWNrCpDmbk6chjukfGeWgQ==",
|
||||
"version": "7.0.0-dev.20260120.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm/-/native-preview-linux-arm-7.0.0-dev.20260120.1.tgz",
|
||||
"integrity": "sha512-vN6OYVySol/kQZjJGmAzd6L30SyVlCgmCXS8WjUYtE5clN0YrzQHop16RK29fYZHMxpkOniVBtRPxUYQANZBlQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
|
|
@ -4020,9 +4020,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@typescript/native-preview-linux-arm64": {
|
||||
"version": "7.0.0-dev.20251212.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm64/-/native-preview-linux-arm64-7.0.0-dev.20251212.1.tgz",
|
||||
"integrity": "sha512-0P59bGDFLppvkdpqQ8/kG+kU6R0iCdQiSLFRNrbrLnaflACBfIi40D3Ono3EmeSxqKsHqh/pNRu3BUJvoNGphw==",
|
||||
"version": "7.0.0-dev.20260120.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm64/-/native-preview-linux-arm64-7.0.0-dev.20260120.1.tgz",
|
||||
"integrity": "sha512-zZGvEGY7wcHYefMZ87KNmvjN3NLIhsCMHEpHZiGCS3khKf+8z6ZsanrzCjOTodvL01VPyBzHxV1EtkSxAcLiQg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
|
@ -4034,9 +4034,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@typescript/native-preview-linux-x64": {
|
||||
"version": "7.0.0-dev.20251212.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-x64/-/native-preview-linux-x64-7.0.0-dev.20251212.1.tgz",
|
||||
"integrity": "sha512-7QFyqcPe/Sz+IakvzCqh0d5WhQg7A7bKyQil38K7rKSTaPI42LrVwLA6mVtTRfQyS5Sy2XYVinyLNXnWM8ImQQ==",
|
||||
"version": "7.0.0-dev.20260120.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-x64/-/native-preview-linux-x64-7.0.0-dev.20260120.1.tgz",
|
||||
"integrity": "sha512-JBfNhWd/asd5MDeS3VgRvE24pGKBkmvLub6tsux6ypr+Yhy+o0WaAEzVpmlRYZUqss2ai5tvOu4dzPBXzZAtFw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -4048,9 +4048,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@typescript/native-preview-win32-arm64": {
|
||||
"version": "7.0.0-dev.20251212.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-arm64/-/native-preview-win32-arm64-7.0.0-dev.20251212.1.tgz",
|
||||
"integrity": "sha512-Y8mh0dPXAcYYNtSZVZYaNcqAOlxOlbJQopJBVATn+ItCxrY4RqBwygzrBWqg+gUo9xLmFI9XLuDVqm1ZAkAfwg==",
|
||||
"version": "7.0.0-dev.20260120.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-arm64/-/native-preview-win32-arm64-7.0.0-dev.20260120.1.tgz",
|
||||
"integrity": "sha512-tTndRtYCq2xwgE0VkTi9ACNiJaV43+PqvBqCxk8ceYi3X36Ve+CCnwlZfZJ4k9NxZthtrAwF/kUmpC9iIYbq1w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
|
@ -4062,9 +4062,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@typescript/native-preview-win32-x64": {
|
||||
"version": "7.0.0-dev.20251212.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-x64/-/native-preview-win32-x64-7.0.0-dev.20251212.1.tgz",
|
||||
"integrity": "sha512-bUPWJgGhPdsoL3OR+I8nFF81P/+hwfqyMKaAWFxTg1zeRdEl61lVdrEfgNDBI7Px5Gr+uFGELlkCsDzy/7dAyw==",
|
||||
"version": "7.0.0-dev.20260120.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-x64/-/native-preview-win32-x64-7.0.0-dev.20260120.1.tgz",
|
||||
"integrity": "sha512-oZia7hFL6k9pVepfonuPI86Jmyz6WlJKR57tWCDwRNmpA7odxuTq1PbvcYgy1z4+wHF1nnKKJY0PMAiq6ac18w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
"devDependencies": {
|
||||
"@biomejs/biome": "2.3.5",
|
||||
"@types/node": "^22.10.5",
|
||||
"@typescript/native-preview": "7.0.0-dev.20251212.1",
|
||||
"@typescript/native-preview": "7.0.0-dev.20260120.1",
|
||||
"concurrently": "^9.2.1",
|
||||
"husky": "^9.1.7",
|
||||
"tsx": "^4.20.3",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,11 @@
|
|||
import os from "node:os";
|
||||
// NEVER convert to top-level import - breaks browser/Vite builds (web-ui)
|
||||
let _os: typeof import("node:os") | null = null;
|
||||
if (typeof process !== "undefined" && process.versions?.node) {
|
||||
import("node:os").then((m) => {
|
||||
_os = m;
|
||||
});
|
||||
}
|
||||
|
||||
import type {
|
||||
ResponseFunctionToolCall,
|
||||
ResponseOutputMessage,
|
||||
|
|
@ -686,7 +693,7 @@ function extractAccountId(token: string): string {
|
|||
try {
|
||||
const parts = token.split(".");
|
||||
if (parts.length !== 3) throw new Error("Invalid token");
|
||||
const payload = JSON.parse(Buffer.from(parts[1], "base64").toString("utf-8"));
|
||||
const payload = JSON.parse(atob(parts[1]));
|
||||
const accountId = payload?.[JWT_CLAIM_PATH]?.chatgpt_account_id;
|
||||
if (!accountId) throw new Error("No account ID in token");
|
||||
return accountId;
|
||||
|
|
@ -707,7 +714,8 @@ function buildHeaders(
|
|||
headers.set("chatgpt-account-id", accountId);
|
||||
headers.set("OpenAI-Beta", "responses=experimental");
|
||||
headers.set("originator", "pi");
|
||||
headers.set("User-Agent", `pi (${os.platform()} ${os.release()}; ${os.arch()})`);
|
||||
const userAgent = _os ? `pi (${_os.platform()} ${_os.release()}; ${_os.arch()})` : "pi (browser)";
|
||||
headers.set("User-Agent", userAgent);
|
||||
headers.set("accept", "text/event-stream");
|
||||
headers.set("content-type", "application/json");
|
||||
for (const [key, value] of Object.entries(additionalHeaders || {})) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,21 @@
|
|||
import { existsSync } from "node:fs";
|
||||
import { homedir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
// NEVER convert to top-level imports - breaks browser/Vite builds (web-ui)
|
||||
let _existsSync: typeof import("node:fs").existsSync | null = null;
|
||||
let _homedir: typeof import("node:os").homedir | null = null;
|
||||
let _join: typeof import("node:path").join | null = null;
|
||||
|
||||
// Eagerly load in Node.js environment only
|
||||
if (typeof process !== "undefined" && process.versions?.node) {
|
||||
import("node:fs").then((m) => {
|
||||
_existsSync = m.existsSync;
|
||||
});
|
||||
import("node:os").then((m) => {
|
||||
_homedir = m.homedir;
|
||||
});
|
||||
import("node:path").then((m) => {
|
||||
_join = m.join;
|
||||
});
|
||||
}
|
||||
|
||||
import { supportsXhigh } from "./models.js";
|
||||
import { type BedrockOptions, streamBedrock } from "./providers/amazon-bedrock.js";
|
||||
import { type AnthropicOptions, streamAnthropic } from "./providers/anthropic.js";
|
||||
|
|
@ -31,14 +46,20 @@ let cachedVertexAdcCredentialsExists: boolean | null = null;
|
|||
|
||||
function hasVertexAdcCredentials(): boolean {
|
||||
if (cachedVertexAdcCredentialsExists === null) {
|
||||
// In browser or if node modules not loaded yet, return false
|
||||
if (!_existsSync || !_homedir || !_join) {
|
||||
cachedVertexAdcCredentialsExists = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check GOOGLE_APPLICATION_CREDENTIALS env var first (standard way)
|
||||
const gacPath = process.env.GOOGLE_APPLICATION_CREDENTIALS;
|
||||
if (gacPath) {
|
||||
cachedVertexAdcCredentialsExists = existsSync(gacPath);
|
||||
cachedVertexAdcCredentialsExists = _existsSync(gacPath);
|
||||
} else {
|
||||
// Fall back to default ADC path (lazy evaluation)
|
||||
cachedVertexAdcCredentialsExists = existsSync(
|
||||
join(homedir(), ".config", "gcloud", "application_default_credentials.json"),
|
||||
cachedVertexAdcCredentialsExists = _existsSync(
|
||||
_join(_homedir(), ".config", "gcloud", "application_default_credentials.json"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,22 @@
|
|||
/**
|
||||
* OpenAI Codex (ChatGPT OAuth) flow
|
||||
*
|
||||
* NOTE: This module uses Node.js crypto and http for the OAuth callback.
|
||||
* It is only intended for CLI use, not browser environments.
|
||||
*/
|
||||
|
||||
import { randomBytes } from "node:crypto";
|
||||
import http from "node:http";
|
||||
// NEVER convert to top-level imports - breaks browser/Vite builds (web-ui)
|
||||
let _randomBytes: typeof import("node:crypto").randomBytes | null = null;
|
||||
let _http: typeof import("node:http") | null = null;
|
||||
if (typeof process !== "undefined" && process.versions?.node) {
|
||||
import("node:crypto").then((m) => {
|
||||
_randomBytes = m.randomBytes;
|
||||
});
|
||||
import("node:http").then((m) => {
|
||||
_http = m;
|
||||
});
|
||||
}
|
||||
|
||||
import { generatePKCE } from "./pkce.js";
|
||||
import type { OAuthCredentials, OAuthPrompt } from "./types.js";
|
||||
|
||||
|
|
@ -38,7 +51,10 @@ type JwtPayload = {
|
|||
};
|
||||
|
||||
function createState(): string {
|
||||
return randomBytes(16).toString("hex");
|
||||
if (!_randomBytes) {
|
||||
throw new Error("OpenAI Codex OAuth is only available in Node.js environments");
|
||||
}
|
||||
return _randomBytes(16).toString("hex");
|
||||
}
|
||||
|
||||
function parseAuthorizationInput(input: string): { code?: string; state?: string } {
|
||||
|
|
@ -76,7 +92,7 @@ function decodeJwt(token: string): JwtPayload | null {
|
|||
const parts = token.split(".");
|
||||
if (parts.length !== 3) return null;
|
||||
const payload = parts[1] ?? "";
|
||||
const decoded = Buffer.from(payload, "base64").toString("utf-8");
|
||||
const decoded = atob(payload);
|
||||
return JSON.parse(decoded) as JwtPayload;
|
||||
} catch {
|
||||
return null;
|
||||
|
|
@ -194,9 +210,12 @@ type OAuthServerInfo = {
|
|||
};
|
||||
|
||||
function startLocalOAuthServer(state: string): Promise<OAuthServerInfo> {
|
||||
if (!_http) {
|
||||
throw new Error("OpenAI Codex OAuth is only available in Node.js environments");
|
||||
}
|
||||
let lastCode: string | null = null;
|
||||
let cancelled = false;
|
||||
const server = http.createServer((req, res) => {
|
||||
const server = _http.createServer((req, res) => {
|
||||
try {
|
||||
const url = new URL(req.url || "", "http://localhost");
|
||||
if (url.pathname !== "/auth/callback") {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue