dsh-grok-subscription 1.0.6 → 1.0.8

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/README.en.md CHANGED
@@ -25,7 +25,7 @@ Models, reasoning effort, and weekly quota all stay inside DSH.
25
25
 
26
26
  ## Three-step start
27
27
 
28
- 1. **Install the plugin.** Run the command below; to select a candidate version, enter the full `package@version`, for example `dsh-grok-subscription@1.0.6`.
28
+ 1. **Install the plugin.** Run the command below; to select a candidate version, enter the full `package@version`, for example `dsh-grok-subscription@1.0.8`.
29
29
 
30
30
  ```sh
31
31
  dsh plugin --profile web add BaronCyrus/dsh-grok-subscription
@@ -91,7 +91,7 @@ dsh plugin --profile web add BaronCyrus/dsh-grok-subscription
91
91
  You can also install the version published on npm:
92
92
 
93
93
  ```sh
94
- dsh plugin --profile web add dsh-grok-subscription@1.0.6
94
+ dsh plugin --profile web add dsh-grok-subscription@1.0.8
95
95
  ```
96
96
 
97
97
  DSH handles target selection, the profile lock, dependency resolution, and bundle activation.
@@ -160,6 +160,10 @@ The badge appears only when the current session's provider is `grok-build` and t
160
160
 
161
161
  `grok-4.7`, `grok-4.7-fast` and `grok-4.6` accept image input: paste or attach an image in the composer and ask about it. Images are normalized to the host's pixel and byte budget by its attachment service before they are sent, and an over-budget image degrades to a text description rather than being dropped silently.
162
162
 
163
+ **Both paths support it**: when the host's official `pi-ai` adapter is available it handles images, and otherwise the bundled fallback adapter reads the attachment bytes itself and inlines them as `input_image`. Image support therefore does not depend on resolving the host's packages. The **Active path** row in Settings shows which one is live and whether image input is available — check it first when a model rejects an image.
164
+
165
+ > If it says "bundled fallback" and images are rejected, `dsh web` most likely was not restarted after updating: the client UI refreshes from disk, but the host adapter is loaded at process start.
166
+
163
167
  `grok-4.5` is **deliberately excluded**. Given a solid red image and asked its colour it answered "green", and it described a yellow square as a "circle with a black outline" — it confabulates instead of looking. The plugin therefore does not advertise image input for it, so it cannot return confident nonsense.
164
168
 
165
169
  ### Reasoning effort
package/README.md CHANGED
@@ -25,7 +25,7 @@
25
25
 
26
26
  ## 三步开始
27
27
 
28
- 1. **安装插件**:在终端运行下面的命令;指定候选版本时填写完整的 `包名@版本`,例如 `dsh-grok-subscription@1.0.6`。
28
+ 1. **安装插件**:在终端运行下面的命令;指定候选版本时填写完整的 `包名@版本`,例如 `dsh-grok-subscription@1.0.8`。
29
29
 
30
30
  ```sh
31
31
  dsh plugin --profile web add BaronCyrus/dsh-grok-subscription
@@ -91,7 +91,7 @@ dsh plugin --profile web add BaronCyrus/dsh-grok-subscription
91
91
  也可以按 npm 上的已发布版本安装:
92
92
 
93
93
  ```sh
94
- dsh plugin --profile web add dsh-grok-subscription@1.0.6
94
+ dsh plugin --profile web add dsh-grok-subscription@1.0.8
95
95
  ```
96
96
 
97
97
  目标选择、profile 锁、依赖解析和 bundle 激活均由 DSH 负责。
@@ -160,6 +160,10 @@ dsh --profile web --dump-config
160
160
 
161
161
  `grok-4.7`、`grok-4.7-fast` 与 `grok-4.6` 支持图片输入:在输入框粘贴或附加图片即可提问。图片由宿主的附件服务按像素与体积预算归一化后发送,超预算时降级为文本说明,而不是静默丢弃。
162
162
 
