ai-zero-token 1.0.0 → 1.0.2
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.md +235 -58
- package/dist/api.js +0 -1
- package/dist/cli/commands/ask.js +131 -5
- package/dist/cli/commands/clear.js +0 -1
- package/dist/cli/commands/help.js +15 -10
- package/dist/cli/commands/login.js +0 -1
- package/dist/cli/commands/models.js +0 -1
- package/dist/cli/commands/serve.js +42 -4
- package/dist/cli/commands/start.js +10 -0
- package/dist/cli/commands/status.js +1 -1
- package/dist/cli/index.js +4 -1
- package/dist/cli/shared.js +57 -6
- package/dist/cli.js +0 -1
- package/dist/core/context.js +7 -2
- package/dist/core/models/openai-codex-models.js +0 -1
- package/dist/core/providers/http-client.js +97 -9
- package/dist/core/providers/openai-codex/chat.js +217 -24
- package/dist/core/providers/openai-codex/oauth.js +15 -4
- package/dist/core/providers/openai-codex/pkce.js +0 -1
- package/dist/core/services/auth-service.js +89 -16
- package/dist/core/services/chat-service.js +24 -14
- package/dist/core/services/config-service.js +0 -1
- package/dist/core/services/image-service.js +360 -0
- package/dist/core/services/model-service.js +4 -2
- package/dist/core/store/profile-store.js +79 -6
- package/dist/core/store/settings-store.js +1 -2
- package/dist/core/types.js +0 -1
- package/dist/http.js +0 -1
- package/dist/models.js +0 -1
- package/dist/oauth.js +0 -1
- package/dist/pkce.js +0 -1
- package/dist/server/admin-page.js +2615 -0
- package/dist/server/app.js +566 -39
- package/dist/server/index.js +13 -3
- package/dist/store.js +0 -1
- package/package.json +14 -6
- package/dist/api.js.map +0 -1
- package/dist/cli/commands/ask.js.map +0 -1
- package/dist/cli/commands/clear.js.map +0 -1
- package/dist/cli/commands/help.js.map +0 -1
- package/dist/cli/commands/login.js.map +0 -1
- package/dist/cli/commands/models.js.map +0 -1
- package/dist/cli/commands/serve.js.map +0 -1
- package/dist/cli/commands/status.js.map +0 -1
- package/dist/cli/index.js.map +0 -1
- package/dist/cli/shared.js.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/core/context.js.map +0 -1
- package/dist/core/models/openai-codex-models.js.map +0 -1
- package/dist/core/providers/http-client.js.map +0 -1
- package/dist/core/providers/openai-codex/chat.js.map +0 -1
- package/dist/core/providers/openai-codex/oauth.js.map +0 -1
- package/dist/core/providers/openai-codex/pkce.js.map +0 -1
- package/dist/core/services/auth-service.js.map +0 -1
- package/dist/core/services/chat-service.js.map +0 -1
- package/dist/core/services/config-service.js.map +0 -1
- package/dist/core/services/model-service.js.map +0 -1
- package/dist/core/store/profile-store.js.map +0 -1
- package/dist/core/store/settings-store.js.map +0 -1
- package/dist/core/types.js.map +0 -1
- package/dist/http.js.map +0 -1
- package/dist/models.js.map +0 -1
- package/dist/oauth.js.map +0 -1
- package/dist/pkce.js.map +0 -1
- package/dist/server/app.js.map +0 -1
- package/dist/server/index.js.map +0 -1
- package/dist/store.js.map +0 -1
|
@@ -2,17 +2,55 @@
|
|
|
2
2
|
import { createGatewayContext } from "../../core/context.js";
|
|
3
3
|
import { startServer } from "../../server/index.js";
|
|
4
4
|
import { parseServeArgs } from "../shared.js";
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
import { spawn } from "node:child_process";
|
|
6
|
+
function createBrowserUrl(host, port) {
|
|
7
|
+
if (host === "0.0.0.0" || host === "::") {
|
|
8
|
+
return `http://127.0.0.1:${port}`;
|
|
9
|
+
}
|
|
10
|
+
return `http://${host}:${port}`;
|
|
11
|
+
}
|
|
12
|
+
function createListenUrl(host, port) {
|
|
13
|
+
return `http://${host}:${port}`;
|
|
14
|
+
}
|
|
15
|
+
function tryOpenBrowser(url) {
|
|
16
|
+
try {
|
|
17
|
+
if (process.platform === "darwin") {
|
|
18
|
+
const child2 = spawn("open", [url], { stdio: "ignore", detached: true });
|
|
19
|
+
child2.unref();
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
if (process.platform === "win32") {
|
|
23
|
+
const child2 = spawn("cmd", ["/c", "start", "", url], { stdio: "ignore", detached: true });
|
|
24
|
+
child2.unref();
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
const child = spawn("xdg-open", [url], { stdio: "ignore", detached: true });
|
|
28
|
+
child.unref();
|
|
29
|
+
return true;
|
|
30
|
+
} catch {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
async function runServeCommand(args, options) {
|
|
35
|
+
const { host, port, openBrowser } = parseServeArgs(args);
|
|
7
36
|
const ctx = createGatewayContext();
|
|
8
37
|
const status = await ctx.authService.getStatus();
|
|
9
38
|
const server = await startServer({ host, port });
|
|
39
|
+
const adminUrl = createBrowserUrl(server.host, server.port);
|
|
40
|
+
const listenUrl = createListenUrl(server.host, server.port);
|
|
41
|
+
const shouldOpenBrowser = openBrowser ?? options?.openBrowserByDefault ?? false;
|
|
10
42
|
console.log("\u672C\u5730\u7F51\u5173\u5DF2\u542F\u52A8\u3002");
|
|
11
|
-
console.log(`url:
|
|
43
|
+
console.log(`url: ${listenUrl}`);
|
|
44
|
+
console.log(`admin: ${adminUrl}`);
|
|
45
|
+
console.log(`apiBase: ${adminUrl}/v1`);
|
|
46
|
+
console.log(`corsOrigin: ${server.corsOrigin}`);
|
|
12
47
|
console.log(`activeProvider: ${status.activeProvider ?? "none"}`);
|
|
13
48
|
console.log(`defaultModel: ${status.defaultModel}`);
|
|
49
|
+
if (shouldOpenBrowser) {
|
|
50
|
+
const opened = tryOpenBrowser(adminUrl);
|
|
51
|
+
console.log(opened ? "\u5DF2\u5C1D\u8BD5\u6253\u5F00\u7BA1\u7406\u9875\u9762\u3002" : "\u672A\u80FD\u81EA\u52A8\u6253\u5F00\u7BA1\u7406\u9875\u9762\uFF0C\u8BF7\u624B\u52A8\u8BBF\u95EE\u4E0A\u9762\u7684 admin \u5730\u5740\u3002");
|
|
52
|
+
}
|
|
14
53
|
}
|
|
15
54
|
export {
|
|
16
55
|
runServeCommand
|
|
17
56
|
};
|
|
18
|
-
//# sourceMappingURL=serve.js.map
|
|
@@ -15,6 +15,7 @@ async function runStatusCommand() {
|
|
|
15
15
|
console.log("\u5F53\u524D\u767B\u5F55\u72B6\u6001:");
|
|
16
16
|
console.log(`provider: ${status.activeProvider}`);
|
|
17
17
|
console.log(`profileId: ${status.activeProfileId}`);
|
|
18
|
+
console.log(`profileCount: ${status.profileCount}`);
|
|
18
19
|
console.log(`defaultModel: ${status.defaultModel}`);
|
|
19
20
|
console.log(`serverHost: ${status.serverHost}`);
|
|
20
21
|
console.log(`serverPort: ${status.serverPort}`);
|
|
@@ -29,4 +30,3 @@ async function runStatusCommand() {
|
|
|
29
30
|
export {
|
|
30
31
|
runStatusCommand
|
|
31
32
|
};
|
|
32
|
-
//# sourceMappingURL=status.js.map
|
package/dist/cli/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import { printHelp } from "./commands/help.js";
|
|
|
5
5
|
import { runLoginCommand } from "./commands/login.js";
|
|
6
6
|
import { runModelsCommand } from "./commands/models.js";
|
|
7
7
|
import { runServeCommand } from "./commands/serve.js";
|
|
8
|
+
import { runStartCommand } from "./commands/start.js";
|
|
8
9
|
import { runStatusCommand } from "./commands/status.js";
|
|
9
10
|
async function runCli(argv = process.argv.slice(2)) {
|
|
10
11
|
const [command, ...rest] = argv;
|
|
@@ -24,6 +25,9 @@ async function runCli(argv = process.argv.slice(2)) {
|
|
|
24
25
|
case "serve":
|
|
25
26
|
await runServeCommand(rest);
|
|
26
27
|
return;
|
|
28
|
+
case "start":
|
|
29
|
+
await runStartCommand(rest);
|
|
30
|
+
return;
|
|
27
31
|
case "clear":
|
|
28
32
|
await runClearCommand();
|
|
29
33
|
return;
|
|
@@ -40,4 +44,3 @@ async function runCli(argv = process.argv.slice(2)) {
|
|
|
40
44
|
export {
|
|
41
45
|
runCli
|
|
42
46
|
};
|
|
43
|
-
//# sourceMappingURL=index.js.map
|
package/dist/cli/shared.js
CHANGED
|
@@ -7,16 +7,55 @@ function formatExpiry(expires) {
|
|
|
7
7
|
function parseAskArgs(args) {
|
|
8
8
|
const rest = [...args];
|
|
9
9
|
let model;
|
|
10
|
+
let payloadFile;
|
|
11
|
+
let dumpRawFile;
|
|
12
|
+
let writeArtifactsDir;
|
|
13
|
+
let printRaw = false;
|
|
14
|
+
let allowUnknownModel = false;
|
|
10
15
|
for (let index = 0; index < rest.length; index += 1) {
|
|
11
|
-
if (rest[index]
|
|
16
|
+
if (rest[index] === "--model") {
|
|
17
|
+
model = rest[index + 1];
|
|
18
|
+
rest.splice(index, 2);
|
|
19
|
+
index -= 1;
|
|
12
20
|
continue;
|
|
13
21
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
22
|
+
if (rest[index] === "--payload-file") {
|
|
23
|
+
payloadFile = rest[index + 1];
|
|
24
|
+
rest.splice(index, 2);
|
|
25
|
+
index -= 1;
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
if (rest[index] === "--dump-raw") {
|
|
29
|
+
dumpRawFile = rest[index + 1];
|
|
30
|
+
rest.splice(index, 2);
|
|
31
|
+
index -= 1;
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (rest[index] === "--write-artifacts-dir") {
|
|
35
|
+
writeArtifactsDir = rest[index + 1];
|
|
36
|
+
rest.splice(index, 2);
|
|
37
|
+
index -= 1;
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (rest[index] === "--print-raw") {
|
|
41
|
+
printRaw = true;
|
|
42
|
+
rest.splice(index, 1);
|
|
43
|
+
index -= 1;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (rest[index] === "--allow-unknown-model") {
|
|
47
|
+
allowUnknownModel = true;
|
|
48
|
+
rest.splice(index, 1);
|
|
49
|
+
index -= 1;
|
|
50
|
+
}
|
|
17
51
|
}
|
|
18
52
|
return {
|
|
19
53
|
model,
|
|
54
|
+
payloadFile,
|
|
55
|
+
dumpRawFile,
|
|
56
|
+
writeArtifactsDir,
|
|
57
|
+
printRaw,
|
|
58
|
+
allowUnknownModel,
|
|
20
59
|
prompt: rest.join(" ").trim()
|
|
21
60
|
};
|
|
22
61
|
}
|
|
@@ -24,6 +63,7 @@ function parseServeArgs(args) {
|
|
|
24
63
|
const rest = [...args];
|
|
25
64
|
let host;
|
|
26
65
|
let port;
|
|
66
|
+
let openBrowser;
|
|
27
67
|
for (let index = 0; index < rest.length; index += 1) {
|
|
28
68
|
if (rest[index] === "--host") {
|
|
29
69
|
host = rest[index + 1];
|
|
@@ -38,13 +78,24 @@ function parseServeArgs(args) {
|
|
|
38
78
|
}
|
|
39
79
|
rest.splice(index, 2);
|
|
40
80
|
index -= 1;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
if (rest[index] === "--open") {
|
|
84
|
+
openBrowser = true;
|
|
85
|
+
rest.splice(index, 1);
|
|
86
|
+
index -= 1;
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (rest[index] === "--no-open") {
|
|
90
|
+
openBrowser = false;
|
|
91
|
+
rest.splice(index, 1);
|
|
92
|
+
index -= 1;
|
|
41
93
|
}
|
|
42
94
|
}
|
|
43
|
-
return { host, port };
|
|
95
|
+
return { host, port, openBrowser };
|
|
44
96
|
}
|
|
45
97
|
export {
|
|
46
98
|
formatExpiry,
|
|
47
99
|
parseAskArgs,
|
|
48
100
|
parseServeArgs
|
|
49
101
|
};
|
|
50
|
-
//# sourceMappingURL=shared.js.map
|
package/dist/cli.js
CHANGED
package/dist/core/context.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { ConfigService } from "./services/config-service.js";
|
|
3
3
|
import { AuthService } from "./services/auth-service.js";
|
|
4
4
|
import { ChatService } from "./services/chat-service.js";
|
|
5
|
+
import { ImageService } from "./services/image-service.js";
|
|
5
6
|
import { ModelService } from "./services/model-service.js";
|
|
6
7
|
function createGatewayContext() {
|
|
7
8
|
const configService = new ConfigService();
|
|
@@ -11,14 +12,18 @@ function createGatewayContext() {
|
|
|
11
12
|
authService,
|
|
12
13
|
modelService
|
|
13
14
|
});
|
|
15
|
+
const imageService = new ImageService({
|
|
16
|
+
authService,
|
|
17
|
+
configService
|
|
18
|
+
});
|
|
14
19
|
return {
|
|
15
20
|
configService,
|
|
16
21
|
authService,
|
|
17
22
|
modelService,
|
|
18
|
-
chatService
|
|
23
|
+
chatService,
|
|
24
|
+
imageService
|
|
19
25
|
};
|
|
20
26
|
}
|
|
21
27
|
export {
|
|
22
28
|
createGatewayContext
|
|
23
29
|
};
|
|
24
|
-
//# sourceMappingURL=context.js.map
|
|
@@ -1,7 +1,45 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { spawn } from "node:child_process";
|
|
3
3
|
const CURL_STATUS_MARKER = "\n__CURL_STATUS__:";
|
|
4
|
-
|
|
4
|
+
let requestSequence = 0;
|
|
5
|
+
function nextRequestId() {
|
|
6
|
+
requestSequence += 1;
|
|
7
|
+
return `http-${String(requestSequence).padStart(4, "0")}`;
|
|
8
|
+
}
|
|
9
|
+
function roundMs(value) {
|
|
10
|
+
return Math.round(value * 100) / 100;
|
|
11
|
+
}
|
|
12
|
+
function finalizeTiming(startedAt, phases) {
|
|
13
|
+
return {
|
|
14
|
+
phasesMs: Object.fromEntries(
|
|
15
|
+
Object.entries(phases).map(([key, value]) => [key, roundMs(value)])
|
|
16
|
+
),
|
|
17
|
+
totalMs: roundMs(performance.now() - startedAt)
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function logHttpTiming(params) {
|
|
21
|
+
console.info("[http] request timing", {
|
|
22
|
+
requestId: params.requestId,
|
|
23
|
+
method: params.method,
|
|
24
|
+
url: params.url,
|
|
25
|
+
transport: params.transport,
|
|
26
|
+
status: params.status,
|
|
27
|
+
bodyLength: params.bodyLength,
|
|
28
|
+
fallbackFrom: params.fallbackFrom,
|
|
29
|
+
phasesMs: params.timing.phasesMs,
|
|
30
|
+
totalMs: params.timing.totalMs
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
function normalizeHeaders(headers) {
|
|
34
|
+
const normalized = {};
|
|
35
|
+
headers.forEach((value, key) => {
|
|
36
|
+
normalized[key.toLowerCase()] = value;
|
|
37
|
+
});
|
|
38
|
+
return normalized;
|
|
39
|
+
}
|
|
40
|
+
async function runCurlRequest(init, params) {
|
|
41
|
+
const requestId = params?.requestId ?? nextRequestId();
|
|
42
|
+
const startedAt = performance.now();
|
|
5
43
|
const args = [
|
|
6
44
|
"--silent",
|
|
7
45
|
"--show-error",
|
|
@@ -22,6 +60,9 @@ async function runCurlRequest(init) {
|
|
|
22
60
|
env: process.env,
|
|
23
61
|
stdio: ["ignore", "pipe", "pipe"]
|
|
24
62
|
});
|
|
63
|
+
const phases = {
|
|
64
|
+
spawnCurlMs: performance.now() - startedAt
|
|
65
|
+
};
|
|
25
66
|
let stdout = "";
|
|
26
67
|
let stderr = "";
|
|
27
68
|
child.stdout.setEncoding("utf8");
|
|
@@ -36,9 +77,11 @@ async function runCurlRequest(init) {
|
|
|
36
77
|
child.on("error", reject);
|
|
37
78
|
child.on("close", (code) => resolve(code ?? 1));
|
|
38
79
|
});
|
|
80
|
+
phases.waitForCurlMs = performance.now() - startedAt - phases.spawnCurlMs;
|
|
39
81
|
if (exitCode !== 0) {
|
|
40
82
|
throw new Error(stderr.trim() || `curl \u8BF7\u6C42\u5931\u8D25\uFF0C\u9000\u51FA\u7801 ${exitCode}`);
|
|
41
83
|
}
|
|
84
|
+
const parseStartedAt = performance.now();
|
|
42
85
|
const markerIndex = stdout.lastIndexOf(CURL_STATUS_MARKER);
|
|
43
86
|
if (markerIndex === -1) {
|
|
44
87
|
throw new Error("curl \u54CD\u5E94\u7F3A\u5C11\u72B6\u6001\u7801\u6807\u8BB0\u3002");
|
|
@@ -49,36 +92,81 @@ async function runCurlRequest(init) {
|
|
|
49
92
|
if (!Number.isFinite(status)) {
|
|
50
93
|
throw new Error(`\u65E0\u6CD5\u89E3\u6790 curl \u72B6\u6001\u7801: ${statusText}`);
|
|
51
94
|
}
|
|
95
|
+
phases.parseResponseMs = performance.now() - parseStartedAt;
|
|
96
|
+
const timing = finalizeTiming(startedAt, phases);
|
|
97
|
+
logHttpTiming({
|
|
98
|
+
requestId,
|
|
99
|
+
method: init.method,
|
|
100
|
+
url: init.url,
|
|
101
|
+
status,
|
|
102
|
+
transport: "curl",
|
|
103
|
+
timing,
|
|
104
|
+
bodyLength: body.length,
|
|
105
|
+
fallbackFrom: params?.fallbackFrom
|
|
106
|
+
});
|
|
52
107
|
return {
|
|
53
108
|
body,
|
|
54
109
|
status,
|
|
55
|
-
transport: "curl"
|
|
110
|
+
transport: "curl",
|
|
111
|
+
timing,
|
|
112
|
+
requestId,
|
|
113
|
+
headers: {}
|
|
56
114
|
};
|
|
57
115
|
}
|
|
58
116
|
async function requestText(init) {
|
|
117
|
+
const requestId = nextRequestId();
|
|
59
118
|
const useCurlOnly = process.env.OAUTH_DEMO_USE_CURL === "1";
|
|
60
|
-
const timeoutMs = init.timeoutMs
|
|
119
|
+
const timeoutMs = init.timeoutMs;
|
|
120
|
+
const signal = typeof timeoutMs === "number" && Number.isFinite(timeoutMs) && timeoutMs > 0 ? AbortSignal.timeout(timeoutMs) : void 0;
|
|
61
121
|
if (!useCurlOnly) {
|
|
122
|
+
const startedAt = performance.now();
|
|
123
|
+
const phases = {};
|
|
62
124
|
try {
|
|
125
|
+
const fetchStartedAt = performance.now();
|
|
63
126
|
const response = await fetch(init.url, {
|
|
64
127
|
method: init.method,
|
|
65
128
|
headers: init.headers,
|
|
66
129
|
body: init.body,
|
|
67
|
-
signal
|
|
130
|
+
signal
|
|
131
|
+
});
|
|
132
|
+
phases.waitForHeadersMs = performance.now() - fetchStartedAt;
|
|
133
|
+
const readBodyStartedAt = performance.now();
|
|
134
|
+
const body = await response.text();
|
|
135
|
+
phases.readBodyMs = performance.now() - readBodyStartedAt;
|
|
136
|
+
const timing = finalizeTiming(startedAt, phases);
|
|
137
|
+
logHttpTiming({
|
|
138
|
+
requestId,
|
|
139
|
+
method: init.method,
|
|
140
|
+
url: init.url,
|
|
141
|
+
status: response.status,
|
|
142
|
+
transport: "fetch",
|
|
143
|
+
timing,
|
|
144
|
+
bodyLength: body.length
|
|
68
145
|
});
|
|
69
146
|
return {
|
|
70
|
-
body
|
|
147
|
+
body,
|
|
71
148
|
status: response.status,
|
|
72
|
-
transport: "fetch"
|
|
149
|
+
transport: "fetch",
|
|
150
|
+
timing,
|
|
151
|
+
requestId,
|
|
152
|
+
headers: normalizeHeaders(response.headers)
|
|
73
153
|
};
|
|
74
154
|
} catch (error) {
|
|
75
155
|
const message = error instanceof Error ? error.message : String(error);
|
|
76
|
-
console.
|
|
156
|
+
console.warn("[http] fetch attempt failed", {
|
|
157
|
+
requestId,
|
|
158
|
+
method: init.method,
|
|
159
|
+
url: init.url,
|
|
160
|
+
elapsedMs: roundMs(performance.now() - startedAt),
|
|
161
|
+
error: message
|
|
162
|
+
});
|
|
77
163
|
}
|
|
78
164
|
}
|
|
79
|
-
return runCurlRequest(init
|
|
165
|
+
return runCurlRequest(init, {
|
|
166
|
+
requestId,
|
|
167
|
+
fallbackFrom: useCurlOnly ? void 0 : "fetch"
|
|
168
|
+
});
|
|
80
169
|
}
|
|
81
170
|
export {
|
|
82
171
|
requestText
|
|
83
172
|
};
|
|
84
|
-
//# sourceMappingURL=http-client.js.map
|
|
@@ -2,6 +2,101 @@
|
|
|
2
2
|
import { DEFAULT_CODEX_MODEL } from "../../models/openai-codex-models.js";
|
|
3
3
|
import { requestText } from "../http-client.js";
|
|
4
4
|
const CODEX_RESPONSES_URL = "https://chatgpt.com/backend-api/codex/responses";
|
|
5
|
+
const URL_KEY_RE = /(url|uri|href|download|preview|thumbnail|image|asset|file)/i;
|
|
6
|
+
const REFERENCE_KEY_RE = /(image|asset|file|media|blob|artifact|download|preview|thumbnail)/i;
|
|
7
|
+
const REFERENCE_VALUE_RE = /^(file|asset|image|img|media|blob)-[\w-]+$/i;
|
|
8
|
+
function parseOptionalNumber(value) {
|
|
9
|
+
if (typeof value !== "string") {
|
|
10
|
+
return void 0;
|
|
11
|
+
}
|
|
12
|
+
const trimmed = value.trim();
|
|
13
|
+
if (!trimmed) {
|
|
14
|
+
return void 0;
|
|
15
|
+
}
|
|
16
|
+
const parsed = Number(trimmed);
|
|
17
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
18
|
+
}
|
|
19
|
+
function parseOptionalBoolean(value) {
|
|
20
|
+
if (typeof value !== "string") {
|
|
21
|
+
return void 0;
|
|
22
|
+
}
|
|
23
|
+
const trimmed = value.trim().toLowerCase();
|
|
24
|
+
if (trimmed === "true") {
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
if (trimmed === "false") {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
return void 0;
|
|
31
|
+
}
|
|
32
|
+
function parseOptionalText(value) {
|
|
33
|
+
if (typeof value !== "string") {
|
|
34
|
+
return void 0;
|
|
35
|
+
}
|
|
36
|
+
const trimmed = value.trim();
|
|
37
|
+
return trimmed ? trimmed : void 0;
|
|
38
|
+
}
|
|
39
|
+
function extractCodexQuotaSnapshot(headers, requestId) {
|
|
40
|
+
const activeLimit = parseOptionalText(headers["x-codex-active-limit"]);
|
|
41
|
+
const planType = parseOptionalText(headers["x-codex-plan-type"]);
|
|
42
|
+
const primaryUsedPercent = parseOptionalNumber(headers["x-codex-primary-used-percent"]);
|
|
43
|
+
const secondaryUsedPercent = parseOptionalNumber(headers["x-codex-secondary-used-percent"]);
|
|
44
|
+
const primaryWindowMinutes = parseOptionalNumber(headers["x-codex-primary-window-minutes"]);
|
|
45
|
+
const secondaryWindowMinutes = parseOptionalNumber(headers["x-codex-secondary-window-minutes"]);
|
|
46
|
+
const primaryResetAfterSeconds = parseOptionalNumber(headers["x-codex-primary-reset-after-seconds"]);
|
|
47
|
+
const secondaryResetAfterSeconds = parseOptionalNumber(headers["x-codex-secondary-reset-after-seconds"]);
|
|
48
|
+
const primaryResetAt = parseOptionalNumber(headers["x-codex-primary-reset-at"]);
|
|
49
|
+
const secondaryResetAt = parseOptionalNumber(headers["x-codex-secondary-reset-at"]);
|
|
50
|
+
const primaryOverSecondaryLimitPercent = parseOptionalNumber(
|
|
51
|
+
headers["x-codex-primary-over-secondary-limit-percent"]
|
|
52
|
+
);
|
|
53
|
+
const creditsHasCredits = parseOptionalBoolean(headers["x-codex-credits-has-credits"]);
|
|
54
|
+
const creditsUnlimited = parseOptionalBoolean(headers["x-codex-credits-unlimited"]);
|
|
55
|
+
const creditsBalance = parseOptionalText(headers["x-codex-credits-balance"]);
|
|
56
|
+
const promoCampaignId = parseOptionalText(headers["x-codex-promo-campaign-id"]);
|
|
57
|
+
const promoMessage = parseOptionalText(headers["x-codex-promo-message"]);
|
|
58
|
+
const hasQuotaData = [
|
|
59
|
+
activeLimit,
|
|
60
|
+
planType,
|
|
61
|
+
primaryUsedPercent,
|
|
62
|
+
secondaryUsedPercent,
|
|
63
|
+
primaryWindowMinutes,
|
|
64
|
+
secondaryWindowMinutes,
|
|
65
|
+
primaryResetAfterSeconds,
|
|
66
|
+
secondaryResetAfterSeconds,
|
|
67
|
+
primaryResetAt,
|
|
68
|
+
secondaryResetAt,
|
|
69
|
+
primaryOverSecondaryLimitPercent,
|
|
70
|
+
creditsHasCredits,
|
|
71
|
+
creditsUnlimited,
|
|
72
|
+
creditsBalance,
|
|
73
|
+
promoCampaignId,
|
|
74
|
+
promoMessage
|
|
75
|
+
].some((value) => typeof value !== "undefined");
|
|
76
|
+
if (!hasQuotaData) {
|
|
77
|
+
return void 0;
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
capturedAt: Date.now(),
|
|
81
|
+
sourceRequestId: requestId,
|
|
82
|
+
activeLimit,
|
|
83
|
+
planType,
|
|
84
|
+
primaryUsedPercent,
|
|
85
|
+
secondaryUsedPercent,
|
|
86
|
+
primaryWindowMinutes,
|
|
87
|
+
secondaryWindowMinutes,
|
|
88
|
+
primaryResetAfterSeconds,
|
|
89
|
+
secondaryResetAfterSeconds,
|
|
90
|
+
primaryResetAt,
|
|
91
|
+
secondaryResetAt,
|
|
92
|
+
primaryOverSecondaryLimitPercent,
|
|
93
|
+
creditsHasCredits,
|
|
94
|
+
creditsUnlimited,
|
|
95
|
+
creditsBalance,
|
|
96
|
+
promoCampaignId,
|
|
97
|
+
promoMessage
|
|
98
|
+
};
|
|
99
|
+
}
|
|
5
100
|
function extractOutputText(payload) {
|
|
6
101
|
if (!payload || typeof payload !== "object") {
|
|
7
102
|
return "";
|
|
@@ -43,12 +138,92 @@ function parseSseEvents(body) {
|
|
|
43
138
|
}
|
|
44
139
|
return events;
|
|
45
140
|
}
|
|
46
|
-
function
|
|
141
|
+
function pushArtifactCandidate(items, dedupe, candidate) {
|
|
142
|
+
const signature = `${candidate.source}:${candidate.path}:${candidate.key}:${candidate.kind}:${candidate.value}`;
|
|
143
|
+
if (dedupe.has(signature)) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
dedupe.add(signature);
|
|
147
|
+
items.push(candidate);
|
|
148
|
+
}
|
|
149
|
+
function collectArtifactCandidates(value, source, path = [], items = [], dedupe = /* @__PURE__ */ new Set()) {
|
|
150
|
+
if (typeof value === "string") {
|
|
151
|
+
const key = path[path.length - 1] ?? "";
|
|
152
|
+
const joinedPath = path.join(".");
|
|
153
|
+
const trimmed = value.trim();
|
|
154
|
+
if (!trimmed) {
|
|
155
|
+
return items;
|
|
156
|
+
}
|
|
157
|
+
if (/^https?:\/\//i.test(trimmed)) {
|
|
158
|
+
pushArtifactCandidate(items, dedupe, {
|
|
159
|
+
source,
|
|
160
|
+
path: joinedPath,
|
|
161
|
+
key,
|
|
162
|
+
kind: "url",
|
|
163
|
+
value: trimmed
|
|
164
|
+
});
|
|
165
|
+
return items;
|
|
166
|
+
}
|
|
167
|
+
if (REFERENCE_KEY_RE.test(key) || REFERENCE_VALUE_RE.test(trimmed)) {
|
|
168
|
+
pushArtifactCandidate(items, dedupe, {
|
|
169
|
+
source,
|
|
170
|
+
path: joinedPath,
|
|
171
|
+
key,
|
|
172
|
+
kind: "reference",
|
|
173
|
+
value: trimmed
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
return items;
|
|
177
|
+
}
|
|
178
|
+
if (Array.isArray(value)) {
|
|
179
|
+
value.forEach((item, index) => {
|
|
180
|
+
collectArtifactCandidates(item, source, [...path, String(index)], items, dedupe);
|
|
181
|
+
});
|
|
182
|
+
return items;
|
|
183
|
+
}
|
|
184
|
+
if (!value || typeof value !== "object") {
|
|
185
|
+
return items;
|
|
186
|
+
}
|
|
187
|
+
for (const [key, nested] of Object.entries(value)) {
|
|
188
|
+
const nextPath = [...path, key];
|
|
189
|
+
if (typeof nested === "string" && (URL_KEY_RE.test(key) || /^https?:\/\//i.test(nested))) {
|
|
190
|
+
collectArtifactCandidates(nested, source, nextPath, items, dedupe);
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
collectArtifactCandidates(nested, source, nextPath, items, dedupe);
|
|
194
|
+
}
|
|
195
|
+
return items;
|
|
196
|
+
}
|
|
197
|
+
function buildDefaultRequestBody(params) {
|
|
198
|
+
const body = {
|
|
199
|
+
model: params.model ?? DEFAULT_CODEX_MODEL,
|
|
200
|
+
store: false,
|
|
201
|
+
stream: true,
|
|
202
|
+
instructions: params.system ?? "",
|
|
203
|
+
text: { verbosity: "medium" },
|
|
204
|
+
include: ["reasoning.encrypted_content"],
|
|
205
|
+
tool_choice: "auto",
|
|
206
|
+
parallel_tool_calls: true
|
|
207
|
+
};
|
|
208
|
+
if (typeof params.prompt === "string" && params.prompt.trim()) {
|
|
209
|
+
body.input = [
|
|
210
|
+
{
|
|
211
|
+
role: "user",
|
|
212
|
+
content: [{ type: "input_text", text: params.prompt }]
|
|
213
|
+
}
|
|
214
|
+
];
|
|
215
|
+
}
|
|
216
|
+
return body;
|
|
217
|
+
}
|
|
218
|
+
function extractCodexText(body, requestBody) {
|
|
47
219
|
const events = parseSseEvents(body);
|
|
48
220
|
let responsePayload;
|
|
49
221
|
let accumulated = "";
|
|
50
222
|
for (const event of events) {
|
|
51
|
-
if (
|
|
223
|
+
if (typeof event.response !== "undefined") {
|
|
224
|
+
responsePayload = event.response;
|
|
225
|
+
}
|
|
226
|
+
if (event.type === "response.completed" || event.type === "response.done" || event.type === "response.incomplete" || event.type === "response.failed") {
|
|
52
227
|
responsePayload = event.response;
|
|
53
228
|
}
|
|
54
229
|
if (typeof event.delta === "string" && event.delta) {
|
|
@@ -56,12 +231,39 @@ function extractCodexText(body) {
|
|
|
56
231
|
}
|
|
57
232
|
}
|
|
58
233
|
const completedText = extractOutputText(responsePayload);
|
|
234
|
+
const artifacts = [
|
|
235
|
+
...collectArtifactCandidates(responsePayload, "response"),
|
|
236
|
+
...collectArtifactCandidates(events, "event")
|
|
237
|
+
];
|
|
59
238
|
if (completedText) {
|
|
60
|
-
return {
|
|
239
|
+
return {
|
|
240
|
+
text: completedText,
|
|
241
|
+
raw: {
|
|
242
|
+
request: requestBody,
|
|
243
|
+
response: responsePayload ?? null,
|
|
244
|
+
events
|
|
245
|
+
},
|
|
246
|
+
artifacts
|
|
247
|
+
};
|
|
61
248
|
}
|
|
62
|
-
return {
|
|
249
|
+
return {
|
|
250
|
+
text: accumulated.trim(),
|
|
251
|
+
raw: {
|
|
252
|
+
request: requestBody,
|
|
253
|
+
response: responsePayload ?? null,
|
|
254
|
+
events
|
|
255
|
+
},
|
|
256
|
+
artifacts
|
|
257
|
+
};
|
|
63
258
|
}
|
|
64
259
|
async function askOpenAICodex(params) {
|
|
260
|
+
const requestBody = {
|
|
261
|
+
...buildDefaultRequestBody(params),
|
|
262
|
+
...params.bodyOverride ?? {}
|
|
263
|
+
};
|
|
264
|
+
if (typeof requestBody.input === "undefined") {
|
|
265
|
+
throw new Error("Codex \u8BF7\u6C42\u7F3A\u5C11 input\u3002\u8BF7\u63D0\u4F9B prompt \u6216\u5728\u5B9E\u9A8C\u8BF7\u6C42\u4F53\u91CC\u663E\u5F0F\u4F20\u5165 input\u3002");
|
|
266
|
+
}
|
|
65
267
|
const response = await requestText({
|
|
66
268
|
method: "POST",
|
|
67
269
|
url: CODEX_RESPONSES_URL,
|
|
@@ -74,29 +276,20 @@ async function askOpenAICodex(params) {
|
|
|
74
276
|
Originator: "pi",
|
|
75
277
|
"User-Agent": "pi (bun demo)"
|
|
76
278
|
},
|
|
77
|
-
body: JSON.stringify(
|
|
78
|
-
model: params.model ?? DEFAULT_CODEX_MODEL,
|
|
79
|
-
store: false,
|
|
80
|
-
stream: true,
|
|
81
|
-
instructions: params.system ?? "",
|
|
82
|
-
input: [
|
|
83
|
-
{
|
|
84
|
-
role: "user",
|
|
85
|
-
content: [{ type: "input_text", text: params.prompt }]
|
|
86
|
-
}
|
|
87
|
-
],
|
|
88
|
-
text: { verbosity: "medium" },
|
|
89
|
-
include: ["reasoning.encrypted_content"],
|
|
90
|
-
tool_choice: "auto",
|
|
91
|
-
parallel_tool_calls: true
|
|
92
|
-
})
|
|
279
|
+
body: JSON.stringify(requestBody)
|
|
93
280
|
});
|
|
281
|
+
const quota = extractCodexQuotaSnapshot(response.headers, response.requestId);
|
|
94
282
|
if (response.status < 200 || response.status >= 300) {
|
|
95
|
-
|
|
283
|
+
const error = new Error(`\u8C03\u7528 Responses API \u5931\u8D25: HTTP ${response.status} via ${response.transport} ${response.body}`);
|
|
284
|
+
error.quota = quota;
|
|
285
|
+
throw error;
|
|
96
286
|
}
|
|
97
|
-
return
|
|
287
|
+
return {
|
|
288
|
+
...extractCodexText(response.body, requestBody),
|
|
289
|
+
quota
|
|
290
|
+
};
|
|
98
291
|
}
|
|
99
292
|
export {
|
|
100
|
-
askOpenAICodex
|
|
293
|
+
askOpenAICodex,
|
|
294
|
+
extractCodexQuotaSnapshot
|
|
101
295
|
};
|
|
102
|
-
//# sourceMappingURL=chat.js.map
|