dsh-grok-subscription 1.2.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.js CHANGED
@@ -7,7 +7,6 @@ var DISPLAY_NAME_ZH = "Grok \u8BA2\u9605";
7
7
  var SETTINGS_NAMESPACE = "grokSubscription";
8
8
  var CREDENTIAL_REF_NAME = "GROK_BUILD_ACCESS_TOKEN";
9
9
  var PROXY_BASE_URL = "https://cli-chat-proxy.grok.com/v1";
10
- var RESPONSES_URL = "https://cli-chat-proxy.grok.com/v1/responses";
11
10
  var MODELS_V2_URL = "https://cli-chat-proxy.grok.com/v1/models-v2";
12
11
  var BILLING_CREDITS_URL = "https://cli-chat-proxy.grok.com/v1/billing?format=credits";
13
12
  var TOKEN_AUTH_HEADER = "X-XAI-Token-Auth";
@@ -418,31 +417,6 @@ function toPiModels(models) {
418
417
  };
419
418
  });
420
419
  }
421
- function reasoningInfoOf(model) {
422
- if (model?.reasoning === false) return void 0;
423
- const efforts = Array.isArray(model?.reasoningEfforts) && model.reasoningEfforts.length ? model.reasoningEfforts : ["low", "medium", "high", "xhigh"];
424
- const title = (id) => `${id.charAt(0).toUpperCase()}${id.slice(1)}`;
425
- const preferred = model?.defaultEffort && efforts.includes(model.defaultEffort) ? model.defaultEffort : efforts.includes("high") ? "high" : efforts[efforts.length - 1];
426
- return {
427
- efforts: efforts.map((id) => ({ id, name: title(id) })),
428
- defaultEffort: preferred
429
- };
430
- }
431
- function toLlmModels(models) {
432
- return models.map((model) => {
433
- const info = {
434
- provider: PROVIDER_ID,
435
- id: model.id,
436
- name: model.name,
437
- // The bundled adapter inlines images through the host attachment store,
438
- // so it advertises the same modality map as the official pi-ai path.
439
- inputModalities: supportsImageInput(model.id) ? ["text", "image"] : ["text"]
440
- };
441
- const reasoning = reasoningInfoOf(model);
442
- if (reasoning) info.reasoning = reasoning;
443
- return info;
444
- });
445
- }
446
420
  async function fetchLiveCatalog(accessToken, options = {}) {
447
421
  const fetchImpl = options.fetch ?? globalThis.fetch;
448
422
  const signal = options.signal ?? AbortSignal.timeout(options.timeoutMs ?? CATALOG_TIMEOUT_MS);
@@ -483,10 +457,11 @@ async function loadCatalog(accessToken, options = {}) {
483
457
  // src/usage.js
484
458
  var USAGE_SOURCE = "billing-credits-undocumented";
485
459
  var SHANGHAI_TZ = "Asia/Shanghai";
486
- function unavailable(reason) {
460
+ function unavailable(reason, extra = {}) {
487
461
  return Object.freeze({
488
462
  status: "unavailable",
489
463
  reason: typeof reason === "string" && reason.trim() ? reason.trim() : "Usage unavailable",
464
+ ...extra,
490
465
  experimental: true,
491
466
  source: USAGE_SOURCE
492
467
  });
@@ -542,6 +517,23 @@ function missingPercentReason(body) {
542
517
  }
543
518
  return `Missing creditUsagePercent (keys: ${keys.join(",")})`;
544
519
  }
520
+ function isUnifiedBillingBody(body) {
521
+ const config = isPlainObject(body.config) ? body.config : void 0;
522
+ return config?.isUnifiedBillingUser === true || isPlainObject(config?.onDemandCap) || isPlainObject(config?.prepaidBalance);
523
+ }
524
+ function unifiedBillingReason(body) {
525
+ const config = isPlainObject(body.config) ? body.config : {};
526
+ const balance = asFiniteNumber(config.prepaidBalance);
527
+ const cap = asFiniteNumber(config.onDemandCap);
528
+ return `No credit percentage in this billing response (unified billing: prepaidBalance ${balance ?? "n/a"}, onDemandCap ${cap ?? "n/a"})`;
529
+ }
530
+ function periodFields(body) {
531
+ const { start, end } = resolvePeriodBounds(body);
532
+ return {
533
+ ...start ? { periodStart: start, periodStartLocal: formatShanghai(start) } : {},
534
+ ...end ? { periodEnd: end, periodEndLocal: formatShanghai(end) } : {}
535
+ };
536
+ }
545
537
  function firstDefined(...values) {
546
538
  for (const value of values) {
547
539
  if (value !== void 0 && value !== null) return value;
@@ -655,7 +647,14 @@ function parseBillingCredits(body) {
655
647
  }
656
648
  const usedPercent = resolveUsedPercent(body);
657
649
  if (usedPercent === void 0) {
658
- return unavailable(missingPercentReason(body));
650
+ const unified = isUnifiedBillingBody(body);
651
+ return unavailable(
652
+ unified ? unifiedBillingReason(body) : missingPercentReason(body),
653
+ {
654
+ code: unified ? "unified-billing" : "missing-percent",
655
+ ...periodFields(body)
656
+ }
657
+ );
659
658
  }
660
659
  const { start: periodStart, end: periodEnd } = resolvePeriodBounds(body);
661
660
  const productUsage = sanitizeProductUsage(resolveProductUsage(body));
@@ -909,81 +908,7 @@ async function optionalImport(specifier, options = {}) {
909
908
  }
910
909
  return void 0;
911
910
  }
912
- function textOf(content) {
913
- if (typeof content === "string") return content;
914
- if (!Array.isArray(content)) return "";
915
- return content.map((block) => {
916
- if (typeof block === "string") return block;
917
- if (block?.type === "text") return block.text ?? "";
918
- if (block?.type === "reasoning") return "";
919
- if (block?.type === "tool-result") {
920
- return typeof block.content === "string" ? block.content : textOf(block.content);
921
- }
922
- return "";
923
- }).join("");
924
- }
925
- function imagePlaceholderText(ref) {
926
- const name2 = typeof ref?.name === "string" && ref.name.trim() ? ` ${JSON.stringify(ref.name.trim())}` : "";
927
- return `[attached image${name2} could not be included in this request]`;
928
- }
929
- async function collectImageParts(options, resolveAttachments, policy = {}) {
930
- const parts = /* @__PURE__ */ new Map();
931
- const refs = [];
932
- for (const message of options.messages ?? []) {
933
- for (const block of message?.content ?? []) {
934
- if (block?.type !== "image" || !block.attachment) continue;
935
- const id = block.attachment.attachmentId;
936
- if (typeof id !== "string" || !id || parts.has(id)) continue;
937
- parts.set(id, void 0);
938
- refs.push(block.attachment);
939
- }
940
- }
941
- if (refs.length === 0) return parts;
942
- let store;
943
- try {
944
- store = resolveAttachments?.();
945
- } catch {
946
- store = void 0;
947
- }
948
- if (!store?.readImageRequest) return parts;
949
- const request = {
950
- maxPixels: policy.maxPixels ?? REQUEST_IMAGE_PIXEL_BUDGET,
951
- maxBytes: policy.maxBytes ?? REQUEST_IMAGE_MAX_BYTES
952
- };
953
- await Promise.all(refs.map(async (ref) => {
954
- try {
955
- const version = await store.readImageRequest(ref, request);
956
- if (!version?.data || typeof version.mediaType !== "string" || !version.mediaType) return;
957
- parts.set(ref.attachmentId, {
958
- mediaType: version.mediaType,
959
- base64: Buffer.from(version.data).toString("base64")
960
- });
961
- } catch {
962
- }
963
- }));
964
- return parts;
965
- }
966
- function imageContentParts(blocks, imageParts) {
967
- const parts = [];
968
- const text = textOf(blocks);
969
- if (text) parts.push({ type: "input_text", text });
970
- for (const block of blocks ?? []) {
971
- if (block?.type !== "image" || !block.attachment) continue;
972
- const resolved = imageParts?.get(block.attachment.attachmentId);
973
- if (resolved) {
974
- parts.push({
975
- type: "input_image",
976
- image_url: `data:${resolved.mediaType};base64,${resolved.base64}`
977
- });
978
- } else {
979
- parts.push({ type: "input_text", text: imagePlaceholderText(block.attachment) });
980
- }
981
- }
982
- return parts;
983
- }
984
911
  var PROMPT_CACHE_KEY_MAX_LENGTH = 64;
985
- var REPLAY_KIND = "grok-build-responses";
986
- var REPLAY_VERSION = 1;
987
912
  function promptCacheKey(options) {
988
913
  const sessionId = typeof options?.sessionId === "string" ? options.sessionId.trim() : "";
989
914
  if (!sessionId) return void 0;
@@ -991,455 +916,10 @@ function promptCacheKey(options) {
991
916
  const key = `grok${suffix}:${sessionId}`;
992
917
  return key.length <= PROMPT_CACHE_KEY_MAX_LENGTH ? key : key.slice(0, PROMPT_CACHE_KEY_MAX_LENGTH);
993
918
  }
994
- function cacheStableTools(tools) {
995
- if (!Array.isArray(tools) || tools.length === 0) return [];
996
- return tools.map((tool, index) => ({ tool, index })).sort((left, right) => {
997
- const byName = String(left.tool?.name ?? "").localeCompare(String(right.tool?.name ?? ""));
998
- return byName === 0 ? left.index - right.index : byName;
999
- }).map(({ tool }) => ({
1000
- type: "function",
1001
- name: tool.name,
1002
- description: tool.description,
1003
- parameters: tool.parameters
1004
- }));
1005
- }
1006
- function replayEnvelope(message) {
1007
- const state = message?.source?.replayState;
1008
- return state?.response?.kind === REPLAY_KIND && state.response.version === REPLAY_VERSION && Array.isArray(state.blocks) ? state : void 0;
1009
- }
1010
- function replayReasoningItem(message, contentIndex) {
1011
- const entry = replayEnvelope(message)?.blocks[contentIndex];
1012
- const item = entry?.type === "reasoning" ? entry.item : void 0;
1013
- return item?.type === "reasoning" && typeof item.encrypted_content === "string" && item.encrypted_content ? item : void 0;
1014
- }
1015
- function responsesInput(options, imageParts) {
1016
- const input = [];
1017
- const system = typeof options.system === "string" && options.system ? options.system : void 0;
1018
- if (system) input.push({ role: "system", content: system });
1019
- for (const message of options.messages ?? []) {
1020
- const role = message.role === "assistant" ? "assistant" : message.role === "system" ? "system" : "user";
1021
- const toolCalls = (message.content ?? []).filter((block) => block?.type === "tool-call");
1022
- const toolResults = (message.content ?? []).filter((block) => block?.type === "tool-result");
1023
- if (toolResults.length) {
1024
- for (const block of toolResults) {
1025
- input.push({
1026
- type: "function_call_output",
1027
- call_id: block.toolCallId ?? block.id,
1028
- output: textOf(block.content)
1029
- });
1030
- }
1031
- continue;
1032
- }
1033
- if (role === "assistant" && toolCalls.length) {
1034
- const content = message.content ?? [];
1035
- for (let index = 0; index < content.length; index++) {
1036
- const block = content[index];
1037
- if (block?.type === "reasoning") {
1038
- const item = replayReasoningItem(message, index);
1039
- if (item) input.push(item);
1040
- continue;
1041
- }
1042
- if (block?.type !== "tool-call") continue;
1043
- input.push({
1044
- type: "function_call",
1045
- call_id: block.id,
1046
- name: block.name,
1047
- arguments: typeof block.arguments === "string" ? block.arguments : JSON.stringify(block.arguments ?? {})
1048
- });
1049
- }
1050
- const text2 = textOf(message.content);
1051
- if (text2) input.push({ role: "assistant", content: text2 });
1052
- continue;
1053
- }
1054
- const hasImage = (message.content ?? []).some((block) => block?.type === "image");
1055
- if (role === "user" && hasImage) {
1056
- const parts = imageContentParts(message.content, imageParts);
1057
- if (parts.length > 0) input.push({ role, content: parts });
1058
- continue;
1059
- }
1060
- if (role === "assistant") {
1061
- const content = message.content ?? [];
1062
- const output = [];
1063
- let text2 = "";
1064
- for (let index = 0; index < content.length; index++) {
1065
- const block = content[index];
1066
- if (block?.type === "reasoning") {
1067
- const item = replayReasoningItem(message, index);
1068
- if (item) output.push(item);
1069
- } else if (block?.type === "text" && block.text) {
1070
- text2 += block.text;
1071
- }
1072
- }
1073
- if (text2) output.push({ role: "assistant", content: text2 });
1074
- input.push(...output);
1075
- continue;
1076
- }
1077
- const text = textOf(message.content);
1078
- if (!text) continue;
1079
- input.push({ role, content: text });
1080
- }
1081
- return input;
1082
- }
1083
- function mapFinish(reason) {
1084
- if (reason === "toolUse" || reason === "tool_calls") return { kind: "tool-calls" };
1085
- if (reason === "length" || reason === "max_tokens") return { kind: "max-tokens" };
1086
- return { kind: "stop" };
1087
- }
1088
- function finiteOr(value, fallback) {
1089
- return typeof value === "number" && Number.isFinite(value) ? value : fallback;
1090
- }
1091
- function jsonSafeChunk(value) {
1092
- if (value === null) return null;
1093
- const type = typeof value;
1094
- if (type === "string" || type === "boolean") return value;
1095
- if (type === "number") return Number.isFinite(value) && !Object.is(value, -0) ? value : void 0;
1096
- if (type !== "object") return void 0;
1097
- if (Array.isArray(value)) {
1098
- const list = [];
1099
- for (const item of value) {
1100
- const safe = jsonSafeChunk(item);
1101
- if (safe !== void 0) list.push(safe);
1102
- }
1103
- return list;
1104
- }
1105
- const out = {};
1106
- for (const [key, item] of Object.entries(value)) {
1107
- const safe = jsonSafeChunk(item);
1108
- if (safe !== void 0) out[key] = safe;
1109
- }
1110
- return out;
1111
- }
1112
- async function* streamResponsesUnsafe(options, token) {
1113
- const headers = {
1114
- Accept: "text/event-stream",
1115
- "Content-Type": "application/json",
1116
- ...buildProxyHeaders(token)
1117
- };
1118
- try {
1119
- const llm = await optionalImport("@deepseek-ai/dsh-llm");
1120
- if (typeof llm?.attributionHeaders === "function") Object.assign(headers, llm.attributionHeaders());
1121
- } catch {
1122
- }
1123
- const body = {
1124
- model: options.model,
1125
- input: responsesInput(options, await collectImageParts(options, options.resolveAttachments)),
1126
- stream: true,
1127
- // grok-4.7 returns ciphertext by default, but naming it keeps replay explicit
1128
- // for every reasoning model on this proxy.
1129
- include: ["reasoning.encrypted_content"]
1130
- };
1131
- const cacheKey = promptCacheKey(options);
1132
- if (cacheKey) body.prompt_cache_key = cacheKey;
1133
- if (typeof options.maxTokens === "number") body.max_output_tokens = options.maxTokens;
1134
- if (typeof options.temperature === "number") body.temperature = options.temperature;
1135
- const tools = cacheStableTools(options.tools);
1136
- if (tools.length) body.tools = tools;
1137
- if (options.reasoningEffort) body.reasoning = { effort: options.reasoningEffort };
1138
- const response = await fetch(RESPONSES_URL, {
1139
- method: "POST",
1140
- headers,
1141
- body: JSON.stringify(body),
1142
- redirect: "error",
1143
- signal: options.signal
1144
- });
1145
- if (!response.ok) {
1146
- const error = new Error(`Grok Build proxy returned HTTP ${response.status}`);
1147
- error.status = response.status;
1148
- throw error;
1149
- }
1150
- if (!response.body) throw new Error("Grok Build proxy returned an empty body");
1151
- const decoder = new TextDecoder();
1152
- let buffer = "";
1153
- let textIndex;
1154
- let reasoningIndex;
1155
- let textContent = "";
1156
- let reasoningContent = "";
1157
- let nextIndex = 0;
1158
- const emittedBlocks = [];
1159
- const toolBlocks = /* @__PURE__ */ new Map();
1160
- const toolNames = /* @__PURE__ */ new Map();
1161
- let usage;
1162
- let finish = { kind: "stop" };
1163
- const toolIdOf = (payload) => {
1164
- const id = payload?.item_id ?? payload?.call_id ?? payload?.id;
1165
- return typeof id === "string" && id ? id : void 0;
1166
- };
1167
- const learnToolName = (id, name2) => {
1168
- if (typeof id !== "string" || !id || typeof name2 !== "string" || !name2) return;
1169
- toolNames.set(id, name2);
1170
- const tool = toolBlocks.get(id);
1171
- if (tool) tool.name = name2;
1172
- };
1173
- const adoptToolArguments = (id, value) => {
1174
- if (typeof id !== "string" || typeof value !== "string" || !value) return;
1175
- const tool = toolBlocks.get(id);
1176
- if (tool && value.length > tool.arguments.length) tool.arguments = value;
1177
- };
1178
- const flushSse = function* (raw) {
1179
- const lines = raw.split("\n");
1180
- let event = "message";
1181
- const data = [];
1182
- for (const line of lines) {
1183
- if (line.startsWith("event:")) event = line.slice(6).trim();
1184
- else if (line.startsWith("data:")) data.push(line.slice(5).trim());
1185
- }
1186
- const payloadText = data.join("\n");
1187
- if (!payloadText || payloadText === "[DONE]") return;
1188
- let payload;
1189
- try {
1190
- payload = JSON.parse(payloadText);
1191
- } catch {
1192
- return;
1193
- }
1194
- const type = payload.type ?? event;
1195
- if (type === "response.output_text.delta" || type === "response.text.delta") {
1196
- const delta = payload.delta ?? payload.text ?? "";
1197
- if (!delta) return;
1198
- if (textIndex === void 0) {
1199
- textIndex = nextIndex++;
1200
- emittedBlocks[textIndex] = { type: "text" };
1201
- yield { type: "block-start", index: textIndex, blockType: "text" };
1202
- }
1203
- textContent += delta;
1204
- yield { type: "text-delta", index: textIndex, text: String(delta) };
1205
- return;
1206
- }
1207
- if (type === "response.reasoning_text.delta" || type === "response.reasoning.delta" || type === "response.reasoning_summary_text.delta") {
1208
- const delta = payload.delta ?? payload.text ?? "";
1209
- if (!delta) return;
1210
- if (reasoningIndex === void 0) {
1211
- reasoningIndex = nextIndex++;
1212
- emittedBlocks[reasoningIndex] = { type: "reasoning" };
1213
- yield { type: "block-start", index: reasoningIndex, blockType: "reasoning" };
1214
- }
1215
- reasoningContent += delta;
1216
- yield { type: "reasoning-delta", index: reasoningIndex, text: String(delta) };
1217
- return;
1218
- }
1219
- if (type === "response.output_item.added" || type === "response.output_item.done") {
1220
- const item = payload.item;
1221
- if (item?.type === "reasoning" && typeof item.encrypted_content === "string" && item.encrypted_content) {
1222
- if (reasoningIndex === void 0) {
1223
- reasoningIndex = nextIndex++;
1224
- emittedBlocks[reasoningIndex] = { type: "reasoning" };
1225
- yield { type: "block-start", index: reasoningIndex, blockType: "reasoning" };
1226
- }
1227
- emittedBlocks[reasoningIndex] = { type: "reasoning", item };
1228
- }
1229
- if (item?.type === "function_call") {
1230
- learnToolName(item.id, item.name);
1231
- learnToolName(item.call_id, item.name);
1232
- adoptToolArguments(item.id, item.arguments);
1233
- }
1234
- return;
1235
- }
1236
- if (type === "response.function_call_arguments.done") {
1237
- const id = toolIdOf(payload);
1238
- learnToolName(id, payload.name);
1239
- adoptToolArguments(id, payload.arguments);
1240
- return;
1241
- }
1242
- if (type === "response.function_call_arguments.delta") {
1243
- const id = toolIdOf(payload);
1244
- if (!id) return;
1245
- let tool = toolBlocks.get(id);
1246
- if (!tool) {
1247
- tool = {
1248
- index: nextIndex++,
1249
- id,
1250
- // Never leave this undefined: an unserializable chunk aborts the turn.
1251
- name: toolNames.get(id) ?? "tool",
1252
- arguments: ""
1253
- };
1254
- emittedBlocks[tool.index] = { type: "tool-call" };
1255
- toolBlocks.set(id, tool);
1256
- yield { type: "block-start", index: tool.index, blockType: "tool-call" };
1257
- }
1258
- const delta = payload.delta ?? payload.arguments ?? "";
1259
- tool.arguments += delta;
1260
- yield { type: "tool-call-delta", index: tool.index, id, name: tool.name, argumentsDelta: String(delta) };
1261
- return;
1262
- }
1263
- if (type === "response.completed") {
1264
- for (const item of payload.response?.output ?? []) {
1265
- if (item?.type !== "function_call") continue;
1266
- learnToolName(item.id, item.name);
1267
- learnToolName(item.call_id, item.name);
1268
- const id = typeof item.id === "string" && item.id ? item.id : void 0;
1269
- if (id && !toolBlocks.has(id)) {
1270
- const tool = { index: nextIndex++, id, name: toolNames.get(id) ?? "tool", arguments: "" };
1271
- toolBlocks.set(id, tool);
1272
- emittedBlocks[tool.index] = { type: "tool-call" };
1273
- yield { type: "block-start", index: tool.index, blockType: "tool-call" };
1274
- }
1275
- adoptToolArguments(id, item.arguments);
1276
- }
1277
- const responseUsage = payload.response?.usage ?? payload.usage;
1278
- if (responseUsage) {
1279
- const details = responseUsage.input_tokens_details ?? responseUsage.prompt_tokens_details ?? {};
1280
- const cachedTokens = finiteOr(details.cached_tokens, 0);
1281
- const cacheWriteTokens = finiteOr(details.cache_write_tokens, 0);
1282
- const promptTotal = finiteOr(
1283
- responseUsage.input_tokens ?? responseUsage.prompt_tokens,
1284
- 0
1285
- );
1286
- const outputTokens = finiteOr(
1287
- responseUsage.output_tokens ?? responseUsage.completion_tokens,
1288
- 0
1289
- );
1290
- usage = {
1291
- // The provider folds cache hits into the prompt count, while DSH's
1292
- // fields are disjoint: billed input = inputTokens + cacheRead +
1293
- // cacheWrite. Subtracting is what makes the host's "cache hit" figure
1294
- // real instead of a permanent 0%. Both cache fields stay numeric so
1295
- // consumers can always add them up.
1296
- inputTokens: Math.max(0, promptTotal - cachedTokens - cacheWriteTokens),
1297
- outputTokens,
1298
- cacheReadTokens: cachedTokens,
1299
- cacheWriteTokens
1300
- };
1301
- const reasoningTokens = finiteOr(responseUsage.output_tokens_details?.reasoning_tokens, void 0);
1302
- if (reasoningTokens !== void 0) usage.reasoningTokens = reasoningTokens;
1303
- usage.totalTokens = finiteOr(responseUsage.total_tokens, promptTotal + outputTokens);
1304
- }
1305
- finish = mapFinish(payload.response?.status === "incomplete" ? "length" : "stop");
1306
- if (toolBlocks.size) finish = { kind: "tool-calls" };
1307
- }
1308
- if (type === "response.failed" || type === "error") {
1309
- const raw2 = payload.error?.message ?? payload.message;
1310
- const failure = {
1311
- message: typeof raw2 === "string" && raw2 ? raw2 : "Grok Build stream failed",
1312
- code: "PROVIDER"
1313
- };
1314
- const status = finiteOr(payload.error?.status, void 0);
1315
- if (status !== void 0) failure.status = status;
1316
- finish = { kind: "error", failure };
1317
- }
1318
- };
1319
- for await (const chunk of response.body) {
1320
- buffer += decoder.decode(chunk, { stream: true });
1321
- let separator;
1322
- while ((separator = buffer.indexOf("\n\n")) !== -1) {
1323
- const raw = buffer.slice(0, separator);
1324
- buffer = buffer.slice(separator + 2);
1325
- yield* flushSse(raw);
1326
- }
1327
- }
1328
- if (buffer.trim()) yield* flushSse(buffer);
1329
- if (reasoningIndex !== void 0) {
1330
- yield { type: "block-end", index: reasoningIndex, block: { type: "reasoning", text: reasoningContent } };
1331
- }
1332
- if (textIndex !== void 0) {
1333
- yield { type: "block-end", index: textIndex, block: { type: "text", text: textContent } };
1334
- }
1335
- for (const tool of toolBlocks.values()) {
1336
- yield {
1337
- type: "block-end",
1338
- index: tool.index,
1339
- block: { type: "tool-call", id: tool.id, name: tool.name ?? "tool", arguments: tool.arguments }
1340
- };
1341
- }
1342
- if (usage) yield { type: "usage", usage };
1343
- const finishChunk = { type: "finish", reason: finish };
1344
- if (finish.kind !== "error" && finish.kind !== "aborted" && emittedBlocks.length === nextIndex) {
1345
- finishChunk.replayState = {
1346
- response: { kind: REPLAY_KIND, version: REPLAY_VERSION },
1347
- blocks: emittedBlocks
1348
- };
1349
- }
1350
- yield finishChunk;
1351
- }
1352
- async function* streamResponses(options, token) {
1353
- for await (const chunk of streamResponsesUnsafe(options, token)) {
1354
- const safe = jsonSafeChunk(chunk);
1355
- if (safe) yield safe;
1356
- }
1357
- }
1358
919
  function visiblePiModels(session) {
1359
920
  if (session.publicAccount()?.signedIn !== true) return [];
1360
921
  return toPiModels(session.models()).map((model) => model.provider === PROVIDER_ID ? model : { ...model, provider: PROVIDER_ID });
1361
922
  }
1362
- function createDuckAdapter(session, adapterOptions = {}) {
1363
- const providerInfo = () => ({ id: PROVIDER_ID, name: DISPLAY_NAME });
1364
- const list = () => {
1365
- const signedIn = session.publicAccount()?.signedIn === true;
1366
- return signedIn ? toLlmModels(session.models()) : [];
1367
- };
1368
- return {
1369
- providerInfo,
1370
- providerRetryPolicy() {
1371
- return void 0;
1372
- },
1373
- async listModels(provider) {
1374
- if (provider !== PROVIDER_ID) return [];
1375
- return list();
1376
- },
1377
- async resolveModel(provider, model) {
1378
- const found = list().find((item) => item.id === model);
1379
- const raw = session.publicAccount()?.signedIn === true ? session.models().find((item) => item.id === model) : void 0;
1380
- const info = {
1381
- provider,
1382
- id: model,
1383
- name: found?.name ?? model,
1384
- // The host gates prompt attachment admission on resolveModelInfo, NOT on
1385
- // listModels, so this must match the catalog's modality map exactly.
1386
- inputModalities: supportsImageInput(model) ? ["text", "image"] : ["text"],
1387
- context: { contextWindow: raw?.contextWindow ?? 5e5 }
1388
- };
1389
- const reasoning = reasoningInfoOf(raw);
1390
- if (reasoning) info.reasoning = reasoning;
1391
- else if (found?.reasoning) info.reasoning = found.reasoning;
1392
- return info;
1393
- },
1394
- async prepareCall(provider, model, signal) {
1395
- const resolved = await this.resolveModel(provider, model, signal);
1396
- return {
1397
- model: resolved,
1398
- stream: (options) => this.stream(options)
1399
- };
1400
- },
1401
- async *stream(options) {
1402
- if (options.provider !== PROVIDER_ID) {
1403
- yield { type: "finish", reason: { kind: "error", failure: { message: "Unknown provider", code: "NO_ADAPTER" } } };
1404
- return;
1405
- }
1406
- const callOptions = typeof adapterOptions.resolveAttachments === "function" ? { ...options, resolveAttachments: adapterOptions.resolveAttachments } : options;
1407
- let token = await session.currentToken();
1408
- if (!token) {
1409
- yield { type: "finish", reason: { kind: "error", failure: { message: "Grok subscription is not signed in", code: "MISSING_CREDENTIAL" } } };
1410
- return;
1411
- }
1412
- for (let attempt = 0; ; attempt++) {
1413
- let emitted = false;
1414
- try {
1415
- for await (const chunk of streamResponses(callOptions, token, callOptions.resolveAttachments)) {
1416
- emitted = true;
1417
- yield chunk;
1418
- }
1419
- return;
1420
- } catch (error) {
1421
- const aborted = options.signal?.aborted === true;
1422
- const status = finiteOr(error?.status, void 0);
1423
- const canRetry = !aborted && !emitted && attempt === 0 && status === 401 && typeof session.refreshToken === "function";
1424
- if (canRetry) {
1425
- const renewed = await session.refreshToken();
1426
- if (renewed && renewed !== token) {
1427
- token = renewed;
1428
- continue;
1429
- }
1430
- }
1431
- const failure = {
1432
- message: status === 401 ? "Grok Build session is expired or unauthorized (HTTP 401). Run grok login, then Pull from Grok CLI." : error instanceof Error ? error.message : "Grok Build request failed",
1433
- code: aborted ? "ABORTED" : status === 401 ? "UNAUTHORIZED" : "PROVIDER"
1434
- };
1435
- if (status !== void 0) failure.status = status;
1436
- yield { type: "finish", reason: { kind: aborted ? "aborted" : "error", failure } };
1437
- return;
1438
- }
1439
- }
1440
- }
1441
- };
1442
- }
1443
923
  function createStore(session) {
1444
924
  return {
1445
925
  async read(providerId) {
@@ -1490,39 +970,6 @@ function withGrokRequestSemantics(api) {
1490
970
  streamSimple: (model, context, options) => api.streamSimple(model, context, inject2(options))
1491
971
  };
1492
972
  }
1493
- function wrapAsHostAdapter(candidate, dshLlm) {
1494
- if (!dshLlm?.LlmAdapter || candidate instanceof dshLlm.LlmAdapter) return candidate;
1495
- class GrokBuildAdapter extends dshLlm.LlmAdapter {
1496
- providerInfo(provider) {
1497
- return candidate.providerInfo(provider);
1498
- }
1499
- providerRetryPolicy(provider) {
1500
- return candidate.providerRetryPolicy(provider);
1501
- }
1502
- listModels(provider) {
1503
- return candidate.listModels(provider);
1504
- }
1505
- resolveModel(provider, model, signal) {
1506
- return candidate.resolveModel(provider, model, signal);
1507
- }
1508
- prepareCall(provider, model, signal) {
1509
- return candidate.prepareCall(provider, model, signal);
1510
- }
1511
- stream(options) {
1512
- return candidate.stream(options);
1513
- }
1514
- }
1515
- return new GrokBuildAdapter();
1516
- }
1517
- function createGrokBuildAdapterSync(session, options = {}) {
1518
- const duck = createDuckAdapter(session, { resolveAttachments: options.resolveAttachments });
1519
- const dshLlm = options.dshLlm;
1520
- return {
1521
- adapter: wrapAsHostAdapter(duck, dshLlm),
1522
- kind: "custom-mvp",
1523
- note: "Registered a sync duck Responses adapter; pi-ai upgrade may follow in the background."
1524
- };
1525
- }
1526
973
  async function createGrokBuildAdapter(session, options = {}) {
1527
974
  const importOpts = options.importOptions ?? {};
1528
975
  const [piAi, dshPi, dshLlm] = await Promise.all([
@@ -1530,13 +977,11 @@ async function createGrokBuildAdapter(session, options = {}) {
1530
977
  optionalImport("@deepseek-ai/dsh-llm-pi-ai", importOpts),
1531
978
  optionalImport("@deepseek-ai/dsh-llm", importOpts)
1532
979
  ]);
1533
- const duck = createDuckAdapter(session, { resolveAttachments: options.resolveAttachments });
1534
- const asHostAdapter = (candidate) => wrapAsHostAdapter(candidate, dshLlm);
1535
980
  if (!piAi?.createProvider || !dshPi?.PiAiAdapter) {
1536
981
  return {
1537
- adapter: asHostAdapter(duck),
1538
- kind: "custom-mvp",
1539
- note: "PiAiAdapter or @earendil-works/pi-ai is not available in this host; using a documented custom Responses adapter."
982
+ adapter: void 0,
983
+ kind: "unavailable",
984
+ note: "the host pi-ai adapter is unavailable: @earendil-works/pi-ai and @deepseek-ai/dsh-llm-pi-ai must be resolvable from the DSH install"
1540
985
  };
1541
986
  }
1542
987
  let responsesApi;
@@ -1547,7 +992,11 @@ async function createGrokBuildAdapter(session, options = {}) {
1547
992
  responsesApi = void 0;
1548
993
  }
1549
994
  if (!responsesApi) {
1550
- return { adapter: asHostAdapter(duck), kind: "custom-mvp", note: "openai-responses API module is unavailable; using the custom adapter." };
995
+ return {
996
+ adapter: void 0,
997
+ kind: "unavailable",
998
+ note: "the pi-ai openai-responses API module is unavailable in this host"
999
+ };
1551
1000
  }
1552
1001
  responsesApi = withGrokRequestSemantics(responsesApi);
1553
1002
  const store = createStore(session);
@@ -2512,6 +1961,10 @@ function sanitizeUsage(usage) {
2512
1961
  };
2513
1962
  if (out.status !== "ok") {
2514
1963
  out.reason = typeof usage.reason === "string" ? usage.reason : "Usage unavailable";
1964
+ if (typeof usage.code === "string") out.code = usage.code;
1965
+ for (const field of ["periodStart", "periodStartLocal", "periodEnd", "periodEndLocal"]) {
1966
+ if (typeof usage[field] === "string") out[field] = usage[field];
1967
+ }
2515
1968
  return out;
2516
1969
  }
2517
1970
  if (typeof usage.usedPercent === "number" && Number.isFinite(usage.usedPercent)) out.usedPercent = usage.usedPercent;
@@ -2697,34 +2150,6 @@ function softService(ctx, key) {
2697
2150
  }
2698
2151
  return void 0;
2699
2152
  }
2700
- function registerProviderAdapter(ctx, adapter) {
2701
- const handle = ctx.llm.registerAdapter([PROVIDER_ID], adapter);
2702
- return typeof handle === "function" ? handle : void 0;
2703
- }
2704
- function upgradeProviderAdapter(ctx, adapter, registration) {
2705
- const previous = registration.adapter;
2706
- registration.release?.();
2707
- registration.release = void 0;
2708
- registration.adapter = void 0;
2709
- try {
2710
- registration.release = registerProviderAdapter(ctx, adapter);
2711
- registration.adapter = adapter;
2712
- } catch (error) {
2713
- if (previous !== void 0) {
2714
- try {
2715
- registration.release = registerProviderAdapter(ctx, previous);
2716
- registration.adapter = previous;
2717
- } catch {
2718
- registration.release = void 0;
2719
- }
2720
- }
2721
- throw error;
2722
- }
2723
- }
2724
- function adapterOverride(env = process.env) {
2725
- const value = typeof env?.DSH_GROK_ADAPTER === "string" ? env.DSH_GROK_ADAPTER.trim().toLowerCase() : "";
2726
- return value === "fallback" ? "fallback" : void 0;
2727
- }
2728
2153
  function attachmentResolver(ctx) {
2729
2154
  return () => {
2730
2155
  try {
@@ -2761,44 +2186,27 @@ function apply(ctx, options = {}) {
2761
2186
  logger: ctx.logger,
2762
2187
  onCatalogChange: notifyCatalogChange
2763
2188
  });
2764
- const adapterState = { kind: "custom-mvp", upgraded: false };
2189
+ const adapterState = { kind: "starting" };
2765
2190
  const pluginManager = options.pluginManager ?? createGrokPluginManager();
2766
2191
  const handler = createRpcHandler(session, {
2767
2192
  pluginManager,
2768
2193
  diagnostics: () => ({
2769
- adapter: adapterState.upgraded ? "pi-ai" : "fallback",
2770
- adapterKind: adapterState.kind,
2194
+ adapter: adapterState.kind,
2771
2195
  imageInput: typeof resolveAttachments()?.readImageRequest === "function",
2772
- hostPeersResolved: adapterState.upgraded
2196
+ hostPeersResolved: adapterState.kind === "pi-ai"
2773
2197
  })
2774
2198
  });
2775
2199
  const resolveAttachments = attachmentResolver(ctx);
2776
- const createSync = options.createSync ?? createGrokBuildAdapterSync;
2777
- const registration = { adapter: void 0, release: void 0 };
2778
- try {
2779
- const created = createSync(session, { resolveAttachments });
2780
- if (created.note) ctx.logger?.debug?.(created.note);
2781
- adapterState.kind = created.kind;
2782
- registration.adapter = created.adapter;
2783
- registration.release = registerProviderAdapter(ctx, created.adapter);
2784
- notifyCatalogChange();
2785
- } catch (error) {
2786
- ctx.logger?.warn?.(
2787
- "Grok subscription duck adapter failed to register: %s",
2788
- error instanceof Error ? error.message : "unknown"
2789
- );
2790
- }
2791
2200
  const defer = options.defer ?? scheduleDeferred2;
2792
- const deferredOptions = adapterOverride() === "fallback" ? { ...options, skipUpgrade: true } : options;
2793
2201
  defer(() => {
2794
- void deferredBoot(ctx, session, notifyCatalogChange, deferredOptions, adapterState, registration);
2202
+ void deferredBoot(ctx, session, notifyCatalogChange, options, adapterState);
2795
2203
  });
2796
2204
  ctx.inject(["connection"], (connectionContext) => connectionContext.effect(
2797
2205
  () => registerSubscriptionTransport(connectionContext.connection, handler),
2798
2206
  "grok-subscription: host-only account RPC"
2799
2207
  ));
2800
2208
  }
2801
- async function deferredBoot(ctx, session, notifyCatalogChange, options = {}, adapterState, registration) {
2209
+ async function deferredBoot(ctx, session, notifyCatalogChange, options = {}, adapterState) {
2802
2210
  if (!options.skipSettings) {
2803
2211
  await tryRegisterSettings(ctx);
2804
2212
  }
@@ -2823,25 +2231,32 @@ async function deferredBoot(ctx, session, notifyCatalogChange, options = {}, ada
2823
2231
  );
2824
2232
  });
2825
2233
  }
2826
- if (options.skipUpgrade) return;
2827
- const createAsync = options.createAsync ?? createGrokBuildAdapter;
2234
+ if (options.skipAdapter) {
2235
+ adapterState.kind = "unavailable";
2236
+ return;
2237
+ }
2238
+ const buildAdapter = options.buildAdapter ?? createGrokBuildAdapter;
2828
2239
  try {
2829
- const created = await createAsync(session, { ...options.adapterOptions, resolveAttachments: attachmentResolver(ctx) });
2830
- if (created.kind === "pi-ai") {
2831
- if (created.note) ctx.logger?.warn?.(created.note);
2832
- if (registration) upgradeProviderAdapter(ctx, created.adapter, registration);
2833
- else ctx.llm.registerAdapter([PROVIDER_ID], created.adapter);
2834
- if (adapterState) {
2835
- adapterState.kind = created.kind;
2836
- adapterState.upgraded = true;
2837
- }
2838
- notifyCatalogChange?.();
2839
- } else if (created.note) {
2840
- ctx.logger?.debug?.(created.note);
2240
+ const created = await buildAdapter(session, {
2241
+ ...options.adapterOptions,
2242
+ resolveAttachments: attachmentResolver(ctx)
2243
+ });
2244
+ if (!created?.adapter) {
2245
+ adapterState.kind = "unavailable";
2246
+ ctx.logger?.warn?.(
2247
+ "Grok subscription adapter is unavailable: %s",
2248
+ created?.note ?? "unknown"
2249
+ );
2250
+ return;
2841
2251
  }
2252
+ if (created.note) ctx.logger?.warn?.(created.note);
2253
+ ctx.llm.registerAdapter([PROVIDER_ID], created.adapter);
2254
+ adapterState.kind = created.kind ?? "pi-ai";
2255
+ notifyCatalogChange?.();
2842
2256
  } catch (error) {
2257
+ adapterState.kind = "unavailable";
2843
2258
  ctx.logger?.warn?.(
2844
- "Grok subscription adapter upgrade failed: %s",
2259
+ "Grok subscription adapter registration failed: %s",
2845
2260
  error instanceof Error ? error.message : "unknown"
2846
2261
  );
2847
2262
  }
@@ -2868,13 +2283,10 @@ export {
2868
2283
  DISPLAY_NAME,
2869
2284
  DISPLAY_NAME_ZH,
2870
2285
  PROVIDER_ID,
2871
- adapterOverride,
2872
2286
  apply,
2873
2287
  deferredBoot,
2874
2288
  inject,
2875
2289
  name,
2876
- registerProviderAdapter,
2877
2290
  scheduleDeferred2 as scheduleDeferred,
2878
- softService,
2879
- upgradeProviderAdapter
2291
+ softService
2880
2292
  };