163
+ **两条通路都支持**:宿主官方 `pi-ai` 适配器可用时走官方实现,否则内置回退适配器自己读取附件字节并内联成 `input_image`。因此贴图能力不依赖宿主包的解析结果。设置页的「运行通路」会显示当前生效的是哪一条,以及图片输入是否可用 —— 遇到「当前模型不支持图片」时先看这一行。
164
+
165
+ > 若显示「内置回退」且贴图被拒,通常是 `dsh web` 更新后没有重启:客户端界面会随刷新更新,但主机端适配器是进程启动时加载的。
166
+
163
167
  `grok-4.5` **不在支持列表内**。实测给它一张纯红图片并询问颜色,它回答 "green",还把黄色方块描述成「带黑边的圆」——它在编造而不是看图。插件因此不为它声明图片能力,避免输出看起来自信却完全错误的答案。
164
168
 
165
169
  ### 推理档位
package/lib/client.js CHANGED
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/client.jsx
21
21
  var client_exports = {};
22
22
  __export(client_exports, {
23
+ DiagnosticsRows: () => DiagnosticsRows,
23
24
  GrokSubscriptionPanel: () => GrokSubscriptionPanel,
24
25
  GrokSubscriptionSection: () => GrokSubscriptionSection,
25
26
  RPC_CALL_TIMEOUT_MS: () => RPC_CALL_TIMEOUT_MS,
@@ -37,7 +38,7 @@ var import_react2 = require("react");
37
38
  var zh = {
38
39
  nav: "Grok \u8BA2\u9605",
39
40
  title: "Grok \u8BA2\u9605",
40
- subtitle: "\u7528 SuperGrok / X Premium\uFF08Grok Build\uFF09\u4F1A\u8BDD\uFF0C\u800C\u4E0D\u662F XAI_API_KEY\u3002\xB7 1.0.6",
41
+ subtitle: "\u7528 SuperGrok / X Premium\uFF08Grok Build\uFF09\u4F1A\u8BDD\uFF0C\u800C\u4E0D\u662F XAI_API_KEY\u3002\xB7 1.0.8",
41
42
  signedIn: "\u5DF2\u767B\u5F55",
42
43
  signedOut: "\u672A\u767B\u5F55",
43
44
  account: "\u8D26\u6237",
@@ -58,6 +59,13 @@ var zh = {
58
59
  loginHelp: "\u767B\u5F55\u65B9\u5F0F\u8BF4\u660E",
59
60
  refreshCatalog: "\u5237\u65B0\u6A21\u578B\u76EE\u5F55",
60
61
  renderError: "\u754C\u9762\u6E32\u67D3\u5931\u8D25",
62
+ diagnostics: "\u8FD0\u884C\u901A\u8DEF",
63
+ adapterPiAi: "\u5B98\u65B9 pi-ai",
64
+ adapterFallback: "\u5185\u7F6E\u56DE\u9000",
65
+ imageInput: "\u56FE\u7247\u8F93\u5165",
66
+ imageInputOn: "\u53EF\u7528",
67
+ imageInputOff: "\u4E0D\u53EF\u7528\uFF08\u672A\u89E3\u6790\u5230\u5BBF\u4E3B\u9644\u4EF6\u670D\u52A1\uFF09",
68
+ adapterHint: "\u82E5\u663E\u793A\u300C\u5185\u7F6E\u56DE\u9000\u300D\u4E14\u8D34\u56FE\u88AB\u62D2\uFF0C\u8BF7\u91CD\u542F dsh web \u8BA9\u65B0\u7248\u4E3B\u673A\u7AEF\u751F\u6548\u3002",
61
69
  busy: "\u5904\u7406\u4E2D\u2026",
62
70
  busyCatalog: "\u6B63\u5728\u5237\u65B0\u6A21\u578B\u76EE\u5F55\u2026",
63
71
  busyUsage: "\u6B63\u5728\u5237\u65B0\u7528\u91CF\u2026",
@@ -87,7 +95,7 @@ var zh = {
87
95
  var en = {
88
96
  nav: "Grok Subscription",
89
97
  title: "Grok Subscription",
90
- subtitle: "Use a SuperGrok / X Premium (Grok Build) session, not XAI_API_KEY. \xB7 1.0.6",
98
+ subtitle: "Use a SuperGrok / X Premium (Grok Build) session, not XAI_API_KEY. \xB7 1.0.8",
91
99
  signedIn: "Signed in",
92
100
  signedOut: "Signed out",
93
101
  account: "Account",
@@ -108,6 +116,13 @@ var en = {
108
116
  loginHelp: "How signing in works",
109
117
  refreshCatalog: "Refresh model catalog",
110
118
  renderError: "Failed to render this panel",
119
+ diagnostics: "Active path",
120
+ adapterPiAi: "official pi-ai",
121
+ adapterFallback: "bundled fallback",
122
+ imageInput: "Image input",
123
+ imageInputOn: "available",
124
+ imageInputOff: "unavailable (host attachment service not resolved)",
125
+ adapterHint: 'If this says "bundled fallback" and images are rejected, restart dsh web so the new host bundle loads.',
111
126
  busy: "Working\u2026",
112
127
  busyCatalog: "Refreshing model catalog\u2026",
113
128
  busyUsage: "Refreshing usage\u2026",
@@ -659,6 +674,19 @@ function Chip({ tone = "off", children }) {
659
674
  children
660
675
  ] });
661
676
  }
677
+ function DiagnosticsRows({ diagnostics, t }) {
678
+ if (!diagnostics) return null;
679
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "gsRows", children: [
680
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "gsRow", children: [
681
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: t("diagnostics") }),
682
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "gsRowValue", children: diagnostics.adapter === "pi-ai" ? t("adapterPiAi") : t("adapterFallback") })
683
+ ] }),
684
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "gsRow", children: [
685
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: t("imageInput") }),
686
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "gsRowValue", children: diagnostics.imageInput ? t("imageInputOn") : t("imageInputOff") })
687
+ ] })
688
+ ] });
689
+ }
662
690
  function UsagePanel({ usage, t, usageBusy, onRefresh, signedIn }) {
663
691
  const ok = usage?.status === "ok";
664
692
  const usedNumber = ok && Number.isFinite(usage.usedPercent) ? usage.usedPercent : void 0;
@@ -835,6 +863,8 @@ function GrokSubscriptionSection({ rpc, t }) {
835
863
  error
836
864
  ] }) : null,
