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/CHANGELOG.md +23 -0
- package/README.en.md +11 -26
- package/README.md +12 -29
- package/docs/guide.en.md +17 -50
- package/docs/guide.zh-CN.md +18 -51
- package/lib/client.js +32 -10
- package/lib/index.js +67 -655
- package/package.json +1 -1
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
|
-
|
|
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:
|
|
1538
|
-
kind: "
|
|
1539
|
-
note: "
|
|
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 {
|
|
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: "
|
|
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.
|
|
2770
|
-
adapterKind: adapterState.kind,
|
|
2194
|
+
adapter: adapterState.kind,
|
|
2771
2195
|
imageInput: typeof resolveAttachments()?.readImageRequest === "function",
|
|
2772
|
-
hostPeersResolved: adapterState.
|
|
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,
|
|
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
|
|
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.
|
|
2827
|
-
|
|
2234
|
+
if (options.skipAdapter) {
|
|
2235
|
+
adapterState.kind = "unavailable";
|
|
2236
|
+
return;
|
|
2237
|
+
}
|
|
2238
|
+
const buildAdapter = options.buildAdapter ?? createGrokBuildAdapter;
|
|
2828
2239
|
try {
|
|
2829
|
-
const created = await
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
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
|
|
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
|
};
|