@eddyskywalker/dsh-chatgpt-subscription 0.40.0 → 0.40.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/CHANGELOG.md +40 -0
- package/README.md +1 -1
- package/lib/client.js.map +1 -1
- package/lib/index.js +1662 -318
- package/lib/types/compat.d.ts +9 -1
- package/lib/types/compat.d.ts.map +1 -1
- package/lib/types/host/antigravity/adapter.d.ts.map +1 -1
- package/lib/types/host/antigravity/mapper.d.ts.map +1 -1
- package/lib/types/host/cline-pass/adapter.d.ts +2 -0
- package/lib/types/host/cline-pass/adapter.d.ts.map +1 -1
- package/lib/types/host/common/request-images.d.ts +15 -5
- package/lib/types/host/common/request-images.d.ts.map +1 -1
- package/lib/types/host/kimi-code/adapter.d.ts +143 -0
- package/lib/types/host/kimi-code/adapter.d.ts.map +1 -1
- package/lib/types/host/kimi-code/mapper.d.ts +166 -1
- package/lib/types/host/kimi-code/mapper.d.ts.map +1 -1
- package/lib/types/host/kimi-code/media-files.d.ts +232 -0
- package/lib/types/host/kimi-code/media-files.d.ts.map +1 -0
- package/lib/types/host/subagent-model-authorization.d.ts.map +1 -1
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -133,7 +133,15 @@ const OAUTH_DEVICE_GRANT_LIFETIME_MS = 15 * 6e4;
|
|
|
133
133
|
const OAUTH_DEVICE_MIN_POLL_INTERVAL_MS = 1e3;
|
|
134
134
|
const TOKEN_REFRESH_MARGIN_MS = 6e4;
|
|
135
135
|
const ROUTE_PREFIX$4 = "/api/dsh-chatgpt-subscription";
|
|
136
|
-
|
|
136
|
+
/**
|
|
137
|
+
* Version this line presents to the Codex backend in its `user-agent`.
|
|
138
|
+
*
|
|
139
|
+
* It must equal `package.json`'s version: a stale value here reports a plugin
|
|
140
|
+
* version that no release ever shipped, and nothing else in the build notices.
|
|
141
|
+
* `test/responses-client.test.ts` asserts the two agree, so a release that
|
|
142
|
+
* forgets this constant fails the suite instead of shipping quietly.
|
|
143
|
+
*/
|
|
144
|
+
const PLUGIN_VERSION = "0.40.2";
|
|
137
145
|
const CODEX_CHATGPT_PROVIDER_ID = "codex-chatgpt";
|
|
138
146
|
const CODEX_API_BASE = "https://chatgpt.com/backend-api/codex";
|
|
139
147
|
const CODEX_RESPONSES_URL = `${CODEX_API_BASE}/responses`;
|
|
@@ -3427,7 +3435,7 @@ var OAuthService = class {
|
|
|
3427
3435
|
throw new OAuthServiceError("oauth-token-exchange-failed", `The ChatGPT device code could not be issued (${response.status}${detail === null ? "" : `, ${detail}`}).`, response.status);
|
|
3428
3436
|
}
|
|
3429
3437
|
const payload = await response.json().catch(() => null);
|
|
3430
|
-
const record = isRecord$
|
|
3438
|
+
const record = isRecord$50(payload) ? payload : {};
|
|
3431
3439
|
const authId = nonEmptyString$10(record.device_auth_id);
|
|
3432
3440
|
const userCode = nonEmptyString$10(record.user_code) ?? nonEmptyString$10(record.usercode);
|
|
3433
3441
|
if (authId === void 0 || userCode === void 0) throw new OAuthServiceError("oauth-token-exchange-failed", "ChatGPT returned no device code.");
|
|
@@ -3494,7 +3502,7 @@ var OAuthService = class {
|
|
|
3494
3502
|
const detail = deviceErrorIdentifier(payload);
|
|
3495
3503
|
throw new OAuthServiceError("oauth-token-exchange-failed", `The ChatGPT device confirmation was refused (${response.status}${detail === void 0 ? "" : `, ${detail}`}).`, response.status);
|
|
3496
3504
|
}
|
|
3497
|
-
const record = isRecord$
|
|
3505
|
+
const record = isRecord$50(payload) ? payload : {};
|
|
3498
3506
|
const authorizationCode = nonEmptyString$10(record.authorization_code);
|
|
3499
3507
|
const codeVerifier = nonEmptyString$10(record.code_verifier);
|
|
3500
3508
|
if (authorizationCode === void 0 || codeVerifier === void 0) throw new OAuthServiceError("oauth-token-exchange-failed", "ChatGPT confirmed the device code but returned no authorization code.");
|
|
@@ -3841,11 +3849,11 @@ const DEVICE_PENDING_STATUSES = /* @__PURE__ */ new Set([
|
|
|
3841
3849
|
function isPendingDeviceAnswer(response, payload) {
|
|
3842
3850
|
if (response.status === 403 || response.status === 404) return true;
|
|
3843
3851
|
if (!response.ok && response.status !== 400) return false;
|
|
3844
|
-
if (!isRecord$
|
|
3852
|
+
if (!isRecord$50(payload)) return false;
|
|
3845
3853
|
const status = payload.status;
|
|
3846
3854
|
if (typeof status === "string" && DEVICE_PENDING_STATUSES.has(status.toLowerCase())) return true;
|
|
3847
3855
|
const error = payload.error;
|
|
3848
|
-
if (isRecord$
|
|
3856
|
+
if (isRecord$50(error)) {
|
|
3849
3857
|
const code = error.code;
|
|
3850
3858
|
if (typeof code === "string" && DEVICE_PENDING_STATUSES.has(code.toLowerCase())) return true;
|
|
3851
3859
|
}
|
|
@@ -3859,18 +3867,18 @@ function isPendingDeviceAnswer(response, payload) {
|
|
|
3859
3867
|
* wrong.
|
|
3860
3868
|
*/
|
|
3861
3869
|
function deviceErrorIdentifier(payload) {
|
|
3862
|
-
if (!isRecord$
|
|
3870
|
+
if (!isRecord$50(payload)) return void 0;
|
|
3863
3871
|
const candidates = [payload.code];
|
|
3864
3872
|
const error = payload.error;
|
|
3865
3873
|
if (typeof error === "string") candidates.push(error);
|
|
3866
|
-
else if (isRecord$
|
|
3874
|
+
else if (isRecord$50(error)) candidates.push(error.code, error.type);
|
|
3867
3875
|
candidates.push(payload.status);
|
|
3868
3876
|
for (const candidate of candidates) if (typeof candidate === "string" && /^[a-z0-9_.-]{1,64}$/i.test(candidate)) return candidate;
|
|
3869
3877
|
}
|
|
3870
3878
|
function nonEmptyString$10(value) {
|
|
3871
3879
|
return typeof value === "string" && value !== "" ? value : void 0;
|
|
3872
3880
|
}
|
|
3873
|
-
function isRecord$
|
|
3881
|
+
function isRecord$50(value) {
|
|
3874
3882
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3875
3883
|
}
|
|
3876
3884
|
async function oauthErrorIdentifier(response) {
|
|
@@ -4053,7 +4061,7 @@ const CODEX_AUTH_CLAIMS_KEY = "https://api.openai.com/auth";
|
|
|
4053
4061
|
* here, and the import has to be repeated afterwards.
|
|
4054
4062
|
*/
|
|
4055
4063
|
const ADOPTED_CODEX_CREDENTIAL_EXPIRED_HINT = "The sign-in imported from the Codex CLI has expired. Sign in again in the Codex CLI, then import it again from this settings card.";
|
|
4056
|
-
function isRecord$
|
|
4064
|
+
function isRecord$49(value) {
|
|
4057
4065
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4058
4066
|
}
|
|
4059
4067
|
/** A trimmed, non-empty string, or nothing. */
|
|
@@ -4155,7 +4163,7 @@ function decodeJwtClaims$1(token) {
|
|
|
4155
4163
|
if (parts.length !== 3) return void 0;
|
|
4156
4164
|
try {
|
|
4157
4165
|
const value = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8"));
|
|
4158
|
-
return isRecord$
|
|
4166
|
+
return isRecord$49(value) ? value : void 0;
|
|
4159
4167
|
} catch {
|
|
4160
4168
|
return;
|
|
4161
4169
|
}
|
|
@@ -4200,10 +4208,10 @@ function expiryFromAccessToken(accessToken) {
|
|
|
4200
4208
|
* the file carries cannot reach the result.
|
|
4201
4209
|
*/
|
|
4202
4210
|
function parseAdoptedCodexCredential(value, sourcePath) {
|
|
4203
|
-
if (!isRecord$
|
|
4211
|
+
if (!isRecord$49(value)) return void 0;
|
|
4204
4212
|
if (value.auth_mode !== "chatgpt") return void 0;
|
|
4205
4213
|
const tokens = value[CODEX_CLI_TOKENS_KEY];
|
|
4206
|
-
if (!isRecord$
|
|
4214
|
+
if (!isRecord$49(tokens)) return void 0;
|
|
4207
4215
|
const accessToken = nonEmptyString$9(tokens.access_token);
|
|
4208
4216
|
if (accessToken === void 0) return void 0;
|
|
4209
4217
|
const refreshToken = nonEmptyString$9(tokens.refresh_token);
|
|
@@ -4222,7 +4230,7 @@ function parseAdoptedCodexCredential(value, sourcePath) {
|
|
|
4222
4230
|
const email = claims === void 0 ? void 0 : nonEmptyString$9(claims.email);
|
|
4223
4231
|
if (email !== void 0) credentials.email = email;
|
|
4224
4232
|
const authClaims = claims === void 0 ? void 0 : claims[CODEX_AUTH_CLAIMS_KEY];
|
|
4225
|
-
const planType = isRecord$
|
|
4233
|
+
const planType = isRecord$49(authClaims) ? nonEmptyString$9(authClaims.chatgpt_plan_type) : void 0;
|
|
4226
4234
|
if (planType !== void 0) credentials.planType = planType;
|
|
4227
4235
|
}
|
|
4228
4236
|
const accountId = nonEmptyString$9(tokens.account_id);
|
|
@@ -4991,13 +4999,13 @@ function webServerOrigin(server) {
|
|
|
4991
4999
|
//#region src/host/common/llm-compat.ts
|
|
4992
5000
|
/** This package's kind in the harness message-source map. */
|
|
4993
5001
|
const PLUGIN_MESSAGE_SOURCE_KIND = "dsh-chatgpt-subscription";
|
|
4994
|
-
function isRecord$
|
|
5002
|
+
function isRecord$48(value) {
|
|
4995
5003
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4996
5004
|
}
|
|
4997
5005
|
/** Read a message body's blocks, keeping every entry that carries a block tag. */
|
|
4998
5006
|
function readBlocks(raw) {
|
|
4999
5007
|
if (!Array.isArray(raw)) return [];
|
|
5000
|
-
return raw.filter((block) => isRecord$
|
|
5008
|
+
return raw.filter((block) => isRecord$48(block) && typeof block.type === "string");
|
|
5001
5009
|
}
|
|
5002
5010
|
/**
|
|
5003
5011
|
* Normalize one harness message list into {@link Message}.
|
|
@@ -5012,10 +5020,10 @@ function readBlocks(raw) {
|
|
|
5012
5020
|
function normalizeMessages(messages) {
|
|
5013
5021
|
const normalized = [];
|
|
5014
5022
|
for (const raw of messages ?? []) {
|
|
5015
|
-
if (!isRecord$
|
|
5023
|
+
if (!isRecord$48(raw)) continue;
|
|
5016
5024
|
const content = readBlocks(raw.content);
|
|
5017
5025
|
if (raw.role === "tool") {
|
|
5018
|
-
const source = isRecord$
|
|
5026
|
+
const source = isRecord$48(raw.source) ? raw.source : void 0;
|
|
5019
5027
|
const callId = String(raw.toolCallId ?? source?.callId ?? "");
|
|
5020
5028
|
normalized.push({
|
|
5021
5029
|
id: raw.id,
|
|
@@ -5037,7 +5045,7 @@ function normalizeMessages(messages) {
|
|
|
5037
5045
|
id: raw.id,
|
|
5038
5046
|
role: typeof raw.role === "string" ? raw.role : "user",
|
|
5039
5047
|
content,
|
|
5040
|
-
...isRecord$
|
|
5048
|
+
...isRecord$48(raw.source) ? { source: raw.source } : {}
|
|
5041
5049
|
});
|
|
5042
5050
|
}
|
|
5043
5051
|
return normalized;
|
|
@@ -6741,7 +6749,7 @@ const schemaFields = /* @__PURE__ */ new Set([
|
|
|
6741
6749
|
"required",
|
|
6742
6750
|
"propertyOrdering"
|
|
6743
6751
|
]);
|
|
6744
|
-
function isRecord$
|
|
6752
|
+
function isRecord$47(value) {
|
|
6745
6753
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6746
6754
|
}
|
|
6747
6755
|
function mergeSchemas(left, right) {
|
|
@@ -6749,7 +6757,7 @@ function mergeSchemas(left, right) {
|
|
|
6749
6757
|
...left,
|
|
6750
6758
|
...right
|
|
6751
6759
|
};
|
|
6752
|
-
if (isRecord$
|
|
6760
|
+
if (isRecord$47(left.properties) && isRecord$47(right.properties)) merged.properties = {
|
|
6753
6761
|
...left.properties,
|
|
6754
6762
|
...right.properties
|
|
6755
6763
|
};
|
|
@@ -6785,9 +6793,9 @@ const mergedTypeKeys = /* @__PURE__ */ new Set([
|
|
|
6785
6793
|
* model with strictly less than the schema it started from.
|
|
6786
6794
|
*/
|
|
6787
6795
|
function describeBranch(branch) {
|
|
6788
|
-
const type = typeof branch.type === "string" ? branch.type : isRecord$
|
|
6796
|
+
const type = typeof branch.type === "string" ? branch.type : isRecord$47(branch.properties) ? "object" : isRecord$47(branch.items) ? "array" : "value";
|
|
6789
6797
|
const details = [];
|
|
6790
|
-
if (isRecord$
|
|
6798
|
+
if (isRecord$47(branch.properties)) {
|
|
6791
6799
|
const names = Object.keys(branch.properties);
|
|
6792
6800
|
if (names.length > 0) details.push(`{${names.join(",")}}`);
|
|
6793
6801
|
}
|
|
@@ -6801,7 +6809,7 @@ function describeBranch(branch) {
|
|
|
6801
6809
|
}
|
|
6802
6810
|
/** How well one branch can stand in for a whole union; a named object shape wins. */
|
|
6803
6811
|
function branchRank(branch) {
|
|
6804
|
-
if (isRecord$
|
|
6812
|
+
if (isRecord$47(branch.properties)) return 3;
|
|
6805
6813
|
if (branch.type === "object") return 2;
|
|
6806
6814
|
if (branch.type === "array") return 1;
|
|
6807
6815
|
return 0;
|
|
@@ -6830,7 +6838,7 @@ function unionShape(branches) {
|
|
|
6830
6838
|
shape: branches[0],
|
|
6831
6839
|
folded: false
|
|
6832
6840
|
};
|
|
6833
|
-
if (new Set(branches.map((branch) => branch.type)).size === 1 && branches.every((branch) => !isRecord$
|
|
6841
|
+
if (new Set(branches.map((branch) => branch.type)).size === 1 && branches.every((branch) => !isRecord$47(branch.properties) && !isRecord$47(branch.items))) {
|
|
6834
6842
|
const shape = { type: branches[0].type };
|
|
6835
6843
|
if (branches.every((branch) => Array.isArray(branch.enum))) {
|
|
6836
6844
|
const values = [...new Set(branches.flatMap((branch) => branch.enum))];
|
|
@@ -6867,7 +6875,7 @@ function foldOwnFields(node) {
|
|
|
6867
6875
|
const out = {};
|
|
6868
6876
|
for (const [key, value] of Object.entries(node)) {
|
|
6869
6877
|
if (key === "anyOf" || key === "oneOf" || key === "allOf") continue;
|
|
6870
|
-
if (key === "properties" && isRecord$
|
|
6878
|
+
if (key === "properties" && isRecord$47(value)) {
|
|
6871
6879
|
out.properties = Object.fromEntries(Object.entries(value).map(([name, child]) => [name, foldSchemaUnions(child)]));
|
|
6872
6880
|
continue;
|
|
6873
6881
|
}
|
|
@@ -6896,15 +6904,15 @@ function foldOwnFields(node) {
|
|
|
6896
6904
|
* argument the model sends anyway fails there, naming the actual problem.
|
|
6897
6905
|
*/
|
|
6898
6906
|
function foldSchemaUnions(node) {
|
|
6899
|
-
if (!isRecord$
|
|
6907
|
+
if (!isRecord$47(node)) return node;
|
|
6900
6908
|
let own = foldOwnFields(node);
|
|
6901
6909
|
if (Array.isArray(node.allOf)) for (const branch of node.allOf) {
|
|
6902
6910
|
const folded = foldSchemaUnions(branch);
|
|
6903
|
-
if (isRecord$
|
|
6911
|
+
if (isRecord$47(folded)) own = mergeSchemas(own, folded);
|
|
6904
6912
|
}
|
|
6905
6913
|
const alternatives = Array.isArray(node.anyOf) ? node.anyOf : Array.isArray(node.oneOf) ? node.oneOf : [];
|
|
6906
6914
|
if (alternatives.length === 0) return own;
|
|
6907
|
-
const branches = alternatives.map((branch) => foldSchemaUnions(branch)).filter(isRecord$
|
|
6915
|
+
const branches = alternatives.map((branch) => foldSchemaUnions(branch)).filter(isRecord$47);
|
|
6908
6916
|
if (branches.length === 0) return own;
|
|
6909
6917
|
const shapes = branches.filter((branch) => branch.type !== "null");
|
|
6910
6918
|
const acceptsNull = branches.some((branch) => branch.type === "null");
|
|
@@ -6920,7 +6928,7 @@ function foldSchemaUnions(node) {
|
|
|
6920
6928
|
return merged;
|
|
6921
6929
|
}
|
|
6922
6930
|
function toAntigravityToolSchema(schema, options = {}) {
|
|
6923
|
-
if (!isRecord$
|
|
6931
|
+
if (!isRecord$47(schema)) return schema;
|
|
6924
6932
|
const root = schema;
|
|
6925
6933
|
function resolveReference(reference) {
|
|
6926
6934
|
let target = root;
|
|
@@ -6928,13 +6936,13 @@ function toAntigravityToolSchema(schema, options = {}) {
|
|
|
6928
6936
|
const path = reference === "#" ? [] : reference.slice(2).split("/");
|
|
6929
6937
|
for (const segment of path) {
|
|
6930
6938
|
const key = segment.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
6931
|
-
target = isRecord$
|
|
6939
|
+
target = isRecord$47(target) && Object.hasOwn(target, key) ? target[key] : void 0;
|
|
6932
6940
|
}
|
|
6933
|
-
if (!isRecord$
|
|
6941
|
+
if (!isRecord$47(target)) throw new LlmError(`Antigravity tool schema reference was not found: ${reference}`, "PROVIDER_ERROR");
|
|
6934
6942
|
return target;
|
|
6935
6943
|
}
|
|
6936
6944
|
function convert(node, references) {
|
|
6937
|
-
if (!isRecord$
|
|
6945
|
+
if (!isRecord$47(node)) return {};
|
|
6938
6946
|
let inherited = {};
|
|
6939
6947
|
if (typeof node.$ref === "string") {
|
|
6940
6948
|
if (references.has(node.$ref)) throw new LlmError(`Antigravity tool schema contains a recursive reference: ${node.$ref}`, "PROVIDER_ERROR");
|
|
@@ -6943,8 +6951,8 @@ function toAntigravityToolSchema(schema, options = {}) {
|
|
|
6943
6951
|
if (Array.isArray(node.allOf)) for (const branch of node.allOf) inherited = mergeSchemas(inherited, convert(branch, references));
|
|
6944
6952
|
const out = {};
|
|
6945
6953
|
for (const [key, value] of Object.entries(node)) if (schemaFields.has(key)) out[key] = value;
|
|
6946
|
-
if (isRecord$
|
|
6947
|
-
if (isRecord$
|
|
6954
|
+
if (isRecord$47(node.properties)) out.properties = Object.fromEntries(Object.entries(node.properties).map(([name, child]) => [name, convert(child, references)]));
|
|
6955
|
+
if (isRecord$47(node.items)) out.items = convert(node.items, references);
|
|
6948
6956
|
const alternatives = Array.isArray(node.anyOf) ? node.anyOf : node.oneOf;
|
|
6949
6957
|
if (Array.isArray(alternatives)) out.anyOf = alternatives.map((child) => convert(child, references));
|
|
6950
6958
|
if (Array.isArray(node.type)) {
|
|
@@ -6980,7 +6988,7 @@ let toolCallCounter = 0;
|
|
|
6980
6988
|
function sanitizeText$8(text) {
|
|
6981
6989
|
return text.replace(/\0/g, "");
|
|
6982
6990
|
}
|
|
6983
|
-
function isRecord$
|
|
6991
|
+
function isRecord$46(value) {
|
|
6984
6992
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6985
6993
|
}
|
|
6986
6994
|
function asString$24(value) {
|
|
@@ -7000,25 +7008,25 @@ function toolCallIdNeeded(modelId, runtimeModel) {
|
|
|
7000
7008
|
return modelId.startsWith("claude-") || modelId.startsWith("gpt-oss-") || runtimeModel.startsWith("claude-") || runtimeModel.startsWith("gpt-oss-");
|
|
7001
7009
|
}
|
|
7002
7010
|
function parseArguments$2(raw) {
|
|
7003
|
-
if (isRecord$
|
|
7011
|
+
if (isRecord$46(raw)) return raw;
|
|
7004
7012
|
if (raw === void 0 || raw === null || raw === "") return {};
|
|
7005
7013
|
const parsed = typeof raw === "string" ? safeJsonParse$8(raw) : raw;
|
|
7006
|
-
return isRecord$
|
|
7014
|
+
return isRecord$46(parsed) ? parsed : {};
|
|
7007
7015
|
}
|
|
7008
7016
|
const NO_RESOLVED_IMAGES$5 = /* @__PURE__ */ new Map();
|
|
7009
7017
|
function attachmentOf$5(block) {
|
|
7010
7018
|
const attachment = block.attachment;
|
|
7011
|
-
if (!isRecord$
|
|
7019
|
+
if (!isRecord$46(attachment)) return void 0;
|
|
7012
7020
|
return typeof attachment.attachmentId === "string" ? attachment : void 0;
|
|
7013
7021
|
}
|
|
7014
7022
|
function attachmentLabel$6(block) {
|
|
7015
|
-
const attachment = isRecord$
|
|
7023
|
+
const attachment = isRecord$46(block.attachment) ? block.attachment : void 0;
|
|
7016
7024
|
return asString$24(attachment?.name) || asString$24(attachment?.attachmentId);
|
|
7017
7025
|
}
|
|
7018
7026
|
function collectImageRefs$3(content, refs) {
|
|
7019
7027
|
if (!Array.isArray(content)) return;
|
|
7020
7028
|
for (const block of content) {
|
|
7021
|
-
if (!isRecord$
|
|
7029
|
+
if (!isRecord$46(block)) continue;
|
|
7022
7030
|
if (block.type === "image") {
|
|
7023
7031
|
const attachment = attachmentOf$5(block);
|
|
7024
7032
|
if (attachment) refs.set(attachment.attachmentId, attachment);
|
|
@@ -7131,7 +7139,7 @@ function requestImageBytes$2(block) {
|
|
|
7131
7139
|
function collectRequestImageBytes$2(content, lengths) {
|
|
7132
7140
|
if (!Array.isArray(content)) return;
|
|
7133
7141
|
for (const block of content) {
|
|
7134
|
-
if (!isRecord$
|
|
7142
|
+
if (!isRecord$46(block)) continue;
|
|
7135
7143
|
if (block.type === "tool-result") {
|
|
7136
7144
|
collectRequestImageBytes$2(block.content, lengths);
|
|
7137
7145
|
continue;
|
|
@@ -7181,7 +7189,7 @@ function offloadOldestRequestImages$3(options) {
|
|
|
7181
7189
|
let replaced = false;
|
|
7182
7190
|
return {
|
|
7183
7191
|
content: content.map((block) => {
|
|
7184
|
-
if (remaining.count === 0 || !isRecord$
|
|
7192
|
+
if (remaining.count === 0 || !isRecord$46(block)) return block;
|
|
7185
7193
|
if (block.type === "image") {
|
|
7186
7194
|
if (requestImageBytes$2(block) === void 0) return block;
|
|
7187
7195
|
remaining.count -= 1;
|
|
@@ -7284,7 +7292,7 @@ function unavailableImageText$6(block) {
|
|
|
7284
7292
|
}
|
|
7285
7293
|
function imageBlockToPart(block, images) {
|
|
7286
7294
|
let data = asString$24(block.data) || asString$24(block.base64);
|
|
7287
|
-
const source = isRecord$
|
|
7295
|
+
const source = isRecord$46(block.source) ? block.source : void 0;
|
|
7288
7296
|
if (!data && source) data = asString$24(source.data) || asString$24(source.base64);
|
|
7289
7297
|
let mimeType = asString$24(block.mimeType) || asString$24(block.mediaType) || (source ? asString$24(source.mimeType) || asString$24(source.mediaType) : void 0) || "image/png";
|
|
7290
7298
|
if (data?.startsWith("data:")) {
|
|
@@ -7309,8 +7317,8 @@ function contentToUserParts(content, images) {
|
|
|
7309
7317
|
if (typeof content === "string") return [{ text: sanitizeText$8(content) }];
|
|
7310
7318
|
if (!Array.isArray(content)) return [];
|
|
7311
7319
|
const parts = [];
|
|
7312
|
-
for (const block of content) if (isRecord$
|
|
7313
|
-
else if (isRecord$
|
|
7320
|
+
for (const block of content) if (isRecord$46(block) && block.type === "text" && typeof block.text === "string") parts.push({ text: sanitizeText$8(block.text) });
|
|
7321
|
+
else if (isRecord$46(block) && block.type === "image") {
|
|
7314
7322
|
const img = imageBlockToPart(block, images);
|
|
7315
7323
|
parts.push(img ?? { text: unavailableImageText$6(block) });
|
|
7316
7324
|
}
|
|
@@ -7325,7 +7333,7 @@ function toolResultImageParts(blocks, images) {
|
|
|
7325
7333
|
if (!Array.isArray(blocks)) return [];
|
|
7326
7334
|
const parts = [];
|
|
7327
7335
|
for (const block of blocks) {
|
|
7328
|
-
if (!isRecord$
|
|
7336
|
+
if (!isRecord$46(block)) continue;
|
|
7329
7337
|
if (block.type === "image") {
|
|
7330
7338
|
parts.push(imageBlockToPart(block, images) ?? { text: unavailableImageText$6(block) });
|
|
7331
7339
|
continue;
|
|
@@ -7337,7 +7345,7 @@ function toolResultImageParts(blocks, images) {
|
|
|
7337
7345
|
function toolResultText$8(blocks) {
|
|
7338
7346
|
if (!Array.isArray(blocks)) return "";
|
|
7339
7347
|
return blocks.map((block) => {
|
|
7340
|
-
if (!isRecord$
|
|
7348
|
+
if (!isRecord$46(block)) return "";
|
|
7341
7349
|
if (block.type === "text" && typeof block.text === "string") return sanitizeText$8(block.text);
|
|
7342
7350
|
if (block.type === "tool-result") return toolResultText$8(block.content);
|
|
7343
7351
|
if (block.type === "image") {
|
|
@@ -7351,9 +7359,9 @@ function replayBlockFor$1(message, index) {
|
|
|
7351
7359
|
const source = message.source;
|
|
7352
7360
|
if (!source || source.kind !== "model" || source.provider !== "antigravity") return void 0;
|
|
7353
7361
|
const state = source.replayState;
|
|
7354
|
-
if (!isRecord$
|
|
7362
|
+
if (!isRecord$46(state)) return void 0;
|
|
7355
7363
|
if (Array.isArray(state.blocks)) return state.blocks[index];
|
|
7356
|
-
const resp = isRecord$
|
|
7364
|
+
const resp = isRecord$46(state.response) ? state.response : void 0;
|
|
7357
7365
|
if (resp) {
|
|
7358
7366
|
if (Array.isArray(resp.outputItems)) return resp.outputItems[index];
|
|
7359
7367
|
if (Array.isArray(resp.blocks)) return resp.blocks[index];
|
|
@@ -7455,10 +7463,10 @@ function assistantParts(message, model, runtimeModel, toolCalls) {
|
|
|
7455
7463
|
if (!Array.isArray(message.content)) return parts;
|
|
7456
7464
|
for (let index = 0; index < message.content.length; index++) {
|
|
7457
7465
|
const block = message.content[index];
|
|
7458
|
-
if (!isRecord$
|
|
7466
|
+
if (!isRecord$46(block)) continue;
|
|
7459
7467
|
if (block.type === "reasoning" && runtimeModel.startsWith("claude-") && (message.source?.kind !== "model" || message.source.provider !== "antigravity" || !("model" in message.source) || message.source.model !== model.id)) continue;
|
|
7460
7468
|
const replay = replayBlockFor$1(message, index);
|
|
7461
|
-
const originalParts = Array.isArray(replay?.parts) ? replay.parts.filter(isRecord$
|
|
7469
|
+
const originalParts = Array.isArray(replay?.parts) ? replay.parts.filter(isRecord$46) : [];
|
|
7462
7470
|
if ((block.type === "text" || block.type === "reasoning") && originalParts.length > 0 && originalParts.every((part) => !part.functionCall) && originalParts.map((part) => asString$24(part.text) || "").join("") === sanitizeText$8(String(block.text || ""))) {
|
|
7463
7471
|
parts.push(...originalParts.map(replayPart));
|
|
7464
7472
|
continue;
|
|
@@ -7479,8 +7487,8 @@ function assistantParts(message, model, runtimeModel, toolCalls) {
|
|
|
7479
7487
|
} else if (block.type === "tool-call") {
|
|
7480
7488
|
const toolId = String(block.id || "");
|
|
7481
7489
|
const toolName = String(block.name || "");
|
|
7482
|
-
const originalCall = originalParts.find((part) => isRecord$
|
|
7483
|
-
const wireId = asString$24((isRecord$
|
|
7490
|
+
const originalCall = originalParts.find((part) => isRecord$46(part.functionCall));
|
|
7491
|
+
const wireId = asString$24((isRecord$46(originalCall?.functionCall) ? originalCall.functionCall : void 0)?.id) || (toolCallIdNeeded(model.id, runtimeModel) ? sanitizeToolCallId(toolId, toolName) : originalCall ? void 0 : toolId || void 0);
|
|
7484
7492
|
toolCalls.set(toolId, {
|
|
7485
7493
|
name: toolName,
|
|
7486
7494
|
id: wireId
|
|
@@ -7532,7 +7540,7 @@ function convertMessages(options, model, runtimeModel, images = NO_RESOLVED_IMAG
|
|
|
7532
7540
|
continue;
|
|
7533
7541
|
}
|
|
7534
7542
|
const content = Array.isArray(message.content) ? message.content : [];
|
|
7535
|
-
const userParts = contentToUserParts(content.filter((b) => !isRecord$
|
|
7543
|
+
const userParts = contentToUserParts(content.filter((b) => !isRecord$46(b) || b.type !== "tool-result"), images);
|
|
7536
7544
|
if (role === "system") {
|
|
7537
7545
|
if (userParts.length) contents.push({
|
|
7538
7546
|
role: GEMINI_ROLE.user,
|
|
@@ -7544,7 +7552,7 @@ function convertMessages(options, model, runtimeModel, images = NO_RESOLVED_IMAG
|
|
|
7544
7552
|
role: GEMINI_ROLE.user,
|
|
7545
7553
|
parts: userParts
|
|
7546
7554
|
});
|
|
7547
|
-
for (const b of content) if (isRecord$
|
|
7555
|
+
for (const b of content) if (isRecord$46(b) && b.type === "tool-result") pushToolResult(contents, b, toolCalls, model, runtimeModel, images);
|
|
7548
7556
|
}
|
|
7549
7557
|
return contents;
|
|
7550
7558
|
}
|
|
@@ -7692,7 +7700,7 @@ const USAGE_FIELDS = [
|
|
|
7692
7700
|
"totalTokenCount"
|
|
7693
7701
|
];
|
|
7694
7702
|
function collectUsage(value, state) {
|
|
7695
|
-
if (!isRecord$
|
|
7703
|
+
if (!isRecord$46(value)) return;
|
|
7696
7704
|
for (const key of USAGE_FIELDS) {
|
|
7697
7705
|
const count = value[key];
|
|
7698
7706
|
if (typeof count !== "number" || !Number.isSafeInteger(count) || count < 0) continue;
|
|
@@ -7722,17 +7730,17 @@ function processStreamLine$3(line, state) {
|
|
|
7722
7730
|
}
|
|
7723
7731
|
if (!json) return [];
|
|
7724
7732
|
const chunk = safeJsonParse$8(json);
|
|
7725
|
-
if (!isRecord$
|
|
7726
|
-
const responseData = isRecord$
|
|
7727
|
-
const error = isRecord$
|
|
7733
|
+
if (!isRecord$46(chunk)) return [];
|
|
7734
|
+
const responseData = isRecord$46(chunk.response) ? chunk.response : chunk;
|
|
7735
|
+
const error = isRecord$46(chunk.error) ? chunk.error : isRecord$46(responseData.error) ? responseData.error : void 0;
|
|
7728
7736
|
if (error !== void 0) throw new LlmError$1(`Antigravity stream error: ${asString$24(error.message) ?? "unknown error"}`, isContextOverflow(error) ? CONTEXT_OVERFLOW_CODE : "PROVIDER_ERROR");
|
|
7729
7737
|
const candidates = Array.isArray(responseData.candidates) ? responseData.candidates : [];
|
|
7730
|
-
const candidate = isRecord$
|
|
7731
|
-
const content = isRecord$
|
|
7738
|
+
const candidate = isRecord$46(candidates[0]) ? candidates[0] : void 0;
|
|
7739
|
+
const content = isRecord$46(candidate?.content) ? candidate.content : void 0;
|
|
7732
7740
|
const parts = Array.isArray(content?.parts) ? content.parts : [];
|
|
7733
7741
|
const out = [];
|
|
7734
7742
|
for (const part of parts) {
|
|
7735
|
-
if (!isRecord$
|
|
7743
|
+
if (!isRecord$46(part)) continue;
|
|
7736
7744
|
if (typeof part.text === "string" && part.text !== "") {
|
|
7737
7745
|
const isThinking = Boolean(part.thought);
|
|
7738
7746
|
const blockType = isThinking ? "reasoning" : "text";
|
|
@@ -7764,7 +7772,7 @@ function processStreamLine$3(line, state) {
|
|
|
7764
7772
|
index: state.currentBlock.index,
|
|
7765
7773
|
text: delta
|
|
7766
7774
|
});
|
|
7767
|
-
} else if (!isRecord$
|
|
7775
|
+
} else if (!isRecord$46(part.functionCall) && thoughtSignature(part)) {
|
|
7768
7776
|
if (state.replayBlocks.length === 0) {
|
|
7769
7777
|
const type = part.thought ? "reasoning" : "text";
|
|
7770
7778
|
state.blocks.push({
|
|
@@ -7788,12 +7796,12 @@ function processStreamLine$3(line, state) {
|
|
|
7788
7796
|
}
|
|
7789
7797
|
state.replayBlocks[state.replayBlocks.length - 1].parts.push(replayPart(part));
|
|
7790
7798
|
}
|
|
7791
|
-
if (isRecord$
|
|
7799
|
+
if (isRecord$46(part.functionCall)) {
|
|
7792
7800
|
out.push(...closeCurrentBlock(state));
|
|
7793
7801
|
const fc = part.functionCall;
|
|
7794
7802
|
const toolName = asString$24(fc.name) || "";
|
|
7795
7803
|
const toolId = asString$24(fc.id) || sanitizeToolCallId("", toolName);
|
|
7796
|
-
const argsText = JSON.stringify(isRecord$
|
|
7804
|
+
const argsText = JSON.stringify(isRecord$46(fc.args) ? fc.args : {});
|
|
7797
7805
|
const index = state.blocks.length;
|
|
7798
7806
|
const block = {
|
|
7799
7807
|
type: "tool-call",
|
|
@@ -7832,7 +7840,7 @@ function processStreamLine$3(line, state) {
|
|
|
7832
7840
|
if (responseData !== chunk) collectUsage(responseData.usageMetadata, state);
|
|
7833
7841
|
const finishMessage = asString$24(candidate?.finishMessage);
|
|
7834
7842
|
if (finishMessage) state.finishMessage = finishMessage;
|
|
7835
|
-
const blockReason = asString$24((isRecord$
|
|
7843
|
+
const blockReason = asString$24((isRecord$46(responseData.promptFeedback) ? responseData.promptFeedback : void 0)?.blockReason);
|
|
7836
7844
|
const finishReason = asString$24(candidate?.finishReason) || asString$24(responseData.finishReason) || (blockReason ? `PROMPT_BLOCKED:${blockReason}` : void 0);
|
|
7837
7845
|
if (finishReason) {
|
|
7838
7846
|
state.finishReason = finishReason;
|
|
@@ -7875,7 +7883,7 @@ function finishReasonFor$8(state) {
|
|
|
7875
7883
|
}
|
|
7876
7884
|
function closeStream$6(state) {
|
|
7877
7885
|
if (state.finished) return [];
|
|
7878
|
-
if (!state.finishReason && !state.done) throw new LlmError$1("Antigravity stream ended before its terminal response", "
|
|
7886
|
+
if (!state.finishReason && !state.done) throw new LlmError$1("Antigravity stream ended before its terminal response", "TRANSPORT");
|
|
7879
7887
|
state.finished = true;
|
|
7880
7888
|
const out = closeCurrentBlock(state);
|
|
7881
7889
|
if (state.usageMetadata) out.push({
|
|
@@ -8594,6 +8602,36 @@ function withoutValidatedToolConfig(body) {
|
|
|
8594
8602
|
delete parsed.request.toolConfig;
|
|
8595
8603
|
return JSON.stringify(parsed);
|
|
8596
8604
|
}
|
|
8605
|
+
/**
|
|
8606
|
+
* The failure a stream that died mid-body is reported as.
|
|
8607
|
+
*
|
|
8608
|
+
* Everything above the response body is already typed: a connection that never
|
|
8609
|
+
* produced a response raises TRANSPORT, a non-2xx raises its status verdict, and
|
|
8610
|
+
* the mapper raises its own protocol or provider one. The body itself was the
|
|
8611
|
+
* gap: a connection that ends before the response does arrives as undici's bare
|
|
8612
|
+
* `TypeError: terminated`, which carries no code of its own, so the harness
|
|
8613
|
+
* normalizes it to UNKNOWN — and UNKNOWN is not a code DSH retries, so one
|
|
8614
|
+
* severed connection ended the long answer the user was reading with no second
|
|
8615
|
+
* attempt at all. The real reason (ECONNRESET, a socket closed by the far side,
|
|
8616
|
+
* a body timeout) sat on `.cause`, which the harness drops before the failure is
|
|
8617
|
+
* persisted, so the report could not even say what had happened.
|
|
8618
|
+
*
|
|
8619
|
+
* So the transport is named here and its cause chain is kept in the message, and
|
|
8620
|
+
* only what the route already typed is left alone: an `LlmError` is this line's
|
|
8621
|
+
* own verdict (an in-band provider error, a stream truncated before its terminal
|
|
8622
|
+
* frame), and a caller abort is a cancellation rather than a fault.
|
|
8623
|
+
*
|
|
8624
|
+
* The code is TRANSPORT even once chunks have been yielded. DSH settles a failed
|
|
8625
|
+
* attempt as a discarded `assistant/attempt` and starts a fresh one on retry, and
|
|
8626
|
+
* a tool call only runs after its stream finishes, so retrying can neither
|
|
8627
|
+
* repeat committed output nor re-run a tool.
|
|
8628
|
+
*/
|
|
8629
|
+
function streamFailure$2(error, signal) {
|
|
8630
|
+
if (error instanceof LlmError) return error;
|
|
8631
|
+
if (signal.aborted) return new LlmError("Antigravity stream aborted", "ABORTED", { cause: error });
|
|
8632
|
+
const chain = errorChain(error).trim();
|
|
8633
|
+
return new LlmError(`Antigravity stream failed: ${chain === "" ? "the response stream ended unexpectedly" : chain.slice(0, 500)}`, "TRANSPORT", { cause: error });
|
|
8634
|
+
}
|
|
8597
8635
|
var AntigravityAdapter = class extends LlmAdapter {
|
|
8598
8636
|
store;
|
|
8599
8637
|
modelSettings;
|
|
@@ -8860,7 +8898,9 @@ var AntigravityAdapter = class extends LlmAdapter {
|
|
|
8860
8898
|
let buffer = "";
|
|
8861
8899
|
try {
|
|
8862
8900
|
while (true) {
|
|
8863
|
-
const { done, value } = await reader.read()
|
|
8901
|
+
const { done, value } = await reader.read().catch((error) => {
|
|
8902
|
+
throw streamFailure$2(error, signal);
|
|
8903
|
+
});
|
|
8864
8904
|
if (done) break;
|
|
8865
8905
|
if (value !== void 0 && value.byteLength > 0) activity?.pulse();
|
|
8866
8906
|
buffer += decoder.decode(value, { stream: true });
|
|
@@ -13816,7 +13856,7 @@ async function compactionCandidates(ctx) {
|
|
|
13816
13856
|
};
|
|
13817
13857
|
}))).filter((provider) => provider.models.length > 0) };
|
|
13818
13858
|
}
|
|
13819
|
-
function isRecord$
|
|
13859
|
+
function isRecord$45(value) {
|
|
13820
13860
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
13821
13861
|
}
|
|
13822
13862
|
function readPreferencesUpdate(value, current) {
|
|
@@ -13857,7 +13897,7 @@ function readPreferencesUpdate(value, current) {
|
|
|
13857
13897
|
};
|
|
13858
13898
|
}
|
|
13859
13899
|
if ("contextWindowOverrides" in value) {
|
|
13860
|
-
if (!isRecord$
|
|
13900
|
+
if (!isRecord$45(value.contextWindowOverrides)) throw new PreferenceError("contextWindowOverrides must be an object.");
|
|
13861
13901
|
const overrides = {};
|
|
13862
13902
|
for (const [model, contextWindow] of Object.entries(value.contextWindowOverrides)) {
|
|
13863
13903
|
if (!isCodexModelId(model)) throw new PreferenceError("Unknown Codex model for a context window override.");
|
|
@@ -18357,11 +18397,11 @@ function commandCodeHeaders(apiKey, extra = {}) {
|
|
|
18357
18397
|
function timeoutSignal$4(signal, ms) {
|
|
18358
18398
|
return signal ? AbortSignal.any([signal, AbortSignal.timeout(ms)]) : AbortSignal.timeout(ms);
|
|
18359
18399
|
}
|
|
18360
|
-
function isRecord$
|
|
18400
|
+
function isRecord$44(value) {
|
|
18361
18401
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
18362
18402
|
}
|
|
18363
18403
|
function asRecord$15(value) {
|
|
18364
|
-
return isRecord$
|
|
18404
|
+
return isRecord$44(value) ? value : void 0;
|
|
18365
18405
|
}
|
|
18366
18406
|
function asString$23(value) {
|
|
18367
18407
|
if (typeof value === "string" && value.trim() !== "") return value;
|
|
@@ -18374,7 +18414,7 @@ function asNumber$5(value) {
|
|
|
18374
18414
|
if (Number.isFinite(parsed)) return parsed;
|
|
18375
18415
|
}
|
|
18376
18416
|
}
|
|
18377
|
-
function firstString$
|
|
18417
|
+
function firstString$2(record, keys) {
|
|
18378
18418
|
for (const key of keys) {
|
|
18379
18419
|
const value = asString$23(record[key]);
|
|
18380
18420
|
if (value !== void 0) return value;
|
|
@@ -18405,7 +18445,7 @@ function deepValue(value, keys, depth = 0) {
|
|
|
18405
18445
|
}
|
|
18406
18446
|
return;
|
|
18407
18447
|
}
|
|
18408
|
-
if (!isRecord$
|
|
18448
|
+
if (!isRecord$44(value)) return void 0;
|
|
18409
18449
|
for (const key of keys) if (value[key] !== void 0 && value[key] !== null) return value[key];
|
|
18410
18450
|
for (const nested of Object.values(value)) {
|
|
18411
18451
|
const hit = deepValue(nested, keys, depth + 1);
|
|
@@ -18419,7 +18459,7 @@ function collectRecords(value, keys, depth = 0, out = []) {
|
|
|
18419
18459
|
for (const entry of value) collectRecords(entry, keys, depth + 1, out);
|
|
18420
18460
|
return out;
|
|
18421
18461
|
}
|
|
18422
|
-
if (!isRecord$
|
|
18462
|
+
if (!isRecord$44(value)) return out;
|
|
18423
18463
|
if (keys.some((key) => value[key] !== void 0)) out.push(value);
|
|
18424
18464
|
for (const nested of Object.values(value)) collectRecords(nested, keys, depth + 1, out);
|
|
18425
18465
|
return out;
|
|
@@ -18453,38 +18493,38 @@ function parseWhoami(payload, fallback = {}) {
|
|
|
18453
18493
|
"plan",
|
|
18454
18494
|
"tier"
|
|
18455
18495
|
])) ?? {};
|
|
18456
|
-
const email = firstString$
|
|
18496
|
+
const email = firstString$2(user, ["email", "primaryEmail"]) ?? (typeof user.email === "string" ? user.email : void 0) ?? fallback.email;
|
|
18457
18497
|
return {
|
|
18458
|
-
userId: firstString$
|
|
18498
|
+
userId: firstString$2(user, [
|
|
18459
18499
|
"id",
|
|
18460
18500
|
"userId",
|
|
18461
18501
|
"uid"
|
|
18462
|
-
]) ?? firstString$
|
|
18463
|
-
userName: firstString$
|
|
18502
|
+
]) ?? firstString$2(root, ["userId"]) ?? fallback.userId ?? null,
|
|
18503
|
+
userName: firstString$2(user, [
|
|
18464
18504
|
"userName",
|
|
18465
18505
|
"username",
|
|
18466
18506
|
"name",
|
|
18467
18507
|
"displayName",
|
|
18468
18508
|
"fullName"
|
|
18469
|
-
]) ?? firstString$
|
|
18509
|
+
]) ?? firstString$2(root, ["userName"]) ?? fallback.userName ?? null,
|
|
18470
18510
|
email: email ?? null,
|
|
18471
|
-
organizationName: firstString$
|
|
18511
|
+
organizationName: firstString$2(org, [
|
|
18472
18512
|
"name",
|
|
18473
18513
|
"displayName",
|
|
18474
18514
|
"slug"
|
|
18475
18515
|
]) ?? fallback.organizationName ?? null,
|
|
18476
|
-
keyName: firstString$
|
|
18516
|
+
keyName: firstString$2(key, [
|
|
18477
18517
|
"name",
|
|
18478
18518
|
"keyName",
|
|
18479
18519
|
"label"
|
|
18480
18520
|
]) ?? fallback.keyName ?? null,
|
|
18481
|
-
planLabel: firstString$
|
|
18521
|
+
planLabel: firstString$2(subscription, [
|
|
18482
18522
|
"name",
|
|
18483
18523
|
"displayName",
|
|
18484
18524
|
"label",
|
|
18485
18525
|
"planName"
|
|
18486
|
-
]) ?? firstString$
|
|
18487
|
-
planId: firstString$
|
|
18526
|
+
]) ?? firstString$2(data, ["planName", "planLabel"]) ?? fallback.planLabel ?? null,
|
|
18527
|
+
planId: firstString$2(subscription, [
|
|
18488
18528
|
"id",
|
|
18489
18529
|
"planId",
|
|
18490
18530
|
"slug",
|
|
@@ -18718,7 +18758,7 @@ function sweepMeters(payload, skipIds, consumed) {
|
|
|
18718
18758
|
usedFraction = Math.max(0, 1 - remainingFraction);
|
|
18719
18759
|
}
|
|
18720
18760
|
if (usedFraction === null && remainingFraction === null && limit === void 0 && balance === void 0) continue;
|
|
18721
|
-
const rawId = firstString$
|
|
18761
|
+
const rawId = firstString$2(record, [
|
|
18722
18762
|
"id",
|
|
18723
18763
|
"bucketId",
|
|
18724
18764
|
"bucket_id",
|
|
@@ -18727,7 +18767,7 @@ function sweepMeters(payload, skipIds, consumed) {
|
|
|
18727
18767
|
"type",
|
|
18728
18768
|
"key"
|
|
18729
18769
|
]);
|
|
18730
|
-
const label = firstString$
|
|
18770
|
+
const label = firstString$2(record, [
|
|
18731
18771
|
"displayName",
|
|
18732
18772
|
"display_name",
|
|
18733
18773
|
"label",
|
|
@@ -18757,7 +18797,7 @@ function sweepMeters(payload, skipIds, consumed) {
|
|
|
18757
18797
|
"periodEnd",
|
|
18758
18798
|
"renewalDate"
|
|
18759
18799
|
])),
|
|
18760
|
-
description: firstString$
|
|
18800
|
+
description: firstString$2(record, [
|
|
18761
18801
|
"description",
|
|
18762
18802
|
"detail",
|
|
18763
18803
|
"subtitle"
|
|
@@ -18828,7 +18868,7 @@ function parseUsageWindows$1(payload) {
|
|
|
18828
18868
|
"percentUsed"
|
|
18829
18869
|
]);
|
|
18830
18870
|
if (percent === void 0) continue;
|
|
18831
|
-
const id = firstString$
|
|
18871
|
+
const id = firstString$2(record, [
|
|
18832
18872
|
"id",
|
|
18833
18873
|
"bucketId",
|
|
18834
18874
|
"name",
|
|
@@ -18840,7 +18880,7 @@ function parseUsageWindows$1(payload) {
|
|
|
18840
18880
|
seen.add(id);
|
|
18841
18881
|
windows.push({
|
|
18842
18882
|
id,
|
|
18843
|
-
label: firstString$
|
|
18883
|
+
label: firstString$2(record, [
|
|
18844
18884
|
"displayName",
|
|
18845
18885
|
"label",
|
|
18846
18886
|
"name",
|
|
@@ -18916,7 +18956,7 @@ function parseProviderModels(payload) {
|
|
|
18916
18956
|
for (const entry of list) {
|
|
18917
18957
|
const record = asRecord$15(entry);
|
|
18918
18958
|
if (!record) continue;
|
|
18919
|
-
const id = firstString$
|
|
18959
|
+
const id = firstString$2(record, [
|
|
18920
18960
|
"id",
|
|
18921
18961
|
"model",
|
|
18922
18962
|
"name"
|
|
@@ -18924,7 +18964,7 @@ function parseProviderModels(payload) {
|
|
|
18924
18964
|
if (id === void 0) continue;
|
|
18925
18965
|
models.push({
|
|
18926
18966
|
id,
|
|
18927
|
-
name: firstString$
|
|
18967
|
+
name: firstString$2(record, ["displayName", "name"]) ?? id,
|
|
18928
18968
|
contextWindow: firstNumber$2(record, [
|
|
18929
18969
|
"context_length",
|
|
18930
18970
|
"contextLength",
|
|
@@ -19229,7 +19269,7 @@ function buildModelOptions$1(catalog, enabledModelIds, overrides) {
|
|
|
19229
19269
|
*
|
|
19230
19270
|
* https://commandcode.ai/blog/command-code-provider-api
|
|
19231
19271
|
*/
|
|
19232
|
-
function isRecord$
|
|
19272
|
+
function isRecord$43(value) {
|
|
19233
19273
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
19234
19274
|
}
|
|
19235
19275
|
function asString$22(value) {
|
|
@@ -19269,17 +19309,17 @@ const SUPPORTED_IMAGE_MEDIA_TYPES$4 = /* @__PURE__ */ new Set([
|
|
|
19269
19309
|
]);
|
|
19270
19310
|
function attachmentOf$4(block) {
|
|
19271
19311
|
const attachment = block.attachment;
|
|
19272
|
-
if (!isRecord$
|
|
19312
|
+
if (!isRecord$43(attachment)) return void 0;
|
|
19273
19313
|
return typeof attachment.attachmentId === "string" ? attachment : void 0;
|
|
19274
19314
|
}
|
|
19275
19315
|
function attachmentLabel$5(block) {
|
|
19276
|
-
const attachment = isRecord$
|
|
19316
|
+
const attachment = isRecord$43(block.attachment) ? block.attachment : void 0;
|
|
19277
19317
|
return asString$22(attachment?.name) || asString$22(attachment?.attachmentId);
|
|
19278
19318
|
}
|
|
19279
19319
|
function collectImageRefs$2(content, refs) {
|
|
19280
19320
|
if (!Array.isArray(content)) return;
|
|
19281
19321
|
for (const block of content) {
|
|
19282
|
-
if (!isRecord$
|
|
19322
|
+
if (!isRecord$43(block)) continue;
|
|
19283
19323
|
if (block.type === "image") {
|
|
19284
19324
|
const attachment = attachmentOf$4(block);
|
|
19285
19325
|
if (attachment) refs.set(attachment.attachmentId, attachment);
|
|
@@ -19300,7 +19340,7 @@ function requestImageBytes$1(block) {
|
|
|
19300
19340
|
function collectRequestImageBytes$1(content, lengths) {
|
|
19301
19341
|
if (!Array.isArray(content)) return;
|
|
19302
19342
|
for (const block of content) {
|
|
19303
|
-
if (!isRecord$
|
|
19343
|
+
if (!isRecord$43(block)) continue;
|
|
19304
19344
|
if (block.type === "tool-result") {
|
|
19305
19345
|
collectRequestImageBytes$1(block.content, lengths);
|
|
19306
19346
|
continue;
|
|
@@ -19336,7 +19376,7 @@ function offloadOldestRequestImages$2(options) {
|
|
|
19336
19376
|
let replaced = false;
|
|
19337
19377
|
return {
|
|
19338
19378
|
content: content.map((block) => {
|
|
19339
|
-
if (remaining.count === 0 || !isRecord$
|
|
19379
|
+
if (remaining.count === 0 || !isRecord$43(block)) return block;
|
|
19340
19380
|
if (block.type === "image") {
|
|
19341
19381
|
if (requestImageBytes$1(block) === void 0) return block;
|
|
19342
19382
|
remaining.count -= 1;
|
|
@@ -19408,7 +19448,7 @@ function unavailableImageText$5(block) {
|
|
|
19408
19448
|
}
|
|
19409
19449
|
function imageBlockToInline$3(block, images) {
|
|
19410
19450
|
let data = asString$22(block.data) || asString$22(block.base64);
|
|
19411
|
-
const source = isRecord$
|
|
19451
|
+
const source = isRecord$43(block.source) ? block.source : void 0;
|
|
19412
19452
|
if (!data && source) data = asString$22(source.data) || asString$22(source.base64);
|
|
19413
19453
|
let mediaType = asString$22(block.mimeType) || asString$22(block.mediaType) || (source ? asString$22(source.mimeType) || asString$22(source.mediaType) : void 0) || "image/png";
|
|
19414
19454
|
if (data?.startsWith("data:")) {
|
|
@@ -19434,7 +19474,7 @@ function textOf$8(content) {
|
|
|
19434
19474
|
if (!Array.isArray(content)) return "";
|
|
19435
19475
|
const parts = [];
|
|
19436
19476
|
for (const block of content) {
|
|
19437
|
-
if (!isRecord$
|
|
19477
|
+
if (!isRecord$43(block)) continue;
|
|
19438
19478
|
if (block.type === "text" && typeof block.text === "string") parts.push(sanitizeText$7(block.text));
|
|
19439
19479
|
else if (block.type === "tool-result") parts.push(textOf$8(block.content));
|
|
19440
19480
|
}
|
|
@@ -19443,7 +19483,7 @@ function textOf$8(content) {
|
|
|
19443
19483
|
function toolResultText$7(blocks) {
|
|
19444
19484
|
if (!Array.isArray(blocks)) return "";
|
|
19445
19485
|
return blocks.map((block) => {
|
|
19446
|
-
if (!isRecord$
|
|
19486
|
+
if (!isRecord$43(block)) return "";
|
|
19447
19487
|
if (block.type === "text" && typeof block.text === "string") return sanitizeText$7(block.text);
|
|
19448
19488
|
if (block.type === "tool-result") return toolResultText$7(block.content);
|
|
19449
19489
|
if (block.type === "image") return `[image: ${attachmentLabel$5(block) ?? "attached image"}]`;
|
|
@@ -19461,7 +19501,7 @@ function toolResultBlocks$2(blocks, images) {
|
|
|
19461
19501
|
const out = [];
|
|
19462
19502
|
let hasImage = false;
|
|
19463
19503
|
for (const block of blocks) {
|
|
19464
|
-
if (!isRecord$
|
|
19504
|
+
if (!isRecord$43(block)) continue;
|
|
19465
19505
|
if (block.type === "text" && typeof block.text === "string") {
|
|
19466
19506
|
out.push({
|
|
19467
19507
|
type: "text",
|
|
@@ -19510,7 +19550,7 @@ function toolResultImageBlocks$4(blocks, images) {
|
|
|
19510
19550
|
if (!Array.isArray(blocks)) return [];
|
|
19511
19551
|
const out = [];
|
|
19512
19552
|
for (const block of blocks) {
|
|
19513
|
-
if (!isRecord$
|
|
19553
|
+
if (!isRecord$43(block)) continue;
|
|
19514
19554
|
if (block.type === "image") {
|
|
19515
19555
|
const inline = imageBlockToInline$3(block, images);
|
|
19516
19556
|
if (inline && SUPPORTED_IMAGE_MEDIA_TYPES$4.has(inline.mediaType)) out.push({
|
|
@@ -19554,7 +19594,7 @@ function nonSystemMessages$7(options) {
|
|
|
19554
19594
|
}
|
|
19555
19595
|
/** Drop the JSON-Schema keywords provider gateways reject or ignore. */
|
|
19556
19596
|
function stripMetaSchema$2(schema) {
|
|
19557
|
-
if (!isRecord$
|
|
19597
|
+
if (!isRecord$43(schema)) return {
|
|
19558
19598
|
type: "object",
|
|
19559
19599
|
properties: {}
|
|
19560
19600
|
};
|
|
@@ -19571,7 +19611,7 @@ function openAIUserContent$3(message, images) {
|
|
|
19571
19611
|
const parts = [];
|
|
19572
19612
|
let hasImage = false;
|
|
19573
19613
|
for (const block of message.content) {
|
|
19574
|
-
if (!isRecord$
|
|
19614
|
+
if (!isRecord$43(block)) continue;
|
|
19575
19615
|
if (block.type === "text" && typeof block.text === "string") {
|
|
19576
19616
|
const text = sanitizeText$7(block.text);
|
|
19577
19617
|
if (text !== "") parts.push({
|
|
@@ -19599,7 +19639,7 @@ function openAIAssistantContent$3(message) {
|
|
|
19599
19639
|
const textParts = [];
|
|
19600
19640
|
const toolCalls = [];
|
|
19601
19641
|
for (const block of message.content) {
|
|
19602
|
-
if (!isRecord$
|
|
19642
|
+
if (!isRecord$43(block)) continue;
|
|
19603
19643
|
if (block.type === "text" && typeof block.text === "string") textParts.push(sanitizeText$7(block.text));
|
|
19604
19644
|
else if (block.type === "tool-call" && typeof block.name === "string") toolCalls.push({
|
|
19605
19645
|
id: typeof block.id === "string" && block.id !== "" ? block.id : `call_${toolCalls.length}`,
|
|
@@ -19631,7 +19671,7 @@ function buildOpenAIRequest$1(options, images = NO_RESOLVED_IMAGES$4) {
|
|
|
19631
19671
|
while (index < conversation.length && isToolResultMessage$7(conversation[index])) {
|
|
19632
19672
|
const current = conversation[index];
|
|
19633
19673
|
const block = current.content[0];
|
|
19634
|
-
const callId = isRecord$
|
|
19674
|
+
const callId = isRecord$43(block) && typeof block.toolCallId === "string" ? block.toolCallId : "";
|
|
19635
19675
|
messages.push({
|
|
19636
19676
|
role: "tool",
|
|
19637
19677
|
tool_call_id: callId,
|
|
@@ -19692,7 +19732,7 @@ function anthropicUserContent$3(message, images) {
|
|
|
19692
19732
|
if (!Array.isArray(message.content)) return [];
|
|
19693
19733
|
const blocks = [];
|
|
19694
19734
|
for (const block of message.content) {
|
|
19695
|
-
if (!isRecord$
|
|
19735
|
+
if (!isRecord$43(block)) continue;
|
|
19696
19736
|
if (block.type === "text" && typeof block.text === "string") {
|
|
19697
19737
|
const text = sanitizeText$7(block.text);
|
|
19698
19738
|
if (text !== "") blocks.push({
|
|
@@ -19729,7 +19769,7 @@ function anthropicUserContent$3(message, images) {
|
|
|
19729
19769
|
function anthropicAssistantContent$3(message) {
|
|
19730
19770
|
const blocks = [];
|
|
19731
19771
|
for (const block of message.content) {
|
|
19732
|
-
if (!isRecord$
|
|
19772
|
+
if (!isRecord$43(block)) continue;
|
|
19733
19773
|
if (block.type === "text" && typeof block.text === "string") {
|
|
19734
19774
|
const text = sanitizeText$7(block.text);
|
|
19735
19775
|
if (text !== "") blocks.push({
|
|
@@ -19742,7 +19782,7 @@ function anthropicAssistantContent$3(message) {
|
|
|
19742
19782
|
type: "tool_use",
|
|
19743
19783
|
id: typeof block.id === "string" && block.id !== "" ? block.id : `toolu_${blocks.length}`,
|
|
19744
19784
|
name: block.name,
|
|
19745
|
-
input: isRecord$
|
|
19785
|
+
input: isRecord$43(parsed) ? parsed : {}
|
|
19746
19786
|
});
|
|
19747
19787
|
}
|
|
19748
19788
|
}
|
|
@@ -19836,7 +19876,7 @@ function responsesUserContent(message, images) {
|
|
|
19836
19876
|
if (!Array.isArray(message.content)) return [];
|
|
19837
19877
|
const parts = [];
|
|
19838
19878
|
for (const block of message.content) {
|
|
19839
|
-
if (!isRecord$
|
|
19879
|
+
if (!isRecord$43(block)) continue;
|
|
19840
19880
|
if (block.type === "text" && typeof block.text === "string") {
|
|
19841
19881
|
const text = sanitizeText$7(block.text);
|
|
19842
19882
|
if (text !== "") parts.push({
|
|
@@ -19861,7 +19901,7 @@ function responsesToolResultImageBlocks(blocks, images) {
|
|
|
19861
19901
|
if (!Array.isArray(blocks)) return [];
|
|
19862
19902
|
const out = [];
|
|
19863
19903
|
for (const block of blocks) {
|
|
19864
|
-
if (!isRecord$
|
|
19904
|
+
if (!isRecord$43(block)) continue;
|
|
19865
19905
|
if (block.type === "image") {
|
|
19866
19906
|
const inline = imageBlockToInline$3(block, images);
|
|
19867
19907
|
if (inline && SUPPORTED_IMAGE_MEDIA_TYPES$4.has(inline.mediaType)) out.push({
|
|
@@ -19888,8 +19928,8 @@ function buildResponsesRequest(options, images = NO_RESOLVED_IMAGES$4) {
|
|
|
19888
19928
|
const imageBlocks = [];
|
|
19889
19929
|
while (index < conversation.length && isToolResultMessage$7(conversation[index])) {
|
|
19890
19930
|
const current = conversation[index];
|
|
19891
|
-
const toolResult = Array.isArray(current.content) ? current.content.find((b) => isRecord$
|
|
19892
|
-
const callId = (isRecord$
|
|
19931
|
+
const toolResult = Array.isArray(current.content) ? current.content.find((b) => isRecord$43(b) && b.type === "tool-result") : void 0;
|
|
19932
|
+
const callId = (isRecord$43(toolResult) && typeof toolResult.toolCallId === "string" ? toolResult.toolCallId : "") || (typeof current.source?.callId === "string" ? current.source.callId : "");
|
|
19893
19933
|
input.push({
|
|
19894
19934
|
type: "function_call_output",
|
|
19895
19935
|
call_id: callId,
|
|
@@ -19912,7 +19952,7 @@ function buildResponsesRequest(options, images = NO_RESOLVED_IMAGES$4) {
|
|
|
19912
19952
|
content
|
|
19913
19953
|
});
|
|
19914
19954
|
for (const call of toolCalls) {
|
|
19915
|
-
const fn = isRecord$
|
|
19955
|
+
const fn = isRecord$43(call.function) ? call.function : void 0;
|
|
19916
19956
|
input.push({
|
|
19917
19957
|
type: "function_call",
|
|
19918
19958
|
call_id: call.id,
|
|
@@ -20035,9 +20075,9 @@ function processOpenAIStreamLine$1(line, state) {
|
|
|
20035
20075
|
}
|
|
20036
20076
|
if (payload === "") return [];
|
|
20037
20077
|
const chunk = safeJsonParse$7(payload);
|
|
20038
|
-
if (!isRecord$
|
|
20078
|
+
if (!isRecord$43(chunk)) return [];
|
|
20039
20079
|
const out = [];
|
|
20040
|
-
if (isRecord$
|
|
20080
|
+
if (isRecord$43(chunk.error)) {
|
|
20041
20081
|
const message = asString$22(chunk.error.message) ?? "unknown error";
|
|
20042
20082
|
state.streamError = {
|
|
20043
20083
|
vocabulary: "openai",
|
|
@@ -20046,20 +20086,20 @@ function processOpenAIStreamLine$1(line, state) {
|
|
|
20046
20086
|
};
|
|
20047
20087
|
throw new LlmError$1(`Command Code stream error: ${message}`, isContextOverflow(chunk.error) ? CONTEXT_OVERFLOW_CODE : "PROVIDER_ERROR");
|
|
20048
20088
|
}
|
|
20049
|
-
const usage = isRecord$
|
|
20089
|
+
const usage = isRecord$43(chunk.usage) ? chunk.usage : void 0;
|
|
20050
20090
|
if (usage) {
|
|
20051
20091
|
state.sawUsage = true;
|
|
20052
20092
|
const prompt = numberOr$8(usage.prompt_tokens, 0);
|
|
20053
|
-
const details = isRecord$
|
|
20093
|
+
const details = isRecord$43(usage.prompt_tokens_details) ? usage.prompt_tokens_details : void 0;
|
|
20054
20094
|
const cached = details ? numberOr$8(details.cached_tokens, 0) : 0;
|
|
20055
20095
|
state.inputTokens = Math.max(0, prompt - cached);
|
|
20056
20096
|
state.cacheReadTokens = cached;
|
|
20057
20097
|
state.outputTokens = numberOr$8(usage.completion_tokens, state.outputTokens);
|
|
20058
|
-
if (isRecord$
|
|
20098
|
+
if (isRecord$43(usage.completion_tokens_details)) state.reasoningTokens = numberOr$8(usage.completion_tokens_details.reasoning_tokens, state.reasoningTokens);
|
|
20059
20099
|
}
|
|
20060
20100
|
const choices = Array.isArray(chunk.choices) ? chunk.choices : [];
|
|
20061
|
-
const choice = isRecord$
|
|
20062
|
-
const delta = isRecord$
|
|
20101
|
+
const choice = isRecord$43(choices[0]) ? choices[0] : void 0;
|
|
20102
|
+
const delta = isRecord$43(choice?.delta) ? choice.delta : void 0;
|
|
20063
20103
|
if (delta) {
|
|
20064
20104
|
const reasoning = asString$22(delta.reasoning_content) ?? asString$22(delta.reasoning);
|
|
20065
20105
|
if (reasoning !== void 0 && reasoning !== "") {
|
|
@@ -20087,7 +20127,7 @@ function processOpenAIStreamLine$1(line, state) {
|
|
|
20087
20127
|
}
|
|
20088
20128
|
const toolDeltas = Array.isArray(delta.tool_calls) ? delta.tool_calls : [];
|
|
20089
20129
|
for (const entry of toolDeltas) {
|
|
20090
|
-
if (!isRecord$
|
|
20130
|
+
if (!isRecord$43(entry)) continue;
|
|
20091
20131
|
out.push(...applyOpenAIToolDelta$1(entry, state));
|
|
20092
20132
|
}
|
|
20093
20133
|
}
|
|
@@ -20101,7 +20141,7 @@ function processOpenAIStreamLine$1(line, state) {
|
|
|
20101
20141
|
}
|
|
20102
20142
|
function applyOpenAIToolDelta$1(entry, state) {
|
|
20103
20143
|
const wireIndex = typeof entry.index === "number" ? entry.index : 0;
|
|
20104
|
-
const fn = isRecord$
|
|
20144
|
+
const fn = isRecord$43(entry.function) ? entry.function : {};
|
|
20105
20145
|
const out = [];
|
|
20106
20146
|
let call = state.toolCalls.get(wireIndex);
|
|
20107
20147
|
if (call === void 0) {
|
|
@@ -20159,12 +20199,12 @@ function processAnthropicStreamLine$1(line, state) {
|
|
|
20159
20199
|
const payload = trimmed.slice(5).trim();
|
|
20160
20200
|
if (payload === "" || payload === "[DONE]") return [];
|
|
20161
20201
|
const event = safeJsonParse$7(payload);
|
|
20162
|
-
if (!isRecord$
|
|
20202
|
+
if (!isRecord$43(event)) return [];
|
|
20163
20203
|
const type = asString$22(event.type);
|
|
20164
20204
|
const out = [];
|
|
20165
20205
|
if (type === "message_start") {
|
|
20166
|
-
const message = isRecord$
|
|
20167
|
-
const usage = message && isRecord$
|
|
20206
|
+
const message = isRecord$43(event.message) ? event.message : void 0;
|
|
20207
|
+
const usage = message && isRecord$43(message.usage) ? message.usage : void 0;
|
|
20168
20208
|
if (usage) {
|
|
20169
20209
|
state.sawUsage = true;
|
|
20170
20210
|
state.inputTokens = numberOr$8(usage.input_tokens, 0);
|
|
@@ -20178,7 +20218,7 @@ function processAnthropicStreamLine$1(line, state) {
|
|
|
20178
20218
|
}
|
|
20179
20219
|
if (type === "content_block_start") {
|
|
20180
20220
|
const contentIndex = numberOr$8(event.index, 0);
|
|
20181
|
-
const block = isRecord$
|
|
20221
|
+
const block = isRecord$43(event.content_block) ? event.content_block : {};
|
|
20182
20222
|
const blockType = asString$22(block.type);
|
|
20183
20223
|
out.push(...closeCurrent$5(state));
|
|
20184
20224
|
if (blockType === "tool_use") {
|
|
@@ -20228,7 +20268,7 @@ function processAnthropicStreamLine$1(line, state) {
|
|
|
20228
20268
|
}
|
|
20229
20269
|
if (type === "content_block_delta") {
|
|
20230
20270
|
const contentIndex = numberOr$8(event.index, 0);
|
|
20231
|
-
const delta = isRecord$
|
|
20271
|
+
const delta = isRecord$43(event.delta) ? event.delta : {};
|
|
20232
20272
|
const deltaType = asString$22(delta.type);
|
|
20233
20273
|
if (deltaType === "input_json_delta") {
|
|
20234
20274
|
const pending = state.toolCalls.get(contentIndex);
|
|
@@ -20301,10 +20341,10 @@ function processAnthropicStreamLine$1(line, state) {
|
|
|
20301
20341
|
return out;
|
|
20302
20342
|
}
|
|
20303
20343
|
if (type === "message_delta") {
|
|
20304
|
-
const delta = isRecord$
|
|
20344
|
+
const delta = isRecord$43(event.delta) ? event.delta : void 0;
|
|
20305
20345
|
const stop = delta ? asString$22(delta.stop_reason) : void 0;
|
|
20306
20346
|
if (stop !== void 0 && stop !== "") state.finishReason = stop;
|
|
20307
|
-
const usage = isRecord$
|
|
20347
|
+
const usage = isRecord$43(event.usage) ? event.usage : void 0;
|
|
20308
20348
|
if (usage) {
|
|
20309
20349
|
state.sawUsage = true;
|
|
20310
20350
|
state.outputTokens = numberOr$8(usage.output_tokens, state.outputTokens);
|
|
@@ -20316,7 +20356,7 @@ function processAnthropicStreamLine$1(line, state) {
|
|
|
20316
20356
|
return closeStream$5(state);
|
|
20317
20357
|
}
|
|
20318
20358
|
if (type === "error") {
|
|
20319
|
-
const error = isRecord$
|
|
20359
|
+
const error = isRecord$43(event.error) ? event.error : {};
|
|
20320
20360
|
const message = asString$22(error.message) ?? "unknown error";
|
|
20321
20361
|
state.streamError = {
|
|
20322
20362
|
vocabulary: "anthropic",
|
|
@@ -20362,7 +20402,7 @@ function processResponsesStreamLine(line, state) {
|
|
|
20362
20402
|
} catch {
|
|
20363
20403
|
return [];
|
|
20364
20404
|
}
|
|
20365
|
-
if (!isRecord$
|
|
20405
|
+
if (!isRecord$43(parsed)) return [];
|
|
20366
20406
|
const type = typeof parsed.type === "string" ? parsed.type : "";
|
|
20367
20407
|
if (type === "response.output_text.delta") {
|
|
20368
20408
|
const delta = typeof parsed.delta === "string" ? parsed.delta : "";
|
|
@@ -20389,7 +20429,7 @@ function processResponsesStreamLine(line, state) {
|
|
|
20389
20429
|
}];
|
|
20390
20430
|
}
|
|
20391
20431
|
if (type === "response.output_item.added") {
|
|
20392
|
-
const item = isRecord$
|
|
20432
|
+
const item = isRecord$43(parsed.item) ? parsed.item : null;
|
|
20393
20433
|
if (item === null || item.type !== "function_call") return [];
|
|
20394
20434
|
return startResponsesToolCall(state, parsed, item);
|
|
20395
20435
|
}
|
|
@@ -20413,11 +20453,11 @@ function processResponsesStreamLine(line, state) {
|
|
|
20413
20453
|
return [];
|
|
20414
20454
|
}
|
|
20415
20455
|
if (type === "response.completed" || type === "response.incomplete") {
|
|
20416
|
-
const response = isRecord$
|
|
20456
|
+
const response = isRecord$43(parsed.response) ? parsed.response : null;
|
|
20417
20457
|
if (response !== null) {
|
|
20418
20458
|
if (response.status === "failed") {
|
|
20419
20459
|
state.done = true;
|
|
20420
|
-
const errorObj = isRecord$
|
|
20460
|
+
const errorObj = isRecord$43(response.error) ? response.error : null;
|
|
20421
20461
|
const detail = errorObj && typeof errorObj.message === "string" ? errorObj.message : typeof response.error === "string" ? response.error : "";
|
|
20422
20462
|
state.streamError = {
|
|
20423
20463
|
vocabulary: "responses",
|
|
@@ -20430,7 +20470,7 @@ function processResponsesStreamLine(line, state) {
|
|
|
20430
20470
|
}
|
|
20431
20471
|
state.done = true;
|
|
20432
20472
|
if (type === "response.incomplete") {
|
|
20433
|
-
const details = response && isRecord$
|
|
20473
|
+
const details = response && isRecord$43(response.incomplete_details) ? response.incomplete_details : null;
|
|
20434
20474
|
const reason = details && typeof details.reason === "string" ? details.reason : "";
|
|
20435
20475
|
state.finishReason = reason === "max_output_tokens" || reason === "length" || reason === "max_tokens" ? "length" : reason || "length";
|
|
20436
20476
|
} else state.finishReason = "stop";
|
|
@@ -20438,8 +20478,8 @@ function processResponsesStreamLine(line, state) {
|
|
|
20438
20478
|
}
|
|
20439
20479
|
if (type === "response.failed" || type === "error") {
|
|
20440
20480
|
state.done = true;
|
|
20441
|
-
const errorObj = isRecord$
|
|
20442
|
-
const detail = (typeof parsed.message === "string" ? parsed.message : "") || (errorObj && typeof errorObj.message === "string" ? errorObj.message : "") || (isRecord$
|
|
20481
|
+
const errorObj = isRecord$43(parsed.error) ? parsed.error : isRecord$43(parsed.response) && isRecord$43(parsed.response.error) ? parsed.response.error : null;
|
|
20482
|
+
const detail = (typeof parsed.message === "string" ? parsed.message : "") || (errorObj && typeof errorObj.message === "string" ? errorObj.message : "") || (isRecord$43(parsed.response) && typeof parsed.response.error === "string" ? parsed.response.error : typeof parsed.error === "string" ? parsed.error : "");
|
|
20443
20483
|
state.streamError = {
|
|
20444
20484
|
vocabulary: "responses",
|
|
20445
20485
|
error: errorObj,
|
|
@@ -20527,15 +20567,15 @@ function responsesToolCall(state, key) {
|
|
|
20527
20567
|
for (const call of state.toolCalls.values()) if (call.id === toToolCallId(key)) return call;
|
|
20528
20568
|
}
|
|
20529
20569
|
function readResponsesUsage(response, state) {
|
|
20530
|
-
const usage = isRecord$
|
|
20570
|
+
const usage = isRecord$43(response.usage) ? response.usage : null;
|
|
20531
20571
|
if (usage === null) return;
|
|
20532
|
-
const cached = isRecord$
|
|
20533
|
-
const written = isRecord$
|
|
20572
|
+
const cached = isRecord$43(usage.input_tokens_details) ? numberOrZero(usage.input_tokens_details.cached_tokens) : 0;
|
|
20573
|
+
const written = isRecord$43(usage.input_tokens_details) ? numberOrZero(usage.input_tokens_details.cache_write_tokens) : 0;
|
|
20534
20574
|
state.inputTokens = Math.max(0, numberOrZero(usage.input_tokens) - cached - written);
|
|
20535
20575
|
state.cacheReadTokens = cached;
|
|
20536
20576
|
state.cacheWriteTokens = written;
|
|
20537
20577
|
state.outputTokens = numberOrZero(usage.output_tokens);
|
|
20538
|
-
const outputDetails = isRecord$
|
|
20578
|
+
const outputDetails = isRecord$43(usage.output_tokens_details) ? usage.output_tokens_details : null;
|
|
20539
20579
|
if (outputDetails !== null) state.reasoningTokens = numberOrZero(outputDetails.reasoning_tokens);
|
|
20540
20580
|
state.sawUsage = true;
|
|
20541
20581
|
}
|
|
@@ -20623,7 +20663,7 @@ const ANTHROPIC_IN_BAND_STATUS = {
|
|
|
20623
20663
|
* Anything not recognized keeps the mapper's verdict.
|
|
20624
20664
|
*/
|
|
20625
20665
|
function inBandResponsesCode(error, message) {
|
|
20626
|
-
const fields = isRecord$
|
|
20666
|
+
const fields = isRecord$42(error) ? error : {};
|
|
20627
20667
|
const rawCode = (asString$21(fields.code) ?? asString$21(fields.type) ?? "").toLowerCase();
|
|
20628
20668
|
const text = message.toLowerCase();
|
|
20629
20669
|
if (text.includes("rate limit") || rawCode === "rate_limit" || rawCode === "rate_limit_exceeded") return "RATE_LIMIT";
|
|
@@ -20682,13 +20722,13 @@ function reclassifyInBandResponsesError(thrown, rawError, message, classify) {
|
|
|
20682
20722
|
}
|
|
20683
20723
|
/** The wire `error` object of an in-band event, read defensively. */
|
|
20684
20724
|
function readErrorType(error) {
|
|
20685
|
-
if (!isRecord$
|
|
20725
|
+
if (!isRecord$42(error)) return null;
|
|
20686
20726
|
return typeof error.type === "string" ? error.type : null;
|
|
20687
20727
|
}
|
|
20688
20728
|
function asString$21(value) {
|
|
20689
20729
|
return typeof value === "string" ? value : void 0;
|
|
20690
20730
|
}
|
|
20691
|
-
function isRecord$
|
|
20731
|
+
function isRecord$42(value) {
|
|
20692
20732
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
20693
20733
|
}
|
|
20694
20734
|
//#endregion
|
|
@@ -23883,14 +23923,14 @@ const IN_BAND_SERVER = [
|
|
|
23883
23923
|
function isAbort$3(error, signal) {
|
|
23884
23924
|
return signal?.aborted === true || error instanceof Error && error.name === "AbortError";
|
|
23885
23925
|
}
|
|
23886
|
-
function isRecord$
|
|
23926
|
+
function isRecord$41(value) {
|
|
23887
23927
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
23888
23928
|
}
|
|
23889
23929
|
function asString$20(value) {
|
|
23890
23930
|
return typeof value === "string" && value !== "" ? value : void 0;
|
|
23891
23931
|
}
|
|
23892
23932
|
function attachmentLabel$4(block) {
|
|
23893
|
-
const attachment = isRecord$
|
|
23933
|
+
const attachment = isRecord$41(block.attachment) ? block.attachment : void 0;
|
|
23894
23934
|
return asString$20(attachment?.name) || asString$20(attachment?.attachmentId);
|
|
23895
23935
|
}
|
|
23896
23936
|
function unavailableImageText$4(block) {
|
|
@@ -23926,7 +23966,7 @@ async function processMessageContent(content, model, attachments, signal) {
|
|
|
23926
23966
|
textParts.push(part);
|
|
23927
23967
|
continue;
|
|
23928
23968
|
}
|
|
23929
|
-
if (!isRecord$
|
|
23969
|
+
if (!isRecord$41(part)) continue;
|
|
23930
23970
|
if (part.type === "text") {
|
|
23931
23971
|
if (typeof part.text === "string" && part.text !== "") textParts.push(part.text);
|
|
23932
23972
|
continue;
|
|
@@ -23955,7 +23995,7 @@ async function processMessageContent(content, model, attachments, signal) {
|
|
|
23955
23995
|
continue;
|
|
23956
23996
|
}
|
|
23957
23997
|
const inline = part.source;
|
|
23958
|
-
if (isRecord$
|
|
23998
|
+
if (isRecord$41(inline)) {
|
|
23959
23999
|
const data = inline.data;
|
|
23960
24000
|
if (typeof data === "string" && data !== "") {
|
|
23961
24001
|
images.push(encodeImage(data, asMediaType(inline.mediaType)));
|
|
@@ -23996,7 +24036,7 @@ async function toOllamaRequest(options, attachments, signal, declared) {
|
|
|
23996
24036
|
const toolResultBlocks = message.content.filter((b) => b.type === "tool-result");
|
|
23997
24037
|
if (toolResultBlocks.length > 0) {
|
|
23998
24038
|
for (const block of toolResultBlocks) {
|
|
23999
|
-
const toolCallId = String(block.toolCallId ?? (isRecord$
|
|
24039
|
+
const toolCallId = String(block.toolCallId ?? (isRecord$41(message.source) ? message.source.callId : "") ?? "");
|
|
24000
24040
|
const processed = await processMessageContent(block.content, options.model, attachments, signal);
|
|
24001
24041
|
messages.push({
|
|
24002
24042
|
role: "tool",
|
|
@@ -24607,7 +24647,7 @@ var OllamaAccountPool = class extends AccountPoolCore {
|
|
|
24607
24647
|
};
|
|
24608
24648
|
//#endregion
|
|
24609
24649
|
//#region src/host/common/request-images.ts
|
|
24610
|
-
function isRecord$
|
|
24650
|
+
function isRecord$40(value) {
|
|
24611
24651
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
24612
24652
|
}
|
|
24613
24653
|
function asString$19(value) {
|
|
@@ -24666,17 +24706,17 @@ const SUPPORTED_IMAGE_MEDIA_TYPES$3 = /* @__PURE__ */ new Set([
|
|
|
24666
24706
|
]);
|
|
24667
24707
|
function attachmentOf$3(block) {
|
|
24668
24708
|
const attachment = block.attachment;
|
|
24669
|
-
if (!isRecord$
|
|
24709
|
+
if (!isRecord$40(attachment)) return void 0;
|
|
24670
24710
|
return typeof attachment.attachmentId === "string" ? attachment : void 0;
|
|
24671
24711
|
}
|
|
24672
24712
|
function attachmentLabel$3(block) {
|
|
24673
|
-
const attachment = isRecord$
|
|
24713
|
+
const attachment = isRecord$40(block.attachment) ? block.attachment : void 0;
|
|
24674
24714
|
return asString$19(attachment?.name) || asString$19(attachment?.attachmentId);
|
|
24675
24715
|
}
|
|
24676
24716
|
function collectImageRefs$1(content, refs) {
|
|
24677
24717
|
if (!Array.isArray(content)) return;
|
|
24678
24718
|
for (const block of content) {
|
|
24679
|
-
if (!isRecord$
|
|
24719
|
+
if (!isRecord$40(block)) continue;
|
|
24680
24720
|
if (block.type === "image") {
|
|
24681
24721
|
const attachment = attachmentOf$3(block);
|
|
24682
24722
|
if (attachment) refs.set(attachment.attachmentId, attachment);
|
|
@@ -24706,7 +24746,7 @@ function base64Length$1(bytes) {
|
|
|
24706
24746
|
*/
|
|
24707
24747
|
function requestImagePayloadLength(block, images) {
|
|
24708
24748
|
let data = asString$19(block.data) || asString$19(block.base64);
|
|
24709
|
-
const source = isRecord$
|
|
24749
|
+
const source = isRecord$40(block.source) ? block.source : void 0;
|
|
24710
24750
|
if (!data && source) data = asString$19(source.data) || asString$19(source.base64);
|
|
24711
24751
|
if (data?.startsWith("data:")) {
|
|
24712
24752
|
const matched = data.match(/^data:([^;,]+);base64,(.*)$/s);
|
|
@@ -24732,7 +24772,7 @@ function requestImagePayloadLength(block, images) {
|
|
|
24732
24772
|
function collectRequestImagePayloads(content, images, lengths) {
|
|
24733
24773
|
if (!Array.isArray(content)) return;
|
|
24734
24774
|
for (const block of content) {
|
|
24735
|
-
if (!isRecord$
|
|
24775
|
+
if (!isRecord$40(block)) continue;
|
|
24736
24776
|
if (block.type === "image") {
|
|
24737
24777
|
const bytes = requestImagePayloadLength(block, images);
|
|
24738
24778
|
if (bytes !== void 0) lengths.push(bytes);
|
|
@@ -24786,7 +24826,7 @@ function replaceOldestRequestImages(options, count, images) {
|
|
|
24786
24826
|
let replaced = false;
|
|
24787
24827
|
return {
|
|
24788
24828
|
content: content.map((block) => {
|
|
24789
|
-
if (remaining.count === 0 || !isRecord$
|
|
24829
|
+
if (remaining.count === 0 || !isRecord$40(block)) return block;
|
|
24790
24830
|
if (block.type === "image") {
|
|
24791
24831
|
if (requestImagePayloadLength(block, images) === void 0) return block;
|
|
24792
24832
|
remaining.count -= 1;
|
|
@@ -24924,10 +24964,20 @@ function requestHasSendableImage(options, images) {
|
|
|
24924
24964
|
* An unreadable image resolves to `unavailable` rather than disappearing, so
|
|
24925
24965
|
* the model is told the picture is missing instead of answering about a blank.
|
|
24926
24966
|
*
|
|
24927
|
-
* An image whose long edge is over
|
|
24928
|
-
*
|
|
24929
|
-
*
|
|
24930
|
-
*
|
|
24967
|
+
* An image whose long edge is over the ceiling is sent as the harness's
|
|
24968
|
+
* downscaled request version (see {@link requestImageTarget}). The stored image
|
|
24969
|
+
* and durable history do not change, and an image that already fits is sent
|
|
24970
|
+
* byte-for-byte as stored.
|
|
24971
|
+
*
|
|
24972
|
+
* The ceiling is a PARAMETER because it belongs to the upstream route, exactly
|
|
24973
|
+
* like the image budget: `edge` defaults to the shared
|
|
24974
|
+
* {@link REQUEST_IMAGE_MAX_EDGE}, so every caller that does not name one keeps
|
|
24975
|
+
* the ceiling it always had. A route whose own CLI downscales to a different
|
|
24976
|
+
* long edge passes its value here and gets the same number in both places that
|
|
24977
|
+
* matter — the target it asks the attachment store for AND the check that the
|
|
24978
|
+
* version handed back really is that target. Deriving the target from one
|
|
24979
|
+
* constant and validating it against another is how a 2000 px request gets
|
|
24980
|
+
* discarded as if the store had ignored it.
|
|
24931
24981
|
*
|
|
24932
24982
|
* WHY scale instead of drop. `offloadOldestRequestImages` has to drop an image
|
|
24933
24983
|
* once the request exceeds `MAX_REQUEST_IMAGE_BYTES`, and the number it drops
|
|
@@ -24937,7 +24987,7 @@ function requestHasSendableImage(options, images) {
|
|
|
24937
24987
|
* outgrew the budget once stays inside it instead of breaking the cache every
|
|
24938
24988
|
* time an image is added.
|
|
24939
24989
|
*/
|
|
24940
|
-
async function resolveRequestImages$1(options, attachments, signal) {
|
|
24990
|
+
async function resolveRequestImages$1(options, attachments, signal, edge = REQUEST_IMAGE_MAX_EDGE) {
|
|
24941
24991
|
const refs = /* @__PURE__ */ new Map();
|
|
24942
24992
|
for (const message of options.messages) collectImageRefs$1(message.content, refs);
|
|
24943
24993
|
if (refs.size === 0) return NO_RESOLVED_IMAGES$3;
|
|
@@ -24948,10 +24998,10 @@ async function resolveRequestImages$1(options, attachments, signal) {
|
|
|
24948
24998
|
return;
|
|
24949
24999
|
}
|
|
24950
25000
|
try {
|
|
24951
|
-
const target = requestImageTarget(ref);
|
|
25001
|
+
const target = requestImageTarget(ref, edge);
|
|
24952
25002
|
if (target !== void 0) {
|
|
24953
25003
|
const version = await attachments.readImageRequest(ref, target, signal);
|
|
24954
|
-
resolved.set(attachmentId, Math.max(version.width, version.height) >
|
|
25004
|
+
resolved.set(attachmentId, Math.max(version.width, version.height) > edge ? { kind: "unavailable" } : {
|
|
24955
25005
|
kind: "inline",
|
|
24956
25006
|
mediaType: version.mediaType,
|
|
24957
25007
|
data: Buffer.from(version.data).toString("base64")
|
|
@@ -24977,7 +25027,7 @@ function unavailableImageText$3(block) {
|
|
|
24977
25027
|
}
|
|
24978
25028
|
function imageBlockToInline$2(block, images) {
|
|
24979
25029
|
let data = asString$19(block.data) || asString$19(block.base64);
|
|
24980
|
-
const source = isRecord$
|
|
25030
|
+
const source = isRecord$40(block.source) ? block.source : void 0;
|
|
24981
25031
|
if (!data && source) data = asString$19(source.data) || asString$19(source.base64);
|
|
24982
25032
|
let mediaType = asString$19(block.mimeType) || asString$19(block.mediaType) || (source ? asString$19(source.mimeType) || asString$19(source.mediaType) : void 0) || "image/png";
|
|
24983
25033
|
if (data?.startsWith("data:")) {
|
|
@@ -26556,11 +26606,11 @@ const MODELS_PATH$2 = "/models";
|
|
|
26556
26606
|
const USAGES_PATH = "/usages";
|
|
26557
26607
|
/** The service reports money in fixed-point units of 1e-6 cents. */
|
|
26558
26608
|
const FIXED_POINT_CENTS = 1e6;
|
|
26559
|
-
function isRecord$
|
|
26609
|
+
function isRecord$39(value) {
|
|
26560
26610
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
26561
26611
|
}
|
|
26562
26612
|
function asRecord$13(value) {
|
|
26563
|
-
return isRecord$
|
|
26613
|
+
return isRecord$39(value) ? value : void 0;
|
|
26564
26614
|
}
|
|
26565
26615
|
function asString$18(value) {
|
|
26566
26616
|
if (typeof value === "string" && value.trim() !== "") return value;
|
|
@@ -26574,7 +26624,7 @@ function asNumber$4(value) {
|
|
|
26574
26624
|
if (Number.isFinite(parsed)) return parsed;
|
|
26575
26625
|
}
|
|
26576
26626
|
}
|
|
26577
|
-
function firstString(record, keys) {
|
|
26627
|
+
function firstString$1(record, keys) {
|
|
26578
26628
|
for (const key of keys) {
|
|
26579
26629
|
const value = asString$18(record[key]);
|
|
26580
26630
|
if (value !== void 0) return value;
|
|
@@ -27195,7 +27245,7 @@ function parseUsageWindows(payload) {
|
|
|
27195
27245
|
const duration = firstNumber(window ?? {}, ["duration"]);
|
|
27196
27246
|
const unit = asString$18(window?.timeUnit ?? window?.time_unit);
|
|
27197
27247
|
const minutes = duration === void 0 ? null : unit === "TIME_UNIT_HOUR" ? duration * 60 : duration;
|
|
27198
|
-
push(minutes === 300 ? "limit_5h" : minutes === 10080 ? "limit_7d" : firstString(record, ["id", "name"]) ?? `limit-${windows.length + 1}`, detail, minutes === null ? void 0 : {
|
|
27248
|
+
push(minutes === 300 ? "limit_5h" : minutes === 10080 ? "limit_7d" : firstString$1(record, ["id", "name"]) ?? `limit-${windows.length + 1}`, detail, minutes === null ? void 0 : {
|
|
27199
27249
|
label: minutes === 300 ? "5-hour" : `${minutes}-minute`,
|
|
27200
27250
|
minutes
|
|
27201
27251
|
});
|
|
@@ -27294,7 +27344,7 @@ function membershipLevelName(level) {
|
|
|
27294
27344
|
*/
|
|
27295
27345
|
function parsePlanName(payload) {
|
|
27296
27346
|
const root = asRecord$13(payload) ?? {};
|
|
27297
|
-
const direct = firstString(root, [
|
|
27347
|
+
const direct = firstString$1(root, [
|
|
27298
27348
|
"user_level_name",
|
|
27299
27349
|
"userLevelName",
|
|
27300
27350
|
"planName",
|
|
@@ -27418,7 +27468,7 @@ function accountFromCredentials$1(credentials, payload, profile) {
|
|
|
27418
27468
|
const planLevel = (profile === void 0 ? null : parsePlanLevel(profile)) ?? (payload === void 0 ? null : parsePlanLevel(payload));
|
|
27419
27469
|
return {
|
|
27420
27470
|
userId: credentials.userId ?? identity.userId ?? null,
|
|
27421
|
-
nickname: (profile === void 0 ? null : firstString(asRecord$13(profile) ?? {}, [
|
|
27471
|
+
nickname: (profile === void 0 ? null : firstString$1(asRecord$13(profile) ?? {}, [
|
|
27422
27472
|
"nickname",
|
|
27423
27473
|
"username",
|
|
27424
27474
|
"name"
|
|
@@ -27532,12 +27582,12 @@ async function testConnection$1(store, options = {}) {
|
|
|
27532
27582
|
*
|
|
27533
27583
|
* @module dsh-chatgpt-subscription/tool-schema
|
|
27534
27584
|
*/
|
|
27535
|
-
function isRecord$
|
|
27585
|
+
function isRecord$38(value) {
|
|
27536
27586
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
27537
27587
|
}
|
|
27538
27588
|
function cloneJsonValue(value) {
|
|
27539
27589
|
if (Array.isArray(value)) return value.map(cloneJsonValue);
|
|
27540
|
-
if (isRecord$
|
|
27590
|
+
if (isRecord$38(value)) {
|
|
27541
27591
|
const res = {};
|
|
27542
27592
|
for (const [k, v] of Object.entries(value)) res[k] = cloneJsonValue(v);
|
|
27543
27593
|
return res;
|
|
@@ -27552,7 +27602,7 @@ function resolveLocalJsonPointer(root, ref) {
|
|
|
27552
27602
|
let current = root;
|
|
27553
27603
|
for (const rawPart of ref.slice(2).split("/")) {
|
|
27554
27604
|
const part = rawPart.replaceAll("~1", "/").replaceAll("~0", "~");
|
|
27555
|
-
if (isRecord$
|
|
27605
|
+
if (isRecord$38(current)) {
|
|
27556
27606
|
if (!Object.prototype.hasOwnProperty.call(current, part)) return { found: false };
|
|
27557
27607
|
current = current[part];
|
|
27558
27608
|
} else if (Array.isArray(current)) {
|
|
@@ -27568,7 +27618,7 @@ function resolveLocalJsonPointer(root, ref) {
|
|
|
27568
27618
|
}
|
|
27569
27619
|
function derefNode(node, root, visited) {
|
|
27570
27620
|
if (Array.isArray(node)) return node.map((item) => derefNode(item, root, visited));
|
|
27571
|
-
if (isRecord$
|
|
27621
|
+
if (isRecord$38(node)) {
|
|
27572
27622
|
if (typeof node["$ref"] === "string" && (node["$ref"] === "#" || node["$ref"].startsWith("#/"))) {
|
|
27573
27623
|
const ref = node["$ref"];
|
|
27574
27624
|
if (visited.has(ref)) return node;
|
|
@@ -27577,7 +27627,7 @@ function derefNode(node, root, visited) {
|
|
|
27577
27627
|
visited.add(ref);
|
|
27578
27628
|
const inlined = derefNode(resolved.value, root, visited);
|
|
27579
27629
|
visited.delete(ref);
|
|
27580
|
-
if (isRecord$
|
|
27630
|
+
if (isRecord$38(inlined)) {
|
|
27581
27631
|
const merged = { ...inlined };
|
|
27582
27632
|
for (const [k, v] of Object.entries(node)) {
|
|
27583
27633
|
if (k === "$ref") continue;
|
|
@@ -27597,7 +27647,7 @@ function derefNode(node, root, visited) {
|
|
|
27597
27647
|
}
|
|
27598
27648
|
function hasUnresolvedDefinitionRef(node, bucketKey) {
|
|
27599
27649
|
if (Array.isArray(node)) return node.some((child) => hasUnresolvedDefinitionRef(child, bucketKey));
|
|
27600
|
-
if (isRecord$
|
|
27650
|
+
if (isRecord$38(node)) {
|
|
27601
27651
|
const ref = node["$ref"];
|
|
27602
27652
|
if (typeof ref === "string" && ref.startsWith(`#/${bucketKey}/`)) return true;
|
|
27603
27653
|
for (const [k, v] of Object.entries(node)) {
|
|
@@ -27628,19 +27678,19 @@ function inferTypeFromValues(values) {
|
|
|
27628
27678
|
if (types.size === 1) return types.values().next().value;
|
|
27629
27679
|
}
|
|
27630
27680
|
function normalizeSchemaProperties(node) {
|
|
27631
|
-
if (!isRecord$
|
|
27632
|
-
if (isRecord$
|
|
27633
|
-
for (const propSchema of Object.values(node.properties)) if (isRecord$
|
|
27681
|
+
if (!isRecord$38(node)) return;
|
|
27682
|
+
if (isRecord$38(node.properties)) {
|
|
27683
|
+
for (const propSchema of Object.values(node.properties)) if (isRecord$38(propSchema)) {
|
|
27634
27684
|
if (!propSchema.type && !propSchema.$ref) {
|
|
27635
27685
|
if (Array.isArray(propSchema.enum) && propSchema.enum.length > 0) propSchema.type = inferTypeFromValues(propSchema.enum) ?? "string";
|
|
27636
27686
|
else if (propSchema.const !== void 0) propSchema.type = inferValueType(propSchema.const) ?? "string";
|
|
27637
|
-
else if (isRecord$
|
|
27687
|
+
else if (isRecord$38(propSchema.properties)) propSchema.type = "object";
|
|
27638
27688
|
else if (propSchema.items) propSchema.type = "array";
|
|
27639
27689
|
}
|
|
27640
27690
|
normalizeSchemaProperties(propSchema);
|
|
27641
27691
|
}
|
|
27642
27692
|
}
|
|
27643
|
-
if (isRecord$
|
|
27693
|
+
if (isRecord$38(node.items)) normalizeSchemaProperties(node.items);
|
|
27644
27694
|
else if (Array.isArray(node.items)) for (const item of node.items) normalizeSchemaProperties(item);
|
|
27645
27695
|
}
|
|
27646
27696
|
/**
|
|
@@ -27648,7 +27698,7 @@ function normalizeSchemaProperties(node) {
|
|
|
27648
27698
|
* inlining definitions ($defs/definitions/$ref), and ensuring property types for enums/consts.
|
|
27649
27699
|
*/
|
|
27650
27700
|
function normalizeKimiToolSchema(schema) {
|
|
27651
|
-
if (!isRecord$
|
|
27701
|
+
if (!isRecord$38(schema)) return {
|
|
27652
27702
|
type: "object",
|
|
27653
27703
|
properties: {}
|
|
27654
27704
|
};
|
|
@@ -27666,7 +27716,7 @@ function stripMetaSchema$1(schema) {
|
|
|
27666
27716
|
}
|
|
27667
27717
|
//#endregion
|
|
27668
27718
|
//#region src/host/common/prompt-estimate.ts
|
|
27669
|
-
function isRecord$
|
|
27719
|
+
function isRecord$37(value) {
|
|
27670
27720
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
27671
27721
|
}
|
|
27672
27722
|
/** Tool-call arguments as the JSON string a wire carries, whatever shape they arrived in. */
|
|
@@ -27699,7 +27749,7 @@ function estimatedInputTokens(options) {
|
|
|
27699
27749
|
const contentCharacters = (content) => {
|
|
27700
27750
|
if (!Array.isArray(content)) return typeof content === "string" ? content.length : 0;
|
|
27701
27751
|
return content.reduce((total, block) => {
|
|
27702
|
-
if (!isRecord$
|
|
27752
|
+
if (!isRecord$37(block)) return total;
|
|
27703
27753
|
if ((block.type === "text" || block.type === "reasoning") && typeof block.text === "string") return total + block.text.length;
|
|
27704
27754
|
if (block.type === "tool-result") return total + contentCharacters(block.content);
|
|
27705
27755
|
if (block.type === "tool-call") {
|
|
@@ -27800,7 +27850,7 @@ function videoOmissionText$1(reason, label) {
|
|
|
27800
27850
|
}
|
|
27801
27851
|
//#endregion
|
|
27802
27852
|
//#region src/host/common/video-request.ts
|
|
27803
|
-
function isRecord$
|
|
27853
|
+
function isRecord$36(value) {
|
|
27804
27854
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
27805
27855
|
}
|
|
27806
27856
|
function asString$17(value) {
|
|
@@ -27808,14 +27858,14 @@ function asString$17(value) {
|
|
|
27808
27858
|
}
|
|
27809
27859
|
function videoAttachmentOf(block) {
|
|
27810
27860
|
const attachment = block.attachment;
|
|
27811
|
-
if (!isRecord$
|
|
27861
|
+
if (!isRecord$36(attachment)) return void 0;
|
|
27812
27862
|
if (typeof attachment.attachmentId !== "string") return void 0;
|
|
27813
27863
|
return attachment;
|
|
27814
27864
|
}
|
|
27815
27865
|
function collectVideoRefs(content, refs) {
|
|
27816
27866
|
if (!Array.isArray(content)) return;
|
|
27817
27867
|
for (const block of content) {
|
|
27818
|
-
if (!isRecord$
|
|
27868
|
+
if (!isRecord$36(block) || block.type !== "video") continue;
|
|
27819
27869
|
const attachment = videoAttachmentOf(block);
|
|
27820
27870
|
if (attachment) refs.set(attachment.attachmentId, attachment);
|
|
27821
27871
|
}
|
|
@@ -27830,7 +27880,7 @@ function requestVideoBytes(block) {
|
|
|
27830
27880
|
function collectRequestVideoBytes(content, lengths) {
|
|
27831
27881
|
if (!Array.isArray(content)) return;
|
|
27832
27882
|
for (const block of content) {
|
|
27833
|
-
if (!isRecord$
|
|
27883
|
+
if (!isRecord$36(block) || block.type !== "video") continue;
|
|
27834
27884
|
const bytes = requestVideoBytes(block);
|
|
27835
27885
|
if (bytes !== void 0) lengths.push(bytes);
|
|
27836
27886
|
}
|
|
@@ -27874,7 +27924,7 @@ function isAbortLike(error, signal) {
|
|
|
27874
27924
|
}
|
|
27875
27925
|
/** True when the request carries any video occurrence at all. */
|
|
27876
27926
|
function requestHasVideo(options) {
|
|
27877
|
-
return options.messages.some((message) => Array.isArray(message.content) && message.content.some((block) => isRecord$
|
|
27927
|
+
return options.messages.some((message) => Array.isArray(message.content) && message.content.some((block) => isRecord$36(block) && block.type === "video"));
|
|
27878
27928
|
}
|
|
27879
27929
|
function omittedVideoText(omit, block) {
|
|
27880
27930
|
return omit("unreadable", videoBlockLabel(block));
|
|
@@ -27909,7 +27959,7 @@ function offloadOldestRequestVideos(options, maxBytes) {
|
|
|
27909
27959
|
if (remaining.count === 0 || !Array.isArray(message.content)) return message;
|
|
27910
27960
|
let replaced = false;
|
|
27911
27961
|
const content = message.content.map((block) => {
|
|
27912
|
-
if (remaining.count === 0 || !isRecord$
|
|
27962
|
+
if (remaining.count === 0 || !isRecord$36(block) || block.type !== "video") return block;
|
|
27913
27963
|
if (requestVideoBytes(block) === void 0) return block;
|
|
27914
27964
|
remaining.count -= 1;
|
|
27915
27965
|
replaced = true;
|
|
@@ -27992,7 +28042,7 @@ function videoBlockToInline(block, videos, videoAccepted, omit) {
|
|
|
27992
28042
|
*
|
|
27993
28043
|
* See https://www.kimi.com/code/docs/en/kimi-code/error-reference.html
|
|
27994
28044
|
*/
|
|
27995
|
-
function isRecord$
|
|
28045
|
+
function isRecord$35(value) {
|
|
27996
28046
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
27997
28047
|
}
|
|
27998
28048
|
function asString$16(value) {
|
|
@@ -28025,6 +28075,118 @@ const KNOWN_REASONING_KEYS = [
|
|
|
28025
28075
|
/** Default outbound reasoning key, used until a response proves otherwise. */
|
|
28026
28076
|
const DEFAULT_REASONING_KEY = KNOWN_REASONING_KEYS[0];
|
|
28027
28077
|
/**
|
|
28078
|
+
* One `reasoning_details` element, in an official or a compatibility shape.
|
|
28079
|
+
*
|
|
28080
|
+
* The official shapes are the ones agent-core-v2's
|
|
28081
|
+
* `bases/openai/reasoning-key.ts` reads: `type` is absent or `'summary'` for a
|
|
28082
|
+
* visible summary (payload in `summary`), or `'encrypted'` for opaque provider
|
|
28083
|
+
* state (payload in `encrypted`). Its `toReasoningDetailsElement` keeps
|
|
28084
|
+
* `record.index` when that is a number and otherwise the element's position, so
|
|
28085
|
+
* every element has an index; this function does the same, and replays it.
|
|
28086
|
+
*
|
|
28087
|
+
* Its `convertReasoningDetails` then walks each element twice, in this order:
|
|
28088
|
+
* a non-encrypted element with a `summary` produces visible thinking, and a
|
|
28089
|
+
* non-summary element with `encrypted` produces opaque thinking. A type-less
|
|
28090
|
+
* element carrying BOTH therefore yields two fragments — the visible summary
|
|
28091
|
+
* first, then the opaque state. An encrypted payload is never text: it is
|
|
28092
|
+
* provider state, and printing it would show a blob as if the model had thought
|
|
28093
|
+
* it.
|
|
28094
|
+
*
|
|
28095
|
+
* The `reasoning.text` / `reasoning.summary` gateway spellings this route
|
|
28096
|
+
* already accepted stay readable, and are replayed under the type they arrived
|
|
28097
|
+
* with. Anything else — an unknown `type`, a missing payload, a non-object — is
|
|
28098
|
+
* ignored rather than mistaken for body text.
|
|
28099
|
+
*/
|
|
28100
|
+
function reasoningDetailElement(entry, position) {
|
|
28101
|
+
const type = asString$16(entry.type);
|
|
28102
|
+
const rawIndex = entry.index;
|
|
28103
|
+
const index = typeof rawIndex === "number" && Number.isInteger(rawIndex) && rawIndex >= 0 ? rawIndex : position;
|
|
28104
|
+
const shape = {
|
|
28105
|
+
key: "reasoning_details",
|
|
28106
|
+
...type === void 0 ? {} : { wireType: type },
|
|
28107
|
+
index
|
|
28108
|
+
};
|
|
28109
|
+
if (type === "reasoning.text") {
|
|
28110
|
+
const text = asString$16(entry.text);
|
|
28111
|
+
return text === void 0 || text === "" ? [] : [{
|
|
28112
|
+
...shape,
|
|
28113
|
+
form: "text",
|
|
28114
|
+
text
|
|
28115
|
+
}];
|
|
28116
|
+
}
|
|
28117
|
+
const summary = asString$16(entry.summary);
|
|
28118
|
+
const encrypted = asString$16(entry.encrypted);
|
|
28119
|
+
const fragments = [];
|
|
28120
|
+
if (type === void 0 || type === "summary" || type === "reasoning.summary") {
|
|
28121
|
+
if (summary !== void 0 && summary !== "") fragments.push({
|
|
28122
|
+
...shape,
|
|
28123
|
+
form: "summary",
|
|
28124
|
+
text: summary
|
|
28125
|
+
});
|
|
28126
|
+
}
|
|
28127
|
+
if (type === void 0 || type === "encrypted") {
|
|
28128
|
+
if (encrypted !== void 0 && encrypted !== "") fragments.push({
|
|
28129
|
+
...shape,
|
|
28130
|
+
form: "encrypted",
|
|
28131
|
+
encrypted,
|
|
28132
|
+
text: ""
|
|
28133
|
+
});
|
|
28134
|
+
}
|
|
28135
|
+
return fragments;
|
|
28136
|
+
}
|
|
28137
|
+
/**
|
|
28138
|
+
* Fragments carried by one `reasoning_details` value.
|
|
28139
|
+
*
|
|
28140
|
+
* A bare string — the older gateway spelling, and already a learned dialect here
|
|
28141
|
+
* — is one `string` fragment. An array keeps its arrival order, exactly as the
|
|
28142
|
+
* official `extractReasoningDetails` does: elements are pushed in the order they
|
|
28143
|
+
* appear and nothing is re-sorted. `index` is metadata (defaulted to the
|
|
28144
|
+
* position), never an ordering key here.
|
|
28145
|
+
*/
|
|
28146
|
+
function reasoningDetailFragments(value) {
|
|
28147
|
+
if (typeof value === "string") return value === "" ? [] : [{
|
|
28148
|
+
key: "reasoning_details",
|
|
28149
|
+
form: "string",
|
|
28150
|
+
text: value
|
|
28151
|
+
}];
|
|
28152
|
+
if (!Array.isArray(value)) return [];
|
|
28153
|
+
const fragments = [];
|
|
28154
|
+
value.forEach((entry, position) => {
|
|
28155
|
+
if (!isRecord$35(entry)) return;
|
|
28156
|
+
fragments.push(...reasoningDetailElement(entry, position));
|
|
28157
|
+
});
|
|
28158
|
+
return fragments;
|
|
28159
|
+
}
|
|
28160
|
+
/**
|
|
28161
|
+
* Every reasoning fragment one inbound object (a stream delta or a message)
|
|
28162
|
+
* carries, in a fixed, documented order.
|
|
28163
|
+
*
|
|
28164
|
+
* `reasoning_content` comes first and `reasoning` last because that is the
|
|
28165
|
+
* order of {@link KNOWN_REASONING_KEYS}: the Kimi field is the one this route is
|
|
28166
|
+
* documented against and `reasoning` is the newer vLLM rename, so a delta
|
|
28167
|
+
* carrying both keeps its text in the order a single-key endpoint would have
|
|
28168
|
+
* produced it in. A `reasoning_details` array keeps its arrival order; `index` is
|
|
28169
|
+
* carried as metadata and never reorders it (see reasoningDetailFragments).
|
|
28170
|
+
*/
|
|
28171
|
+
function reasoningFragmentsOf(source) {
|
|
28172
|
+
if (typeof source !== "object" || source === null) return [];
|
|
28173
|
+
const record = source;
|
|
28174
|
+
const fragments = [];
|
|
28175
|
+
for (const key of KNOWN_REASONING_KEYS) {
|
|
28176
|
+
const value = record[key];
|
|
28177
|
+
if (key === "reasoning_details") {
|
|
28178
|
+
fragments.push(...reasoningDetailFragments(value));
|
|
28179
|
+
continue;
|
|
28180
|
+
}
|
|
28181
|
+
if (typeof value !== "string" || value === "") continue;
|
|
28182
|
+
fragments.push({
|
|
28183
|
+
key,
|
|
28184
|
+
text: value
|
|
28185
|
+
});
|
|
28186
|
+
}
|
|
28187
|
+
return fragments;
|
|
28188
|
+
}
|
|
28189
|
+
/**
|
|
28028
28190
|
* Per-endpoint reasoning-field dialect: observes what the endpoint actually
|
|
28029
28191
|
* sends, and echoes thinking back under the same key.
|
|
28030
28192
|
*
|
|
@@ -28036,16 +28198,40 @@ const DEFAULT_REASONING_KEY = KNOWN_REASONING_KEYS[0];
|
|
|
28036
28198
|
*/
|
|
28037
28199
|
var ReasoningKeyDialect = class {
|
|
28038
28200
|
detected;
|
|
28039
|
-
/**
|
|
28040
|
-
|
|
28041
|
-
|
|
28042
|
-
|
|
28043
|
-
|
|
28044
|
-
|
|
28045
|
-
|
|
28046
|
-
|
|
28047
|
-
|
|
28201
|
+
/**
|
|
28202
|
+
* Every reasoning fragment one inbound delta carries, remembering the dialect.
|
|
28203
|
+
*
|
|
28204
|
+
* The FIRST string-shaped fragment names the key this endpoint speaks, which is
|
|
28205
|
+
* exactly the field the earlier single-match read picked: an endpoint answering
|
|
28206
|
+
* under `reasoning_content` keeps that outbound key even when the same delta
|
|
28207
|
+
* also carries a sibling field, so learning does not change just because a peer
|
|
28208
|
+
* became chattier.
|
|
28209
|
+
*
|
|
28210
|
+
* An element of a `reasoning_details` ARRAY never teaches the dialect: the
|
|
28211
|
+
* outbound key must be a field that takes a plain string, and array elements
|
|
28212
|
+
* could only teach `reasoning_details`, which on that wire is an array. A bare
|
|
28213
|
+
* string `reasoning_details` still teaches it, because that spelling really is
|
|
28214
|
+
* a string.
|
|
28215
|
+
*/
|
|
28216
|
+
observeAll(source) {
|
|
28217
|
+
const fragments = reasoningFragmentsOf(source);
|
|
28218
|
+
const teaching = fragments.find((fragment) => fragment.form === void 0 || fragment.form === "string");
|
|
28219
|
+
if (teaching !== void 0) {
|
|
28220
|
+
this.detected = teaching.key;
|
|
28221
|
+
return fragments;
|
|
28222
|
+
}
|
|
28223
|
+
if (typeof source === "object" && source !== null) {
|
|
28224
|
+
const record = source;
|
|
28225
|
+
for (const key of KNOWN_REASONING_KEYS) if (typeof record[key] === "string") {
|
|
28226
|
+
this.detected = key;
|
|
28227
|
+
break;
|
|
28228
|
+
}
|
|
28048
28229
|
}
|
|
28230
|
+
return fragments;
|
|
28231
|
+
}
|
|
28232
|
+
/** First reasoning fragment on an inbound message or delta, remembering its key. */
|
|
28233
|
+
observe(source) {
|
|
28234
|
+
return this.observeAll(source)[0]?.text;
|
|
28049
28235
|
}
|
|
28050
28236
|
/** The key to serialize thinking into on an outbound assistant message. */
|
|
28051
28237
|
outboundKey() {
|
|
@@ -28213,7 +28399,7 @@ function textOf$6(content) {
|
|
|
28213
28399
|
if (!Array.isArray(content)) return "";
|
|
28214
28400
|
const parts = [];
|
|
28215
28401
|
for (const block of content) {
|
|
28216
|
-
if (!isRecord$
|
|
28402
|
+
if (!isRecord$35(block)) continue;
|
|
28217
28403
|
if (block.type === "text" && typeof block.text === "string") parts.push(sanitizeText$6(block.text));
|
|
28218
28404
|
else if (block.type === "tool-result") parts.push(textOf$6(block.content));
|
|
28219
28405
|
}
|
|
@@ -28222,7 +28408,7 @@ function textOf$6(content) {
|
|
|
28222
28408
|
function toolResultText$6(blocks) {
|
|
28223
28409
|
if (!Array.isArray(blocks)) return "";
|
|
28224
28410
|
return blocks.map((block) => {
|
|
28225
|
-
if (!isRecord$
|
|
28411
|
+
if (!isRecord$35(block)) return "";
|
|
28226
28412
|
if (block.type === "text" && typeof block.text === "string") return sanitizeText$6(block.text);
|
|
28227
28413
|
if (block.type === "tool-result") return toolResultText$6(block.content);
|
|
28228
28414
|
if (block.type === "image") return `[image: ${attachmentLabel$3(block) ?? "attached image"}]`;
|
|
@@ -28240,7 +28426,7 @@ function toolResultBlocks$1(blocks, images) {
|
|
|
28240
28426
|
const out = [];
|
|
28241
28427
|
let hasImage = false;
|
|
28242
28428
|
for (const block of blocks) {
|
|
28243
|
-
if (!isRecord$
|
|
28429
|
+
if (!isRecord$35(block)) continue;
|
|
28244
28430
|
if (block.type === "text" && typeof block.text === "string") {
|
|
28245
28431
|
out.push({
|
|
28246
28432
|
type: "text",
|
|
@@ -28284,13 +28470,27 @@ function toolResultBlocks$1(blocks, images) {
|
|
|
28284
28470
|
* OpenAI `image_url` blocks for one tool result. A `role: "tool"` message can
|
|
28285
28471
|
* only carry text, so these ride on a `user` message appended after the run of
|
|
28286
28472
|
* tool messages rather than inside it.
|
|
28473
|
+
*
|
|
28474
|
+
* A hosted reference is honoured here too, because a `read_image` result or a
|
|
28475
|
+
* screenshot is exactly the kind of image that would otherwise inline a
|
|
28476
|
+
* megabyte into a request the conversation already made large. Sending base64
|
|
28477
|
+
* for an image this request uploaded would also contradict the reference it
|
|
28478
|
+
* cites elsewhere.
|
|
28287
28479
|
*/
|
|
28288
|
-
function toolResultImageBlocks$3(blocks, images) {
|
|
28480
|
+
function toolResultImageBlocks$3(blocks, images, media = {}) {
|
|
28289
28481
|
if (!Array.isArray(blocks)) return [];
|
|
28290
28482
|
const out = [];
|
|
28291
28483
|
for (const block of blocks) {
|
|
28292
|
-
if (!isRecord$
|
|
28484
|
+
if (!isRecord$35(block)) continue;
|
|
28293
28485
|
if (block.type === "image") {
|
|
28486
|
+
const reference = hostedReference(media.imageReferences, block);
|
|
28487
|
+
if (reference !== void 0) {
|
|
28488
|
+
out.push({
|
|
28489
|
+
type: "image_url",
|
|
28490
|
+
image_url: { url: reference }
|
|
28491
|
+
});
|
|
28492
|
+
continue;
|
|
28493
|
+
}
|
|
28294
28494
|
const inline = imageBlockToInline$2(block, images);
|
|
28295
28495
|
if (inline && SUPPORTED_IMAGE_MEDIA_TYPES$3.has(inline.mediaType)) out.push({
|
|
28296
28496
|
type: "image_url",
|
|
@@ -28302,10 +28502,41 @@ function toolResultImageBlocks$3(blocks, images) {
|
|
|
28302
28502
|
});
|
|
28303
28503
|
continue;
|
|
28304
28504
|
}
|
|
28305
|
-
if (block.type === "tool-result") out.push(...toolResultImageBlocks$3(block.content, images));
|
|
28505
|
+
if (block.type === "tool-result") out.push(...toolResultImageBlocks$3(block.content, images, media));
|
|
28306
28506
|
}
|
|
28307
28507
|
return out;
|
|
28308
28508
|
}
|
|
28509
|
+
/** Scheme under which this route cites a file it uploaded. */
|
|
28510
|
+
const HOSTED_FILE_SCHEME = "ms://";
|
|
28511
|
+
/**
|
|
28512
|
+
* The attachment id one block cites, when it cites a durable attachment.
|
|
28513
|
+
*
|
|
28514
|
+
* Only a durable occurrence can have been uploaded: a block carrying its own
|
|
28515
|
+
* `data:` URL has no id, so it is never looked up here and always keeps its
|
|
28516
|
+
* bytes.
|
|
28517
|
+
*/
|
|
28518
|
+
function attachmentIdOf(block) {
|
|
28519
|
+
const attachment = isRecord$35(block.attachment) ? block.attachment : void 0;
|
|
28520
|
+
const id = attachment === void 0 ? void 0 : asString$16(attachment.attachmentId);
|
|
28521
|
+
return id === void 0 || id === "" ? void 0 : id;
|
|
28522
|
+
}
|
|
28523
|
+
/**
|
|
28524
|
+
* The hosted reference for one block, when this request uploaded it.
|
|
28525
|
+
*
|
|
28526
|
+
* A value that is not an `ms://` reference is IGNORED rather than sent. This is
|
|
28527
|
+
* the one place a per-account cache key could reach the wire, so a bare id, an
|
|
28528
|
+
* empty string or an http URL is dropped instead of being trusted; the
|
|
28529
|
+
* occurrence then falls back to its inline bytes, which always work.
|
|
28530
|
+
*/
|
|
28531
|
+
function hostedReference(references, block) {
|
|
28532
|
+
if (references === void 0) return void 0;
|
|
28533
|
+
const id = attachmentIdOf(block);
|
|
28534
|
+
if (id === void 0) return void 0;
|
|
28535
|
+
const reference = references.get(id);
|
|
28536
|
+
if (reference === void 0) return void 0;
|
|
28537
|
+
const trimmed = reference.trim();
|
|
28538
|
+
return trimmed.startsWith(HOSTED_FILE_SCHEME) && trimmed.length > 5 ? trimmed : void 0;
|
|
28539
|
+
}
|
|
28309
28540
|
function toolCallArguments$5(raw) {
|
|
28310
28541
|
if (typeof raw === "string") return raw;
|
|
28311
28542
|
if (raw === void 0 || raw === null) return "{}";
|
|
@@ -28350,12 +28581,135 @@ function leadingSystemText$6(options) {
|
|
|
28350
28581
|
function nonSystemMessages$6(options) {
|
|
28351
28582
|
return options.messages.filter((message) => message.role !== "system");
|
|
28352
28583
|
}
|
|
28353
|
-
|
|
28354
|
-
|
|
28355
|
-
|
|
28356
|
-
|
|
28357
|
-
|
|
28358
|
-
|
|
28584
|
+
const NO_REASONING = {
|
|
28585
|
+
fields: [],
|
|
28586
|
+
details: [],
|
|
28587
|
+
joined: ""
|
|
28588
|
+
};
|
|
28589
|
+
/** Form tag read back from persisted provenance; undefined for an unknown one. */
|
|
28590
|
+
function readReasoningForm(value) {
|
|
28591
|
+
return value === "string" || value === "text" || value === "summary" || value === "encrypted" ? value : void 0;
|
|
28592
|
+
}
|
|
28593
|
+
/**
|
|
28594
|
+
* Provenance recorded for one reasoning block by the stream.
|
|
28595
|
+
*
|
|
28596
|
+
* Every shape that cannot be verified returns undefined, so a block written by
|
|
28597
|
+
* an older generation of this file - or one whose metadata was lost in transit -
|
|
28598
|
+
* falls back to the single dialect key instead of being split on a guess.
|
|
28599
|
+
*/
|
|
28600
|
+
function reasoningRunsAt(message, blockIndex) {
|
|
28601
|
+
const state = message.source?.replayState;
|
|
28602
|
+
if (!isRecord$35(state) || !Array.isArray(state.blocks)) return void 0;
|
|
28603
|
+
const entry = state.blocks[blockIndex];
|
|
28604
|
+
if (!isRecord$35(entry) || !Array.isArray(entry.reasoning)) return void 0;
|
|
28605
|
+
const runs = [];
|
|
28606
|
+
for (const raw of entry.reasoning) {
|
|
28607
|
+
if (!isRecord$35(raw)) return void 0;
|
|
28608
|
+
const key = asString$16(raw.key);
|
|
28609
|
+
const length = raw.length;
|
|
28610
|
+
if (key === void 0 || typeof length !== "number" || !Number.isInteger(length) || length < 0) return void 0;
|
|
28611
|
+
const form = readReasoningForm(raw.form);
|
|
28612
|
+
const wireType = asString$16(raw.wireType);
|
|
28613
|
+
const index = typeof raw.index === "number" && Number.isInteger(raw.index) && raw.index >= 0 ? raw.index : void 0;
|
|
28614
|
+
const encrypted = asString$16(raw.encrypted);
|
|
28615
|
+
runs.push({
|
|
28616
|
+
key,
|
|
28617
|
+
...form === void 0 ? {} : { form },
|
|
28618
|
+
...wireType === void 0 ? {} : { wireType },
|
|
28619
|
+
...index === void 0 ? {} : { index },
|
|
28620
|
+
...encrypted === void 0 ? {} : { encrypted },
|
|
28621
|
+
length
|
|
28622
|
+
});
|
|
28623
|
+
}
|
|
28624
|
+
return runs.length === 0 ? void 0 : runs;
|
|
28625
|
+
}
|
|
28626
|
+
/**
|
|
28627
|
+
* Split one message's reasoning back onto the shapes it arrived in.
|
|
28628
|
+
*
|
|
28629
|
+
* The block text stays authoritative: the recorded runs only say where its
|
|
28630
|
+
* slices belong. Their total must equal the block's length exactly, and one
|
|
28631
|
+
* mismatch abandons the split for that block rather than writing a truncated
|
|
28632
|
+
* prefix under the wrong field. An encrypted run has length 0, so it changes
|
|
28633
|
+
* neither the total nor the offsets while still producing its element.
|
|
28634
|
+
*
|
|
28635
|
+
* `fallbackKey` is the learned dialect, used for reasoning with no surviving
|
|
28636
|
+
* provenance - every message written before this provenance existed, and any
|
|
28637
|
+
* message whose metadata was dropped in transit.
|
|
28638
|
+
*/
|
|
28639
|
+
function replayedReasoning(message, fallbackKey) {
|
|
28640
|
+
if (!Array.isArray(message.content)) return NO_REASONING;
|
|
28641
|
+
const order = [];
|
|
28642
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
28643
|
+
const details = [];
|
|
28644
|
+
let detailsString;
|
|
28645
|
+
let joined = "";
|
|
28646
|
+
const put = (key, text) => {
|
|
28647
|
+
let parts = byKey.get(key);
|
|
28648
|
+
if (parts === void 0) {
|
|
28649
|
+
parts = [];
|
|
28650
|
+
order.push(key);
|
|
28651
|
+
byKey.set(key, parts);
|
|
28652
|
+
}
|
|
28653
|
+
parts.push(text);
|
|
28654
|
+
};
|
|
28655
|
+
for (let blockIndex = 0; blockIndex < message.content.length; blockIndex++) {
|
|
28656
|
+
const block = message.content[blockIndex];
|
|
28657
|
+
if (!isRecord$35(block) || block.type !== "reasoning" || typeof block.text !== "string") continue;
|
|
28658
|
+
const text = sanitizeText$6(block.text);
|
|
28659
|
+
joined += text;
|
|
28660
|
+
const runs = reasoningRunsAt(message, blockIndex);
|
|
28661
|
+
const total = runs === void 0 ? -1 : runs.reduce((sum, run) => sum + run.length, 0);
|
|
28662
|
+
if (runs === void 0 || total !== text.length) {
|
|
28663
|
+
if (text !== "") put(fallbackKey, text);
|
|
28664
|
+
continue;
|
|
28665
|
+
}
|
|
28666
|
+
let offset = 0;
|
|
28667
|
+
for (const run of runs) {
|
|
28668
|
+
const slice = text.slice(offset, offset + run.length);
|
|
28669
|
+
offset += run.length;
|
|
28670
|
+
if (run.key !== "reasoning_details") {
|
|
28671
|
+
if (slice !== "") put(run.key, slice);
|
|
28672
|
+
continue;
|
|
28673
|
+
}
|
|
28674
|
+
if (run.form === "encrypted") {
|
|
28675
|
+
if (run.encrypted !== void 0 && run.encrypted !== "") details.push({
|
|
28676
|
+
form: "encrypted",
|
|
28677
|
+
encrypted: run.encrypted,
|
|
28678
|
+
...run.wireType === void 0 ? {} : { wireType: run.wireType },
|
|
28679
|
+
...run.index === void 0 ? {} : { index: run.index }
|
|
28680
|
+
});
|
|
28681
|
+
continue;
|
|
28682
|
+
}
|
|
28683
|
+
if (slice === "") continue;
|
|
28684
|
+
if (run.form === "text") {
|
|
28685
|
+
details.push({
|
|
28686
|
+
form: "text",
|
|
28687
|
+
text: slice,
|
|
28688
|
+
...run.index === void 0 ? {} : { index: run.index }
|
|
28689
|
+
});
|
|
28690
|
+
continue;
|
|
28691
|
+
}
|
|
28692
|
+
if (run.form === "summary") {
|
|
28693
|
+
details.push({
|
|
28694
|
+
form: "summary",
|
|
28695
|
+
summary: slice,
|
|
28696
|
+
...run.wireType === void 0 ? {} : { wireType: run.wireType },
|
|
28697
|
+
...run.index === void 0 ? {} : { index: run.index }
|
|
28698
|
+
});
|
|
28699
|
+
continue;
|
|
28700
|
+
}
|
|
28701
|
+
detailsString = (detailsString ?? "") + slice;
|
|
28702
|
+
}
|
|
28703
|
+
}
|
|
28704
|
+
return {
|
|
28705
|
+
fields: order.map((key) => ({
|
|
28706
|
+
key,
|
|
28707
|
+
text: byKey.get(key).join("")
|
|
28708
|
+
})),
|
|
28709
|
+
...detailsString === void 0 ? {} : { detailsString },
|
|
28710
|
+
details,
|
|
28711
|
+
joined
|
|
28712
|
+
};
|
|
28359
28713
|
}
|
|
28360
28714
|
/**
|
|
28361
28715
|
* A tool declaration that belongs to a message rather than the request.
|
|
@@ -28402,7 +28756,7 @@ function openAIUserContent$2(message, images, media = {}) {
|
|
|
28402
28756
|
const parts = [];
|
|
28403
28757
|
let hasRichPart = false;
|
|
28404
28758
|
for (const block of message.content) {
|
|
28405
|
-
if (!isRecord$
|
|
28759
|
+
if (!isRecord$35(block)) continue;
|
|
28406
28760
|
if (block.type === "text" && typeof block.text === "string") {
|
|
28407
28761
|
const text = sanitizeText$6(block.text);
|
|
28408
28762
|
if (text !== "") parts.push({
|
|
@@ -28410,18 +28764,36 @@ function openAIUserContent$2(message, images, media = {}) {
|
|
|
28410
28764
|
text
|
|
28411
28765
|
});
|
|
28412
28766
|
} else if (block.type === "image") {
|
|
28413
|
-
const
|
|
28414
|
-
if (
|
|
28767
|
+
const reference = hostedReference(media.imageReferences, block);
|
|
28768
|
+
if (reference !== void 0) {
|
|
28415
28769
|
hasRichPart = true;
|
|
28416
28770
|
parts.push({
|
|
28417
28771
|
type: "image_url",
|
|
28418
|
-
image_url: { url:
|
|
28772
|
+
image_url: { url: reference }
|
|
28419
28773
|
});
|
|
28420
|
-
} else
|
|
28421
|
-
|
|
28422
|
-
|
|
28423
|
-
|
|
28774
|
+
} else {
|
|
28775
|
+
const inline = imageBlockToInline$2(block, images);
|
|
28776
|
+
if (inline && SUPPORTED_IMAGE_MEDIA_TYPES$3.has(inline.mediaType)) {
|
|
28777
|
+
hasRichPart = true;
|
|
28778
|
+
parts.push({
|
|
28779
|
+
type: "image_url",
|
|
28780
|
+
image_url: { url: `data:${inline.mediaType};base64,${inline.data}` }
|
|
28781
|
+
});
|
|
28782
|
+
} else parts.push({
|
|
28783
|
+
type: "text",
|
|
28784
|
+
text: unavailableImageText$3(block)
|
|
28785
|
+
});
|
|
28786
|
+
}
|
|
28424
28787
|
} else if (block.type === "video") {
|
|
28788
|
+
const reference = hostedReference(media.videoReferences, block);
|
|
28789
|
+
if (reference !== void 0) {
|
|
28790
|
+
hasRichPart = true;
|
|
28791
|
+
parts.push({
|
|
28792
|
+
type: "video_url",
|
|
28793
|
+
video_url: { url: reference }
|
|
28794
|
+
});
|
|
28795
|
+
continue;
|
|
28796
|
+
}
|
|
28425
28797
|
const outcome = videoBlockToInline(block, media.videos ?? /* @__PURE__ */ new Map(), media.videoAccepted === true, videoOmissionText$1);
|
|
28426
28798
|
if ("inline" in outcome) {
|
|
28427
28799
|
hasRichPart = true;
|
|
@@ -28438,11 +28810,11 @@ function openAIUserContent$2(message, images, media = {}) {
|
|
|
28438
28810
|
if (!hasRichPart) return parts.map((part) => typeof part.text === "string" ? part.text : "").join("");
|
|
28439
28811
|
return parts;
|
|
28440
28812
|
}
|
|
28441
|
-
function openAIAssistantContent$2(message, toolCallIds) {
|
|
28813
|
+
function openAIAssistantContent$2(message, toolCallIds, reasoningKey) {
|
|
28442
28814
|
const textParts = [];
|
|
28443
28815
|
const toolCalls = [];
|
|
28444
28816
|
for (const block of message.content) {
|
|
28445
|
-
if (!isRecord$
|
|
28817
|
+
if (!isRecord$35(block)) continue;
|
|
28446
28818
|
if (block.type === "text" && typeof block.text === "string") textParts.push(sanitizeText$6(block.text));
|
|
28447
28819
|
else if (block.type === "tool-call" && typeof block.name === "string") toolCalls.push({
|
|
28448
28820
|
id: toolCallIds.normalize(typeof block.id === "string" && block.id !== "" ? block.id : `call_${toolCalls.length}`),
|
|
@@ -28456,7 +28828,7 @@ function openAIAssistantContent$2(message, toolCallIds) {
|
|
|
28456
28828
|
return {
|
|
28457
28829
|
content: textParts.join(""),
|
|
28458
28830
|
toolCalls,
|
|
28459
|
-
reasoning:
|
|
28831
|
+
reasoning: replayedReasoning(message, reasoningKey)
|
|
28460
28832
|
};
|
|
28461
28833
|
}
|
|
28462
28834
|
/** Why one declaration could not be put on the wire, as the model sees it. */
|
|
@@ -28518,6 +28890,58 @@ function declarationSlots(options, media) {
|
|
|
28518
28890
|
}
|
|
28519
28891
|
return slots;
|
|
28520
28892
|
}
|
|
28893
|
+
/**
|
|
28894
|
+
* Write one assistant turn's reasoning under the field it arrived under.
|
|
28895
|
+
*
|
|
28896
|
+
* Two rules are in tension here and both matter:
|
|
28897
|
+
*
|
|
28898
|
+
* - Preserved Thinking requires a reasoning field on every assistant message, so
|
|
28899
|
+
* the learned dialect key is ALWAYS written, with an empty string when the
|
|
28900
|
+
* turn produced no reasoning. Omitting it is the documented cause of
|
|
28901
|
+
* "thinking is enabled but reasoning_content is missing in assistant tool call
|
|
28902
|
+
* message at index N".
|
|
28903
|
+
* - A replayed fragment must not be written under a key it did not come from, so
|
|
28904
|
+
* each surviving field is written on its own and nothing is concatenated onto
|
|
28905
|
+
* the dialect key. `reasoning_details` goes back in the shape it arrived in: a
|
|
28906
|
+
* bare string stays a string, elements stay an array.
|
|
28907
|
+
*/
|
|
28908
|
+
function applyReplayedReasoning(entry, reasoning, dialectKey) {
|
|
28909
|
+
const fields = reasoning.fields.length === 0 ? [{
|
|
28910
|
+
key: dialectKey,
|
|
28911
|
+
text: ""
|
|
28912
|
+
}] : reasoning.fields;
|
|
28913
|
+
for (const field of fields) entry[field.key] = field.text;
|
|
28914
|
+
if (fields.every((field) => field.key !== dialectKey)) entry[dialectKey] = "";
|
|
28915
|
+
if (reasoning.details.length > 0) {
|
|
28916
|
+
const elements = reasoning.details.map(replayedDetailElement);
|
|
28917
|
+
if (reasoning.detailsString !== void 0 && reasoning.detailsString !== "") elements.unshift({ summary: reasoning.detailsString });
|
|
28918
|
+
entry.reasoning_details = elements;
|
|
28919
|
+
} else if (reasoning.detailsString !== void 0) entry.reasoning_details = reasoning.detailsString;
|
|
28920
|
+
}
|
|
28921
|
+
/**
|
|
28922
|
+
* One replayed element, in the shape the peer sent it in.
|
|
28923
|
+
*
|
|
28924
|
+
* `type` is echoed only when the wire carried one (a summary may have none), and
|
|
28925
|
+
* `index` is echoed only when the wire carried one - neither is invented.
|
|
28926
|
+
*/
|
|
28927
|
+
function replayedDetailElement(detail) {
|
|
28928
|
+
const index = detail.index === void 0 ? {} : { index: detail.index };
|
|
28929
|
+
if (detail.form === "encrypted") return {
|
|
28930
|
+
...detail.wireType === void 0 ? {} : { type: detail.wireType },
|
|
28931
|
+
encrypted: detail.encrypted,
|
|
28932
|
+
...index
|
|
28933
|
+
};
|
|
28934
|
+
if (detail.form === "summary") return {
|
|
28935
|
+
...detail.wireType === void 0 ? {} : { type: detail.wireType },
|
|
28936
|
+
summary: detail.summary,
|
|
28937
|
+
...index
|
|
28938
|
+
};
|
|
28939
|
+
return {
|
|
28940
|
+
type: "reasoning.text",
|
|
28941
|
+
text: detail.text,
|
|
28942
|
+
...index
|
|
28943
|
+
};
|
|
28944
|
+
}
|
|
28521
28945
|
/** Build one `/chat/completions` body. */
|
|
28522
28946
|
function buildOpenAIRequest(options, images = NO_RESOLVED_IMAGES$3, preserveThinking = preserveThinkingEnabled(), media = {}) {
|
|
28523
28947
|
const effort = mapReasoningEffort(options.reasoningEffort === void 0 ? void 0 : String(options.reasoningEffort));
|
|
@@ -28553,13 +28977,13 @@ function buildOpenAIRequest(options, images = NO_RESOLVED_IMAGES$3, preserveThin
|
|
|
28553
28977
|
nonSystemIndex += 1;
|
|
28554
28978
|
}
|
|
28555
28979
|
const block = current.content[0];
|
|
28556
|
-
const callId = isRecord$
|
|
28980
|
+
const callId = isRecord$35(block) && typeof block.toolCallId === "string" ? block.toolCallId : "";
|
|
28557
28981
|
messages.push({
|
|
28558
28982
|
role: "tool",
|
|
28559
28983
|
tool_call_id: toolCallIds.normalize(callId),
|
|
28560
28984
|
content: toolResultText$6(current.content)
|
|
28561
28985
|
});
|
|
28562
|
-
imageBlocks.push(...toolResultImageBlocks$3(current.content, images));
|
|
28986
|
+
imageBlocks.push(...toolResultImageBlocks$3(current.content, images, media));
|
|
28563
28987
|
index += 1;
|
|
28564
28988
|
}
|
|
28565
28989
|
index -= 1;
|
|
@@ -28570,12 +28994,13 @@ function buildOpenAIRequest(options, images = NO_RESOLVED_IMAGES$3, preserveThin
|
|
|
28570
28994
|
continue;
|
|
28571
28995
|
}
|
|
28572
28996
|
if (message.role === "assistant") {
|
|
28573
|
-
const
|
|
28574
|
-
|
|
28997
|
+
const reasoningKey = reasoningDialect.outboundKey();
|
|
28998
|
+
const { content, toolCalls, reasoning } = openAIAssistantContent$2(message, toolCallIds, reasoningKey);
|
|
28999
|
+
if (content === "" && toolCalls.length === 0 && reasoning.fields.length === 0 && reasoning.details.length === 0) continue;
|
|
28575
29000
|
const entry = { role: "assistant" };
|
|
28576
29001
|
if (content !== "" || toolCalls.length === 0) entry.content = content;
|
|
28577
29002
|
if (toolCalls.length > 0) entry.tool_calls = toolCalls;
|
|
28578
|
-
if (thinkingOn) entry
|
|
29003
|
+
if (thinkingOn) applyReplayedReasoning(entry, reasoning, reasoningKey);
|
|
28579
29004
|
messages.push(entry);
|
|
28580
29005
|
continue;
|
|
28581
29006
|
}
|
|
@@ -28639,7 +29064,7 @@ function anthropicUserContent$2(message, images, toolCallIds) {
|
|
|
28639
29064
|
if (!Array.isArray(message.content)) return [];
|
|
28640
29065
|
const blocks = [];
|
|
28641
29066
|
for (const block of message.content) {
|
|
28642
|
-
if (!isRecord$
|
|
29067
|
+
if (!isRecord$35(block)) continue;
|
|
28643
29068
|
if (block.type === "video") {
|
|
28644
29069
|
blocks.push({
|
|
28645
29070
|
type: "text",
|
|
@@ -28683,7 +29108,7 @@ function anthropicUserContent$2(message, images, toolCallIds) {
|
|
|
28683
29108
|
function anthropicAssistantContent$2(message, toolCallIds) {
|
|
28684
29109
|
const blocks = [];
|
|
28685
29110
|
for (const block of message.content) {
|
|
28686
|
-
if (!isRecord$
|
|
29111
|
+
if (!isRecord$35(block)) continue;
|
|
28687
29112
|
if (block.type === "text" && typeof block.text === "string") {
|
|
28688
29113
|
const text = sanitizeText$6(block.text);
|
|
28689
29114
|
if (text !== "") blocks.push({
|
|
@@ -28696,7 +29121,7 @@ function anthropicAssistantContent$2(message, toolCallIds) {
|
|
|
28696
29121
|
type: "tool_use",
|
|
28697
29122
|
id: toolCallIds.normalize(typeof block.id === "string" && block.id !== "" ? block.id : `toolu_${blocks.length}`),
|
|
28698
29123
|
name: block.name,
|
|
28699
|
-
input: isRecord$
|
|
29124
|
+
input: isRecord$35(parsed) ? parsed : {}
|
|
28700
29125
|
});
|
|
28701
29126
|
}
|
|
28702
29127
|
}
|
|
@@ -28818,7 +29243,7 @@ function walkJson(value, visit) {
|
|
|
28818
29243
|
for (const item of value) walkJson(item, visit);
|
|
28819
29244
|
return;
|
|
28820
29245
|
}
|
|
28821
|
-
if (!isRecord$
|
|
29246
|
+
if (!isRecord$35(value)) return;
|
|
28822
29247
|
visit(value);
|
|
28823
29248
|
for (const nested of Object.values(value)) walkJson(nested, visit);
|
|
28824
29249
|
}
|
|
@@ -28834,12 +29259,12 @@ function requestBodyBreakdown(body, carriesVideo = false) {
|
|
|
28834
29259
|
const totalBytes = Buffer.byteLength(serialized, "utf8");
|
|
28835
29260
|
let imageBytes = 0;
|
|
28836
29261
|
walkJson(body, (node) => {
|
|
28837
|
-
const url = isRecord$
|
|
29262
|
+
const url = isRecord$35(node.image_url) ? asString$16(node.image_url.url) : void 0;
|
|
28838
29263
|
if (url?.startsWith("data:")) {
|
|
28839
29264
|
imageBytes += Buffer.byteLength(url, "utf8");
|
|
28840
29265
|
return;
|
|
28841
29266
|
}
|
|
28842
|
-
const source = isRecord$
|
|
29267
|
+
const source = isRecord$35(node.source) ? node.source : void 0;
|
|
28843
29268
|
if (source && asString$16(source.data) !== void 0 && asString$16(source.media_type) !== void 0) imageBytes += Buffer.byteLength(asString$16(source.data) ?? "", "utf8");
|
|
28844
29269
|
});
|
|
28845
29270
|
const toolSchemaBytes = Buffer.byteLength(JSON.stringify(body.tools ?? []), "utf8");
|
|
@@ -28878,6 +29303,7 @@ function createStreamState$4(wire, sessionId) {
|
|
|
28878
29303
|
sessionId: typeof sessionId === "string" && sessionId.trim() !== "" ? sessionId.trim() : void 0,
|
|
28879
29304
|
blocks: [],
|
|
28880
29305
|
current: null,
|
|
29306
|
+
reasoningRuns: /* @__PURE__ */ new Map(),
|
|
28881
29307
|
toolCalls: /* @__PURE__ */ new Map(),
|
|
28882
29308
|
contentIndexes: /* @__PURE__ */ new Map(),
|
|
28883
29309
|
openContentIndex: null,
|
|
@@ -28964,9 +29390,9 @@ function processOpenAIStreamLine(line, state) {
|
|
|
28964
29390
|
}
|
|
28965
29391
|
if (payload === "") return [];
|
|
28966
29392
|
const chunk = safeJsonParse$6(payload);
|
|
28967
|
-
if (!isRecord$
|
|
29393
|
+
if (!isRecord$35(chunk)) return [];
|
|
28968
29394
|
const out = [];
|
|
28969
|
-
const errorPayload = isRecord$
|
|
29395
|
+
const errorPayload = isRecord$35(chunk.error) ? chunk.error : void 0;
|
|
28970
29396
|
if (errorPayload !== void 0) {
|
|
28971
29397
|
const message = asString$16(errorPayload.message) ?? "unknown error";
|
|
28972
29398
|
state.streamError = {
|
|
@@ -28976,34 +29402,47 @@ function processOpenAIStreamLine(line, state) {
|
|
|
28976
29402
|
};
|
|
28977
29403
|
throw new LlmError$1(`Kimi Code stream error: ${message}`, isContextOverflow(errorPayload) ? CONTEXT_OVERFLOW_CODE : "PROVIDER_ERROR");
|
|
28978
29404
|
}
|
|
28979
|
-
const usage = isRecord$
|
|
29405
|
+
const usage = isRecord$35(chunk.usage) ? chunk.usage : void 0;
|
|
28980
29406
|
if (usage) {
|
|
28981
29407
|
state.sawUsage = true;
|
|
28982
29408
|
const prompt = numberOr$7(usage.prompt_tokens, 0);
|
|
28983
|
-
const details = isRecord$
|
|
29409
|
+
const details = isRecord$35(usage.prompt_tokens_details) ? usage.prompt_tokens_details : void 0;
|
|
28984
29410
|
const cached = details ? numberOr$7(details.cached_tokens, 0) : 0;
|
|
28985
29411
|
const written = details ? numberOr$7(details.cache_write_tokens, 0) : 0;
|
|
28986
29412
|
state.inputTokens = Math.max(0, prompt - cached - written);
|
|
28987
29413
|
state.cacheReadTokens = cached;
|
|
28988
29414
|
state.cacheWriteTokens = written;
|
|
28989
29415
|
state.outputTokens = numberOr$7(usage.completion_tokens, state.outputTokens);
|
|
28990
|
-
if (isRecord$
|
|
29416
|
+
if (isRecord$35(usage.completion_tokens_details)) state.reasoningTokens = numberOr$7(usage.completion_tokens_details.reasoning_tokens, state.reasoningTokens);
|
|
28991
29417
|
}
|
|
28992
29418
|
const choices = Array.isArray(chunk.choices) ? chunk.choices : [];
|
|
28993
|
-
const choice = isRecord$
|
|
28994
|
-
const delta = isRecord$
|
|
29419
|
+
const choice = isRecord$35(choices[0]) ? choices[0] : void 0;
|
|
29420
|
+
const delta = isRecord$35(choice?.delta) ? choice.delta : void 0;
|
|
28995
29421
|
if (delta) {
|
|
28996
|
-
const
|
|
28997
|
-
|
|
29422
|
+
for (const fragment of reasoningDialect.observeAll(delta)) {
|
|
29423
|
+
const text = sanitizeText$6(fragment.text);
|
|
29424
|
+
if (text === "" && fragment.form !== "encrypted") continue;
|
|
28998
29425
|
out.push(...closeToolCalls$4(state));
|
|
28999
29426
|
if (state.current === null || state.current.type !== "reasoning") out.push(...openTextBlock$4(state, "reasoning"));
|
|
29000
|
-
|
|
29001
|
-
|
|
29002
|
-
|
|
29003
|
-
|
|
29004
|
-
|
|
29005
|
-
|
|
29427
|
+
if (text !== "") {
|
|
29428
|
+
state.current.text += text;
|
|
29429
|
+
state.hasContent = true;
|
|
29430
|
+
out.push({
|
|
29431
|
+
type: "reasoning-delta",
|
|
29432
|
+
index: state.current.index,
|
|
29433
|
+
text
|
|
29434
|
+
});
|
|
29435
|
+
}
|
|
29436
|
+
const runs = state.reasoningRuns.get(state.current.index) ?? [];
|
|
29437
|
+
runs.push({
|
|
29438
|
+
key: fragment.key,
|
|
29439
|
+
...fragment.form === void 0 ? {} : { form: fragment.form },
|
|
29440
|
+
...fragment.wireType === void 0 ? {} : { wireType: fragment.wireType },
|
|
29441
|
+
...fragment.index === void 0 ? {} : { index: fragment.index },
|
|
29442
|
+
...fragment.encrypted === void 0 ? {} : { encrypted: fragment.encrypted },
|
|
29443
|
+
length: text.length
|
|
29006
29444
|
});
|
|
29445
|
+
state.reasoningRuns.set(state.current.index, runs);
|
|
29007
29446
|
}
|
|
29008
29447
|
const content = asString$16(delta.content);
|
|
29009
29448
|
if (content !== void 0 && content !== "") {
|
|
@@ -29019,7 +29458,7 @@ function processOpenAIStreamLine(line, state) {
|
|
|
29019
29458
|
}
|
|
29020
29459
|
const toolDeltas = Array.isArray(delta.tool_calls) ? delta.tool_calls : [];
|
|
29021
29460
|
for (const entry of toolDeltas) {
|
|
29022
|
-
if (!isRecord$
|
|
29461
|
+
if (!isRecord$35(entry)) continue;
|
|
29023
29462
|
out.push(...applyOpenAIToolDelta(entry, state));
|
|
29024
29463
|
}
|
|
29025
29464
|
}
|
|
@@ -29033,7 +29472,7 @@ function processOpenAIStreamLine(line, state) {
|
|
|
29033
29472
|
}
|
|
29034
29473
|
function applyOpenAIToolDelta(entry, state) {
|
|
29035
29474
|
const wireIndex = typeof entry.index === "number" ? entry.index : 0;
|
|
29036
|
-
const fn = isRecord$
|
|
29475
|
+
const fn = isRecord$35(entry.function) ? entry.function : {};
|
|
29037
29476
|
const out = [];
|
|
29038
29477
|
let call = state.toolCalls.get(wireIndex);
|
|
29039
29478
|
if (call === void 0) {
|
|
@@ -29088,12 +29527,12 @@ function processAnthropicStreamLine(line, state) {
|
|
|
29088
29527
|
const payload = trimmed.slice(5).trim();
|
|
29089
29528
|
if (payload === "" || payload === "[DONE]") return [];
|
|
29090
29529
|
const event = safeJsonParse$6(payload);
|
|
29091
|
-
if (!isRecord$
|
|
29530
|
+
if (!isRecord$35(event)) return [];
|
|
29092
29531
|
const type = asString$16(event.type);
|
|
29093
29532
|
const out = [];
|
|
29094
29533
|
if (type === "message_start") {
|
|
29095
|
-
const message = isRecord$
|
|
29096
|
-
const usage = message && isRecord$
|
|
29534
|
+
const message = isRecord$35(event.message) ? event.message : void 0;
|
|
29535
|
+
const usage = message && isRecord$35(message.usage) ? message.usage : void 0;
|
|
29097
29536
|
if (usage) {
|
|
29098
29537
|
state.sawUsage = true;
|
|
29099
29538
|
state.inputTokens = numberOr$7(usage.input_tokens, 0);
|
|
@@ -29107,7 +29546,7 @@ function processAnthropicStreamLine(line, state) {
|
|
|
29107
29546
|
}
|
|
29108
29547
|
if (type === "content_block_start") {
|
|
29109
29548
|
const contentIndex = numberOr$7(event.index, 0);
|
|
29110
|
-
const block = isRecord$
|
|
29549
|
+
const block = isRecord$35(event.content_block) ? event.content_block : {};
|
|
29111
29550
|
const blockType = asString$16(block.type);
|
|
29112
29551
|
out.push(...closeCurrent$4(state));
|
|
29113
29552
|
if (blockType === "tool_use") {
|
|
@@ -29157,7 +29596,7 @@ function processAnthropicStreamLine(line, state) {
|
|
|
29157
29596
|
}
|
|
29158
29597
|
if (type === "content_block_delta") {
|
|
29159
29598
|
const contentIndex = numberOr$7(event.index, 0);
|
|
29160
|
-
const delta = isRecord$
|
|
29599
|
+
const delta = isRecord$35(event.delta) ? event.delta : {};
|
|
29161
29600
|
const deltaType = asString$16(delta.type);
|
|
29162
29601
|
if (deltaType === "input_json_delta") {
|
|
29163
29602
|
const pending = state.toolCalls.get(contentIndex);
|
|
@@ -29230,10 +29669,10 @@ function processAnthropicStreamLine(line, state) {
|
|
|
29230
29669
|
return out;
|
|
29231
29670
|
}
|
|
29232
29671
|
if (type === "message_delta") {
|
|
29233
|
-
const delta = isRecord$
|
|
29672
|
+
const delta = isRecord$35(event.delta) ? event.delta : void 0;
|
|
29234
29673
|
const stop = delta ? asString$16(delta.stop_reason) : void 0;
|
|
29235
29674
|
if (stop !== void 0 && stop !== "") state.finishReason = stop;
|
|
29236
|
-
const usage = isRecord$
|
|
29675
|
+
const usage = isRecord$35(event.usage) ? event.usage : void 0;
|
|
29237
29676
|
if (usage) {
|
|
29238
29677
|
state.sawUsage = true;
|
|
29239
29678
|
state.outputTokens = numberOr$7(usage.output_tokens, state.outputTokens);
|
|
@@ -29245,7 +29684,7 @@ function processAnthropicStreamLine(line, state) {
|
|
|
29245
29684
|
return closeStream$3(state);
|
|
29246
29685
|
}
|
|
29247
29686
|
if (type === "error") {
|
|
29248
|
-
const error = isRecord$
|
|
29687
|
+
const error = isRecord$35(event.error) ? event.error : {};
|
|
29249
29688
|
const message = asString$16(error.message) ?? "unknown error";
|
|
29250
29689
|
state.streamError = {
|
|
29251
29690
|
vocabulary: "anthropic",
|
|
@@ -29504,6 +29943,46 @@ function finishReasonFor$6(state) {
|
|
|
29504
29943
|
if (state.hasToolCall || reason === "tool_calls" || reason === "tool_use") return { kind: "tool-calls" };
|
|
29505
29944
|
return { kind: "stop" };
|
|
29506
29945
|
}
|
|
29946
|
+
/**
|
|
29947
|
+
* Replay metadata: which wire field every reasoning slice arrived under.
|
|
29948
|
+
*
|
|
29949
|
+
* The envelope is the only channel this route has for provenance. The harness's
|
|
29950
|
+
* `ReasoningBlock` is `{type, text}`, and its assembler rebuilds a streamed
|
|
29951
|
+
* reasoning block from the accumulated deltas, so a field added to the block
|
|
29952
|
+
* would be dropped before the message is stored. A terminal `finish` chunk's
|
|
29953
|
+
* `replayState` is persisted verbatim onto the assembled message's model
|
|
29954
|
+
* source, which is where the request builder reads it back - the Claude route in
|
|
29955
|
+
* this package relies on the same seam.
|
|
29956
|
+
*
|
|
29957
|
+
* Shape: one entry per emitted block, because assembly discards an envelope
|
|
29958
|
+
* whose block list does not match the emitted block count. A text or tool-call
|
|
29959
|
+
* block is therefore an explicit `null` rather than a skipped slot, and a
|
|
29960
|
+
* reasoning block is `{ reasoning: [{key, form?, wireType?, index?, encrypted?,
|
|
29961
|
+
* length}] }`. Only lengths are stored, never the text, and an encrypted run
|
|
29962
|
+
* carries `length: 0` plus the opaque payload — the one thing that must be
|
|
29963
|
+
* handed back to the provider unchanged. Everything here is plain JSON (strings,
|
|
29964
|
+
* numbers, arrays, nulls), which is what the harness's lossless-JSON check
|
|
29965
|
+
* requires.
|
|
29966
|
+
*/
|
|
29967
|
+
function reasoningReplayState(state) {
|
|
29968
|
+
if (state.reasoningRuns.size === 0) return void 0;
|
|
29969
|
+
const blocks = state.blocks.map((block, index) => {
|
|
29970
|
+
const runs = state.reasoningRuns.get(index);
|
|
29971
|
+
if (runs === void 0 || runs.length === 0 || block.type !== "reasoning") return null;
|
|
29972
|
+
return { reasoning: runs.map((run) => ({
|
|
29973
|
+
key: run.key,
|
|
29974
|
+
...run.form === void 0 ? {} : { form: run.form },
|
|
29975
|
+
...run.wireType === void 0 ? {} : { wireType: run.wireType },
|
|
29976
|
+
...run.index === void 0 ? {} : { index: run.index },
|
|
29977
|
+
...run.encrypted === void 0 ? {} : { encrypted: run.encrypted },
|
|
29978
|
+
length: run.length
|
|
29979
|
+
})) };
|
|
29980
|
+
});
|
|
29981
|
+
return {
|
|
29982
|
+
response: { wire: state.wire },
|
|
29983
|
+
blocks
|
|
29984
|
+
};
|
|
29985
|
+
}
|
|
29507
29986
|
/** Flush every open block, then emit usage and the terminal finish. */
|
|
29508
29987
|
function closeStream$3(state, accountId) {
|
|
29509
29988
|
if (state.finished) return [];
|
|
@@ -29516,9 +29995,11 @@ function closeStream$3(state, accountId) {
|
|
|
29516
29995
|
usage: tokenUsage$4(state)
|
|
29517
29996
|
});
|
|
29518
29997
|
}
|
|
29998
|
+
const replayState = reasoningReplayState(state);
|
|
29519
29999
|
out.push({
|
|
29520
30000
|
type: "finish",
|
|
29521
|
-
reason: finishReasonFor$6(state)
|
|
30001
|
+
reason: finishReasonFor$6(state),
|
|
30002
|
+
...replayState === void 0 ? {} : { replayState }
|
|
29522
30003
|
});
|
|
29523
30004
|
return out;
|
|
29524
30005
|
}
|
|
@@ -29527,6 +30008,532 @@ function assertStreamComplete$4(state) {
|
|
|
29527
30008
|
if (!state.done && state.finishReason === null) throw new LlmError$1("Kimi Code stream ended before its terminal event", "TRANSPORT");
|
|
29528
30009
|
}
|
|
29529
30010
|
//#endregion
|
|
30011
|
+
//#region src/host/kimi-code/media-files.ts
|
|
30012
|
+
/**
|
|
30013
|
+
* Kimi Code hosted-file (media upload) client.
|
|
30014
|
+
*
|
|
30015
|
+
* WHY THIS FILE EXISTS. Everything this plugin has ever sent to the Kimi Code
|
|
30016
|
+
* gateway carries media INLINE, as a `data:<type>;base64,...` URL
|
|
30017
|
+
* (mapper.ts builds both the image and the video block that way). The gateway
|
|
30018
|
+
* also accepts a hosted reference instead: upload the bytes once, cite
|
|
30019
|
+
* `ms://<id>` afterwards. That is the only way to send a clip whose base64 would
|
|
30020
|
+
* overrun the request body ceiling, and it is what this module implements.
|
|
30021
|
+
*
|
|
30022
|
+
* EVERY WIRE FACT BELOW WAS MEASURED live against the subscription gateway by
|
|
30023
|
+
* `scripts/probe-kimi-files.probe.ts` on this line's own account and region,
|
|
30024
|
+
* not copied from the official client:
|
|
30025
|
+
*
|
|
30026
|
+
* - the upload is `POST {coding base}/v1/files`, `multipart/form-data` with a
|
|
30027
|
+
* `file` part and a `purpose` part whose value is `image` or `video`
|
|
30028
|
+
* (note: NOT the `*_understanding` vocabulary the MiniMax line uses);
|
|
30029
|
+
* - it authenticates with the bearer token plus the same `X-Msh-*` identity
|
|
30030
|
+
* headers every other request on this line sends;
|
|
30031
|
+
* - the body answers with the id at the top level or nested under
|
|
30032
|
+
* `data`/`file`/`result`, and the reference a later chat body cites is
|
|
30033
|
+
* `ms://<id>`;
|
|
30034
|
+
* - `content-type` is never set by hand: the runtime writes
|
|
30035
|
+
* `multipart/form-data; boundary=...` itself, and a hand-written JSON header
|
|
30036
|
+
* on a form body is a malformed request.
|
|
30037
|
+
*
|
|
30038
|
+
* DELIBERATELY NARROW. No adapter, mapper or route is touched here: this module
|
|
30039
|
+
* only uploads, caches and returns a reference. Integration is a later change.
|
|
30040
|
+
*
|
|
30041
|
+
* @module dsh-chatgpt-subscription/kimi-media-files
|
|
30042
|
+
*/
|
|
30043
|
+
/** Upload route, relative to a base URL that may already carry `/v1`. */
|
|
30044
|
+
const FILES_UPLOAD_PATH$1 = "/v1/files";
|
|
30045
|
+
/** Scheme a stored id is cited by on the wire. */
|
|
30046
|
+
const FILE_REF_SCHEME$1 = "ms://";
|
|
30047
|
+
/** Time budget for one upload request. */
|
|
30048
|
+
const MEDIA_UPLOAD_TIMEOUT_MS = 12e4;
|
|
30049
|
+
/**
|
|
30050
|
+
* One failed upload.
|
|
30051
|
+
*
|
|
30052
|
+
* Carries the HTTP status and a REDACTED digest of the response body so a
|
|
30053
|
+
* caller can decide (401 -> sign in again, 5xx -> retry) without the raw body
|
|
30054
|
+
* reaching a log. The access token is never placed in `message` or `detail`;
|
|
30055
|
+
* see {@link redact}.
|
|
30056
|
+
*/
|
|
30057
|
+
var KimiMediaUploadError = class extends Error {
|
|
30058
|
+
failure;
|
|
30059
|
+
status;
|
|
30060
|
+
/** Redacted one-line digest of the response body, or '' when there was none. */
|
|
30061
|
+
detail;
|
|
30062
|
+
constructor(failure, message, options = {}) {
|
|
30063
|
+
super(message);
|
|
30064
|
+
this.name = "KimiMediaUploadError";
|
|
30065
|
+
this.failure = failure;
|
|
30066
|
+
this.status = options.status ?? null;
|
|
30067
|
+
this.detail = options.detail ?? "";
|
|
30068
|
+
}
|
|
30069
|
+
};
|
|
30070
|
+
/**
|
|
30071
|
+
* The upload URL for one coding base.
|
|
30072
|
+
*
|
|
30073
|
+
* The base this line resolves normally carries neither a version nor a trailing
|
|
30074
|
+
* slash (`https://api.kimi.com/coding`), so the measured route is built by
|
|
30075
|
+
* appending `/v1/files` and the answer is `.../coding/v1/files`. A caller that
|
|
30076
|
+
* passes a base which ALREADY ends in `/v1` — the official client's own
|
|
30077
|
+
* KIMI_CODE_BASE_URL shape — gets the prefix removed once rather than doubled:
|
|
30078
|
+
* `.../coding/v1/v1/files` is a 404 that reads like a missing route.
|
|
30079
|
+
*/
|
|
30080
|
+
function filesUploadUrl$1(baseUrl) {
|
|
30081
|
+
const trimmed = baseUrl.trim().replace(/\/+$/, "");
|
|
30082
|
+
if (trimmed === "") throw new KimiMediaUploadError("invalid-request", "no base URL was given for the media upload");
|
|
30083
|
+
const base = trimmed.replace(/\/v1$/i, "").replace(/\/+$/, "");
|
|
30084
|
+
if (base === "") throw new KimiMediaUploadError("invalid-request", "the media upload base URL has no host");
|
|
30085
|
+
return base + FILES_UPLOAD_PATH$1;
|
|
30086
|
+
}
|
|
30087
|
+
/** The upload purpose one media type maps to, or undefined when unsupported. */
|
|
30088
|
+
function mediaKindFor(mediaType) {
|
|
30089
|
+
const normalized = mediaType.trim().toLowerCase();
|
|
30090
|
+
if (normalized.startsWith("image/")) return "image";
|
|
30091
|
+
if (normalized.startsWith("video/")) return "video";
|
|
30092
|
+
}
|
|
30093
|
+
/** File extensions for the media types this line sends, for the file part's name. */
|
|
30094
|
+
const MEDIA_TYPE_FILENAMES = {
|
|
30095
|
+
"image/png": "image.png",
|
|
30096
|
+
"image/jpeg": "image.jpg",
|
|
30097
|
+
"image/gif": "image.gif",
|
|
30098
|
+
"image/webp": "image.webp",
|
|
30099
|
+
"image/heic": "image.heic",
|
|
30100
|
+
"image/bmp": "image.bmp",
|
|
30101
|
+
"video/mp4": "video.mp4",
|
|
30102
|
+
"video/quicktime": "video.mov",
|
|
30103
|
+
"video/webm": "video.webm",
|
|
30104
|
+
"video/x-msvideo": "video.avi",
|
|
30105
|
+
"video/mpeg": "video.mpeg",
|
|
30106
|
+
"video/mpg": "video.mpg",
|
|
30107
|
+
"video/x-flv": "video.flv",
|
|
30108
|
+
"video/3gpp": "video.3gp"
|
|
30109
|
+
};
|
|
30110
|
+
/**
|
|
30111
|
+
* The name the file part carries.
|
|
30112
|
+
*
|
|
30113
|
+
* A caller-supplied name is reduced to its leaf and stripped of control
|
|
30114
|
+
* characters: the part name is metadata, never a path, so a Windows-style
|
|
30115
|
+
* source name must not travel with its directories. Nothing depends on the
|
|
30116
|
+
* extension, but a reviewer looking at a captured request benefits from a real
|
|
30117
|
+
* one, and some gateways sniff it.
|
|
30118
|
+
*/
|
|
30119
|
+
function filenameFor(kind, mediaType, provided) {
|
|
30120
|
+
const fallback = MEDIA_TYPE_FILENAMES[mediaType.trim().toLowerCase()] ?? (kind === "image" ? "image.bin" : "video.bin");
|
|
30121
|
+
if (provided === void 0) return fallback;
|
|
30122
|
+
const safe = (provided.split(/[\\/]/).pop() ?? "").replace(/[\u0000-\u001f\u007f"]/g, "").trim();
|
|
30123
|
+
return safe === "" ? fallback : safe;
|
|
30124
|
+
}
|
|
30125
|
+
/**
|
|
30126
|
+
* Remove anything token-shaped from a string that may reach a log or an error.
|
|
30127
|
+
*
|
|
30128
|
+
* The token this upload used is removed by exact match first — a body echoing
|
|
30129
|
+
* the request, a proxy page quoting the Authorization header, or a service that
|
|
30130
|
+
* reflects the credential all end up here — then the generic shapes (bearer
|
|
30131
|
+
* values, JWTs, e-mail addresses) are blanked. The result is whitespace-flattened
|
|
30132
|
+
* and bounded so one refusal cannot become a wall of text.
|
|
30133
|
+
*/
|
|
30134
|
+
function redact(text, token, limit = 240) {
|
|
30135
|
+
let out = text;
|
|
30136
|
+
if (token !== "") out = out.split(token).join("<redacted>");
|
|
30137
|
+
return out.replace(/Bearer\s+[A-Za-z0-9._~+/=-]{6,}/gi, "Bearer <redacted>").replace(/eyJ[A-Za-z0-9._-]{8,}/g, "<jwt>").replace(/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g, "<email>").replace(/\s+/g, " ").trim().slice(0, limit);
|
|
30138
|
+
}
|
|
30139
|
+
/** Parse a body without throwing, reporting whether it was JSON at all. */
|
|
30140
|
+
function parseJson(raw) {
|
|
30141
|
+
const text = raw.trim();
|
|
30142
|
+
if (text === "") return {
|
|
30143
|
+
ok: false,
|
|
30144
|
+
value: void 0
|
|
30145
|
+
};
|
|
30146
|
+
try {
|
|
30147
|
+
return {
|
|
30148
|
+
ok: true,
|
|
30149
|
+
value: JSON.parse(text)
|
|
30150
|
+
};
|
|
30151
|
+
} catch {
|
|
30152
|
+
return {
|
|
30153
|
+
ok: false,
|
|
30154
|
+
value: void 0
|
|
30155
|
+
};
|
|
30156
|
+
}
|
|
30157
|
+
}
|
|
30158
|
+
/**
|
|
30159
|
+
* One-line digest of a refusal body.
|
|
30160
|
+
*
|
|
30161
|
+
* A JSON refusal names a code and a sentence; an HTML gateway page names
|
|
30162
|
+
* neither. Both are reduced to a short redacted line, because "the server said
|
|
30163
|
+
* no" and "the server said no because the model does not accept this type" lead
|
|
30164
|
+
* to different fixes.
|
|
30165
|
+
*/
|
|
30166
|
+
function bodyDigest(raw, token) {
|
|
30167
|
+
const text = raw.trim();
|
|
30168
|
+
if (text === "") return "";
|
|
30169
|
+
const parsed = parseJson(text);
|
|
30170
|
+
if (parsed.ok && isRecord$34(parsed.value)) {
|
|
30171
|
+
const root = parsed.value;
|
|
30172
|
+
const nested = isRecord$34(root.error) ? root.error : void 0;
|
|
30173
|
+
const code = firstString(nested?.code) ?? firstString(root.code) ?? firstString(root.error_code) ?? "";
|
|
30174
|
+
const message = nested !== void 0 ? firstString(nested.message) ?? firstString(nested.code) ?? "" : typeof root.error === "string" ? root.error : firstString(root.message) ?? firstString(root.detail) ?? "";
|
|
30175
|
+
const composed = [code === "" ? "" : "code=" + code, message].filter((part) => part !== "").join(" ");
|
|
30176
|
+
if (composed !== "") return redact(composed, token);
|
|
30177
|
+
}
|
|
30178
|
+
return redact(text, token);
|
|
30179
|
+
}
|
|
30180
|
+
/** Keys the id was measured to hide behind, besides a top-level one. */
|
|
30181
|
+
const NESTED_ID_KEYS = [
|
|
30182
|
+
"data",
|
|
30183
|
+
"file",
|
|
30184
|
+
"result"
|
|
30185
|
+
];
|
|
30186
|
+
/** Longest id accepted, so a body echoing a document cannot become a reference. */
|
|
30187
|
+
const MAX_FILE_ID_LENGTH = 200;
|
|
30188
|
+
/** A non-empty, single-token id; anything else is not a reference this line cites. */
|
|
30189
|
+
function normalizeFileId(value) {
|
|
30190
|
+
if (typeof value === "number") return Number.isSafeInteger(value) && value >= 0 ? String(value) : void 0;
|
|
30191
|
+
if (typeof value !== "string") return void 0;
|
|
30192
|
+
const trimmed = value.trim();
|
|
30193
|
+
const bare = trimmed.startsWith("ms://") ? trimmed.slice(5) : trimmed;
|
|
30194
|
+
if (bare === "" || bare.length > MAX_FILE_ID_LENGTH) return void 0;
|
|
30195
|
+
if (/[\s\u0000-\u001f\u007f]/.test(bare)) return void 0;
|
|
30196
|
+
return bare;
|
|
30197
|
+
}
|
|
30198
|
+
/**
|
|
30199
|
+
* The id from a successful upload body.
|
|
30200
|
+
*
|
|
30201
|
+
* The measured body carries it at the top level, and documented shapes nest it
|
|
30202
|
+
* under `data`, `file` or `result`; both are read so a service-side change of
|
|
30203
|
+
* envelope does not blank the whole chain. A body with no id is reported by the
|
|
30204
|
+
* caller as `no-id` rather than accepted as an empty reference.
|
|
30205
|
+
*/
|
|
30206
|
+
function readFileId$1(value, depth = 0) {
|
|
30207
|
+
if (depth > 3) return void 0;
|
|
30208
|
+
if (!isRecord$34(value)) return void 0;
|
|
30209
|
+
const direct = normalizeFileId(value.id);
|
|
30210
|
+
if (direct !== void 0) return direct;
|
|
30211
|
+
for (const key of NESTED_ID_KEYS) {
|
|
30212
|
+
const nested = readFileId$1(value[key], depth + 1);
|
|
30213
|
+
if (nested !== void 0) return nested;
|
|
30214
|
+
}
|
|
30215
|
+
}
|
|
30216
|
+
/** The wire reference for a stored id. */
|
|
30217
|
+
function fileReference(id) {
|
|
30218
|
+
return FILE_REF_SCHEME$1 + id;
|
|
30219
|
+
}
|
|
30220
|
+
/** Hex SHA-256 of the bytes; the content half of the key. */
|
|
30221
|
+
function contentSha256(data) {
|
|
30222
|
+
return createHash("sha256").update(data).digest("hex");
|
|
30223
|
+
}
|
|
30224
|
+
/**
|
|
30225
|
+
* The cache key for one upload.
|
|
30226
|
+
*
|
|
30227
|
+
* Five things, and each of them is load-bearing:
|
|
30228
|
+
*
|
|
30229
|
+
* - ACCOUNT SCOPE, because an id minted for one account is never assumed to be
|
|
30230
|
+
* readable by another (see {@link KimiMediaUploadRequest.accountScope});
|
|
30231
|
+
* - BASE URL (normalized through {@link filesUploadUrl}, so a trailing slash
|
|
30232
|
+
* cannot split one endpoint into two slots), because two regions or two
|
|
30233
|
+
* deployments are two distinct file stores;
|
|
30234
|
+
* - MEDIA KIND and MEDIA TYPE, because the same bytes uploaded as an image and
|
|
30235
|
+
* as a video are two different resources as far as the purpose is concerned;
|
|
30236
|
+
* - CONTENT SHA-256, so identical bytes reuse one upload and any change at all
|
|
30237
|
+
* misses the cache.
|
|
30238
|
+
*
|
|
30239
|
+
* The access token is NOT part of it: a key is written to memory only, but a
|
|
30240
|
+
* token in a key is a token in the next dump, and the account is already
|
|
30241
|
+
* identified by its scope. `|` cannot appear in a scope because the scope is
|
|
30242
|
+
* sanitized here.
|
|
30243
|
+
*/
|
|
30244
|
+
function mediaFileCacheKey(input) {
|
|
30245
|
+
const kind = mediaKindFor(input.mediaType) ?? "unsupported";
|
|
30246
|
+
return [
|
|
30247
|
+
"v1",
|
|
30248
|
+
input.accountScope.trim().replace(/[|\s]+/g, "_"),
|
|
30249
|
+
filesUploadUrl$1(input.baseUrl),
|
|
30250
|
+
kind,
|
|
30251
|
+
input.mediaType.trim().toLowerCase(),
|
|
30252
|
+
contentSha256(input.data)
|
|
30253
|
+
].join("|");
|
|
30254
|
+
}
|
|
30255
|
+
function isRecord$34(value) {
|
|
30256
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
30257
|
+
}
|
|
30258
|
+
function firstString(value) {
|
|
30259
|
+
return typeof value === "string" && value.trim() !== "" ? value.trim() : void 0;
|
|
30260
|
+
}
|
|
30261
|
+
/** Whether one rejection is a cancellation rather than an upload failure. */
|
|
30262
|
+
function looksAborted(error) {
|
|
30263
|
+
if (typeof error !== "object" || error === null) return false;
|
|
30264
|
+
return error.name === "AbortError";
|
|
30265
|
+
}
|
|
30266
|
+
/** The abort to reject a caller with, keeping the reason it supplied. */
|
|
30267
|
+
function abortError(signal) {
|
|
30268
|
+
const reason = signal?.reason;
|
|
30269
|
+
if (reason instanceof Error) return reason;
|
|
30270
|
+
const error = /* @__PURE__ */ new Error("the media upload was aborted");
|
|
30271
|
+
error.name = "AbortError";
|
|
30272
|
+
return error;
|
|
30273
|
+
}
|
|
30274
|
+
/**
|
|
30275
|
+
* Uploads one media file per distinct key, caching and single-flighting them.
|
|
30276
|
+
*
|
|
30277
|
+
* Two behaviours are deliberate and easy to get wrong:
|
|
30278
|
+
*
|
|
30279
|
+
* 1. SINGLE FLIGHT. Concurrent callers with the same key share one request.
|
|
30280
|
+
* A caller that aborts stops waiting immediately and gets an AbortError, but
|
|
30281
|
+
* the shared request is only cancelled once NO caller is still waiting — so
|
|
30282
|
+
* one cancelled turn does not fail another turn that wants the same clip.
|
|
30283
|
+
* 2. NO TTL. A successful reference is cached until it is evicted by the LRU
|
|
30284
|
+
* ceiling. Inventing an expiry would either expire a live id (a failed turn)
|
|
30285
|
+
* or outlive it silently; nothing here measured a lifetime, so nothing here
|
|
30286
|
+
* pretends to know one. A reference the service later rejects is dropped with
|
|
30287
|
+
* {@link forget} by whoever sees that rejection.
|
|
30288
|
+
*/
|
|
30289
|
+
var KimiMediaFilesUploader = class {
|
|
30290
|
+
fetchFn;
|
|
30291
|
+
maxCacheEntries;
|
|
30292
|
+
timeoutMs;
|
|
30293
|
+
/** key -> `ms://<id>`, in least-recently-used order. */
|
|
30294
|
+
cache = /* @__PURE__ */ new Map();
|
|
30295
|
+
flights = /* @__PURE__ */ new Map();
|
|
30296
|
+
constructor(options = {}) {
|
|
30297
|
+
this.fetchFn = options.fetchFn ?? fetch;
|
|
30298
|
+
const cap = options.maxCacheEntries;
|
|
30299
|
+
this.maxCacheEntries = cap !== void 0 && Number.isFinite(cap) && cap > 0 ? Math.floor(cap) : 256;
|
|
30300
|
+
const timeout = options.timeoutMs;
|
|
30301
|
+
this.timeoutMs = timeout !== void 0 && Number.isFinite(timeout) ? timeout : MEDIA_UPLOAD_TIMEOUT_MS;
|
|
30302
|
+
}
|
|
30303
|
+
/** Cached references currently held, for a settings surface or a test. */
|
|
30304
|
+
get size() {
|
|
30305
|
+
return this.cache.size;
|
|
30306
|
+
}
|
|
30307
|
+
/** Uploads one file and returns the `ms://<id>` reference a request cites. */
|
|
30308
|
+
async upload(request) {
|
|
30309
|
+
const resolved = this.resolve(request);
|
|
30310
|
+
if (resolved.signal?.aborted === true) throw abortError(resolved.signal);
|
|
30311
|
+
const cached = this.readCache(resolved.key);
|
|
30312
|
+
if (cached !== void 0) return cached;
|
|
30313
|
+
let flight = this.flights.get(resolved.key);
|
|
30314
|
+
if (flight === void 0) {
|
|
30315
|
+
flight = this.startFlight(resolved);
|
|
30316
|
+
this.flights.set(resolved.key, flight);
|
|
30317
|
+
}
|
|
30318
|
+
return this.join(flight, resolved);
|
|
30319
|
+
}
|
|
30320
|
+
/**
|
|
30321
|
+
* Drop the reference one upload would use.
|
|
30322
|
+
*
|
|
30323
|
+
* The caller that sees a stored id REJECTED on the wire calls this so the next
|
|
30324
|
+
* attempt uploads again instead of replaying the same dead reference.
|
|
30325
|
+
*/
|
|
30326
|
+
forget(request) {
|
|
30327
|
+
let key;
|
|
30328
|
+
try {
|
|
30329
|
+
key = mediaFileCacheKey({
|
|
30330
|
+
accountScope: request.accountScope,
|
|
30331
|
+
baseUrl: request.baseUrl,
|
|
30332
|
+
mediaType: request.mediaType,
|
|
30333
|
+
data: request.data
|
|
30334
|
+
});
|
|
30335
|
+
} catch {
|
|
30336
|
+
return false;
|
|
30337
|
+
}
|
|
30338
|
+
return this.cache.delete(key);
|
|
30339
|
+
}
|
|
30340
|
+
/** Forget everything; a sign-out or a test starting over. */
|
|
30341
|
+
clear() {
|
|
30342
|
+
this.cache.clear();
|
|
30343
|
+
}
|
|
30344
|
+
/** Validate and normalize one request, or throw before anything is sent. */
|
|
30345
|
+
resolve(request) {
|
|
30346
|
+
const accessToken = request.accessToken.trim();
|
|
30347
|
+
if (accessToken === "") throw new KimiMediaUploadError("invalid-request", "the media upload needs an access token");
|
|
30348
|
+
const accountScope = request.accountScope.trim();
|
|
30349
|
+
if (accountScope === "") throw new KimiMediaUploadError("invalid-request", "the media upload needs an account scope for its cache key");
|
|
30350
|
+
if (accountScope === request.accessToken) throw new KimiMediaUploadError("invalid-request", "the media upload cache scope must not be the access token");
|
|
30351
|
+
const mediaType = request.mediaType.trim();
|
|
30352
|
+
const kind = mediaKindFor(mediaType);
|
|
30353
|
+
if (kind === void 0) throw new KimiMediaUploadError("unsupported-media", "the media upload accepts image/* or video/* only, not \"" + mediaType + "\"");
|
|
30354
|
+
if (request.data.byteLength === 0) throw new KimiMediaUploadError("invalid-request", "the media upload was given no bytes");
|
|
30355
|
+
filesUploadUrl$1(request.baseUrl);
|
|
30356
|
+
return {
|
|
30357
|
+
accessToken,
|
|
30358
|
+
baseUrl: request.baseUrl,
|
|
30359
|
+
accountScope,
|
|
30360
|
+
data: request.data,
|
|
30361
|
+
mediaType,
|
|
30362
|
+
kind,
|
|
30363
|
+
filename: filenameFor(kind, mediaType, request.filename),
|
|
30364
|
+
...request.signal === void 0 ? {} : { signal: request.signal },
|
|
30365
|
+
fetchFn: this.fetchFn,
|
|
30366
|
+
timeoutMs: this.timeoutMs,
|
|
30367
|
+
key: mediaFileCacheKey({
|
|
30368
|
+
accountScope,
|
|
30369
|
+
baseUrl: request.baseUrl,
|
|
30370
|
+
mediaType,
|
|
30371
|
+
data: request.data
|
|
30372
|
+
})
|
|
30373
|
+
};
|
|
30374
|
+
}
|
|
30375
|
+
readCache(key) {
|
|
30376
|
+
const ref = this.cache.get(key);
|
|
30377
|
+
if (ref === void 0) return void 0;
|
|
30378
|
+
this.cache.delete(key);
|
|
30379
|
+
this.cache.set(key, ref);
|
|
30380
|
+
return ref;
|
|
30381
|
+
}
|
|
30382
|
+
writeCache(key, ref) {
|
|
30383
|
+
this.cache.delete(key);
|
|
30384
|
+
this.cache.set(key, ref);
|
|
30385
|
+
while (this.cache.size > this.maxCacheEntries) {
|
|
30386
|
+
const oldest = this.cache.keys().next();
|
|
30387
|
+
if (oldest.done === true) break;
|
|
30388
|
+
this.cache.delete(oldest.value);
|
|
30389
|
+
}
|
|
30390
|
+
}
|
|
30391
|
+
/** Open one flight and run it; the map entry is dropped as it settles. */
|
|
30392
|
+
startFlight(request) {
|
|
30393
|
+
const controller = new AbortController();
|
|
30394
|
+
const state = { timedOut: false };
|
|
30395
|
+
const promise = this.performUpload(controller, state, request).finally(() => {
|
|
30396
|
+
if (this.flights.get(request.key)?.promise === promise) this.flights.delete(request.key);
|
|
30397
|
+
});
|
|
30398
|
+
promise.catch(() => void 0);
|
|
30399
|
+
return {
|
|
30400
|
+
promise,
|
|
30401
|
+
controller,
|
|
30402
|
+
waiters: 0,
|
|
30403
|
+
state
|
|
30404
|
+
};
|
|
30405
|
+
}
|
|
30406
|
+
/**
|
|
30407
|
+
* Wait for one flight, respecting THIS caller's abort.
|
|
30408
|
+
*
|
|
30409
|
+
* The flight is not bound to the caller's signal: a caller that aborts
|
|
30410
|
+
* detaches, and the transport is cancelled only when the last waiter has gone.
|
|
30411
|
+
*/
|
|
30412
|
+
async join(flight, request) {
|
|
30413
|
+
const signal = request.signal;
|
|
30414
|
+
if (signal?.aborted === true) throw abortError(signal);
|
|
30415
|
+
flight.waiters += 1;
|
|
30416
|
+
let released = false;
|
|
30417
|
+
const release = () => {
|
|
30418
|
+
if (released) return;
|
|
30419
|
+
released = true;
|
|
30420
|
+
flight.waiters -= 1;
|
|
30421
|
+
if (flight.waiters <= 0) {
|
|
30422
|
+
if (this.flights.get(request.key) === flight) this.flights.delete(request.key);
|
|
30423
|
+
flight.controller.abort();
|
|
30424
|
+
}
|
|
30425
|
+
};
|
|
30426
|
+
if (signal === void 0) try {
|
|
30427
|
+
return await flight.promise;
|
|
30428
|
+
} finally {
|
|
30429
|
+
release();
|
|
30430
|
+
}
|
|
30431
|
+
const callerSignal = signal;
|
|
30432
|
+
let detach;
|
|
30433
|
+
const cancelled = new Promise((_resolve, reject) => {
|
|
30434
|
+
const onAbort = () => reject(abortError(callerSignal));
|
|
30435
|
+
detach = () => callerSignal.removeEventListener("abort", onAbort);
|
|
30436
|
+
callerSignal.addEventListener("abort", onAbort, { once: true });
|
|
30437
|
+
});
|
|
30438
|
+
try {
|
|
30439
|
+
return await Promise.race([flight.promise, cancelled]);
|
|
30440
|
+
} finally {
|
|
30441
|
+
detach?.();
|
|
30442
|
+
release();
|
|
30443
|
+
}
|
|
30444
|
+
}
|
|
30445
|
+
/** The one request a flight performs. */
|
|
30446
|
+
async performUpload(controller, state, request) {
|
|
30447
|
+
const form = new FormData();
|
|
30448
|
+
form.append("file", new Blob([request.data], { type: request.mediaType }), request.filename);
|
|
30449
|
+
form.append("purpose", request.kind);
|
|
30450
|
+
const headers = await kimiIdentityHeaders({
|
|
30451
|
+
authorization: "Bearer " + request.accessToken,
|
|
30452
|
+
accept: "application/json"
|
|
30453
|
+
});
|
|
30454
|
+
const timer = request.timeoutMs > 0 ? setTimeout(() => {
|
|
30455
|
+
state.timedOut = true;
|
|
30456
|
+
controller.abort();
|
|
30457
|
+
}, request.timeoutMs) : void 0;
|
|
30458
|
+
timer?.unref();
|
|
30459
|
+
try {
|
|
30460
|
+
let response;
|
|
30461
|
+
try {
|
|
30462
|
+
response = await request.fetchFn(filesUploadUrl$1(request.baseUrl), {
|
|
30463
|
+
method: "POST",
|
|
30464
|
+
headers,
|
|
30465
|
+
body: form,
|
|
30466
|
+
signal: controller.signal
|
|
30467
|
+
});
|
|
30468
|
+
} catch (error) {
|
|
30469
|
+
throw this.transportFailure(error, state, request);
|
|
30470
|
+
}
|
|
30471
|
+
let raw = "";
|
|
30472
|
+
try {
|
|
30473
|
+
raw = await response.text();
|
|
30474
|
+
} catch (error) {
|
|
30475
|
+
throw this.transportFailure(error, state, request);
|
|
30476
|
+
}
|
|
30477
|
+
return this.settle(response, raw, request);
|
|
30478
|
+
} finally {
|
|
30479
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
30480
|
+
}
|
|
30481
|
+
}
|
|
30482
|
+
/** Turn a transport rejection into the error the caller must see. */
|
|
30483
|
+
transportFailure(error, state, request) {
|
|
30484
|
+
if (looksAborted(error)) {
|
|
30485
|
+
if (state.timedOut) return new KimiMediaUploadError("timeout", "the media upload did not finish within " + request.timeoutMs + " ms");
|
|
30486
|
+
return abortError();
|
|
30487
|
+
}
|
|
30488
|
+
return new KimiMediaUploadError("network", "the media upload did not complete: " + redact(error instanceof Error ? error.message : String(error), request.accessToken));
|
|
30489
|
+
}
|
|
30490
|
+
/** Read one response into a reference, or into a typed failure. */
|
|
30491
|
+
settle(response, raw, request) {
|
|
30492
|
+
const status = response.status;
|
|
30493
|
+
if (response.ok !== true) {
|
|
30494
|
+
const detail = bodyDigest(raw, request.accessToken);
|
|
30495
|
+
if (status === 401 || status === 403) throw new KimiMediaUploadError("unauthorized", "the Kimi Code hosted-file endpoint rejected the credential (HTTP " + status + ")", {
|
|
30496
|
+
status,
|
|
30497
|
+
detail
|
|
30498
|
+
});
|
|
30499
|
+
if (status === 404 || status === 405) throw new KimiMediaUploadError("not-found", "the Kimi Code hosted-file endpoint is not available on this base URL (HTTP " + status + ")", {
|
|
30500
|
+
status,
|
|
30501
|
+
detail
|
|
30502
|
+
});
|
|
30503
|
+
if (status === 413) throw new KimiMediaUploadError("too-large", "the Kimi Code hosted-file endpoint refused the upload as too large (HTTP 413)", {
|
|
30504
|
+
status,
|
|
30505
|
+
detail
|
|
30506
|
+
});
|
|
30507
|
+
if (status >= 500) throw new KimiMediaUploadError("server", "the Kimi Code hosted-file endpoint failed (HTTP " + status + ")", {
|
|
30508
|
+
status,
|
|
30509
|
+
detail
|
|
30510
|
+
});
|
|
30511
|
+
throw new KimiMediaUploadError("rejected", "the Kimi Code hosted-file endpoint refused the upload (HTTP " + status + ")", {
|
|
30512
|
+
status,
|
|
30513
|
+
detail
|
|
30514
|
+
});
|
|
30515
|
+
}
|
|
30516
|
+
const parsed = parseJson(raw);
|
|
30517
|
+
if (!parsed.ok) throw new KimiMediaUploadError("not-json", "the media upload answered HTTP " + status + " without a JSON body", {
|
|
30518
|
+
status,
|
|
30519
|
+
detail: redact(raw, request.accessToken)
|
|
30520
|
+
});
|
|
30521
|
+
const id = readFileId$1(parsed.value);
|
|
30522
|
+
if (id === void 0) throw new KimiMediaUploadError("no-id", "the media upload answered HTTP " + status + " without a usable file id", {
|
|
30523
|
+
status,
|
|
30524
|
+
detail: redact(raw, request.accessToken)
|
|
30525
|
+
});
|
|
30526
|
+
const ref = fileReference(id);
|
|
30527
|
+
this.writeCache(request.key, ref);
|
|
30528
|
+
return ref;
|
|
30529
|
+
}
|
|
30530
|
+
};
|
|
30531
|
+
/** One uploader with the default transport and cache size. */
|
|
30532
|
+
function createMediaFilesUploader(options = {}) {
|
|
30533
|
+
return new KimiMediaFilesUploader(options);
|
|
30534
|
+
}
|
|
30535
|
+
createMediaFilesUploader();
|
|
30536
|
+
//#endregion
|
|
29530
30537
|
//#region src/host/kimi-code/adapter.ts
|
|
29531
30538
|
/**
|
|
29532
30539
|
* Rebuild attempts allowed while shrinking a request into its body ceiling.
|
|
@@ -29691,6 +30698,24 @@ const ACCOUNT_LIMIT_PATTERNS = [
|
|
|
29691
30698
|
function matchesAny$1(text, patterns) {
|
|
29692
30699
|
return patterns.some((pattern) => pattern.test(text));
|
|
29693
30700
|
}
|
|
30701
|
+
/**
|
|
30702
|
+
* Cache scope for the single stored credential.
|
|
30703
|
+
*
|
|
30704
|
+
* The user id the sign-in reported is the only stable identity that file has, and
|
|
30705
|
+
* the constant covers a credential stored before any id was recorded — or one
|
|
30706
|
+
* whose sign-in never answered with one. It must stay constant for an account:
|
|
30707
|
+
* a scope that drifted would re-upload every clip on the next turn, while a scope
|
|
30708
|
+
* shared between two accounts would hand one account's file id to another.
|
|
30709
|
+
*/
|
|
30710
|
+
const LEGACY_ACCOUNT_SCOPE = "legacy";
|
|
30711
|
+
function legacyAccountScope(credentials) {
|
|
30712
|
+
const userId = credentials.userId?.trim();
|
|
30713
|
+
return userId === void 0 || userId === "" ? LEGACY_ACCOUNT_SCOPE : userId;
|
|
30714
|
+
}
|
|
30715
|
+
/** Whether one rejection is a cancellation rather than a failure to report. */
|
|
30716
|
+
function isAbortError(error) {
|
|
30717
|
+
return typeof error === "object" && error !== null && error.name === "AbortError";
|
|
30718
|
+
}
|
|
29694
30719
|
/** Short, single-line excerpt of one error body, safe to show a user. */
|
|
29695
30720
|
function summarizeFailureBody$1(raw) {
|
|
29696
30721
|
const text = raw.replace(/[\r\n\t]+/g, " ").trim();
|
|
@@ -29726,6 +30751,129 @@ function isKimiBodySizeRefusal(detail) {
|
|
|
29726
30751
|
return /\btotal message size\b[^;]{0,64}?\bexceed(?:s|ed)?\b[^;]{0,64}?\blimit\b/i.test(detail);
|
|
29727
30752
|
}
|
|
29728
30753
|
/**
|
|
30754
|
+
* The sentence the service answers with when a cited hosted file is GONE.
|
|
30755
|
+
*
|
|
30756
|
+
* Measured on this line: a chat body that cites `ms://<id>` for a file the
|
|
30757
|
+
* store no longer holds is refused with HTTP 404 and exactly this text. It is
|
|
30758
|
+
* checked as a case-insensitive substring rather than as an exact body so a JSON
|
|
30759
|
+
* wrapper (`{"error":{"message":"The requested resource was not found"}}`) and a
|
|
30760
|
+
* trailing hash match too.
|
|
30761
|
+
*
|
|
30762
|
+
* DELIBERATELY NARROW, because 404 also means "no such model" and "no such
|
|
30763
|
+
* route" on this endpoint, and neither of those is fixed by resending the same
|
|
30764
|
+
* conversation with inline media. Only this sentence, on a request that really
|
|
30765
|
+
* cited a reference, opens the one inline retry.
|
|
30766
|
+
*/
|
|
30767
|
+
const MISSING_RESOURCE_PATTERN = /\bthe requested resource was not found\b/i;
|
|
30768
|
+
/** Whether one 404 body is the service refusing a cited file rather than the model. */
|
|
30769
|
+
function isMissingResourceBody(bodyText) {
|
|
30770
|
+
return MISSING_RESOURCE_PATTERN.test(bodyText);
|
|
30771
|
+
}
|
|
30772
|
+
/**
|
|
30773
|
+
* Body length assumed for one reference while the request is measured.
|
|
30774
|
+
*
|
|
30775
|
+
* The body is measured BEFORE anything is uploaded, so the real id does not
|
|
30776
|
+
* exist yet. 68 characters is longer than an id the uploaded-file route is
|
|
30777
|
+
* documented to mint, and it is deliberately on the long side: a measurement
|
|
30778
|
+
* that over-estimates sends nothing it cannot fit, while one that
|
|
30779
|
+
* under-estimates would discover the overflow only after the upload was already
|
|
30780
|
+
* paid for.
|
|
30781
|
+
*/
|
|
30782
|
+
const PLANNED_MEDIA_REFERENCE = "ms://" + "0".repeat(64);
|
|
30783
|
+
/**
|
|
30784
|
+
* Which occurrences of one request would be uploaded, if any.
|
|
30785
|
+
*
|
|
30786
|
+
* Nothing is uploaded here and no network is touched: this only decides WHICH
|
|
30787
|
+
* readable occurrences the reference path would cover, so the body-fit guard can
|
|
30788
|
+
* measure the body that will actually be sent instead of measuring an inline
|
|
30789
|
+
* body the reference path would never produce.
|
|
30790
|
+
*
|
|
30791
|
+
* An occurrence is eligible when all four hold, and each exclusion is load
|
|
30792
|
+
* bearing:
|
|
30793
|
+
*
|
|
30794
|
+
* - the wire is OpenAI-compatible — the Anthropic surface documents no hosted
|
|
30795
|
+
* media and must upload nothing at all;
|
|
30796
|
+
* - the selected model declares the matching modality — sending a purpose the
|
|
30797
|
+
* model cannot read uploads bytes nobody will look at;
|
|
30798
|
+
* - the occurrence resolved to `inline`, i.e. its bytes were actually read —
|
|
30799
|
+
* an unreadable media has nothing to upload and keeps its placeholder;
|
|
30800
|
+
* - the occurrence cites a durable attachment, because only that is what a
|
|
30801
|
+
* reference can be keyed by.
|
|
30802
|
+
*/
|
|
30803
|
+
function planMediaReferences(input) {
|
|
30804
|
+
if (input.wire !== "openai") return [];
|
|
30805
|
+
const planned = [];
|
|
30806
|
+
const collect = (resolved, kind) => {
|
|
30807
|
+
for (const [attachmentId, occurrence] of resolved) {
|
|
30808
|
+
if (occurrence.kind !== "inline") continue;
|
|
30809
|
+
const data = Buffer.from(occurrence.data, "base64");
|
|
30810
|
+
if (data.byteLength === 0) continue;
|
|
30811
|
+
planned.push({
|
|
30812
|
+
attachmentId,
|
|
30813
|
+
kind,
|
|
30814
|
+
mediaType: occurrence.mediaType,
|
|
30815
|
+
data
|
|
30816
|
+
});
|
|
30817
|
+
}
|
|
30818
|
+
};
|
|
30819
|
+
if (input.imageAccepted) collect(input.images, "image");
|
|
30820
|
+
if (input.videoAccepted) collect(input.videos, "video");
|
|
30821
|
+
return planned;
|
|
30822
|
+
}
|
|
30823
|
+
/**
|
|
30824
|
+
* Attachment ids one built request STILL sends as media occurrences.
|
|
30825
|
+
*
|
|
30826
|
+
* Two stages can take an occurrence away, and both run before a reference could
|
|
30827
|
+
* be cited:
|
|
30828
|
+
*
|
|
30829
|
+
* - the image/video budget pass replaces the oldest occurrences with a text
|
|
30830
|
+
* placeholder, and
|
|
30831
|
+
* - the body-fit loop replaces more of them when the real serialized body is over
|
|
30832
|
+
* the ceiling.
|
|
30833
|
+
*
|
|
30834
|
+
* An occurrence either stage removed is no longer part of the request, so
|
|
30835
|
+
* uploading it would pay for bytes nobody reads and mint a reference nothing
|
|
30836
|
+
* cites. The upload set is therefore read off the FINAL build rather than off
|
|
30837
|
+
* what was merely readable when the request was planned.
|
|
30838
|
+
*
|
|
30839
|
+
* Tool results nest their own content, and a `read_image` result carries its
|
|
30840
|
+
* pixels there, so the traversal recurses exactly the way the budget does.
|
|
30841
|
+
*/
|
|
30842
|
+
function mediaAttachmentIdsIn(options) {
|
|
30843
|
+
const ids = /* @__PURE__ */ new Set();
|
|
30844
|
+
const visit = (content) => {
|
|
30845
|
+
if (!Array.isArray(content)) return;
|
|
30846
|
+
for (const block of content) {
|
|
30847
|
+
if (typeof block !== "object" || block === null) continue;
|
|
30848
|
+
const record = block;
|
|
30849
|
+
if (record.type === "tool-result") {
|
|
30850
|
+
visit(record.content);
|
|
30851
|
+
continue;
|
|
30852
|
+
}
|
|
30853
|
+
if (record.type !== "image" && record.type !== "video") continue;
|
|
30854
|
+
const id = (typeof record.attachment === "object" && record.attachment !== null ? record.attachment : void 0)?.attachmentId;
|
|
30855
|
+
if (typeof id === "string" && id !== "") ids.add(id);
|
|
30856
|
+
}
|
|
30857
|
+
};
|
|
30858
|
+
for (const message of options.messages) visit(message.content);
|
|
30859
|
+
return ids;
|
|
30860
|
+
}
|
|
30861
|
+
/**
|
|
30862
|
+
* The placeholder reference maps one planned set measures the body with.
|
|
30863
|
+
*
|
|
30864
|
+
* Returned separately for images and videos because the mapper keys them by
|
|
30865
|
+
* field, not by kind.
|
|
30866
|
+
*/
|
|
30867
|
+
function plannedReferenceMaps(planned) {
|
|
30868
|
+
const imageReferences = /* @__PURE__ */ new Map();
|
|
30869
|
+
const videoReferences = /* @__PURE__ */ new Map();
|
|
30870
|
+
for (const item of planned) (item.kind === "image" ? imageReferences : videoReferences).set(item.attachmentId, PLANNED_MEDIA_REFERENCE);
|
|
30871
|
+
return {
|
|
30872
|
+
imageReferences,
|
|
30873
|
+
videoReferences
|
|
30874
|
+
};
|
|
30875
|
+
}
|
|
30876
|
+
/**
|
|
29729
30877
|
* Classify one non-2xx response for the retry policy.
|
|
29730
30878
|
*
|
|
29731
30879
|
* @param status - HTTP status the service answered with.
|
|
@@ -29877,6 +31025,19 @@ const ACCOUNT_LIMIT_COOLDOWN_MS = 300 * 6e4;
|
|
|
29877
31025
|
const BILLING_CYCLE_COOLDOWN_MS = 720 * 60 * 6e4;
|
|
29878
31026
|
/** Ceiling, so a malformed reset time cannot park an account for years. */
|
|
29879
31027
|
const MAX_ACCOUNT_LIMIT_COOLDOWN_MS = BILLING_CYCLE_COOLDOWN_MS;
|
|
31028
|
+
/**
|
|
31029
|
+
* Longest edge of the request version this route asks the attachment store for.
|
|
31030
|
+
*
|
|
31031
|
+
* Kimi's own CLI downscales an oversized image to a 2000 px long edge by default,
|
|
31032
|
+
* so a screenshot its client would send at 2000 px must not be handed to this
|
|
31033
|
+
* route at the shared 1024 px ceiling: that kept a screenshot the model could
|
|
31034
|
+
* read at 2000 px legible-sized only by dropping and re-reading it. The
|
|
31035
|
+
* encoded-byte target is deliberately NOT raised with it — 256 KiB per request
|
|
31036
|
+
* version still fits four images inside the shared 1.5 MB budget — and an image
|
|
31037
|
+
* already inside this edge is still sent as stored, so small images, references
|
|
31038
|
+
* without dimensions and the body-fit ceiling all behave exactly as before.
|
|
31039
|
+
*/
|
|
31040
|
+
const KIMI_CODE_REQUEST_IMAGE_MAX_EDGE = 2e3;
|
|
29880
31041
|
var KimiCodeAdapter = class extends LlmAdapter {
|
|
29881
31042
|
store;
|
|
29882
31043
|
modelSettings;
|
|
@@ -29898,6 +31059,72 @@ var KimiCodeAdapter = class extends LlmAdapter {
|
|
|
29898
31059
|
this.options = options;
|
|
29899
31060
|
this.accountPool = accountPool ?? null;
|
|
29900
31061
|
}
|
|
31062
|
+
/**
|
|
31063
|
+
* The uploader this adapter cites files through, built on first use.
|
|
31064
|
+
*
|
|
31065
|
+
* Built lazily for two reasons: a turn with no media pays nothing, and a test
|
|
31066
|
+
* that stubs the global transport before the first request still reaches the
|
|
31067
|
+
* default uploader, because the transport is read at construction rather than
|
|
31068
|
+
* at module load.
|
|
31069
|
+
*
|
|
31070
|
+
* Deliberately NOT {@link kimiMediaFiles}, the module-level singleton: that one
|
|
31071
|
+
* captured the global `fetch` when this module was imported, so an adapter
|
|
31072
|
+
* given its own transport would upload through a different one than it chats
|
|
31073
|
+
* through — the one thing this route must not do, since the reference it gets
|
|
31074
|
+
* back is only meaningful to the endpoint the chat request goes to.
|
|
31075
|
+
*/
|
|
31076
|
+
mediaUploader;
|
|
31077
|
+
/** The shared uploader, created on first use with THIS adapter's transport. */
|
|
31078
|
+
mediaFiles() {
|
|
31079
|
+
if (this.mediaUploader === void 0) this.mediaUploader = this.options.mediaFiles ?? createMediaFilesUploader(this.options.fetchFn === void 0 ? {} : { fetchFn: this.options.fetchFn });
|
|
31080
|
+
return this.mediaUploader;
|
|
31081
|
+
}
|
|
31082
|
+
/**
|
|
31083
|
+
* Upload every planned occurrence under ONE account and collect its references.
|
|
31084
|
+
*
|
|
31085
|
+
* The credential, base URL and scope are the ones the chat request about to be
|
|
31086
|
+
* sent will use, which is what makes a reference citable at all: an id minted
|
|
31087
|
+
* for another account or another deployment is not assumed to be readable.
|
|
31088
|
+
*
|
|
31089
|
+
* A failure is contained per occurrence. Uploading is an optimisation — the
|
|
31090
|
+
* inline path always works — so a refused, overloaded or unreachable upload
|
|
31091
|
+
* endpoint leaves THAT media inline and the turn runs. What is never
|
|
31092
|
+
* contained is a cancellation: `signal` aborted, or an AbortError out of the
|
|
31093
|
+
* transport, is a turn the caller deliberately stopped, and continuing to send
|
|
31094
|
+
* the chat request would answer it anyway.
|
|
31095
|
+
*
|
|
31096
|
+
* This deliberately touches no account state: a 401/403/404/405/413/5xx or a
|
|
31097
|
+
* network failure of the UPLOAD is a fact about the hosted-file endpoint, not
|
|
31098
|
+
* a verdict on this account's quota, so it neither cools nor retires the
|
|
31099
|
+
* account. The chat request's own classification owns that decision.
|
|
31100
|
+
*/
|
|
31101
|
+
async uploadPlannedReferences(input) {
|
|
31102
|
+
const uploader = this.mediaFiles();
|
|
31103
|
+
const imageReferences = /* @__PURE__ */ new Map();
|
|
31104
|
+
const videoReferences = /* @__PURE__ */ new Map();
|
|
31105
|
+
const cited = [];
|
|
31106
|
+
await Promise.all(input.planned.map(async (item) => {
|
|
31107
|
+
try {
|
|
31108
|
+
const reference = await uploader.upload({
|
|
31109
|
+
accessToken: input.accessToken,
|
|
31110
|
+
baseUrl: input.baseUrl,
|
|
31111
|
+
accountScope: input.accountScope,
|
|
31112
|
+
data: item.data,
|
|
31113
|
+
mediaType: item.mediaType,
|
|
31114
|
+
signal: input.signal
|
|
31115
|
+
});
|
|
31116
|
+
(item.kind === "image" ? imageReferences : videoReferences).set(item.attachmentId, reference);
|
|
31117
|
+
cited.push(item);
|
|
31118
|
+
} catch (error) {
|
|
31119
|
+
if (input.signal.aborted || isAbortError(error)) throw new LlmError("Kimi Code media upload aborted", "ABORTED", { cause: error });
|
|
31120
|
+
}
|
|
31121
|
+
}));
|
|
31122
|
+
return {
|
|
31123
|
+
imageReferences,
|
|
31124
|
+
videoReferences,
|
|
31125
|
+
cited
|
|
31126
|
+
};
|
|
31127
|
+
}
|
|
29901
31128
|
providerInfo(provider) {
|
|
29902
31129
|
return {
|
|
29903
31130
|
id: provider,
|
|
@@ -29909,7 +31136,11 @@ var KimiCodeAdapter = class extends LlmAdapter {
|
|
|
29909
31136
|
}
|
|
29910
31137
|
imageRequestPricing() {}
|
|
29911
31138
|
imageRequestTarget(_provider, _model, image) {
|
|
29912
|
-
return
|
|
31139
|
+
return requestImageTarget(image, 2e3) ?? {
|
|
31140
|
+
width: image.width,
|
|
31141
|
+
height: image.height,
|
|
31142
|
+
maxBytes: image.bytes
|
|
31143
|
+
};
|
|
29913
31144
|
}
|
|
29914
31145
|
settings() {
|
|
29915
31146
|
return this.preferences ? Promise.resolve(this.preferences.status()) : this.modelSettings.read();
|
|
@@ -30020,7 +31251,7 @@ var KimiCodeAdapter = class extends LlmAdapter {
|
|
|
30020
31251
|
const wire = wireForCatalogEntry(options.model, catalog);
|
|
30021
31252
|
const entry = catalog.find((model) => model.id === options.model);
|
|
30022
31253
|
const normalized = normalizeGenerateOptions(options);
|
|
30023
|
-
const images = await resolveRequestImages$1(normalized, this.options.attachments, signal);
|
|
31254
|
+
const images = await resolveRequestImages$1(normalized, this.options.attachments, signal, KIMI_CODE_REQUEST_IMAGE_MAX_EDGE);
|
|
30024
31255
|
const imageTrimmed = offloadOldestRequestImages$1(normalized, maxRequestImageBytes$1(), images);
|
|
30025
31256
|
const gatedEffort = coerceThinkingEffort(options.model, mapReasoningEffort(options.reasoningEffort === void 0 || options.reasoningEffort === null ? void 0 : String(options.reasoningEffort)));
|
|
30026
31257
|
if (gatedEffort.coercedFrom !== null) recordThinkingCoercion({
|
|
@@ -30036,11 +31267,33 @@ var KimiCodeAdapter = class extends LlmAdapter {
|
|
|
30036
31267
|
};
|
|
30037
31268
|
const videos = await resolveRequestVideos(requestOptions, this.options.videos, signal);
|
|
30038
31269
|
const settings = await this.settings();
|
|
30039
|
-
const
|
|
31270
|
+
const modalities = inputModalitiesForEntry(options.model, catalog);
|
|
31271
|
+
/**
|
|
31272
|
+
* Everything every attempt shares: the media reads and the capability gates.
|
|
31273
|
+
*
|
|
31274
|
+
* Account-specific references are merged on top of this per attempt, so the
|
|
31275
|
+
* gate is applied once and a reference can never be cited for a modality the
|
|
31276
|
+
* model does not declare.
|
|
31277
|
+
*/
|
|
31278
|
+
const baseMedia = {
|
|
30040
31279
|
videos,
|
|
30041
|
-
videoAccepted:
|
|
31280
|
+
videoAccepted: modalities.includes("video"),
|
|
30042
31281
|
messageTools: dynamicToolsForEntry(options.model, catalog)
|
|
30043
31282
|
};
|
|
31283
|
+
/**
|
|
31284
|
+
* Which readable occurrences the reference path would cover.
|
|
31285
|
+
*
|
|
31286
|
+
* Decided here so the body-fit guard can measure the body that will actually
|
|
31287
|
+
* be sent; nothing is uploaded, and no network is touched, until that guard
|
|
31288
|
+
* has accepted the request (see the rotation loop).
|
|
31289
|
+
*/
|
|
31290
|
+
const planned = planMediaReferences({
|
|
31291
|
+
wire,
|
|
31292
|
+
imageAccepted: modalities.includes("image"),
|
|
31293
|
+
videoAccepted: baseMedia.videoAccepted === true,
|
|
31294
|
+
images,
|
|
31295
|
+
videos
|
|
31296
|
+
});
|
|
30044
31297
|
const contextWindow = this.contextWindowFor(options.model, entry, settings.contextWindowOverrides);
|
|
30045
31298
|
const requestedMax = options.maxTokens ?? maxOutputTokensFor$4(options.model, contextWindow);
|
|
30046
31299
|
const inputCap = maxInputTokensForEntry(options.model, catalog);
|
|
@@ -30051,29 +31304,57 @@ var KimiCodeAdapter = class extends LlmAdapter {
|
|
|
30051
31304
|
};
|
|
30052
31305
|
const carriesVideo = requestHasVideo(requestOptions);
|
|
30053
31306
|
const bodyLimit = carriesVideo ? MAX_VIDEO_MESSAGE_BODY_BYTES : maxRequestBodyBytesFor(kimiCodeModelDef(entry?.id ?? options.model), process.env);
|
|
30054
|
-
|
|
30055
|
-
|
|
30056
|
-
|
|
30057
|
-
|
|
30058
|
-
|
|
30059
|
-
|
|
30060
|
-
|
|
30061
|
-
|
|
30062
|
-
|
|
30063
|
-
|
|
30064
|
-
|
|
30065
|
-
|
|
30066
|
-
|
|
30067
|
-
|
|
30068
|
-
|
|
30069
|
-
|
|
30070
|
-
|
|
30071
|
-
|
|
30072
|
-
|
|
30073
|
-
|
|
31307
|
+
/**
|
|
31308
|
+
* Run the greedy body-fit loop for ONE set of media references.
|
|
31309
|
+
*
|
|
31310
|
+
* A function rather than a loop in place because the same loop now serves
|
|
31311
|
+
* every build of one request: the pre-upload MEASUREMENT (placeholder
|
|
31312
|
+
* references), the real reference build after the upload, and the all-inline
|
|
31313
|
+
* rebuild the missing-resource fallback re-sends.
|
|
31314
|
+
*
|
|
31315
|
+
* Every call restarts from `boundedOptions`. That is load bearing rather than
|
|
31316
|
+
* tidy: the inline fallback has to re-fit the inline body from scratch and
|
|
31317
|
+
* stay inside the same ceiling instead of inheriting an omission the
|
|
31318
|
+
* reference path made to fit a different, much smaller body.
|
|
31319
|
+
*/
|
|
31320
|
+
const buildBodyWithinLimit = (media) => {
|
|
31321
|
+
let buildOptions = boundedOptions;
|
|
31322
|
+
for (let attempt = 0;; attempt++) {
|
|
31323
|
+
const built = buildRequest(buildOptions, wire, images, void 0, media);
|
|
31324
|
+
const body = JSON.stringify(built);
|
|
31325
|
+
const bytes = Buffer.byteLength(body, "utf8");
|
|
31326
|
+
if (bytes <= bodyLimit) return {
|
|
31327
|
+
body,
|
|
31328
|
+
options: buildOptions
|
|
31329
|
+
};
|
|
31330
|
+
const context = () => ({
|
|
31331
|
+
droppedImages: countOmitted(buildOptions, requestOptions, images),
|
|
31332
|
+
sendableImagesRemaining: requestImagePayloadLengths(buildOptions, images).length,
|
|
31333
|
+
excessBytes: bytes - bodyLimit
|
|
31334
|
+
});
|
|
31335
|
+
if (attempt > MAX_BODY_FIT_ATTEMPTS || !requestHasSendableImage(buildOptions, images)) {
|
|
31336
|
+
assertRequestBodyFits$1(built, carriesVideo, context(), bodyLimit);
|
|
31337
|
+
throw new Error("unreachable: assertRequestBodyFits returns or throws");
|
|
31338
|
+
}
|
|
31339
|
+
const drop = dropOldestImagesUntilFits(buildOptions, images, bytes - bodyLimit, requestOptions);
|
|
31340
|
+
if (drop.dropped === 0) {
|
|
31341
|
+
assertRequestBodyFits$1(built, carriesVideo, context(), bodyLimit);
|
|
31342
|
+
throw new Error("unreachable: assertRequestBodyFits returns or throws");
|
|
31343
|
+
}
|
|
31344
|
+
buildOptions = drop.options;
|
|
30074
31345
|
}
|
|
30075
|
-
|
|
30076
|
-
|
|
31346
|
+
};
|
|
31347
|
+
/**
|
|
31348
|
+
* The measured build for the reference path, done at most once.
|
|
31349
|
+
*
|
|
31350
|
+
* Held across rotation attempts because it is account-independent: it decides
|
|
31351
|
+
* whether this request can be sent at all, and that answer cannot change
|
|
31352
|
+
* because a different account answered.
|
|
31353
|
+
*
|
|
31354
|
+
* The OPTIONS travel with the body because they, not the plan, name the media
|
|
31355
|
+
* this request still carries: see {@link mediaAttachmentIdsIn}.
|
|
31356
|
+
*/
|
|
31357
|
+
let measured;
|
|
30077
31358
|
const pool = this.accountPool;
|
|
30078
31359
|
const tried = /* @__PURE__ */ new Set();
|
|
30079
31360
|
let servedByAccountId;
|
|
@@ -30107,19 +31388,69 @@ var KimiCodeAdapter = class extends LlmAdapter {
|
|
|
30107
31388
|
const base = (apiCredentials.baseUrl ?? codingBaseUrl(region)).replace(/\/+$/, "");
|
|
30108
31389
|
const endpoint = wire === "anthropic" ? `${base}/v1/messages?beta=true` : `${base}/v1/chat/completions`;
|
|
30109
31390
|
const headers = await modelRequestHeaders$1(apiCredentials.accessToken, wire);
|
|
30110
|
-
|
|
30111
|
-
|
|
30112
|
-
|
|
30113
|
-
|
|
30114
|
-
|
|
30115
|
-
|
|
31391
|
+
/**
|
|
31392
|
+
* Which account's file store this attempt writes to and cites from.
|
|
31393
|
+
*
|
|
31394
|
+
* A pooled account's own id, because that is the only identity a reference
|
|
31395
|
+
* may be cached under; a single stored credential uses the user id its
|
|
31396
|
+
* sign-in reported, or a constant when it reported none. The access token is
|
|
31397
|
+
* never used, here or anywhere a cache key is built.
|
|
31398
|
+
*/
|
|
31399
|
+
const accountScope = accountId ?? legacyAccountScope(apiCredentials);
|
|
31400
|
+
if (measured === void 0) measured = buildBodyWithinLimit(planned.length === 0 ? baseMedia : {
|
|
31401
|
+
...baseMedia,
|
|
31402
|
+
...plannedReferenceMaps(planned)
|
|
31403
|
+
});
|
|
31404
|
+
const stillSent = mediaAttachmentIdsIn(measured.options);
|
|
31405
|
+
const uploadable = planned.filter((item) => stillSent.has(item.attachmentId));
|
|
31406
|
+
const uploads = uploadable.length === 0 ? void 0 : await this.uploadPlannedReferences({
|
|
31407
|
+
planned: uploadable,
|
|
31408
|
+
accessToken: apiCredentials.accessToken,
|
|
31409
|
+
baseUrl: base,
|
|
31410
|
+
accountScope,
|
|
31411
|
+
signal
|
|
31412
|
+
});
|
|
31413
|
+
let body = uploads === void 0 ? measured.body : buildBodyWithinLimit({
|
|
31414
|
+
...baseMedia,
|
|
31415
|
+
imageReferences: uploads.imageReferences,
|
|
31416
|
+
videoReferences: uploads.videoReferences
|
|
31417
|
+
}).body;
|
|
31418
|
+
const post = async (payload) => {
|
|
31419
|
+
try {
|
|
31420
|
+
return await fetchWithContextBudgetRecovery(fetchFn)(endpoint, {
|
|
31421
|
+
method: "POST",
|
|
31422
|
+
headers,
|
|
31423
|
+
body: payload,
|
|
31424
|
+
signal
|
|
31425
|
+
});
|
|
31426
|
+
} catch (error) {
|
|
31427
|
+
if (signal.aborted) throw new LlmError("Kimi Code request aborted", "ABORTED", { cause: error });
|
|
31428
|
+
throw new LlmError(`Kimi Code request failed: ${error instanceof Error ? error.message : String(error)}`, "TRANSPORT", { cause: error });
|
|
31429
|
+
}
|
|
31430
|
+
};
|
|
31431
|
+
response = await post(body);
|
|
31432
|
+
let detail = response.ok ? "" : (await response.text().catch(() => "")).slice(0, 2e3);
|
|
31433
|
+
if (response.status === 404 && uploads !== void 0 && uploads.cited.length > 0 && isMissingResourceBody(detail)) {
|
|
31434
|
+
const uploader = this.mediaFiles();
|
|
31435
|
+
for (const item of uploads.cited) uploader.forget({
|
|
31436
|
+
baseUrl: base,
|
|
31437
|
+
accountScope,
|
|
31438
|
+
mediaType: item.mediaType,
|
|
31439
|
+
data: item.data
|
|
30116
31440
|
});
|
|
30117
|
-
|
|
30118
|
-
|
|
30119
|
-
|
|
31441
|
+
let inline;
|
|
31442
|
+
try {
|
|
31443
|
+
inline = buildBodyWithinLimit(baseMedia).body;
|
|
31444
|
+
} catch {
|
|
31445
|
+
inline = void 0;
|
|
31446
|
+
}
|
|
31447
|
+
if (inline !== void 0) {
|
|
31448
|
+
body = inline;
|
|
31449
|
+
response = await post(body);
|
|
31450
|
+
detail = response.ok ? "" : (await response.text().catch(() => "")).slice(0, 2e3);
|
|
31451
|
+
}
|
|
30120
31452
|
}
|
|
30121
31453
|
if (response.ok) break;
|
|
30122
|
-
const detail = (await response.text().catch(() => "")).slice(0, 2e3);
|
|
30123
31454
|
const failure = classifyKimiFailure(response.status, detail);
|
|
30124
31455
|
const after = response.status === 429 ? retryAfterMs$1(response.headers) : void 0;
|
|
30125
31456
|
if (pool !== null && accountId !== void 0) {
|
|
@@ -62224,22 +63555,27 @@ var ClinePassAdapter = class extends LlmAdapter {
|
|
|
62224
63555
|
const pinned = injectPrefs(body, meta, attempt);
|
|
62225
63556
|
let response;
|
|
62226
63557
|
let transportError;
|
|
62227
|
-
for (let transportTry = 0; transportTry <= TRANSPORT_RETRIES$1; transportTry += 1)
|
|
62228
|
-
|
|
62229
|
-
|
|
62230
|
-
|
|
62231
|
-
|
|
62232
|
-
|
|
62233
|
-
|
|
62234
|
-
|
|
62235
|
-
|
|
62236
|
-
|
|
62237
|
-
|
|
62238
|
-
|
|
63558
|
+
for (let transportTry = 0; transportTry <= TRANSPORT_RETRIES$1; transportTry += 1) {
|
|
63559
|
+
const headerDeadline = withAttemptTimeout$1(upstream, this.options.headerTimeoutMs);
|
|
63560
|
+
try {
|
|
63561
|
+
response = await this.engine.openStream(account, pinned, headerDeadline.signal);
|
|
63562
|
+
headerDeadline.clear();
|
|
63563
|
+
break;
|
|
63564
|
+
} catch (error) {
|
|
63565
|
+
headerDeadline.clear();
|
|
63566
|
+
if (signal.aborted) throw new LlmError("Cline Pass request aborted by caller", "ABORTED", { cause: error });
|
|
63567
|
+
transportError = error;
|
|
63568
|
+
if (transportTry < TRANSPORT_RETRIES$1 && isPreConnectionFailure$1(error)) {
|
|
63569
|
+
try {
|
|
63570
|
+
await setTimeout$1(TRANSPORT_RETRY_BASE_MS$1 * (transportTry + 1), void 0, { signal: upstream });
|
|
63571
|
+
} catch (waitError) {
|
|
63572
|
+
if (signal.aborted) throw new LlmError("Cline Pass request aborted by caller", "ABORTED", { cause: waitError });
|
|
63573
|
+
throw waitError;
|
|
63574
|
+
}
|
|
63575
|
+
continue;
|
|
62239
63576
|
}
|
|
62240
|
-
|
|
63577
|
+
break;
|
|
62241
63578
|
}
|
|
62242
|
-
break;
|
|
62243
63579
|
}
|
|
62244
63580
|
if (response === void 0) {
|
|
62245
63581
|
const note = errorChain$2(transportError);
|
|
@@ -62418,9 +63754,16 @@ var ClinePassAdapter = class extends LlmAdapter {
|
|
|
62418
63754
|
await this.accountPool.markCooldown(accountId, POOL_COOLDOWN_MS, `${PROVIDER_NAME$4} quota exhausted`).catch(() => void 0);
|
|
62419
63755
|
}
|
|
62420
63756
|
};
|
|
62421
|
-
/** A caller signal combined with
|
|
62422
|
-
function withAttemptTimeout$1(signal) {
|
|
62423
|
-
|
|
63757
|
+
/** A caller signal combined with a clearable response-header deadline. */
|
|
63758
|
+
function withAttemptTimeout$1(signal, timeoutMs = ATTEMPT_TIMEOUT_MS$1) {
|
|
63759
|
+
const deadline = new AbortController();
|
|
63760
|
+
const timer = setTimeout(() => {
|
|
63761
|
+
deadline.abort(new DOMException("The operation was aborted due to timeout", "TimeoutError"));
|
|
63762
|
+
}, timeoutMs);
|
|
63763
|
+
return {
|
|
63764
|
+
signal: AbortSignal.any([signal, deadline.signal]),
|
|
63765
|
+
clear: () => clearTimeout(timer)
|
|
63766
|
+
};
|
|
62424
63767
|
}
|
|
62425
63768
|
/**
|
|
62426
63769
|
* Whether a transport failure happened before any request was sent.
|
|
@@ -75906,9 +77249,8 @@ function delegationDenialReason(agent, toolName, args, preference, sessions, too
|
|
|
75906
77249
|
return inheritedRouteDenial(agent, toolName, allowed);
|
|
75907
77250
|
}
|
|
75908
77251
|
if (declaresRouteParameters?.(agent, toolName) === false) {
|
|
75909
|
-
if (requestedProvider
|
|
75910
|
-
if (requestedProvider
|
|
75911
|
-
return inheritedRouteDenial(agent, toolName, allowed);
|
|
77252
|
+
if (requestedProvider === void 0 && requestedModel === void 0) return inheritedRouteDenial(agent, toolName, allowed);
|
|
77253
|
+
if (requestedProvider === void 0 || requestedModel === void 0) return routeFieldsUnavailableReason(toolName, inheritedRouteOf(agent), allowed);
|
|
75912
77254
|
}
|
|
75913
77255
|
if (requestedProvider === void 0) return requestedModel === void 0 ? missingRouteReason(allowed) : partialRouteReason("provider", requestedModel, allowed);
|
|
75914
77256
|
if (requestedModel === void 0) return partialRouteReason("model", requestedProvider, allowed);
|
|
@@ -75990,6 +77332,8 @@ function routeParameterProbe(ctx) {
|
|
|
75990
77332
|
if (definition === void 0) return void 0;
|
|
75991
77333
|
const parameters = asRecord$1(definition.parameters);
|
|
75992
77334
|
if (parameters === void 0) return void 0;
|
|
77335
|
+
const properties = asRecord$1(parameters["properties"]);
|
|
77336
|
+
if (properties !== void 0) return "provider" in properties || "model" in properties;
|
|
75993
77337
|
return "provider" in parameters || "model" in parameters;
|
|
75994
77338
|
};
|
|
75995
77339
|
}
|