@nodetool-ai/runtime 0.8.2 → 0.8.4-a13.1
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/dist/.nodetool-build-stamp +1 -1
- package/dist/canvas-codec.d.ts +3 -0
- package/dist/canvas-codec.d.ts.map +1 -0
- package/dist/canvas-codec.js +12 -0
- package/dist/canvas-codec.js.map +1 -0
- package/dist/context-packer.d.ts +1 -1
- package/dist/context-packer.js +1 -1
- package/dist/context.d.ts +3 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +16 -5
- package/dist/context.js.map +1 -1
- package/dist/host-binaries.d.ts.map +1 -1
- package/dist/host-binaries.js +4 -3
- package/dist/host-binaries.js.map +1 -1
- package/dist/http-client-spans.d.ts +9 -0
- package/dist/http-client-spans.d.ts.map +1 -0
- package/dist/http-client-spans.js +88 -0
- package/dist/http-client-spans.js.map +1 -0
- package/dist/image-codec.d.ts +6 -3
- package/dist/image-codec.d.ts.map +1 -1
- package/dist/image-codec.js +17 -17
- package/dist/image-codec.js.map +1 -1
- package/dist/image-model-tasks.d.ts +20 -0
- package/dist/image-model-tasks.d.ts.map +1 -1
- package/dist/image-model-tasks.js +44 -1
- package/dist/image-model-tasks.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/media-ref-bytes.d.ts.map +1 -1
- package/dist/media-ref-bytes.js +31 -6
- package/dist/media-ref-bytes.js.map +1 -1
- package/dist/otlp-json-trace-exporter.d.ts +89 -0
- package/dist/otlp-json-trace-exporter.d.ts.map +1 -0
- package/dist/otlp-json-trace-exporter.js +155 -0
- package/dist/otlp-json-trace-exporter.js.map +1 -0
- package/dist/prompt-asset-refs.d.ts +12 -1
- package/dist/prompt-asset-refs.d.ts.map +1 -1
- package/dist/prompt-asset-refs.js +9 -4
- package/dist/prompt-asset-refs.js.map +1 -1
- package/dist/providers/antigravity-provider.d.ts +113 -0
- package/dist/providers/antigravity-provider.d.ts.map +1 -0
- package/dist/providers/antigravity-provider.js +527 -0
- package/dist/providers/antigravity-provider.js.map +1 -0
- package/dist/providers/api-route-provider.d.ts +22 -0
- package/dist/providers/api-route-provider.d.ts.map +1 -0
- package/dist/providers/api-route-provider.js +56 -0
- package/dist/providers/api-route-provider.js.map +1 -0
- package/dist/providers/azure-openai-provider.d.ts +69 -0
- package/dist/providers/azure-openai-provider.d.ts.map +1 -0
- package/dist/providers/azure-openai-provider.js +233 -0
- package/dist/providers/azure-openai-provider.js.map +1 -0
- package/dist/providers/base-provider.d.ts.map +1 -1
- package/dist/providers/base-provider.js +41 -4
- package/dist/providers/base-provider.js.map +1 -1
- package/dist/providers/bedrock-provider.d.ts +52 -0
- package/dist/providers/bedrock-provider.d.ts.map +1 -0
- package/dist/providers/bedrock-provider.js +648 -0
- package/dist/providers/bedrock-provider.js.map +1 -0
- package/dist/providers/bedrock-transport.d.ts +37 -0
- package/dist/providers/bedrock-transport.d.ts.map +1 -0
- package/dist/providers/bedrock-transport.js +186 -0
- package/dist/providers/bedrock-transport.js.map +1 -0
- package/dist/providers/chatgpt-provider.d.ts +48 -0
- package/dist/providers/chatgpt-provider.d.ts.map +1 -0
- package/dist/providers/chatgpt-provider.js +551 -0
- package/dist/providers/chatgpt-provider.js.map +1 -0
- package/dist/providers/claude-agent-provider.d.ts +29 -51
- package/dist/providers/claude-agent-provider.d.ts.map +1 -1
- package/dist/providers/claude-agent-provider.js +144 -202
- package/dist/providers/claude-agent-provider.js.map +1 -1
- package/dist/providers/claude-cli.d.ts +265 -0
- package/dist/providers/claude-cli.d.ts.map +1 -0
- package/dist/providers/claude-cli.js +488 -0
- package/dist/providers/claude-cli.js.map +1 -0
- package/dist/providers/codex-provider.d.ts +9 -2
- package/dist/providers/codex-provider.d.ts.map +1 -1
- package/dist/providers/codex-provider.js +25 -11
- package/dist/providers/codex-provider.js.map +1 -1
- package/dist/providers/context-window.d.ts.map +1 -1
- package/dist/providers/context-window.js +1 -0
- package/dist/providers/context-window.js.map +1 -1
- package/dist/providers/core-tools.d.ts +4 -1
- package/dist/providers/core-tools.d.ts.map +1 -1
- package/dist/providers/core-tools.js +5 -3
- package/dist/providers/core-tools.js.map +1 -1
- package/dist/providers/cost-calculator.d.ts.map +1 -1
- package/dist/providers/cost-calculator.js +9 -0
- package/dist/providers/cost-calculator.js.map +1 -1
- package/dist/providers/credential-check.d.ts +8 -0
- package/dist/providers/credential-check.d.ts.map +1 -1
- package/dist/providers/credential-check.js +22 -0
- package/dist/providers/credential-check.js.map +1 -1
- package/dist/providers/custom-openai-provider.d.ts.map +1 -1
- package/dist/providers/custom-openai-provider.js +19 -1
- package/dist/providers/custom-openai-provider.js.map +1 -1
- package/dist/providers/dreamina-pending.d.ts +22 -0
- package/dist/providers/dreamina-pending.d.ts.map +1 -0
- package/dist/providers/dreamina-pending.js +86 -0
- package/dist/providers/dreamina-pending.js.map +1 -0
- package/dist/providers/dreamina-provider.d.ts +10 -3
- package/dist/providers/dreamina-provider.d.ts.map +1 -1
- package/dist/providers/dreamina-provider.js +325 -45
- package/dist/providers/dreamina-provider.js.map +1 -1
- package/dist/providers/extension-tab.d.ts +42 -0
- package/dist/providers/extension-tab.d.ts.map +1 -0
- package/dist/providers/extension-tab.js +200 -0
- package/dist/providers/extension-tab.js.map +1 -0
- package/dist/providers/fake-provider.d.ts +3 -1
- package/dist/providers/fake-provider.d.ts.map +1 -1
- package/dist/providers/fake-provider.js +63 -9
- package/dist/providers/fake-provider.js.map +1 -1
- package/dist/providers/fake-schema-answer.d.ts +10 -0
- package/dist/providers/fake-schema-answer.d.ts.map +1 -0
- package/dist/providers/fake-schema-answer.js +64 -0
- package/dist/providers/fake-schema-answer.js.map +1 -0
- package/dist/providers/fal-provider.d.ts.map +1 -1
- package/dist/providers/fal-provider.js +5 -2
- package/dist/providers/fal-provider.js.map +1 -1
- package/dist/providers/gemini-web-provider.d.ts +76 -0
- package/dist/providers/gemini-web-provider.d.ts.map +1 -0
- package/dist/providers/gemini-web-provider.js +827 -0
- package/dist/providers/gemini-web-provider.js.map +1 -0
- package/dist/providers/http-transport.d.ts.map +1 -1
- package/dist/providers/http-transport.js +2 -0
- package/dist/providers/http-transport.js.map +1 -1
- package/dist/providers/huggingface-provider.d.ts.map +1 -1
- package/dist/providers/huggingface-provider.js +17 -1
- package/dist/providers/huggingface-provider.js.map +1 -1
- package/dist/providers/index.d.ts +18 -2
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +66 -15
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/llama-provider.d.ts +8 -0
- package/dist/providers/llama-provider.d.ts.map +1 -1
- package/dist/providers/llama-provider.js +23 -5
- package/dist/providers/llama-provider.js.map +1 -1
- package/dist/providers/lmstudio-provider.js +2 -2
- package/dist/providers/lmstudio-provider.js.map +1 -1
- package/dist/providers/manifest-models.d.ts +2 -12
- package/dist/providers/manifest-models.d.ts.map +1 -1
- package/dist/providers/manifest-models.js +45 -3
- package/dist/providers/manifest-models.js.map +1 -1
- package/dist/providers/meta-provider.d.ts +53 -6
- package/dist/providers/meta-provider.d.ts.map +1 -1
- package/dist/providers/meta-provider.js +289 -6
- package/dist/providers/meta-provider.js.map +1 -1
- package/dist/providers/meta-segmentation.d.ts +27 -0
- package/dist/providers/meta-segmentation.d.ts.map +1 -0
- package/dist/providers/meta-segmentation.js +141 -0
- package/dist/providers/meta-segmentation.js.map +1 -0
- package/dist/providers/meta-transcription.d.ts +31 -0
- package/dist/providers/meta-transcription.d.ts.map +1 -0
- package/dist/providers/meta-transcription.js +187 -0
- package/dist/providers/meta-transcription.js.map +1 -0
- package/dist/providers/node-llama-cpp-provider.d.ts +6 -3
- package/dist/providers/node-llama-cpp-provider.d.ts.map +1 -1
- package/dist/providers/node-llama-cpp-provider.js +77 -62
- package/dist/providers/node-llama-cpp-provider.js.map +1 -1
- package/dist/providers/ollama-provider.d.ts +23 -0
- package/dist/providers/ollama-provider.d.ts.map +1 -1
- package/dist/providers/ollama-provider.js +140 -27
- package/dist/providers/ollama-provider.js.map +1 -1
- package/dist/providers/openai-compat/client.d.ts +10 -1
- package/dist/providers/openai-compat/client.d.ts.map +1 -1
- package/dist/providers/openai-compat/client.js +21 -3
- package/dist/providers/openai-compat/client.js.map +1 -1
- package/dist/providers/openai-compat/index.d.ts +1 -1
- package/dist/providers/openai-compat/index.d.ts.map +1 -1
- package/dist/providers/openai-compat/index.js +1 -1
- package/dist/providers/openai-compat/index.js.map +1 -1
- package/dist/providers/openai-compat/types.d.ts +4 -0
- package/dist/providers/openai-compat/types.d.ts.map +1 -1
- package/dist/providers/openai-compat-provider.d.ts +11 -0
- package/dist/providers/openai-compat-provider.d.ts.map +1 -1
- package/dist/providers/openai-compat-provider.js +47 -2
- package/dist/providers/openai-compat-provider.js.map +1 -1
- package/dist/providers/openai-provider.d.ts +15 -0
- package/dist/providers/openai-provider.d.ts.map +1 -1
- package/dist/providers/openai-provider.js +50 -12
- package/dist/providers/openai-provider.js.map +1 -1
- package/dist/providers/opper-provider.d.ts +31 -0
- package/dist/providers/opper-provider.d.ts.map +1 -0
- package/dist/providers/opper-provider.js +91 -0
- package/dist/providers/opper-provider.js.map +1 -0
- package/dist/providers/provider-request-log.d.ts.map +1 -1
- package/dist/providers/provider-request-log.js +3 -2
- package/dist/providers/provider-request-log.js.map +1 -1
- package/dist/providers/python-provider.d.ts.map +1 -1
- package/dist/providers/python-provider.js +5 -3
- package/dist/providers/python-provider.js.map +1 -1
- package/dist/providers/responses-api.d.ts +12 -2
- package/dist/providers/responses-api.d.ts.map +1 -1
- package/dist/providers/responses-api.js +54 -3
- package/dist/providers/responses-api.js.map +1 -1
- package/dist/providers/safe-url.d.ts.map +1 -1
- package/dist/providers/safe-url.js +8 -0
- package/dist/providers/safe-url.js.map +1 -1
- package/dist/providers/scripted-provider.d.ts.map +1 -1
- package/dist/providers/scripted-provider.js +6 -1
- package/dist/providers/scripted-provider.js.map +1 -1
- package/dist/providers/types.d.ts +16 -0
- package/dist/providers/types.d.ts.map +1 -1
- package/dist/providers/types.js.map +1 -1
- package/dist/providers/vgenv-provider.d.ts +33 -0
- package/dist/providers/vgenv-provider.d.ts.map +1 -0
- package/dist/providers/vgenv-provider.js +261 -0
- package/dist/providers/vgenv-provider.js.map +1 -0
- package/dist/providers/vllm-provider.d.ts +7 -0
- package/dist/providers/vllm-provider.d.ts.map +1 -1
- package/dist/providers/vllm-provider.js +15 -3
- package/dist/providers/vllm-provider.js.map +1 -1
- package/dist/python-bridge-base.d.ts +16 -6
- package/dist/python-bridge-base.d.ts.map +1 -1
- package/dist/python-bridge-base.js +117 -40
- package/dist/python-bridge-base.js.map +1 -1
- package/dist/python-bridge-codec.d.ts +16 -1
- package/dist/python-bridge-codec.d.ts.map +1 -1
- package/dist/python-bridge-codec.js +60 -2
- package/dist/python-bridge-codec.js.map +1 -1
- package/dist/python-bridge-framing.d.ts +10 -1
- package/dist/python-bridge-framing.d.ts.map +1 -1
- package/dist/python-bridge-framing.js +33 -8
- package/dist/python-bridge-framing.js.map +1 -1
- package/dist/python-bridge-types.d.ts +26 -5
- package/dist/python-bridge-types.d.ts.map +1 -1
- package/dist/python-bridge-types.js.map +1 -1
- package/dist/python-graph-resolver.d.ts.map +1 -1
- package/dist/python-graph-resolver.js +12 -2
- package/dist/python-graph-resolver.js.map +1 -1
- package/dist/python-node-executor.d.ts +14 -3
- package/dist/python-node-executor.d.ts.map +1 -1
- package/dist/python-node-executor.js +185 -3
- package/dist/python-node-executor.js.map +1 -1
- package/dist/python-stdio-bridge.d.ts +6 -0
- package/dist/python-stdio-bridge.d.ts.map +1 -1
- package/dist/python-stdio-bridge.js +58 -12
- package/dist/python-stdio-bridge.js.map +1 -1
- package/dist/run-trace-context.d.ts +2 -27
- package/dist/run-trace-context.d.ts.map +1 -1
- package/dist/run-trace-context.js +4 -51
- package/dist/run-trace-context.js.map +1 -1
- package/dist/run-trace-processor.d.ts +3 -0
- package/dist/run-trace-processor.d.ts.map +1 -1
- package/dist/run-trace-processor.js +63 -46
- package/dist/run-trace-processor.js.map +1 -1
- package/dist/run-trace-scope.d.ts +28 -0
- package/dist/run-trace-scope.d.ts.map +1 -0
- package/dist/run-trace-scope.js +51 -0
- package/dist/run-trace-scope.js.map +1 -0
- package/dist/run-trace-serialization.d.ts.map +1 -1
- package/dist/run-trace-serialization.js +4 -3
- package/dist/run-trace-serialization.js.map +1 -1
- package/dist/span-record.d.ts +4 -0
- package/dist/span-record.d.ts.map +1 -0
- package/dist/span-record.js +48 -0
- package/dist/span-record.js.map +1 -0
- package/dist/swappable-python-bridge.d.ts +6 -6
- package/dist/swappable-python-bridge.d.ts.map +1 -1
- package/dist/swappable-python-bridge.js +10 -10
- package/dist/swappable-python-bridge.js.map +1 -1
- package/dist/telemetry.d.ts +2 -2
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +33 -34
- package/dist/telemetry.js.map +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +55 -3
- package/dist/testing.js.map +1 -1
- package/dist/token-counter.d.ts +4 -13
- package/dist/token-counter.d.ts.map +1 -1
- package/dist/token-counter.js +68 -18
- package/dist/token-counter.js.map +1 -1
- package/dist/trace-context-manager.d.ts +12 -0
- package/dist/trace-context-manager.d.ts.map +1 -0
- package/dist/trace-context-manager.js +30 -0
- package/dist/trace-context-manager.js.map +1 -0
- package/dist/trace-exporters.d.ts +2 -3
- package/dist/trace-exporters.d.ts.map +1 -1
- package/dist/trace-exporters.js +5 -52
- package/dist/trace-exporters.js.map +1 -1
- package/dist/trace-semantic-conventions.d.ts +2 -0
- package/dist/trace-semantic-conventions.d.ts.map +1 -0
- package/dist/trace-semantic-conventions.js +2 -0
- package/dist/trace-semantic-conventions.js.map +1 -0
- package/dist/traced-storage.d.ts +17 -0
- package/dist/traced-storage.d.ts.map +1 -0
- package/dist/traced-storage.js +41 -0
- package/dist/traced-storage.js.map +1 -0
- package/dist/tracing-module.d.ts +3 -0
- package/dist/tracing-module.d.ts.map +1 -0
- package/dist/tracing-module.js +12 -0
- package/dist/tracing-module.js.map +1 -0
- package/package.json +37 -18
|
@@ -0,0 +1,551 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ChatGPT through the user's own logged-in chatgpt.com tab, driven by the
|
|
3
|
+
* NodeTool Chrome extension. No API key: requests run on the user's ChatGPT
|
|
4
|
+
* subscription.
|
|
5
|
+
*
|
|
6
|
+
* A turn is submitted through the page's own composer, so the site computes
|
|
7
|
+
* its anti-abuse tokens itself. The reply is read back from the conversation
|
|
8
|
+
* API (`/backend-api/conversation/<id>`), which needs only the session's
|
|
9
|
+
* bearer token.
|
|
10
|
+
*
|
|
11
|
+
* Every turn runs in a normal ChatGPT thread, so it shows in the user's
|
|
12
|
+
* history. A chat records the thread as its provider session and the next turn
|
|
13
|
+
* continues it, sending only the new messages. Temporary chats would keep the
|
|
14
|
+
* history clean, but ChatGPT can neither reopen them nor generate images in
|
|
15
|
+
* them.
|
|
16
|
+
*
|
|
17
|
+
* One tab serves every call, so calls run one at a time.
|
|
18
|
+
*/
|
|
19
|
+
import { createHash } from "node:crypto";
|
|
20
|
+
import { createLogger } from "@nodetool-ai/config";
|
|
21
|
+
import { PROVIDER_IDS } from "@nodetool-ai/protocol";
|
|
22
|
+
import { fetchExternalMedia } from "../external-media-fetch.js";
|
|
23
|
+
import { BaseProvider } from "./base-provider.js";
|
|
24
|
+
import { createExtensionTab, pollTab, stageBytesInTab } from "./extension-tab.js";
|
|
25
|
+
import { detectImageMime } from "./image-mime.js";
|
|
26
|
+
const log = createLogger("nodetool.runtime.providers.chatgpt");
|
|
27
|
+
const HOST = "chatgpt.com";
|
|
28
|
+
const BASE_URL = `https://${HOST}`;
|
|
29
|
+
/** The model id that leaves the choice to ChatGPT. */
|
|
30
|
+
export const CHATGPT_AUTO_MODEL = "auto";
|
|
31
|
+
/** The one image model: ChatGPT's own image tool, run by the default chat model. */
|
|
32
|
+
export const CHATGPT_IMAGE_MODEL = "chatgpt-image";
|
|
33
|
+
const COMPOSER = 'form .ProseMirror[contenteditable="true"]';
|
|
34
|
+
const SUBMIT = 'form button[type="submit"]';
|
|
35
|
+
const POLL_INTERVAL_MS = 1_500;
|
|
36
|
+
const READY_TIMEOUT_MS = 20_000;
|
|
37
|
+
const CONVERSATION_ID_TIMEOUT_MS = 30_000;
|
|
38
|
+
const CHAT_TIMEOUT_MS = 10 * 60_000;
|
|
39
|
+
const IMAGE_TIMEOUT_MS = 10 * 60_000;
|
|
40
|
+
/** The send script waits in the page for uploads to finish before it clicks. */
|
|
41
|
+
const SEND_TIMEOUT_MS = 85_000;
|
|
42
|
+
/** How long after a send click the composer has to empty before the click is repeated. */
|
|
43
|
+
const SEND_ACCEPT_TIMEOUT_MS = 3_000;
|
|
44
|
+
/** Files set before the page is ready show no preview. Set them again after this wait. */
|
|
45
|
+
const ATTACH_TIMEOUT_MS = 5_000;
|
|
46
|
+
const ATTACH_ATTEMPTS = 4;
|
|
47
|
+
const DOWNLOAD_TIMEOUT_MS = 120_000;
|
|
48
|
+
const MAX_POLL_FAILURES = 5;
|
|
49
|
+
const MODELS_TTL_MS = 10 * 60_000;
|
|
50
|
+
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
51
|
+
let tab = null;
|
|
52
|
+
/** Replace the tab. Tests use this to avoid a real browser. */
|
|
53
|
+
export function setChatGPTTab(next) {
|
|
54
|
+
tab = next;
|
|
55
|
+
liveModels = null;
|
|
56
|
+
}
|
|
57
|
+
function currentTab() {
|
|
58
|
+
return (tab ??= createExtensionTab(HOST));
|
|
59
|
+
}
|
|
60
|
+
/** Calls share one tab, so each waits for the previous one. */
|
|
61
|
+
let activeSignal;
|
|
62
|
+
let queue = Promise.resolve();
|
|
63
|
+
function serialized(run) {
|
|
64
|
+
const owned = async () => {
|
|
65
|
+
try {
|
|
66
|
+
return await run();
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
activeSignal = undefined;
|
|
70
|
+
await tab?.release?.();
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
const next = queue.then(owned, owned);
|
|
74
|
+
queue = next.catch(() => undefined);
|
|
75
|
+
return next;
|
|
76
|
+
}
|
|
77
|
+
/** Models read from the page during an earlier call, so listing never attaches. */
|
|
78
|
+
let liveModels = null;
|
|
79
|
+
/** The page fetches the session's bearer token first; every API script starts with this. */
|
|
80
|
+
const AUTH = `const __s = await (await fetch("/api/auth/session", { credentials: "include" })).json();
|
|
81
|
+
if (!__s || !__s.accessToken) throw new Error("NT_NOT_SIGNED_IN");
|
|
82
|
+
const __auth = { authorization: "Bearer " + __s.accessToken };`;
|
|
83
|
+
function signedOut(error) {
|
|
84
|
+
return error instanceof Error && error.message.includes("NT_NOT_SIGNED_IN");
|
|
85
|
+
}
|
|
86
|
+
function signInError() {
|
|
87
|
+
return new Error("ChatGPT is not signed in. Open https://chatgpt.com in Chrome, sign in, and try again");
|
|
88
|
+
}
|
|
89
|
+
function sleep(ms, signal) {
|
|
90
|
+
return new Promise((resolve, reject) => {
|
|
91
|
+
if (signal?.aborted)
|
|
92
|
+
return reject(signal.reason ?? new Error("Aborted"));
|
|
93
|
+
const timer = setTimeout(() => { signal?.removeEventListener("abort", onAbort); resolve(); }, ms);
|
|
94
|
+
const onAbort = () => { clearTimeout(timer); reject(signal?.reason ?? new Error("Aborted")); };
|
|
95
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
async function evaluate(expression, timeoutMs) {
|
|
99
|
+
activeSignal?.throwIfAborted();
|
|
100
|
+
try {
|
|
101
|
+
return (await currentTab().evaluate(expression, timeoutMs, activeSignal));
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
if (signedOut(error))
|
|
105
|
+
throw signInError();
|
|
106
|
+
throw error;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/** {@link pollTab} on the ChatGPT tab, with the sign-in check of {@link evaluate}. */
|
|
110
|
+
async function poll(expression, timeoutMs) {
|
|
111
|
+
try {
|
|
112
|
+
return await pollTab(currentTab(), expression, timeoutMs, activeSignal);
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
if (signedOut(error))
|
|
116
|
+
throw signInError();
|
|
117
|
+
throw error;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
async function waitForComposer() {
|
|
121
|
+
const deadline = Date.now() + READY_TIMEOUT_MS;
|
|
122
|
+
while (Date.now() < deadline) {
|
|
123
|
+
if (await evaluate(`/*nt:ready*/ !!document.querySelector(${JSON.stringify(COMPOSER)})`))
|
|
124
|
+
return;
|
|
125
|
+
await sleep(250, activeSignal);
|
|
126
|
+
}
|
|
127
|
+
// A signed-out page has no composer, so tell that apart from a layout change.
|
|
128
|
+
await evaluate(`/*nt:session*/ (async () => { ${AUTH} return true; })()`);
|
|
129
|
+
throw new Error("The ChatGPT composer did not appear. The chatgpt.com page layout may have changed");
|
|
130
|
+
}
|
|
131
|
+
/** Read the conversation's current branch, root first, compacted in the page. */
|
|
132
|
+
async function readConversation(conversationId) {
|
|
133
|
+
return evaluate(`/*nt:conversation*/ (async () => {
|
|
134
|
+
${AUTH}
|
|
135
|
+
const response = await fetch("/backend-api/conversation/" + ${JSON.stringify(conversationId)}, { headers: __auth });
|
|
136
|
+
if (!response.ok) throw new Error("ChatGPT conversation request failed: HTTP " + response.status);
|
|
137
|
+
const data = await response.json();
|
|
138
|
+
const path = [];
|
|
139
|
+
let node = data.mapping && data.mapping[data.current_node];
|
|
140
|
+
while (node) {
|
|
141
|
+
const m = node.message;
|
|
142
|
+
if (m) {
|
|
143
|
+
const parts = (m.content && m.content.parts) || [];
|
|
144
|
+
path.unshift({
|
|
145
|
+
id: node.id,
|
|
146
|
+
role: m.author.role,
|
|
147
|
+
contentType: m.content.content_type,
|
|
148
|
+
status: m.status ?? null,
|
|
149
|
+
endTurn: m.end_turn ?? null,
|
|
150
|
+
text: parts.filter((p) => typeof p === "string").join(""),
|
|
151
|
+
images: parts.filter((p) => p && p.content_type === "image_asset_pointer").map((p) => p.asset_pointer)
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
node = data.mapping[node.parent];
|
|
155
|
+
}
|
|
156
|
+
return { currentNode: data.current_node ?? null, path };
|
|
157
|
+
})()`);
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Put images into the composer's file input, the way a file picker would. The
|
|
161
|
+
* page drops files that arrive before it is ready, so set them again until
|
|
162
|
+
* the previews show.
|
|
163
|
+
*/
|
|
164
|
+
async function attachImages(images) {
|
|
165
|
+
if (images.length === 0)
|
|
166
|
+
return;
|
|
167
|
+
const files = [];
|
|
168
|
+
for (const [index, image] of images.entries()) {
|
|
169
|
+
const type = detectImageMime(image);
|
|
170
|
+
const id = await stageBytesInTab(currentTab(), image, activeSignal);
|
|
171
|
+
files.push({ id, name: `image-${index + 1}.${type.split("/")[1] ?? "png"}`, type });
|
|
172
|
+
}
|
|
173
|
+
const pick = `/*nt:attach*/ (() => {
|
|
174
|
+
const files = ${JSON.stringify(files)};
|
|
175
|
+
const inputs = [...document.querySelectorAll('input[type="file"]')];
|
|
176
|
+
const input = inputs.find((i) => i.multiple && (i.accept === "" || i.accept.includes("image/"))) || inputs[0];
|
|
177
|
+
if (!input) throw new Error("The ChatGPT composer has no file input");
|
|
178
|
+
const transfer = new DataTransfer();
|
|
179
|
+
for (const f of files) {
|
|
180
|
+
const binary = atob(window.__ntStage[f.id]);
|
|
181
|
+
transfer.items.add(new File([Uint8Array.from(binary, (c) => c.charCodeAt(0))], f.name, { type: f.type }));
|
|
182
|
+
}
|
|
183
|
+
input.files = transfer.files;
|
|
184
|
+
input.dispatchEvent(new Event("change", { bubbles: true }));
|
|
185
|
+
return true;
|
|
186
|
+
})()`;
|
|
187
|
+
let attached = false;
|
|
188
|
+
for (let attempt = 1; !attached && attempt <= ATTACH_ATTEMPTS; attempt++) {
|
|
189
|
+
await evaluate(pick);
|
|
190
|
+
attached = !!(await poll(`/*nt:attached*/ document.querySelectorAll("form img").length >= ${files.length}`, ATTACH_TIMEOUT_MS));
|
|
191
|
+
}
|
|
192
|
+
await evaluate(`/*nt:unstage*/ (() => { for (const id of ${JSON.stringify(files.map((f) => f.id))}) delete window.__ntStage[id]; return true; })()`);
|
|
193
|
+
if (!attached)
|
|
194
|
+
throw new Error("ChatGPT did not take the images: no attachment preview appeared");
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Type the text and click send. An attachment's preview appears before its
|
|
198
|
+
* upload finishes, and a click during the upload is ignored while the button
|
|
199
|
+
* still looks enabled. So the provider clicks, checks that the composer
|
|
200
|
+
* emptied, and clicks again until the page takes the message. Every wait polls
|
|
201
|
+
* from here: Chrome throttles the timers of a page hidden for a while to one
|
|
202
|
+
* wake-up a minute, so a wait inside the page could take minutes per step.
|
|
203
|
+
*/
|
|
204
|
+
async function submit(text, attachments) {
|
|
205
|
+
await evaluate(`/*nt:send*/ (() => {
|
|
206
|
+
const composer = document.querySelector(${JSON.stringify(COMPOSER)});
|
|
207
|
+
composer.focus();
|
|
208
|
+
document.execCommand("insertText", false, ${JSON.stringify(text)});
|
|
209
|
+
return true;
|
|
210
|
+
})()`);
|
|
211
|
+
const deadline = Date.now() + SEND_TIMEOUT_MS;
|
|
212
|
+
while (Date.now() < deadline) {
|
|
213
|
+
const ready = await poll(`/*nt:sendready*/ (() => {
|
|
214
|
+
const button = document.querySelector(${JSON.stringify(SUBMIT)});
|
|
215
|
+
return !!button && !button.disabled && document.querySelectorAll("form img").length >= ${attachments};
|
|
216
|
+
})()`, Math.max(0, deadline - Date.now()));
|
|
217
|
+
if (!ready)
|
|
218
|
+
break;
|
|
219
|
+
await evaluate(`/*nt:click*/ (() => { document.querySelector(${JSON.stringify(SUBMIT)}).click(); return true; })()`);
|
|
220
|
+
const accepted = await poll(`/*nt:accepted*/ (() => {
|
|
221
|
+
const box = document.querySelector(${JSON.stringify(COMPOSER)});
|
|
222
|
+
return !box || box.innerText.trim() === "";
|
|
223
|
+
})()`, SEND_ACCEPT_TIMEOUT_MS);
|
|
224
|
+
if (accepted)
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
throw new Error("ChatGPT did not accept the message: the send button stayed disabled or ignored the click");
|
|
228
|
+
}
|
|
229
|
+
async function waitForConversationId(signal) {
|
|
230
|
+
const deadline = Date.now() + CONVERSATION_ID_TIMEOUT_MS;
|
|
231
|
+
while (Date.now() < deadline) {
|
|
232
|
+
await sleep(500, signal);
|
|
233
|
+
// A new chat first shows a placeholder id (`local-…`); only a UUID is real.
|
|
234
|
+
const id = (await evaluate(`/*nt:location*/ location.pathname`)).match(/\/c\/([0-9a-f-]{36})/)?.[1];
|
|
235
|
+
if (id && UUID.test(id))
|
|
236
|
+
return id;
|
|
237
|
+
}
|
|
238
|
+
throw new Error("ChatGPT did not start a conversation after the message was sent");
|
|
239
|
+
}
|
|
240
|
+
/** The thread to continue is gone, so the caller starts a new one. Thrown before anything is sent. */
|
|
241
|
+
class ThreadUnavailableError extends Error {
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Poll until the turn ends: the current node is a new assistant message with
|
|
245
|
+
* `end_turn`. `before` is the current node before the send, whose finished
|
|
246
|
+
* reply must not count.
|
|
247
|
+
*/
|
|
248
|
+
async function waitForReply(conversationId, timeoutMs, signal, before = null) {
|
|
249
|
+
const started = Date.now();
|
|
250
|
+
let failures = 0;
|
|
251
|
+
let last = null;
|
|
252
|
+
for (;;) {
|
|
253
|
+
await sleep(POLL_INTERVAL_MS, signal);
|
|
254
|
+
try {
|
|
255
|
+
last = await readConversation(conversationId);
|
|
256
|
+
failures = 0;
|
|
257
|
+
}
|
|
258
|
+
catch (error) {
|
|
259
|
+
if (error instanceof Error && error.message.startsWith("ChatGPT is not signed in"))
|
|
260
|
+
throw error;
|
|
261
|
+
log.warn("ChatGPT poll failed", { conversationId, failures: failures + 1, error: error instanceof Error ? error.message : String(error) });
|
|
262
|
+
if (++failures > MAX_POLL_FAILURES)
|
|
263
|
+
throw error;
|
|
264
|
+
}
|
|
265
|
+
const tail = last?.path.at(-1);
|
|
266
|
+
if (tail && tail.role === "assistant" && tail.endTurn === true && last.currentNode !== before)
|
|
267
|
+
return last;
|
|
268
|
+
if (Date.now() - started > timeoutMs) {
|
|
269
|
+
throw new Error(`ChatGPT did not finish within ${timeoutMs / 1000}s (last message: ${tail ? `${tail.role} ${tail.contentType} ${tail.status ?? ""}`.trim() : "none"}). The conversation is ${BASE_URL}/c/${conversationId}`);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
/** Run one turn, in a new thread or a continued one, and return the reply. The caller holds the tab. */
|
|
274
|
+
async function runTurnHoldingTab(request) {
|
|
275
|
+
activeSignal = request.signal;
|
|
276
|
+
activeSignal?.throwIfAborted();
|
|
277
|
+
const query = new URLSearchParams();
|
|
278
|
+
if (request.model && request.model !== CHATGPT_AUTO_MODEL && request.model !== CHATGPT_IMAGE_MODEL)
|
|
279
|
+
query.set("model", request.model);
|
|
280
|
+
const search = query.toString() ? `?${query}` : "";
|
|
281
|
+
let before = null;
|
|
282
|
+
if (request.conversationId) {
|
|
283
|
+
await currentTab().navigate(`${BASE_URL}/c/${request.conversationId}${search}`, activeSignal);
|
|
284
|
+
await waitForComposer();
|
|
285
|
+
// A deleted or foreign thread redirects to a new chat.
|
|
286
|
+
const pathname = await evaluate(`/*nt:location*/ location.pathname`);
|
|
287
|
+
if (!pathname.includes(request.conversationId))
|
|
288
|
+
throw new ThreadUnavailableError(`ChatGPT thread ${request.conversationId} is no longer available`);
|
|
289
|
+
try {
|
|
290
|
+
before = (await readConversation(request.conversationId)).currentNode;
|
|
291
|
+
}
|
|
292
|
+
catch (error) {
|
|
293
|
+
throw new ThreadUnavailableError(error instanceof Error ? error.message : String(error));
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
await currentTab().navigate(`${BASE_URL}/${search}`, activeSignal);
|
|
298
|
+
await waitForComposer();
|
|
299
|
+
}
|
|
300
|
+
activeSignal?.throwIfAborted();
|
|
301
|
+
await attachImages(request.images);
|
|
302
|
+
activeSignal?.throwIfAborted();
|
|
303
|
+
await submit(request.text, request.images.length);
|
|
304
|
+
const conversationId = request.conversationId ?? (await waitForConversationId(request.signal));
|
|
305
|
+
log.info("ChatGPT turn submitted", { conversationId, model: request.model, continued: Boolean(request.conversationId), images: request.images.length });
|
|
306
|
+
const state = await waitForReply(conversationId, request.timeoutMs, request.signal, before);
|
|
307
|
+
await refreshModels();
|
|
308
|
+
return collectReply(conversationId, state);
|
|
309
|
+
}
|
|
310
|
+
/** The reply is everything after the last user message on the branch. */
|
|
311
|
+
function collectReply(conversationId, state) {
|
|
312
|
+
let lastUser = -1;
|
|
313
|
+
state.path.forEach((node, index) => { if (node.role === "user")
|
|
314
|
+
lastUser = index; });
|
|
315
|
+
const reply = state.path.slice(lastUser + 1);
|
|
316
|
+
const tail = reply.at(-1);
|
|
317
|
+
const text = tail && tail.contentType === "text" ? tail.text : "";
|
|
318
|
+
const images = [...new Set(reply.filter((node) => node.role === "tool").flatMap((node) => node.images))];
|
|
319
|
+
return { conversationId, text, images };
|
|
320
|
+
}
|
|
321
|
+
/** Resolve an image pointer (`sediment://file_…` or `file-service://file-…`) and fetch it in the tab. */
|
|
322
|
+
async function downloadImage(conversationId, pointer) {
|
|
323
|
+
const fileId = pointer.replace(/^[a-z-]+:\/\//, "");
|
|
324
|
+
const base64 = await evaluate(`/*nt:download*/ (async () => {
|
|
325
|
+
${AUTH}
|
|
326
|
+
const meta = await fetch("/backend-api/files/download/" + ${JSON.stringify(fileId)} + "?conversation_id=" + ${JSON.stringify(conversationId)} + "&inline=false", { headers: __auth });
|
|
327
|
+
if (!meta.ok) throw new Error("ChatGPT file lookup failed: HTTP " + meta.status);
|
|
328
|
+
const info = await meta.json();
|
|
329
|
+
if (!info.download_url) throw new Error("ChatGPT returned no download URL for the image");
|
|
330
|
+
const response = await fetch(info.download_url, { credentials: "include" });
|
|
331
|
+
if (!response.ok) throw new Error("ChatGPT image download failed: HTTP " + response.status);
|
|
332
|
+
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
333
|
+
let binary = "";
|
|
334
|
+
for (let i = 0; i < bytes.length; i += 0x8000) binary += String.fromCharCode.apply(null, bytes.subarray(i, i + 0x8000));
|
|
335
|
+
return btoa(binary);
|
|
336
|
+
})()`, DOWNLOAD_TIMEOUT_MS);
|
|
337
|
+
return new Uint8Array(Buffer.from(base64, "base64"));
|
|
338
|
+
}
|
|
339
|
+
/** Read the account's model picker while the tab is attached anyway. */
|
|
340
|
+
async function refreshModels() {
|
|
341
|
+
if (liveModels && Date.now() - liveModels.at < MODELS_TTL_MS)
|
|
342
|
+
return;
|
|
343
|
+
try {
|
|
344
|
+
const listed = await evaluate(`/*nt:models*/ (async () => {
|
|
345
|
+
${AUTH}
|
|
346
|
+
const response = await fetch("/backend-api/models", { headers: __auth });
|
|
347
|
+
if (!response.ok) return [];
|
|
348
|
+
const data = await response.json();
|
|
349
|
+
return (data.models || []).map((m) => ({ slug: m.slug, title: m.title }));
|
|
350
|
+
})()`);
|
|
351
|
+
liveModels = {
|
|
352
|
+
at: Date.now(),
|
|
353
|
+
models: listed.filter((m) => typeof m.slug === "string" && m.slug).map((m) => ({ id: m.slug, name: `${m.title || m.slug} (${m.slug})`, provider: PROVIDER_IDS.CHATGPT }))
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
catch (error) {
|
|
357
|
+
log.debug("ChatGPT model list unavailable", { error: error instanceof Error ? error.message : String(error) });
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
function textOf(content) {
|
|
361
|
+
if (typeof content === "string")
|
|
362
|
+
return content;
|
|
363
|
+
if (!Array.isArray(content))
|
|
364
|
+
return "";
|
|
365
|
+
return content.filter((part) => part.type === "text").map((part) => part.text).join("\n");
|
|
366
|
+
}
|
|
367
|
+
function imagesOf(content) {
|
|
368
|
+
return Array.isArray(content) ? content.filter((part) => part.type === "image_url") : [];
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Flatten a conversation into one composer message. A single user message goes
|
|
372
|
+
* as it is. Otherwise the system prompt and the earlier turns become a
|
|
373
|
+
* transcript that ends with the last user message.
|
|
374
|
+
*/
|
|
375
|
+
export function composePrompt(messages) {
|
|
376
|
+
const system = messages.filter((m) => m.role === "system").map((m) => textOf(m.content)).filter(Boolean).join("\n\n");
|
|
377
|
+
const turns = messages.filter((m) => m.role !== "system");
|
|
378
|
+
if (!system && turns.length === 1 && turns[0].role === "user")
|
|
379
|
+
return textOf(turns[0].content);
|
|
380
|
+
const label = (m) => (m.role === "user" ? "User" : m.role === "assistant" ? "Assistant" : "Tool result");
|
|
381
|
+
const transcript = turns.map((m) => `${label(m)}: ${textOf(m.content)}`.trimEnd()).join("\n\n");
|
|
382
|
+
return [
|
|
383
|
+
system ? `Instructions:\n${system}` : "",
|
|
384
|
+
turns.length > 1 ? `Conversation so far:\n${transcript}\n\nReply to the last User message.` : textOf(turns[0]?.content ?? "")
|
|
385
|
+
].filter(Boolean).join("\n\n");
|
|
386
|
+
}
|
|
387
|
+
/** The new messages of a continued thread: ChatGPT already holds its own replies and the system prompt. */
|
|
388
|
+
export function composeDelta(delta) {
|
|
389
|
+
const turns = delta.filter((m) => m.role !== "assistant" && m.role !== "system");
|
|
390
|
+
if (turns.length === 1)
|
|
391
|
+
return textOf(turns[0].content);
|
|
392
|
+
return turns.map((m) => `${m.role === "tool" ? "Tool result" : "User"}: ${textOf(m.content)}`.trimEnd()).join("\n\n");
|
|
393
|
+
}
|
|
394
|
+
function hashSystemPrompt(messages) {
|
|
395
|
+
const system = messages.filter((m) => m.role === "system").map((m) => textOf(m.content)).join("\n\n");
|
|
396
|
+
return createHash("sha256").update(system).digest("hex").slice(0, 16);
|
|
397
|
+
}
|
|
398
|
+
function aspectHint(aspectRatio, width, height) {
|
|
399
|
+
if (aspectRatio)
|
|
400
|
+
return `Aspect ratio: ${aspectRatio}.`;
|
|
401
|
+
if (width && height)
|
|
402
|
+
return `Size: about ${width}x${height} pixels.`;
|
|
403
|
+
return "";
|
|
404
|
+
}
|
|
405
|
+
export class ChatGPTProvider extends BaseProvider {
|
|
406
|
+
static requiredSecrets() {
|
|
407
|
+
return [];
|
|
408
|
+
}
|
|
409
|
+
constructor(_secrets = {}) {
|
|
410
|
+
super(PROVIDER_IDS.CHATGPT);
|
|
411
|
+
}
|
|
412
|
+
declaredCapabilities() {
|
|
413
|
+
return ["text_to_image", "image_to_image"];
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Listing never attaches to the tab: it returns `auto` plus the account's
|
|
417
|
+
* models read during an earlier call. Any ChatGPT model slug also works as
|
|
418
|
+
* a model id.
|
|
419
|
+
*/
|
|
420
|
+
async getAvailableLanguageModels() {
|
|
421
|
+
const auto = { id: CHATGPT_AUTO_MODEL, name: "ChatGPT (default model)", provider: PROVIDER_IDS.CHATGPT };
|
|
422
|
+
return [auto, ...(liveModels?.models ?? [])];
|
|
423
|
+
}
|
|
424
|
+
async getAvailableImageModels() {
|
|
425
|
+
return [{
|
|
426
|
+
id: CHATGPT_IMAGE_MODEL,
|
|
427
|
+
name: "ChatGPT Images",
|
|
428
|
+
provider: PROVIDER_IDS.CHATGPT,
|
|
429
|
+
supportedTasks: ["text_to_image", "image_to_image"],
|
|
430
|
+
aspectRatios: ["1:1", "3:2", "2:3"]
|
|
431
|
+
}];
|
|
432
|
+
}
|
|
433
|
+
/** Threads by conversation thread id, for callers that do not persist the session themselves. */
|
|
434
|
+
sessions = new Map();
|
|
435
|
+
async generateMessage(args) {
|
|
436
|
+
const { result } = await this.chatTurn(args);
|
|
437
|
+
return { role: "assistant", content: result.text };
|
|
438
|
+
}
|
|
439
|
+
async *generateMessages(args) {
|
|
440
|
+
const { result, session } = await this.chatTurn(args);
|
|
441
|
+
if (args.threadId)
|
|
442
|
+
yield { type: "session", session };
|
|
443
|
+
yield { type: "chunk", content: result.text, content_type: "text", done: true };
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Continue the thread the prior session names, or start a new one. A thread
|
|
447
|
+
* continues when the model and system prompt still match and there are new
|
|
448
|
+
* messages; then only those are sent. A thread that is gone falls back to a
|
|
449
|
+
* new one with the whole conversation.
|
|
450
|
+
*/
|
|
451
|
+
async chatTurn(args) {
|
|
452
|
+
if (args.tools && args.tools.length > 0) {
|
|
453
|
+
log.warn("ChatGPT in the browser cannot call tools; sending the conversation without them", { tools: args.tools.length });
|
|
454
|
+
}
|
|
455
|
+
const systemHash = hashSystemPrompt(args.messages);
|
|
456
|
+
const threadId = args.threadId ?? null;
|
|
457
|
+
const prior = args.providerSession ?? (threadId ? this.sessions.get(threadId) ?? null : null);
|
|
458
|
+
const canResume = prior != null &&
|
|
459
|
+
prior.providerId === this.provider &&
|
|
460
|
+
prior.model === args.model &&
|
|
461
|
+
(prior.systemHash == null || prior.systemHash === systemHash) &&
|
|
462
|
+
args.messages.length > prior.checkpoint;
|
|
463
|
+
let result = null;
|
|
464
|
+
if (canResume && prior) {
|
|
465
|
+
const delta = args.messages.slice(prior.checkpoint);
|
|
466
|
+
const request = await this.turnRequest(args.model, composeDelta(delta), delta, args.signal);
|
|
467
|
+
try {
|
|
468
|
+
result = await serialized(() => runTurnHoldingTab({ ...request, conversationId: prior.token }));
|
|
469
|
+
}
|
|
470
|
+
catch (error) {
|
|
471
|
+
if (!(error instanceof ThreadUnavailableError))
|
|
472
|
+
throw error;
|
|
473
|
+
log.warn("ChatGPT thread cannot continue; starting a new one", { conversationId: prior.token, error: error.message });
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
if (!result) {
|
|
477
|
+
// The caller may have sent only the delta; a new thread needs the whole conversation.
|
|
478
|
+
const messages = args.loadFullHistory ? await args.loadFullHistory() : args.messages;
|
|
479
|
+
const request = await this.turnRequest(args.model, composePrompt(messages), messages, args.signal);
|
|
480
|
+
result = await serialized(() => runTurnHoldingTab(request));
|
|
481
|
+
}
|
|
482
|
+
const session = {
|
|
483
|
+
providerId: this.provider,
|
|
484
|
+
model: args.model,
|
|
485
|
+
token: result.conversationId,
|
|
486
|
+
checkpoint: args.messages.length,
|
|
487
|
+
systemHash
|
|
488
|
+
};
|
|
489
|
+
// Cache only when the caller does not thread the session itself; its copy is authoritative.
|
|
490
|
+
if (threadId && args.providerSession == null)
|
|
491
|
+
this.sessions.set(threadId, session);
|
|
492
|
+
return { result, session };
|
|
493
|
+
}
|
|
494
|
+
/** A chat turn's request: the text plus the images of the last user message among `messages`. */
|
|
495
|
+
async turnRequest(model, text, messages, signal) {
|
|
496
|
+
const last = [...messages].reverse().find((m) => m.role === "user");
|
|
497
|
+
const images = last ? await Promise.all(imagesOf(last.content).map((part) => this.imageBytes(part, signal))) : [];
|
|
498
|
+
const dropped = messages.filter((m) => m !== last).reduce((n, m) => n + imagesOf(m.content).length, 0);
|
|
499
|
+
if (dropped > 0)
|
|
500
|
+
log.warn("ChatGPT gets images from the last user message only; dropping earlier ones", { dropped });
|
|
501
|
+
return { model, text, images, timeoutMs: CHAT_TIMEOUT_MS, signal };
|
|
502
|
+
}
|
|
503
|
+
async textToImage(params) {
|
|
504
|
+
return this.generateImage(params.prompt, [], params);
|
|
505
|
+
}
|
|
506
|
+
async imageToImage(images, params) {
|
|
507
|
+
if (images.length === 0)
|
|
508
|
+
throw new Error("imageToImage needs at least one source image");
|
|
509
|
+
return this.generateImage(params.prompt, images, { ...params, width: params.targetWidth, height: params.targetHeight });
|
|
510
|
+
}
|
|
511
|
+
async generateImage(prompt, images, params) {
|
|
512
|
+
const text = [
|
|
513
|
+
images.length > 0
|
|
514
|
+
? "Create one image with the image generation tool, based on the attached image(s). Do not ask questions."
|
|
515
|
+
: "Create one image with the image generation tool. Do not ask questions.",
|
|
516
|
+
prompt,
|
|
517
|
+
aspectHint(params.aspectRatio, params.width, params.height),
|
|
518
|
+
params.negativePrompt ? `Avoid: ${params.negativePrompt}.` : ""
|
|
519
|
+
].filter(Boolean).join("\n\n");
|
|
520
|
+
// The download runs in the same turn on the tab, so no other call can
|
|
521
|
+
// navigate the tab away in between.
|
|
522
|
+
return serialized(async () => {
|
|
523
|
+
const result = await runTurnHoldingTab({ model: CHATGPT_IMAGE_MODEL, text, images, timeoutMs: IMAGE_TIMEOUT_MS, signal: params.signal });
|
|
524
|
+
const pointer = result.images.at(-1);
|
|
525
|
+
if (!pointer) {
|
|
526
|
+
const said = result.text.trim();
|
|
527
|
+
throw new Error(`ChatGPT finished without an image${said ? `: ${said.slice(0, 300)}` : ""}. The conversation is ${BASE_URL}/c/${result.conversationId}`);
|
|
528
|
+
}
|
|
529
|
+
return downloadImage(result.conversationId, pointer);
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
/** Bytes of one image part: inline data, a data URI, an asset URI or a URL. */
|
|
533
|
+
async imageBytes(part, signal) {
|
|
534
|
+
const { data, uri } = part.image;
|
|
535
|
+
if (data instanceof Uint8Array && data.length > 0)
|
|
536
|
+
return data;
|
|
537
|
+
const fromDataUri = (value) => new Uint8Array(Buffer.from(value.slice(value.indexOf(",") + 1), "base64"));
|
|
538
|
+
if (typeof data === "string" && data.length > 0)
|
|
539
|
+
return data.startsWith("data:") ? fromDataUri(data) : new Uint8Array(Buffer.from(data, "base64"));
|
|
540
|
+
if (!uri)
|
|
541
|
+
throw new Error("Image part has neither data nor a URI");
|
|
542
|
+
const resolved = uri.startsWith("data:") ? uri : await this.resolveUri(uri);
|
|
543
|
+
if (resolved.startsWith("data:"))
|
|
544
|
+
return fromDataUri(resolved);
|
|
545
|
+
const response = await fetchExternalMedia(resolved, signal ? { signal } : undefined);
|
|
546
|
+
if (!response.ok)
|
|
547
|
+
throw new Error(`Image download failed: HTTP ${response.status}`);
|
|
548
|
+
return new Uint8Array(await response.arrayBuffer());
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
//# sourceMappingURL=chatgpt-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chatgpt-provider.js","sourceRoot":"","sources":["../../src/providers/chatgpt-provider.ts"],"names":[],"mappings":"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"}
|