@omnicross/subscriptions 0.1.9 → 0.2.0
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/LICENSE +21 -21
- package/NOTICE +12 -12
- package/README.md +15 -15
- package/dist/index.cjs +874 -2
- package/dist/index.d.cts +97 -1
- package/dist/index.d.ts +97 -1
- package/dist/index.js +872 -0
- package/package.json +60 -59
package/dist/index.js
CHANGED
|
@@ -1663,6 +1663,876 @@ function stripAuthHeaders(headers) {
|
|
|
1663
1663
|
delete headers["x-goog-api-key"];
|
|
1664
1664
|
delete headers["X-Goog-Api-Key"];
|
|
1665
1665
|
}
|
|
1666
|
+
|
|
1667
|
+
// src/image-generation/CodexSubscriptionImageProvider.ts
|
|
1668
|
+
import { createHash } from "crypto";
|
|
1669
|
+
import {
|
|
1670
|
+
ImageGenerationError as ImageGenerationError4,
|
|
1671
|
+
normalizeImageGenerationError,
|
|
1672
|
+
resolveImageCapabilities,
|
|
1673
|
+
serializeImageGenerationError
|
|
1674
|
+
} from "@omnicross/core/image-generation";
|
|
1675
|
+
import { fetchUpstream } from "@omnicross/core/pipeline/upstreamFetch";
|
|
1676
|
+
|
|
1677
|
+
// src/image-generation/capabilityEvidence.ts
|
|
1678
|
+
var CODEX_IMAGE_ADAPTER_VALUES = {
|
|
1679
|
+
available: true,
|
|
1680
|
+
models: ["gpt-image-2"],
|
|
1681
|
+
generate: true,
|
|
1682
|
+
edit: true,
|
|
1683
|
+
maskEdit: false,
|
|
1684
|
+
maxInputImages: 1,
|
|
1685
|
+
maxOutputImages: 1,
|
|
1686
|
+
streaming: false,
|
|
1687
|
+
maxPartialImages: 0,
|
|
1688
|
+
transparentBackground: false,
|
|
1689
|
+
flexibleSizes: true,
|
|
1690
|
+
outputFormats: ["png", "jpeg", "webp"],
|
|
1691
|
+
qualityLevels: ["auto", "low", "medium", "high"],
|
|
1692
|
+
moderationModes: ["auto", "low"],
|
|
1693
|
+
outputCompression: { supported: true, formats: ["jpeg", "webp"], min: 0, max: 100 },
|
|
1694
|
+
responsesTool: true,
|
|
1695
|
+
multiTurnEdit: false,
|
|
1696
|
+
supportsFileId: false,
|
|
1697
|
+
supportsImageUrl: false
|
|
1698
|
+
};
|
|
1699
|
+
function createCodexImageAdapterEvidence(now = Date.now()) {
|
|
1700
|
+
return {
|
|
1701
|
+
kind: "adapter",
|
|
1702
|
+
source: "codex-image-adapter-declaration",
|
|
1703
|
+
verifiedAt: now,
|
|
1704
|
+
values: CODEX_IMAGE_ADAPTER_VALUES
|
|
1705
|
+
};
|
|
1706
|
+
}
|
|
1707
|
+
var UnknownCodexImageCapabilityEvidenceSource = class {
|
|
1708
|
+
async resolve(_request) {
|
|
1709
|
+
return {
|
|
1710
|
+
account: { kind: "account", source: "codex-image-entitlement-unknown" },
|
|
1711
|
+
upstream: { kind: "upstream", source: "codex-image-protocol-unverified" }
|
|
1712
|
+
};
|
|
1713
|
+
}
|
|
1714
|
+
};
|
|
1715
|
+
|
|
1716
|
+
// src/image-generation/privateWireErrors.ts
|
|
1717
|
+
import {
|
|
1718
|
+
ImageGenerationError
|
|
1719
|
+
} from "@omnicross/core/image-generation";
|
|
1720
|
+
function parseRetryAfter(headers, now = Date.now()) {
|
|
1721
|
+
const value = headers.get("retry-after");
|
|
1722
|
+
if (!value) return void 0;
|
|
1723
|
+
if (/^\d+$/.test(value)) return Math.min(604800, Number(value));
|
|
1724
|
+
const at = Date.parse(value);
|
|
1725
|
+
if (!Number.isFinite(at) || at <= now) return void 0;
|
|
1726
|
+
return Math.min(604800, Math.ceil((at - now) / 1e3));
|
|
1727
|
+
}
|
|
1728
|
+
function privateErrorCode(body) {
|
|
1729
|
+
if (!body.trim() || body.length > 1e6 || /^\s*</.test(body)) return void 0;
|
|
1730
|
+
try {
|
|
1731
|
+
const value = JSON.parse(body);
|
|
1732
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
1733
|
+
const error = value.error;
|
|
1734
|
+
if (!error || typeof error !== "object" || Array.isArray(error)) return void 0;
|
|
1735
|
+
const code = error.code;
|
|
1736
|
+
return typeof code === "string" && code.length <= 80 ? code : void 0;
|
|
1737
|
+
} catch {
|
|
1738
|
+
return void 0;
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
function mapCandidateCodexImageFailure(response, body) {
|
|
1742
|
+
const retryAfterSeconds = parseRetryAfter(response.headers);
|
|
1743
|
+
const code = privateErrorCode(body);
|
|
1744
|
+
const uncertain = { retryAfterSeconds, retrySafety: "unknown" };
|
|
1745
|
+
if (response.status === 401 || response.status === 403) {
|
|
1746
|
+
return new ImageGenerationError("upstream_auth_required", {
|
|
1747
|
+
retryAfterSeconds,
|
|
1748
|
+
retrySafety: "before_acceptance"
|
|
1749
|
+
});
|
|
1750
|
+
}
|
|
1751
|
+
if (code === "subscription_usage_limit_reached" || code === "usage_limit_reached") {
|
|
1752
|
+
return new ImageGenerationError("subscription_usage_limit_reached", uncertain);
|
|
1753
|
+
}
|
|
1754
|
+
if (code === "moderation_blocked") {
|
|
1755
|
+
return new ImageGenerationError("moderation_blocked", uncertain);
|
|
1756
|
+
}
|
|
1757
|
+
if (response.status === 429) return new ImageGenerationError("upstream_rate_limited", uncertain);
|
|
1758
|
+
if (response.status === 408 || response.status === 504) {
|
|
1759
|
+
return new ImageGenerationError("image_generation_timeout", uncertain);
|
|
1760
|
+
}
|
|
1761
|
+
if (response.status >= 500) return new ImageGenerationError("image_generation_failed", uncertain);
|
|
1762
|
+
return new ImageGenerationError("upstream_protocol_changed", uncertain);
|
|
1763
|
+
}
|
|
1764
|
+
|
|
1765
|
+
// src/image-generation/privateWireRequest.ts
|
|
1766
|
+
import {
|
|
1767
|
+
ImageGenerationError as ImageGenerationError2,
|
|
1768
|
+
readImageAssetBytes
|
|
1769
|
+
} from "@omnicross/core/image-generation";
|
|
1770
|
+
import {
|
|
1771
|
+
codexAcceptHeader,
|
|
1772
|
+
DEFAULT_CODEX_CLI_HEADERS,
|
|
1773
|
+
fillMissingHeaders
|
|
1774
|
+
} from "@omnicross/core/provider-proxy/identity/codexCliHeaders";
|
|
1775
|
+
var CANDIDATE_CODEX_IMAGE_URL = "https://chatgpt.com/backend-api/codex/responses";
|
|
1776
|
+
var CANDIDATE_CODEX_IMAGE_EDIT_URL = "https://chatgpt.com/backend-api/codex/images/edits";
|
|
1777
|
+
var CANDIDATE_CODEX_IMAGE_CARRIER_MODEL = "gpt-5.6-luna";
|
|
1778
|
+
var MAX_INPUT_IMAGE_BYTES = 50 * 1024 * 1024;
|
|
1779
|
+
function applyCandidateCodexImageHeaders(headers) {
|
|
1780
|
+
fillMissingHeaders(headers, DEFAULT_CODEX_CLI_HEADERS);
|
|
1781
|
+
fillMissingHeaders(headers, {
|
|
1782
|
+
accept: codexAcceptHeader(true),
|
|
1783
|
+
"content-type": "application/json"
|
|
1784
|
+
});
|
|
1785
|
+
}
|
|
1786
|
+
function candidateCodexImageUrl(action) {
|
|
1787
|
+
return action === "edit" ? CANDIDATE_CODEX_IMAGE_EDIT_URL : CANDIDATE_CODEX_IMAGE_URL;
|
|
1788
|
+
}
|
|
1789
|
+
function applyCandidateCodexImageActionHeaders(headers, action) {
|
|
1790
|
+
headers.accept = action === "edit" ? "application/json" : codexAcceptHeader(true);
|
|
1791
|
+
}
|
|
1792
|
+
async function encodeInputImage(asset, signal) {
|
|
1793
|
+
if (!["image/png", "image/jpeg", "image/webp"].includes(asset.mimeType)) {
|
|
1794
|
+
throw new ImageGenerationError2("unsupported_image_type", { param: "image" });
|
|
1795
|
+
}
|
|
1796
|
+
let bytes;
|
|
1797
|
+
try {
|
|
1798
|
+
bytes = await readImageAssetBytes(asset, MAX_INPUT_IMAGE_BYTES, signal);
|
|
1799
|
+
} catch (cause) {
|
|
1800
|
+
if (signal?.aborted) throw signal.reason;
|
|
1801
|
+
if (cause instanceof RangeError) {
|
|
1802
|
+
throw new ImageGenerationError2("image_too_large", { param: "image", cause });
|
|
1803
|
+
}
|
|
1804
|
+
throw cause;
|
|
1805
|
+
}
|
|
1806
|
+
try {
|
|
1807
|
+
const base64 = Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString("base64");
|
|
1808
|
+
return `data:${asset.mimeType};base64,${base64}`;
|
|
1809
|
+
} finally {
|
|
1810
|
+
bytes.fill(0);
|
|
1811
|
+
}
|
|
1812
|
+
}
|
|
1813
|
+
async function buildCandidateCodexImageRequest(request, signal) {
|
|
1814
|
+
if (request.action === "edit") {
|
|
1815
|
+
if (request.mask || request.images.length !== 1) {
|
|
1816
|
+
throw new ImageGenerationError2("unsupported_capability", { param: request.mask ? "mask" : "images" });
|
|
1817
|
+
}
|
|
1818
|
+
return JSON.stringify({
|
|
1819
|
+
images: [{ image_url: await encodeInputImage(request.images[0], signal) }],
|
|
1820
|
+
prompt: request.prompt,
|
|
1821
|
+
background: request.background,
|
|
1822
|
+
model: request.model,
|
|
1823
|
+
quality: request.quality,
|
|
1824
|
+
size: request.size.kind === "pixels" ? `${request.size.width}x${request.size.height}` : "auto"
|
|
1825
|
+
});
|
|
1826
|
+
}
|
|
1827
|
+
const tool = {
|
|
1828
|
+
type: "image_generation",
|
|
1829
|
+
action: request.action,
|
|
1830
|
+
model: request.model,
|
|
1831
|
+
quality: request.quality,
|
|
1832
|
+
background: request.background,
|
|
1833
|
+
output_format: request.outputFormat
|
|
1834
|
+
};
|
|
1835
|
+
if (request.size.kind === "pixels") tool.size = `${request.size.width}x${request.size.height}`;
|
|
1836
|
+
if (request.outputCompression !== void 0) tool.output_compression = request.outputCompression;
|
|
1837
|
+
if (request.moderation !== "auto") tool.moderation = request.moderation;
|
|
1838
|
+
const body = {
|
|
1839
|
+
instructions: "",
|
|
1840
|
+
model: CANDIDATE_CODEX_IMAGE_CARRIER_MODEL,
|
|
1841
|
+
input: [{
|
|
1842
|
+
type: "message",
|
|
1843
|
+
role: "user",
|
|
1844
|
+
content: [{ type: "input_text", text: request.prompt }]
|
|
1845
|
+
}],
|
|
1846
|
+
tools: [tool],
|
|
1847
|
+
tool_choice: { type: "image_generation" },
|
|
1848
|
+
reasoning: { effort: "medium", summary: "auto" },
|
|
1849
|
+
parallel_tool_calls: true,
|
|
1850
|
+
include: ["reasoning.encrypted_content"],
|
|
1851
|
+
stream: true,
|
|
1852
|
+
store: false
|
|
1853
|
+
};
|
|
1854
|
+
return JSON.stringify(body);
|
|
1855
|
+
}
|
|
1856
|
+
|
|
1857
|
+
// src/image-generation/privateWireResponse.ts
|
|
1858
|
+
import {
|
|
1859
|
+
ImageGenerationError as ImageGenerationError3,
|
|
1860
|
+
InMemoryImageAsset
|
|
1861
|
+
} from "@omnicross/core/image-generation";
|
|
1862
|
+
import sharp from "sharp";
|
|
1863
|
+
function disposeCandidateCodexImageResponse(parsed) {
|
|
1864
|
+
if (!parsed) return;
|
|
1865
|
+
for (const image of parsed.images) {
|
|
1866
|
+
if (image instanceof InMemoryImageAsset) image.dispose();
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1869
|
+
var MAX_CANDIDATE_RESPONSE_BYTES = 7e7;
|
|
1870
|
+
var MAX_DECODED_IMAGE_BYTES = 50 * 1024 * 1024;
|
|
1871
|
+
var MAX_DECODED_IMAGE_PIXELS = 8294400;
|
|
1872
|
+
var MAX_DECODED_RAW_BYTES = MAX_DECODED_IMAGE_PIXELS * 4;
|
|
1873
|
+
async function readCandidateCodexImageResponseBody(response) {
|
|
1874
|
+
const declared = response.headers.get("content-length");
|
|
1875
|
+
if (declared && (!/^\d+$/.test(declared) || Number(declared) > MAX_CANDIDATE_RESPONSE_BYTES)) {
|
|
1876
|
+
return protocolChanged();
|
|
1877
|
+
}
|
|
1878
|
+
if (!response.body) return "";
|
|
1879
|
+
const reader = response.body.getReader();
|
|
1880
|
+
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
1881
|
+
let total = 0;
|
|
1882
|
+
let body = "";
|
|
1883
|
+
try {
|
|
1884
|
+
while (true) {
|
|
1885
|
+
const next = await reader.read();
|
|
1886
|
+
if (next.done) break;
|
|
1887
|
+
total += next.value.byteLength;
|
|
1888
|
+
if (total > MAX_CANDIDATE_RESPONSE_BYTES) {
|
|
1889
|
+
await reader.cancel();
|
|
1890
|
+
return protocolChanged();
|
|
1891
|
+
}
|
|
1892
|
+
body += decoder.decode(next.value, { stream: true });
|
|
1893
|
+
}
|
|
1894
|
+
body += decoder.decode();
|
|
1895
|
+
return body;
|
|
1896
|
+
} catch (cause) {
|
|
1897
|
+
return protocolChanged(cause);
|
|
1898
|
+
} finally {
|
|
1899
|
+
reader.releaseLock();
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
function selectVerifiedCandidateResponseMetadata(parsed, verified) {
|
|
1903
|
+
return {
|
|
1904
|
+
...verified?.usage && parsed.usage ? { usage: parsed.usage } : {},
|
|
1905
|
+
...verified?.revisedPrompt && parsed.revisedPrompt ? { revisedPrompt: parsed.revisedPrompt } : {}
|
|
1906
|
+
};
|
|
1907
|
+
}
|
|
1908
|
+
function protocolChanged(cause) {
|
|
1909
|
+
throw new ImageGenerationError3("upstream_protocol_changed", { cause });
|
|
1910
|
+
}
|
|
1911
|
+
function decodeCandidateBase64ForTests(value) {
|
|
1912
|
+
if (typeof value !== "string" || value.length === 0 || value.length % 4 !== 0) {
|
|
1913
|
+
return protocolChanged();
|
|
1914
|
+
}
|
|
1915
|
+
const padding = value.endsWith("==") ? 2 : value.endsWith("=") ? 1 : 0;
|
|
1916
|
+
const decodedLength = value.length / 4 * 3 - padding;
|
|
1917
|
+
if (decodedLength <= 0 || decodedLength > MAX_DECODED_IMAGE_BYTES) return protocolChanged();
|
|
1918
|
+
const alphabetEnd = value.length - padding;
|
|
1919
|
+
for (let index = 0; index < alphabetEnd; index += 1) {
|
|
1920
|
+
const code = value.charCodeAt(index);
|
|
1921
|
+
const allowed = code >= 65 && code <= 90 || code >= 97 && code <= 122 || code >= 48 && code <= 57 || code === 43 || code === 47;
|
|
1922
|
+
if (!allowed) return protocolChanged();
|
|
1923
|
+
}
|
|
1924
|
+
for (let index = alphabetEnd; index < value.length; index += 1) {
|
|
1925
|
+
if (value.charCodeAt(index) !== 61) return protocolChanged();
|
|
1926
|
+
}
|
|
1927
|
+
if (padding === 1 && value.charCodeAt(value.length - 2) === 61) return protocolChanged();
|
|
1928
|
+
const decoded = Buffer.from(value, "base64");
|
|
1929
|
+
if (decoded.byteLength !== decodedLength || decoded.toString("base64") !== value) return protocolChanged();
|
|
1930
|
+
return new Uint8Array(decoded);
|
|
1931
|
+
}
|
|
1932
|
+
function readU32Be(bytes, offset) {
|
|
1933
|
+
return (bytes[offset] << 24 | bytes[offset + 1] << 16 | bytes[offset + 2] << 8 | bytes[offset + 3]) >>> 0;
|
|
1934
|
+
}
|
|
1935
|
+
function readU32Le(bytes, offset) {
|
|
1936
|
+
return (bytes[offset] | bytes[offset + 1] << 8 | bytes[offset + 2] << 16 | bytes[offset + 3] << 24) >>> 0;
|
|
1937
|
+
}
|
|
1938
|
+
function assertCompleteContainer(bytes, format) {
|
|
1939
|
+
if (format === "jpeg") {
|
|
1940
|
+
if (bytes.byteLength < 4 || bytes.at(-2) !== 255 || bytes.at(-1) !== 217) protocolChanged();
|
|
1941
|
+
return;
|
|
1942
|
+
}
|
|
1943
|
+
if (format === "webp") {
|
|
1944
|
+
if (bytes.byteLength < 20 || Buffer.from(bytes.subarray(0, 4)).toString("ascii") !== "RIFF" || Buffer.from(bytes.subarray(8, 12)).toString("ascii") !== "WEBP" || readU32Le(bytes, 4) + 8 !== bytes.byteLength) protocolChanged();
|
|
1945
|
+
let offset2 = 12;
|
|
1946
|
+
while (offset2 < bytes.byteLength) {
|
|
1947
|
+
if (offset2 + 8 > bytes.byteLength) protocolChanged();
|
|
1948
|
+
const length = readU32Le(bytes, offset2 + 4);
|
|
1949
|
+
const next = offset2 + 8 + length + length % 2;
|
|
1950
|
+
if (next > bytes.byteLength) protocolChanged();
|
|
1951
|
+
offset2 = next;
|
|
1952
|
+
}
|
|
1953
|
+
if (offset2 !== bytes.byteLength) protocolChanged();
|
|
1954
|
+
return;
|
|
1955
|
+
}
|
|
1956
|
+
const signature = [137, 80, 78, 71, 13, 10, 26, 10];
|
|
1957
|
+
if (bytes.byteLength < 20 || !signature.every((value, index) => bytes[index] === value)) {
|
|
1958
|
+
protocolChanged();
|
|
1959
|
+
}
|
|
1960
|
+
let offset = 8;
|
|
1961
|
+
let sawEnd = false;
|
|
1962
|
+
while (offset < bytes.byteLength) {
|
|
1963
|
+
if (offset + 12 > bytes.byteLength) protocolChanged();
|
|
1964
|
+
const length = readU32Be(bytes, offset);
|
|
1965
|
+
const next = offset + 12 + length;
|
|
1966
|
+
if (next > bytes.byteLength) protocolChanged();
|
|
1967
|
+
const type = Buffer.from(bytes.subarray(offset + 4, offset + 8)).toString("ascii");
|
|
1968
|
+
if (type === "IEND") {
|
|
1969
|
+
if (length !== 0 || next !== bytes.byteLength) protocolChanged();
|
|
1970
|
+
sawEnd = true;
|
|
1971
|
+
}
|
|
1972
|
+
offset = next;
|
|
1973
|
+
}
|
|
1974
|
+
if (!sawEnd || offset !== bytes.byteLength) protocolChanged();
|
|
1975
|
+
}
|
|
1976
|
+
async function createAsset(value, format) {
|
|
1977
|
+
const bytes = decodeCandidateBase64ForTests(value);
|
|
1978
|
+
assertCompleteContainer(bytes, format);
|
|
1979
|
+
const input = Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
1980
|
+
try {
|
|
1981
|
+
const decoder = sharp(input, {
|
|
1982
|
+
failOn: "warning",
|
|
1983
|
+
limitInputPixels: MAX_DECODED_IMAGE_PIXELS,
|
|
1984
|
+
sequentialRead: true
|
|
1985
|
+
});
|
|
1986
|
+
const metadata = await decoder.metadata();
|
|
1987
|
+
if (metadata.format !== format || !Number.isSafeInteger(metadata.width) || !Number.isSafeInteger(metadata.height) || metadata.width <= 0 || metadata.height <= 0 || metadata.width * metadata.height > MAX_DECODED_IMAGE_PIXELS) return protocolChanged();
|
|
1988
|
+
const decoded = await decoder.raw().toBuffer({ resolveWithObject: true });
|
|
1989
|
+
if (decoded.info.width !== metadata.width || decoded.info.height !== metadata.height || !Number.isSafeInteger(decoded.info.channels) || decoded.info.channels <= 0 || decoded.info.channels > 4 || decoded.data.byteLength !== decoded.info.width * decoded.info.height * decoded.info.channels || decoded.data.byteLength > MAX_DECODED_RAW_BYTES) return protocolChanged();
|
|
1990
|
+
return new InMemoryImageAsset(bytes, {
|
|
1991
|
+
mimeType: `image/${format}`,
|
|
1992
|
+
width: decoded.info.width,
|
|
1993
|
+
height: decoded.info.height,
|
|
1994
|
+
...metadata.hasAlpha !== void 0 ? { hasAlpha: metadata.hasAlpha } : {}
|
|
1995
|
+
});
|
|
1996
|
+
} catch (cause) {
|
|
1997
|
+
return protocolChanged(cause);
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
function parseUsage(value) {
|
|
2001
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
2002
|
+
const record = value;
|
|
2003
|
+
const read = (key) => {
|
|
2004
|
+
const item = record[key];
|
|
2005
|
+
return Number.isSafeInteger(item) && item >= 0 ? item : void 0;
|
|
2006
|
+
};
|
|
2007
|
+
const usage = {
|
|
2008
|
+
totalTokens: read("total_tokens"),
|
|
2009
|
+
inputTokens: read("input_tokens"),
|
|
2010
|
+
outputTokens: read("output_tokens"),
|
|
2011
|
+
generatedImages: read("generated_images")
|
|
2012
|
+
};
|
|
2013
|
+
return Object.values(usage).some((item) => item !== void 0) ? usage : void 0;
|
|
2014
|
+
}
|
|
2015
|
+
async function parseCandidateCodexImageResponse(body, expectedCount, expectedFormat) {
|
|
2016
|
+
if (!body.trim() || /^s*</.test(body)) return protocolChanged();
|
|
2017
|
+
if (/^\s*(?:data|event):/u.test(body)) {
|
|
2018
|
+
return parseCandidateCodexImageSse(body, expectedCount, expectedFormat);
|
|
2019
|
+
}
|
|
2020
|
+
let parsed;
|
|
2021
|
+
try {
|
|
2022
|
+
parsed = JSON.parse(body);
|
|
2023
|
+
} catch (cause) {
|
|
2024
|
+
return protocolChanged(cause);
|
|
2025
|
+
}
|
|
2026
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return protocolChanged();
|
|
2027
|
+
const record = parsed;
|
|
2028
|
+
if (Array.isArray(record.data)) {
|
|
2029
|
+
if (record.data.length !== expectedCount) return protocolChanged();
|
|
2030
|
+
const rows = record.data.map((item) => {
|
|
2031
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) return protocolChanged();
|
|
2032
|
+
return item;
|
|
2033
|
+
});
|
|
2034
|
+
const images2 = await Promise.all(rows.map((item) => createAsset(item.b64_json, expectedFormat)));
|
|
2035
|
+
const revised2 = rows.length === 1 && typeof rows[0]?.revised_prompt === "string" ? rows[0].revised_prompt : void 0;
|
|
2036
|
+
return {
|
|
2037
|
+
images: images2,
|
|
2038
|
+
revisedPrompt: revised2,
|
|
2039
|
+
usage: parseUsage(record.usage)
|
|
2040
|
+
};
|
|
2041
|
+
}
|
|
2042
|
+
if (!Array.isArray(record.output)) return protocolChanged();
|
|
2043
|
+
const calls = record.output.filter(
|
|
2044
|
+
(item) => !!item && typeof item === "object" && !Array.isArray(item) && item.type === "image_generation_call"
|
|
2045
|
+
);
|
|
2046
|
+
if (calls.length !== expectedCount) return protocolChanged();
|
|
2047
|
+
const images = await Promise.all(calls.map(async (call) => {
|
|
2048
|
+
if (call.status !== "completed" || typeof call.result !== "string") return protocolChanged();
|
|
2049
|
+
return createAsset(call.result, expectedFormat);
|
|
2050
|
+
}));
|
|
2051
|
+
const revised = calls.length === 1 && typeof calls[0]?.revised_prompt === "string" ? calls[0].revised_prompt : void 0;
|
|
2052
|
+
return {
|
|
2053
|
+
images,
|
|
2054
|
+
revisedPrompt: revised,
|
|
2055
|
+
usage: parseUsage(record.usage)
|
|
2056
|
+
};
|
|
2057
|
+
}
|
|
2058
|
+
async function parseCandidateCodexImageSse(body, expectedCount, expectedFormat) {
|
|
2059
|
+
const best = /* @__PURE__ */ new Map();
|
|
2060
|
+
const completedEventResults = [];
|
|
2061
|
+
let completedResponse;
|
|
2062
|
+
for (const line of body.split(/\r?\n/u)) {
|
|
2063
|
+
if (!line.startsWith("data:")) continue;
|
|
2064
|
+
const payload = line.slice(5).trim();
|
|
2065
|
+
if (!payload || payload === "[DONE]") continue;
|
|
2066
|
+
let event;
|
|
2067
|
+
try {
|
|
2068
|
+
event = JSON.parse(payload);
|
|
2069
|
+
} catch {
|
|
2070
|
+
continue;
|
|
2071
|
+
}
|
|
2072
|
+
if (!event || typeof event !== "object" || Array.isArray(event)) continue;
|
|
2073
|
+
const record = event;
|
|
2074
|
+
if (typeof record.partial_image_b64 === "string") {
|
|
2075
|
+
const index = record.partial_image_index === void 0 ? 0 : record.partial_image_index;
|
|
2076
|
+
if (!Number.isSafeInteger(index) || index < 0 || index >= expectedCount) continue;
|
|
2077
|
+
const previous = best.get(index);
|
|
2078
|
+
if (!previous || record.partial_image_b64.length >= previous.length) {
|
|
2079
|
+
best.set(index, record.partial_image_b64);
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
if (record.type === "response.completed") {
|
|
2083
|
+
if (!record.response || typeof record.response !== "object" || Array.isArray(record.response)) {
|
|
2084
|
+
return protocolChanged();
|
|
2085
|
+
}
|
|
2086
|
+
completedResponse = record.response;
|
|
2087
|
+
}
|
|
2088
|
+
if (record.type === "response.output_item.done" && record.item && typeof record.item === "object" && !Array.isArray(record.item)) {
|
|
2089
|
+
const item = record.item;
|
|
2090
|
+
if (item.type === "image_generation_call" && item.status === "completed" && typeof item.result === "string") {
|
|
2091
|
+
completedEventResults.push(item.result);
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
}
|
|
2095
|
+
const output = completedResponse?.output;
|
|
2096
|
+
const calls = Array.isArray(output) ? output.filter(
|
|
2097
|
+
(item) => !!item && typeof item === "object" && !Array.isArray(item) && item.type === "image_generation_call"
|
|
2098
|
+
) : [];
|
|
2099
|
+
const finalResults = calls.filter(
|
|
2100
|
+
(call) => call.status === "completed" && typeof call.result === "string"
|
|
2101
|
+
);
|
|
2102
|
+
if (best.size !== expectedCount && completedEventResults.length !== expectedCount && finalResults.length !== expectedCount) {
|
|
2103
|
+
return protocolChanged();
|
|
2104
|
+
}
|
|
2105
|
+
const images = await Promise.all(Array.from({ length: expectedCount }, async (_unused, index) => {
|
|
2106
|
+
const encoded = best.get(index) ?? completedEventResults[index] ?? finalResults[index]?.result;
|
|
2107
|
+
if (!encoded) return protocolChanged();
|
|
2108
|
+
return createAsset(encoded, expectedFormat);
|
|
2109
|
+
}));
|
|
2110
|
+
const revised = calls.length === 1 && typeof calls[0]?.revised_prompt === "string" ? calls[0].revised_prompt : void 0;
|
|
2111
|
+
return {
|
|
2112
|
+
images,
|
|
2113
|
+
revisedPrompt: revised,
|
|
2114
|
+
usage: parseUsage(completedResponse?.usage)
|
|
2115
|
+
};
|
|
2116
|
+
}
|
|
2117
|
+
|
|
2118
|
+
// src/image-generation/CodexSubscriptionImageProvider.ts
|
|
2119
|
+
var PROVIDER_ID = "codex-subscription";
|
|
2120
|
+
function traceAccountFingerprint(accountId) {
|
|
2121
|
+
return `sha256:${createHash("sha256").update(accountId, "utf8").digest("hex")}`;
|
|
2122
|
+
}
|
|
2123
|
+
function failed(error) {
|
|
2124
|
+
return { type: "failed", error: serializeImageGenerationError(error) };
|
|
2125
|
+
}
|
|
2126
|
+
var CodexSubscriptionImageProvider = class {
|
|
2127
|
+
id = PROVIDER_ID;
|
|
2128
|
+
#auth;
|
|
2129
|
+
#evidence;
|
|
2130
|
+
#executionScheduler;
|
|
2131
|
+
#generationTimeoutMs;
|
|
2132
|
+
#now;
|
|
2133
|
+
constructor(options) {
|
|
2134
|
+
this.#auth = options.authStrategy;
|
|
2135
|
+
this.#evidence = options.evidenceSource ?? new UnknownCodexImageCapabilityEvidenceSource();
|
|
2136
|
+
this.#executionScheduler = options.executionScheduler;
|
|
2137
|
+
this.#generationTimeoutMs = options.generationTimeoutMs ?? 18e4;
|
|
2138
|
+
this.#now = options.now ?? Date.now;
|
|
2139
|
+
}
|
|
2140
|
+
async acquire(context) {
|
|
2141
|
+
if (context.signal.aborted) throw new ImageGenerationError4("request_cancelled", { cause: context.signal.reason });
|
|
2142
|
+
if (this.#auth.providerId !== "codex") throw new ImageGenerationError4("upstream_auth_required");
|
|
2143
|
+
let selectedAccountId;
|
|
2144
|
+
const headers = {};
|
|
2145
|
+
applyCandidateCodexImageHeaders(headers);
|
|
2146
|
+
try {
|
|
2147
|
+
await this.#auth.applyHeaders(headers, {
|
|
2148
|
+
upstreamUrl: CANDIDATE_CODEX_IMAGE_URL,
|
|
2149
|
+
resolvedModel: CANDIDATE_CODEX_IMAGE_CARRIER_MODEL,
|
|
2150
|
+
sessionKey: context.sessionKey,
|
|
2151
|
+
preferredAccountId: context.preferredAccountId,
|
|
2152
|
+
preferredAccountGroup: context.preferredAccountGroup,
|
|
2153
|
+
boundAccountFallbackPolicy: context.boundAccountFallbackPolicy,
|
|
2154
|
+
reportSelection: (accountId) => {
|
|
2155
|
+
selectedAccountId = accountId;
|
|
2156
|
+
}
|
|
2157
|
+
});
|
|
2158
|
+
} catch (cause) {
|
|
2159
|
+
throw new ImageGenerationError4("upstream_auth_required", { cause });
|
|
2160
|
+
}
|
|
2161
|
+
if (!selectedAccountId || !/^Bearer\s+\S+$/i.test(headers.Authorization ?? "")) {
|
|
2162
|
+
headers.Authorization = "";
|
|
2163
|
+
throw new ImageGenerationError4("upstream_auth_required");
|
|
2164
|
+
}
|
|
2165
|
+
if (context.signal.aborted) {
|
|
2166
|
+
headers.Authorization = "";
|
|
2167
|
+
throw new ImageGenerationError4("request_cancelled", { cause: context.signal.reason });
|
|
2168
|
+
}
|
|
2169
|
+
let evidence;
|
|
2170
|
+
try {
|
|
2171
|
+
evidence = await this.#evidence.resolve({
|
|
2172
|
+
accountId: selectedAccountId,
|
|
2173
|
+
signal: context.signal
|
|
2174
|
+
});
|
|
2175
|
+
} catch (cause) {
|
|
2176
|
+
if (context.signal.aborted) {
|
|
2177
|
+
headers.Authorization = "";
|
|
2178
|
+
selectedAccountId = void 0;
|
|
2179
|
+
throw new ImageGenerationError4("request_cancelled", { cause: context.signal.reason });
|
|
2180
|
+
}
|
|
2181
|
+
evidence = {
|
|
2182
|
+
account: { kind: "account", source: "codex-image-evidence-source-failed" },
|
|
2183
|
+
upstream: { kind: "upstream", source: "codex-image-evidence-source-failed" }
|
|
2184
|
+
};
|
|
2185
|
+
}
|
|
2186
|
+
if (context.signal.aborted) {
|
|
2187
|
+
headers.Authorization = "";
|
|
2188
|
+
selectedAccountId = void 0;
|
|
2189
|
+
throw new ImageGenerationError4("request_cancelled", { cause: context.signal.reason });
|
|
2190
|
+
}
|
|
2191
|
+
const resolvedCapabilities = resolveImageCapabilities({
|
|
2192
|
+
adapter: createCodexImageAdapterEvidence(this.#now()),
|
|
2193
|
+
account: evidence.account,
|
|
2194
|
+
upstream: evidence.upstream
|
|
2195
|
+
}, this.#now());
|
|
2196
|
+
const bootstrapEligible = evidence.account.source === "codex-image-entitlement-unknown" && evidence.upstream.source === "codex-image-protocol-unverified";
|
|
2197
|
+
const capabilities = resolvedCapabilities.available ? resolvedCapabilities : bootstrapEligible ? Object.freeze({
|
|
2198
|
+
...CODEX_IMAGE_ADAPTER_VALUES,
|
|
2199
|
+
resolvedAt: this.#now()
|
|
2200
|
+
}) : resolvedCapabilities;
|
|
2201
|
+
let released = false;
|
|
2202
|
+
let started = false;
|
|
2203
|
+
const release = async () => {
|
|
2204
|
+
if (released) return;
|
|
2205
|
+
released = true;
|
|
2206
|
+
headers.Authorization = "";
|
|
2207
|
+
selectedAccountId = void 0;
|
|
2208
|
+
};
|
|
2209
|
+
return {
|
|
2210
|
+
providerId: PROVIDER_ID,
|
|
2211
|
+
capabilities,
|
|
2212
|
+
start: (request) => {
|
|
2213
|
+
if (released) throw new ImageGenerationError4("upstream_auth_required");
|
|
2214
|
+
if (started) throw new ImageGenerationError4("invalid_image_request");
|
|
2215
|
+
started = true;
|
|
2216
|
+
if (!capabilities.available) throw new ImageGenerationError4("unsupported_capability");
|
|
2217
|
+
const unsupportedAction = request.action === "generate" ? !capabilities.generate : !capabilities.edit || request.images.length === 0 || request.images.length > capabilities.maxInputImages || request.mask !== void 0 && !capabilities.maskEdit;
|
|
2218
|
+
if (unsupportedAction || request.stream || request.partialImages > 0 || request.n !== 1 || !capabilities.models.includes(request.model) || !capabilities.outputFormats.includes(request.outputFormat) || !capabilities.qualityLevels.includes(request.quality) || !capabilities.moderationModes.includes(request.moderation) || request.outputCompression !== void 0 && (!Number.isInteger(request.outputCompression) || capabilities.outputCompression.supported !== true || !capabilities.outputCompression.formats.includes(request.outputFormat) || request.outputCompression < capabilities.outputCompression.min || request.outputCompression > capabilities.outputCompression.max)) {
|
|
2219
|
+
throw new ImageGenerationError4("unsupported_capability");
|
|
2220
|
+
}
|
|
2221
|
+
return this.#createJob(
|
|
2222
|
+
request,
|
|
2223
|
+
context,
|
|
2224
|
+
headers,
|
|
2225
|
+
selectedAccountId,
|
|
2226
|
+
evidence.verifiedResponseFields
|
|
2227
|
+
);
|
|
2228
|
+
},
|
|
2229
|
+
release
|
|
2230
|
+
};
|
|
2231
|
+
}
|
|
2232
|
+
#createJob(request, context, leaseHeaders, accountId, verifiedFields) {
|
|
2233
|
+
const controller = new AbortController();
|
|
2234
|
+
let cancelled = false;
|
|
2235
|
+
let queueWaitMs;
|
|
2236
|
+
let generationStartedAt;
|
|
2237
|
+
let retryCount = 0;
|
|
2238
|
+
let authRefreshCount = 0;
|
|
2239
|
+
const onCallerAbort = () => controller.abort(context.signal.reason);
|
|
2240
|
+
context.signal.addEventListener("abort", onCallerAbort, { once: true });
|
|
2241
|
+
const cancel = async () => {
|
|
2242
|
+
if (cancelled) return;
|
|
2243
|
+
cancelled = true;
|
|
2244
|
+
controller.abort(new Error("request_cancelled"));
|
|
2245
|
+
};
|
|
2246
|
+
const events = (async function* (self) {
|
|
2247
|
+
let schedulerGrant;
|
|
2248
|
+
let schedulerGrantReleased = false;
|
|
2249
|
+
let schedulerGrantSignal;
|
|
2250
|
+
let onSchedulerAbort;
|
|
2251
|
+
let timeout;
|
|
2252
|
+
let accepted = false;
|
|
2253
|
+
try {
|
|
2254
|
+
if (controller.signal.aborted) throw controller.signal.reason;
|
|
2255
|
+
if (self.#executionScheduler) {
|
|
2256
|
+
const queueStartedAt = self.#now();
|
|
2257
|
+
try {
|
|
2258
|
+
const accountKey = self.#executionScheduler.deriveAccountKey(accountId);
|
|
2259
|
+
schedulerGrant = await self.#executionScheduler.acquire({
|
|
2260
|
+
tenantId: context.tenantId,
|
|
2261
|
+
accountKey,
|
|
2262
|
+
signal: controller.signal
|
|
2263
|
+
});
|
|
2264
|
+
} finally {
|
|
2265
|
+
queueWaitMs = Math.max(0, self.#now() - queueStartedAt);
|
|
2266
|
+
}
|
|
2267
|
+
schedulerGrantSignal = schedulerGrant.signal;
|
|
2268
|
+
if (schedulerGrantSignal) {
|
|
2269
|
+
onSchedulerAbort = () => controller.abort(schedulerGrantSignal?.reason);
|
|
2270
|
+
if (schedulerGrantSignal.aborted) onSchedulerAbort();
|
|
2271
|
+
else schedulerGrantSignal.addEventListener("abort", onSchedulerAbort, { once: true });
|
|
2272
|
+
}
|
|
2273
|
+
}
|
|
2274
|
+
if (controller.signal.aborted) throw controller.signal.reason;
|
|
2275
|
+
generationStartedAt = self.#now();
|
|
2276
|
+
timeout = setTimeout(
|
|
2277
|
+
() => controller.abort(new ImageGenerationError4("image_generation_timeout")),
|
|
2278
|
+
self.#generationTimeoutMs
|
|
2279
|
+
);
|
|
2280
|
+
const body = await buildCandidateCodexImageRequest(request, controller.signal);
|
|
2281
|
+
const upstreamUrl = candidateCodexImageUrl(request.action);
|
|
2282
|
+
let response;
|
|
2283
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
2284
|
+
if (controller.signal.aborted) throw controller.signal.reason;
|
|
2285
|
+
if (attempt > 0) retryCount += 1;
|
|
2286
|
+
const requestHeaders = { ...leaseHeaders };
|
|
2287
|
+
applyCandidateCodexImageActionHeaders(requestHeaders, request.action);
|
|
2288
|
+
response = await fetchUpstream(
|
|
2289
|
+
upstreamUrl,
|
|
2290
|
+
{
|
|
2291
|
+
method: "POST",
|
|
2292
|
+
headers: requestHeaders,
|
|
2293
|
+
body,
|
|
2294
|
+
signal: controller.signal
|
|
2295
|
+
},
|
|
2296
|
+
{
|
|
2297
|
+
providerId: "codex",
|
|
2298
|
+
accountId,
|
|
2299
|
+
traceAccountFingerprint: traceAccountFingerprint(accountId),
|
|
2300
|
+
redactBodies: true
|
|
2301
|
+
}
|
|
2302
|
+
);
|
|
2303
|
+
if (response.status !== 401 || attempt === 1) break;
|
|
2304
|
+
const refreshed = await self.#auth.onUnauthorized(context.sessionKey);
|
|
2305
|
+
if (!refreshed) break;
|
|
2306
|
+
authRefreshCount += 1;
|
|
2307
|
+
let refreshedAccount;
|
|
2308
|
+
const refreshedHeaders = {};
|
|
2309
|
+
applyCandidateCodexImageHeaders(refreshedHeaders);
|
|
2310
|
+
await self.#auth.applyHeaders(refreshedHeaders, {
|
|
2311
|
+
upstreamUrl,
|
|
2312
|
+
resolvedModel: CANDIDATE_CODEX_IMAGE_CARRIER_MODEL,
|
|
2313
|
+
sessionKey: context.sessionKey,
|
|
2314
|
+
preferredAccountId: accountId,
|
|
2315
|
+
boundAccountFallbackPolicy: context.boundAccountFallbackPolicy,
|
|
2316
|
+
reportSelection: (id) => {
|
|
2317
|
+
refreshedAccount = id;
|
|
2318
|
+
}
|
|
2319
|
+
});
|
|
2320
|
+
if (refreshedAccount !== accountId || !/^Bearer\s+\S+$/i.test(refreshedHeaders.Authorization ?? "")) {
|
|
2321
|
+
throw new ImageGenerationError4("upstream_auth_required");
|
|
2322
|
+
}
|
|
2323
|
+
Object.assign(leaseHeaders, refreshedHeaders);
|
|
2324
|
+
}
|
|
2325
|
+
if (!response) throw new ImageGenerationError4("image_generation_failed", { retrySafety: "unknown" });
|
|
2326
|
+
const responseBody = await readCandidateCodexImageResponseBody(response);
|
|
2327
|
+
if (!response.ok) {
|
|
2328
|
+
yield failed(mapCandidateCodexImageFailure(response, responseBody));
|
|
2329
|
+
return;
|
|
2330
|
+
}
|
|
2331
|
+
accepted = true;
|
|
2332
|
+
yield { type: "accepted", acceptedAt: self.#now() };
|
|
2333
|
+
const parsed = await parseCandidateCodexImageResponse(responseBody, request.n, request.outputFormat);
|
|
2334
|
+
const verified = selectVerifiedCandidateResponseMetadata(parsed, verifiedFields);
|
|
2335
|
+
const completed = {
|
|
2336
|
+
type: "completed",
|
|
2337
|
+
images: parsed.images.map((artifact, index) => ({
|
|
2338
|
+
artifact,
|
|
2339
|
+
...index === 0 && verified.revisedPrompt ? { revisedPrompt: verified.revisedPrompt } : {}
|
|
2340
|
+
})),
|
|
2341
|
+
...verified.usage ? { usage: verified.usage } : {}
|
|
2342
|
+
};
|
|
2343
|
+
yield completed;
|
|
2344
|
+
} catch (cause) {
|
|
2345
|
+
const normalized = controller.signal.aborted ? controller.signal.reason instanceof ImageGenerationError4 ? controller.signal.reason : new ImageGenerationError4("request_cancelled", { cause: controller.signal.reason }) : normalizeImageGenerationError(cause, "image_generation_failed", {
|
|
2346
|
+
retrySafety: accepted ? "after_acceptance" : "unknown"
|
|
2347
|
+
});
|
|
2348
|
+
yield failed(normalized);
|
|
2349
|
+
} finally {
|
|
2350
|
+
if (timeout !== void 0) clearTimeout(timeout);
|
|
2351
|
+
if (schedulerGrantSignal && onSchedulerAbort) {
|
|
2352
|
+
schedulerGrantSignal.removeEventListener("abort", onSchedulerAbort);
|
|
2353
|
+
}
|
|
2354
|
+
if (schedulerGrant && !schedulerGrantReleased) {
|
|
2355
|
+
schedulerGrantReleased = true;
|
|
2356
|
+
await schedulerGrant.release();
|
|
2357
|
+
}
|
|
2358
|
+
context.signal.removeEventListener("abort", onCallerAbort);
|
|
2359
|
+
}
|
|
2360
|
+
})(this);
|
|
2361
|
+
return {
|
|
2362
|
+
events,
|
|
2363
|
+
cancel,
|
|
2364
|
+
observability: {
|
|
2365
|
+
snapshot: () => ({
|
|
2366
|
+
queueWaitMs,
|
|
2367
|
+
generationStartedAt,
|
|
2368
|
+
retryCount,
|
|
2369
|
+
authRefreshCount
|
|
2370
|
+
})
|
|
2371
|
+
}
|
|
2372
|
+
};
|
|
2373
|
+
}
|
|
2374
|
+
};
|
|
2375
|
+
function createCodexSubscriptionImageProvider(options) {
|
|
2376
|
+
return new CodexSubscriptionImageProvider(options);
|
|
2377
|
+
}
|
|
2378
|
+
|
|
2379
|
+
// src/image-generation/CodexImageLiveVerifier.ts
|
|
2380
|
+
import { createHash as createHash2 } from "crypto";
|
|
2381
|
+
import {
|
|
2382
|
+
ImageGenerationError as ImageGenerationError5,
|
|
2383
|
+
normalizeImageGenerationError as normalizeImageGenerationError2
|
|
2384
|
+
} from "@omnicross/core/image-generation";
|
|
2385
|
+
import { fetchUpstream as fetchUpstream2 } from "@omnicross/core/pipeline/upstreamFetch";
|
|
2386
|
+
var VERIFICATION_PROMPT = "A single solid black square.";
|
|
2387
|
+
var TESTED_REQUEST = Object.freeze({
|
|
2388
|
+
action: "generate",
|
|
2389
|
+
model: "gpt-image-2",
|
|
2390
|
+
prompt: VERIFICATION_PROMPT,
|
|
2391
|
+
n: 1,
|
|
2392
|
+
quality: "low",
|
|
2393
|
+
size: { kind: "auto" },
|
|
2394
|
+
background: "opaque",
|
|
2395
|
+
outputFormat: "png",
|
|
2396
|
+
moderation: "auto",
|
|
2397
|
+
stream: false,
|
|
2398
|
+
partialImages: 0
|
|
2399
|
+
});
|
|
2400
|
+
function traceAccountFingerprint2(accountId) {
|
|
2401
|
+
return `sha256:${createHash2("sha256").update(accountId, "utf8").digest("hex")}`;
|
|
2402
|
+
}
|
|
2403
|
+
function observation(accountId, parsed) {
|
|
2404
|
+
const responseFields = {
|
|
2405
|
+
...parsed.usage ? { usage: true } : {},
|
|
2406
|
+
...parsed.revisedPrompt ? { revisedPrompt: true } : {}
|
|
2407
|
+
};
|
|
2408
|
+
return Object.freeze({
|
|
2409
|
+
accountId,
|
|
2410
|
+
model: "gpt-image-2",
|
|
2411
|
+
request: Object.freeze({
|
|
2412
|
+
action: "generate",
|
|
2413
|
+
n: 1,
|
|
2414
|
+
quality: "low",
|
|
2415
|
+
size: "auto",
|
|
2416
|
+
background: "opaque",
|
|
2417
|
+
outputFormat: "png",
|
|
2418
|
+
moderation: "auto",
|
|
2419
|
+
stream: false,
|
|
2420
|
+
partialImages: 0
|
|
2421
|
+
}),
|
|
2422
|
+
...Object.keys(responseFields).length > 0 ? { responseFields: Object.freeze(responseFields) } : {}
|
|
2423
|
+
});
|
|
2424
|
+
}
|
|
2425
|
+
var DefaultCodexImageLiveVerifier = class {
|
|
2426
|
+
#auth;
|
|
2427
|
+
#generationTimeoutMs;
|
|
2428
|
+
constructor(options) {
|
|
2429
|
+
if (!Number.isSafeInteger(options.generationTimeoutMs ?? 18e4) || (options.generationTimeoutMs ?? 18e4) <= 0) {
|
|
2430
|
+
throw new TypeError("Codex image live verification timeout must be positive");
|
|
2431
|
+
}
|
|
2432
|
+
this.#auth = options.authStrategy;
|
|
2433
|
+
this.#generationTimeoutMs = options.generationTimeoutMs ?? 18e4;
|
|
2434
|
+
}
|
|
2435
|
+
async verify(request) {
|
|
2436
|
+
if (request.signal.aborted) {
|
|
2437
|
+
throw new ImageGenerationError5("request_cancelled", { cause: request.signal.reason });
|
|
2438
|
+
}
|
|
2439
|
+
if (this.#auth.providerId !== "codex") {
|
|
2440
|
+
throw new ImageGenerationError5("upstream_auth_required");
|
|
2441
|
+
}
|
|
2442
|
+
const controller = new AbortController();
|
|
2443
|
+
const onCallerAbort = () => controller.abort(request.signal.reason);
|
|
2444
|
+
request.signal.addEventListener("abort", onCallerAbort, { once: true });
|
|
2445
|
+
const timeout = setTimeout(() => {
|
|
2446
|
+
controller.abort(new ImageGenerationError5("image_generation_timeout"));
|
|
2447
|
+
}, this.#generationTimeoutMs);
|
|
2448
|
+
timeout.unref();
|
|
2449
|
+
const headers = {};
|
|
2450
|
+
applyCandidateCodexImageHeaders(headers);
|
|
2451
|
+
let accountId;
|
|
2452
|
+
let parsed;
|
|
2453
|
+
let parsedEdit;
|
|
2454
|
+
try {
|
|
2455
|
+
await this.#auth.applyHeaders(headers, {
|
|
2456
|
+
upstreamUrl: CANDIDATE_CODEX_IMAGE_URL,
|
|
2457
|
+
resolvedModel: CANDIDATE_CODEX_IMAGE_CARRIER_MODEL,
|
|
2458
|
+
sessionKey: request.sessionKey,
|
|
2459
|
+
preferredAccountId: request.preferredAccountId,
|
|
2460
|
+
preferredAccountGroup: request.preferredAccountGroup,
|
|
2461
|
+
boundAccountFallbackPolicy: request.boundAccountFallbackPolicy,
|
|
2462
|
+
reportSelection: (selectedAccountId) => {
|
|
2463
|
+
accountId = selectedAccountId;
|
|
2464
|
+
}
|
|
2465
|
+
});
|
|
2466
|
+
if (!accountId || !/^Bearer\s+\S+$/iu.test(headers.Authorization ?? "")) {
|
|
2467
|
+
throw new ImageGenerationError5("upstream_auth_required");
|
|
2468
|
+
}
|
|
2469
|
+
if (controller.signal.aborted) throw controller.signal.reason;
|
|
2470
|
+
const response = await fetchUpstream2(
|
|
2471
|
+
CANDIDATE_CODEX_IMAGE_URL,
|
|
2472
|
+
{
|
|
2473
|
+
method: "POST",
|
|
2474
|
+
headers: { ...headers },
|
|
2475
|
+
body: await buildCandidateCodexImageRequest(TESTED_REQUEST, controller.signal),
|
|
2476
|
+
signal: controller.signal
|
|
2477
|
+
},
|
|
2478
|
+
{
|
|
2479
|
+
providerId: "codex",
|
|
2480
|
+
accountId,
|
|
2481
|
+
traceAccountFingerprint: traceAccountFingerprint2(accountId),
|
|
2482
|
+
redactBodies: true
|
|
2483
|
+
}
|
|
2484
|
+
);
|
|
2485
|
+
const responseBody = await readCandidateCodexImageResponseBody(response);
|
|
2486
|
+
if (!response.ok) throw mapCandidateCodexImageFailure(response, responseBody);
|
|
2487
|
+
parsed = await parseCandidateCodexImageResponse(responseBody, 1, "png");
|
|
2488
|
+
if (controller.signal.aborted) throw controller.signal.reason;
|
|
2489
|
+
const editRequest = {
|
|
2490
|
+
...TESTED_REQUEST,
|
|
2491
|
+
action: "edit",
|
|
2492
|
+
images: [parsed.images[0]]
|
|
2493
|
+
};
|
|
2494
|
+
const editHeaders = { ...headers };
|
|
2495
|
+
applyCandidateCodexImageActionHeaders(editHeaders, "edit");
|
|
2496
|
+
const editResponse = await fetchUpstream2(
|
|
2497
|
+
candidateCodexImageUrl("edit"),
|
|
2498
|
+
{
|
|
2499
|
+
method: "POST",
|
|
2500
|
+
headers: editHeaders,
|
|
2501
|
+
body: await buildCandidateCodexImageRequest(editRequest, controller.signal),
|
|
2502
|
+
signal: controller.signal
|
|
2503
|
+
},
|
|
2504
|
+
{
|
|
2505
|
+
providerId: "codex",
|
|
2506
|
+
accountId,
|
|
2507
|
+
traceAccountFingerprint: traceAccountFingerprint2(accountId),
|
|
2508
|
+
redactBodies: true
|
|
2509
|
+
}
|
|
2510
|
+
);
|
|
2511
|
+
const editResponseBody = await readCandidateCodexImageResponseBody(editResponse);
|
|
2512
|
+
if (!editResponse.ok) throw mapCandidateCodexImageFailure(editResponse, editResponseBody);
|
|
2513
|
+
parsedEdit = await parseCandidateCodexImageResponse(editResponseBody, 1, "png");
|
|
2514
|
+
if (controller.signal.aborted) throw controller.signal.reason;
|
|
2515
|
+
return observation(accountId, parsed);
|
|
2516
|
+
} catch (cause) {
|
|
2517
|
+
if (controller.signal.aborted) {
|
|
2518
|
+
throw controller.signal.reason instanceof ImageGenerationError5 ? controller.signal.reason : new ImageGenerationError5("request_cancelled", { cause: controller.signal.reason });
|
|
2519
|
+
}
|
|
2520
|
+
throw normalizeImageGenerationError2(cause, "image_generation_failed", {
|
|
2521
|
+
retrySafety: "before_acceptance"
|
|
2522
|
+
});
|
|
2523
|
+
} finally {
|
|
2524
|
+
disposeCandidateCodexImageResponse(parsed);
|
|
2525
|
+
disposeCandidateCodexImageResponse(parsedEdit);
|
|
2526
|
+
headers.Authorization = "";
|
|
2527
|
+
accountId = void 0;
|
|
2528
|
+
clearTimeout(timeout);
|
|
2529
|
+
request.signal.removeEventListener("abort", onCallerAbort);
|
|
2530
|
+
}
|
|
2531
|
+
}
|
|
2532
|
+
};
|
|
2533
|
+
function createCodexImageLiveVerifier(options) {
|
|
2534
|
+
return new DefaultCodexImageLiveVerifier(options);
|
|
2535
|
+
}
|
|
1666
2536
|
export {
|
|
1667
2537
|
DEFAULT_ACCOUNT_PRIORITY,
|
|
1668
2538
|
LAST_USED_PERSIST_THROTTLE_MS,
|
|
@@ -1673,6 +2543,8 @@ export {
|
|
|
1673
2543
|
SubscriptionProviderRegistry,
|
|
1674
2544
|
claude_exports as claudeOAuth,
|
|
1675
2545
|
codex_exports as codexOAuth,
|
|
2546
|
+
createCodexImageLiveVerifier,
|
|
2547
|
+
createCodexSubscriptionImageProvider,
|
|
1676
2548
|
gemini_exports as geminiOAuth,
|
|
1677
2549
|
getSubscriptionAccountService,
|
|
1678
2550
|
getSubscriptionProviderRegistry,
|