837
865
  status?.cliAvailable === false ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "gsStatus gsStatus--warn", children: t("cliMissing") }) : null,
866
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(DiagnosticsRows, { diagnostics: status?.diagnostics, t }),
867
+ status?.diagnostics && !status.diagnostics.imageInput ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "gsHint", children: t("adapterHint") }) : null,
838
868
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("details", { className: "gsDisclosure", children: [
839
869
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("summary", { children: [
840
870
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Chevron, {}),
package/lib/index.js CHANGED
@@ -389,7 +389,9 @@ function toLlmModels(models) {
389
389
  provider: PROVIDER_ID,
390
390
  id: model.id,
391
391
  name: model.name,
392
- inputModalities: ["text"]
392
+ // The bundled adapter inlines images through the host attachment store,
393
+ // so it advertises the same modality map as the official pi-ai path.
394
+ inputModalities: supportsImageInput(model.id) ? ["text", "image"] : ["text"]
393
395
  };
394
396
  const reasoning = reasoningInfoOf(model);
395
397
  if (reasoning) info.reasoning = reasoning;
@@ -751,6 +753,17 @@ function hostModuleRoots(env = process.env, argv1 = process.argv[1]) {
751
753
  }
752
754
  const prefix = env.NPM_CONFIG_PREFIX;
753
755
  if (typeof prefix === "string" && prefix.trim()) push(join2(prefix.trim(), "lib", "node_modules"));
756
+ if (typeof process.execPath === "string" && process.execPath) {
757
+ push(join2(dirname(process.execPath), "..", "lib", "node_modules"));
758
+ }
759
+ push(join2("/opt/homebrew", "lib", "node_modules"));
760
+ push(join2("/usr/local", "lib", "node_modules"));
761
+ for (const segment of ["Library/pnpm", ".local/share/pnpm", ".pnpm-global"]) {
762
+ push(join2(homedir2(), segment, "node_modules"));
763
+ }
764
+ if (typeof env.DSH_PORTABLE_HOME === "string" && env.DSH_PORTABLE_HOME.trim()) {
765
+ push(join2(env.DSH_PORTABLE_HOME.trim(), "node_modules"));
766
+ }
754
767
  push(join2(homedir2(), ".local", "lib", "node_modules"));
755
768
  const dshHome = typeof env.DSH_HOME === "string" && env.DSH_HOME.trim() ? env.DSH_HOME.trim() : join2(homedir2(), ".dsh");
756
769
  push(join2(dshHome, "profiles", "node_modules"));
@@ -796,7 +809,13 @@ function resolveExportsTarget(exportsField, subpath) {
796
809
  }
797
810
  function resolveHostSpecifierManually(root, specifier) {
798
811
  const { name: name2, subpath } = splitSpecifier(specifier);
799
- for (const pkgDir of [join2(root, name2), join2(root, "node_modules", name2)]) {
812
+ const candidates = [
813
+ join2(root, name2),
814
+ join2(root, "node_modules", name2),
815
+ join2(root, "@deepseek-ai", "dsh", "node_modules", name2),
816
+ join2(root, "node_modules", "@deepseek-ai", "dsh", "node_modules", name2)
817
+ ];
818
+ for (const pkgDir of candidates) {
800
819
  const manifest = join2(pkgDir, "package.json");
801
820
  if (!existsSync2(manifest)) continue;
802
821
  let pkg;
@@ -858,7 +877,66 @@ function textOf(content) {
858
877
  return "";
859
878
  }).join("");
860
879
  }
861
- function responsesInput(options) {
880
+ function imagePlaceholderText(ref) {
881
+ const name2 = typeof ref?.name === "string" && ref.name.trim() ? ` ${JSON.stringify(ref.name.trim())}` : "";
882
+ return `[attached image${name2} could not be included in this request]`;
883
+ }
884
+ async function collectImageParts(options, resolveAttachments, policy = {}) {
885
+ const parts = /* @__PURE__ */ new Map();
886
+ const refs = [];
887
+ for (const message of options.messages ?? []) {
888
+ for (const block of message?.content ?? []) {
889
+ if (block?.type !== "image" || !block.attachment) continue;
890
+ const id = block.attachment.attachmentId;
891
+ if (typeof id !== "string" || !id || parts.has(id)) continue;
892
+ parts.set(id, void 0);
893
+ refs.push(block.attachment);
894
+ }
895
+ }
896
+ if (refs.length === 0) return parts;
897
+ let store;
898
+ try {
899
+ store = resolveAttachments?.();
900
+ } catch {
901
+ store = void 0;
902
+ }
903
+ if (!store?.readImageRequest) return parts;
904
+ const request = {
905
+ maxPixels: policy.maxPixels ?? REQUEST_IMAGE_PIXEL_BUDGET,
906
+ maxBytes: policy.maxBytes ?? REQUEST_IMAGE_MAX_BYTES
907
+ };
908
+ await Promise.all(refs.map(async (ref) => {
909
+ try {
910
+ const version = await store.readImageRequest(ref, request);
911
+ if (!version?.data || typeof version.mediaType !== "string" || !version.mediaType) return;
912
+ parts.set(ref.attachmentId, {
913
+ mediaType: version.mediaType,
914
+ base64: Buffer.from(version.data).toString("base64")
915
+ });
916
+ } catch {
917
+ }
918
+ }));
919
+ return parts;
920
+ }
921
+ function imageContentParts(blocks, imageParts) {
922
+ const parts = [];
923
+ const text = textOf(blocks);
924
+ if (text) parts.push({ type: "input_text", text });
925
+ for (const block of blocks ?? []) {
926
+ if (block?.type !== "image" || !block.attachment) continue;
927
+ const resolved = imageParts?.get(block.attachment.attachmentId);
928
+ if (resolved) {
929
+ parts.push({
930
+ type: "input_image",
931
+ image_url: `data:${resolved.mediaType};base64,${resolved.base64}`
932
+ });
933
+ } else {
934
+ parts.push({ type: "input_text", text: imagePlaceholderText(block.attachment) });
935
+ }
936
+ }
937
+ return parts;
938
+ }
939
+ function responsesInput(options, imageParts) {
862
940
  const input = [];
863
941
  const system = typeof options.system === "string" && options.system ? options.system : void 0;
864
942
  if (system) input.push({ role: "system", content: system });
@@ -889,6 +967,12 @@ function responsesInput(options) {
889
967
  if (text2) input.push({ role: "assistant", content: text2 });
890
968
  continue;
891
969
  }
970
+ const hasImage = (message.content ?? []).some((block) => block?.type === "image");
971
+ if (role === "user" && hasImage) {
972
+ const parts = imageContentParts(message.content, imageParts);
973
+ if (parts.length > 0) input.push({ role, content: parts });
974
+ continue;
975
+ }
892
976
  const text = textOf(message.content);
893
977
  if (!text) continue;
894
978
  input.push({ role, content: text });
@@ -937,7 +1021,7 @@ async function* streamResponsesUnsafe(options, token) {
937
1021
  }
938
1022
  const body = {
939
1023
  model: options.model,
940
- input: responsesInput(options),
1024
+ input: responsesInput(options, await collectImageParts(options, options.resolveAttachments)),
941
1025
  stream: true
942
1026
  };
943
1027
  if (typeof options.maxTokens === "number") body.max_output_tokens = options.maxTokens;
@@ -1138,7 +1222,7 @@ function visiblePiModels(session) {
1138
1222
  if (session.publicAccount()?.signedIn !== true) return [];
1139
1223
  return toPiModels(session.models()).map((model) => model.provider === PROVIDER_ID ? model : { ...model, provider: PROVIDER_ID });
1140
1224
  }
1141
- function createDuckAdapter(session) {
1225
+ function createDuckAdapter(session, adapterOptions = {}) {
1142
1226
  const providerInfo = () => ({ id: PROVIDER_ID, name: DISPLAY_NAME });
1143
1227
  const list = () => {
1144
1228
  const signedIn = session.publicAccount()?.signedIn === true;
@@ -1160,7 +1244,9 @@ function createDuckAdapter(session) {
1160
1244
  provider,
1161
1245
  id: model,
1162
1246
  name: found?.name ?? model,
1163
- inputModalities: ["text"],
1247
+ // The host gates prompt attachment admission on resolveModelInfo, NOT on
1248
+ // listModels, so this must match the catalog's modality map exactly.
1249
+ inputModalities: supportsImageInput(model) ? ["text", "image"] : ["text"],
1164
1250
  context: { contextWindow: raw?.contextWindow ?? 5e5 }
1165
1251
  };
1166
1252
  const reasoning = reasoningInfoOf(raw);
@@ -1180,6 +1266,7 @@ function createDuckAdapter(session) {
1180
1266
  yield { type: "finish", reason: { kind: "error", failure: { message: "Unknown provider", code: "NO_ADAPTER" } } };
1181
1267
  return;
1182
1268
  }
1269
+ const callOptions = typeof adapterOptions.resolveAttachments === "function" ? { ...options, resolveAttachments: adapterOptions.resolveAttachments } : options;
1183
1270
  let token = await session.currentToken();
1184
1271
  if (!token) {
1185
1272
  yield { type: "finish", reason: { kind: "error", failure: { message: "Grok subscription is not signed in", code: "MISSING_CREDENTIAL" } } };
@@ -1188,7 +1275,7 @@ function createDuckAdapter(session) {
1188
1275
  for (let attempt = 0; ; attempt++) {
1189
1276
  let emitted = false;
1190
1277
  try {
1191
- for await (const chunk of streamResponses(options, token)) {
1278
+ for await (const chunk of streamResponses(callOptions, token, callOptions.resolveAttachments)) {
1192
1279
  emitted = true;
1193
1280
  yield chunk;
1194
1281
  }
@@ -1287,7 +1374,7 @@ function wrapAsHostAdapter(candidate, dshLlm) {
1287
1374
  return new GrokBuildAdapter();
1288
1375
  }
1289
1376
  function createGrokBuildAdapterSync(session, options = {}) {
1290
- const duck = createDuckAdapter(session);
1377
+ const duck = createDuckAdapter(session, { resolveAttachments: options.resolveAttachments });
1291
1378
  const dshLlm = options.dshLlm;
1292
1379
  return {
1293
1380
  adapter: wrapAsHostAdapter(duck, dshLlm),
@@ -1302,7 +1389,7 @@ async function createGrokBuildAdapter(session, options = {}) {
1302
1389
  optionalImport("@deepseek-ai/dsh-llm-pi-ai", importOpts),
1303
1390
  optionalImport("@deepseek-ai/dsh-llm", importOpts)
1304
1391
  ]);
1305
- const duck = createDuckAdapter(session);
1392
+ const duck = createDuckAdapter(session, { resolveAttachments: options.resolveAttachments });
1306
1393
  const asHostAdapter = (candidate) => wrapAsHostAdapter(candidate, dshLlm);
1307
1394
  if (!piAi?.createProvider || !dshPi?.PiAiAdapter) {
1308
1395
  return {
@@ -1878,8 +1965,17 @@ function sanitizeUsage(usage) {
1878
1965
  }
1879
1966
  return out;
1880
1967
  }
1881
- async function dispatch(session, endpoint) {
1882
- if (endpoint === "status") return publicResult(stripSecrets(await session.status()));
1968
+ async function dispatch(session, endpoint, diagnostics) {
1969
+ if (endpoint === "status") {
1970
+ const status = await session.status();
1971
+ return publicResult(stripSecrets({
1972
+ ...status,
1973
+ // Which adapter is actually serving this route: the host's official
1974
+ // pi-ai implementation or the bundled fallback. Diagnosing "model does
1975
+ // not support images" starts here.
1976
+ diagnostics: typeof diagnostics === "function" ? diagnostics() : diagnostics
1977
+ }));
1978
+ }
1883
1979
  if (endpoint === "pull") return publicResult(stripSecrets(await session.pull()));
1884
1980
  if (endpoint === "logout") return publicResult(stripSecrets(await session.logout()));
1885
1981
  if (endpoint === "catalog/refresh") {
@@ -1902,7 +1998,7 @@ function createRpcHandler(session, options = {}) {
1902
1998
  return async function handle(endpoint, _payload, _signal) {
1903
1999
  try {
1904
2000
  return await withTimeout(
1905
- dispatch(session, endpoint),
2001
+ dispatch(session, endpoint, options.diagnostics),
1906
2002
  timeoutMs,
1907
2003
  `Grok subscription RPC "${endpoint}" timed out after ${timeoutMs}ms`,
1908
2004
  { unref: false }
@@ -2011,6 +2107,15 @@ function softService(ctx, key) {
2011
2107
  }
2012
2108
  return void 0;
2013
2109
  }
2110
+ function attachmentResolver(ctx) {
2111
+ return () => {
2112
+ try {
2113
+ return typeof ctx.get === "function" ? ctx.get("attachments") : void 0;
2114
+ } catch {
2115
+ return void 0;
2116
+ }
2117
+ };
2118
+ }
2014
2119
  function apply(ctx, options = {}) {
2015
2120
  let active = true;
2016
2121
  if (typeof ctx.effect === "function") {
@@ -2038,11 +2143,21 @@ function apply(ctx, options = {}) {
2038
2143
  logger: ctx.logger,
2039
2144
  onCatalogChange: notifyCatalogChange
2040
2145
  });
2041
- const handler = createRpcHandler(session);
2146
+ const adapterState = { kind: "custom-mvp", upgraded: false };
2147
+ const handler = createRpcHandler(session, {
2148
+ diagnostics: () => ({
2149
+ adapter: adapterState.upgraded ? "pi-ai" : "fallback",
2150
+ adapterKind: adapterState.kind,
2151
+ imageInput: typeof resolveAttachments()?.readImageRequest === "function",
2152
+ hostPeersResolved: adapterState.upgraded
2153
+ })
2154
+ });
2155
+ const resolveAttachments = attachmentResolver(ctx);
2042
2156
  const createSync = options.createSync ?? createGrokBuildAdapterSync;
2043
2157
  try {
2044
- const created = createSync(session);
2158
+ const created = createSync(session, { resolveAttachments });
2045
2159
  if (created.note) ctx.logger?.debug?.(created.note);
2160
+ adapterState.kind = created.kind;
2046
2161
  ctx.llm.registerAdapter([PROVIDER_ID], created.adapter);
2047
2162
  notifyCatalogChange();
2048
2163
  } catch (error) {
@@ -2053,14 +2168,14 @@ function apply(ctx, options = {}) {
2053
2168
  }
2054
2169
  const defer = options.defer ?? scheduleDeferred2;
2055
2170
  defer(() => {
2056
- void deferredBoot(ctx, session, notifyCatalogChange, options);
2171
+ void deferredBoot(ctx, session, notifyCatalogChange, options, adapterState);
2057
2172
  });
2058
2173
  ctx.inject(["connection"], (connectionContext) => connectionContext.effect(
2059
2174
  () => registerSubscriptionTransport(connectionContext.connection, handler),
2060
2175
  "grok-subscription: host-only account RPC"
2061
2176
  ));
2062
2177
  }
2063
- async function deferredBoot(ctx, session, notifyCatalogChange, options = {}) {
2178
+ async function deferredBoot(ctx, session, notifyCatalogChange, options = {}, adapterState) {
2064
2179
  if (!options.skipSettings) {
2065
2180
  await tryRegisterSettings(ctx);
2066
2181
  }
@@ -2087,18 +2202,15 @@ async function deferredBoot(ctx, session, notifyCatalogChange, options = {}) {
2087
2202
  }
2088
2203
  if (options.skipUpgrade) return;
2089
2204
  const createAsync = options.createAsync ?? createGrokBuildAdapter;
2090
- const resolveAttachments = () => {
2091
- try {
2092
- return typeof ctx.get === "function" ? ctx.get("attachments") : void 0;
2093
- } catch {
2094
- return void 0;
2095
- }
2096
- };
2097
2205
  try {
2098
- const created = await createAsync(session, { ...options.adapterOptions, resolveAttachments });
2206
+ const created = await createAsync(session, { ...options.adapterOptions, resolveAttachments: attachmentResolver(ctx) });
2099
2207
  if (created.kind === "pi-ai") {
2100
2208
  if (created.note) ctx.logger?.warn?.(created.note);
2101
2209
  ctx.llm.registerAdapter([PROVIDER_ID], created.adapter);
2210
+ if (adapterState) {
2211
+ adapterState.kind = created.kind;
2212
+ adapterState.upgraded = true;
2213
+ }
2102
2214
  notifyCatalogChange?.();
2103
2215
  } else if (created.note) {
2104
2216
  ctx.logger?.debug?.(created.note);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-grok-subscription",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "Use a SuperGrok or X Premium Grok Build subscription in DeepSeek Harness",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",