@dan-ai-studio/dshopencodego 0.1.74 → 0.1.76

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
@@ -73672,7 +73672,7 @@ import dc from "node:diagnostics_channel";
73672
73672
  import { credentialRef } from "@deepseek-ai/dsh-credentials";
73673
73673
  import { launchEnvironmentOf } from "@deepseek-ai/dsh-launch-environment";
73674
73674
  import * as llm2 from "@deepseek-ai/dsh-llm";
73675
- import { LlmError as LlmError12 } from "@deepseek-ai/dsh-llm";
73675
+ import { LlmError as LlmError13 } from "@deepseek-ai/dsh-llm";
73676
73676
 
73677
73677
  // src/adapter.ts
73678
73678
  init_models();
@@ -73682,7 +73682,7 @@ import {
73682
73682
  contentHasImage as contentHasImage2,
73683
73683
  isTokenDelta,
73684
73684
  LlmAdapter,
73685
- LlmError as LlmError8,
73685
+ LlmError as LlmError9,
73686
73686
  ReasoningEffortId,
73687
73687
  resolveRetryPolicy
73688
73688
  } from "@deepseek-ai/dsh-llm";
@@ -74973,7 +74973,7 @@ async function discoverCatalogModels(catalog, signal) {
74973
74973
  }
74974
74974
 
74975
74975
  // src/config.ts
74976
- import { RetryPolicySchema } from "@deepseek-ai/dsh-llm";
74976
+ import { LlmError as LlmError5, RetryPolicySchema } from "@deepseek-ai/dsh-llm";
74977
74977
  import { MAX_TIMER_DELAY_MS } from "@deepseek-ai/dsh-timeout";
74978
74978
 
74979
74979
  // node_modules/@deepseek-ai/cosmokit/lib/index.js
@@ -75890,6 +75890,14 @@ var PlainConfig = Schema.object(fields);
75890
75890
  var Config = Schema.object(Object.fromEntries(
75891
75891
  Object.entries(fields).map(([key, schema]) => [key, schema.volatile()])
75892
75892
  ));
75893
+ function assertStreamIdleTimeoutMs(value) {
75894
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0 || value > MAX_TIMER_DELAY_MS) {
75895
+ throw new LlmError5(
75896
+ `dshopencodego: streamIdleTimeoutMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`,
75897
+ "INVALID_CONFIG"
75898
+ );
75899
+ }
75900
+ }
75893
75901
  function readConfig(config) {
75894
75902
  return Object.fromEntries(Object.keys(fields).flatMap((key) => {
75895
75903
  const field = config[key];
@@ -75921,11 +75929,11 @@ function assertBaseURL(raw) {
75921
75929
  // src/conversion/context.ts
75922
75930
  import { brandString } from "@deepseek-ai/dsh-brand";
75923
75931
  import * as llm from "@deepseek-ai/dsh-llm";
75924
- import { contentHasImage, LlmError as LlmError6, requestImageHandleText } from "@deepseek-ai/dsh-llm";
75932
+ import { contentHasImage, LlmError as LlmError7, requestImageHandleText } from "@deepseek-ai/dsh-llm";
75925
75933
  import { requestImageDimensions } from "@deepseek-ai/dsh-attachment";
75926
75934
 
75927
75935
  // src/conversion/replay.ts
75928
- import { LlmError as LlmError5 } from "@deepseek-ai/dsh-llm";
75936
+ import { LlmError as LlmError6 } from "@deepseek-ai/dsh-llm";
75929
75937
  var REPLAYABLE_STOP_REASONS = ["stop", "length", "toolUse", "error", "aborted"];
75930
75938
  function replayableStopReason(stopReason) {
75931
75939
  return REPLAYABLE_STOP_REASONS.includes(stopReason) ? stopReason : "error";
@@ -75988,7 +75996,7 @@ function toPiReplayState(message, requestedModel = message.model) {
75988
75996
  };
75989
75997
  }
75990
75998
  function invalidReplay(message) {
75991
- throw new LlmError5(`invalid pi-ai replay state: ${message}`, "INVALID_REPLAY_STATE");
75999
+ throw new LlmError6(`invalid pi-ai replay state: ${message}`, "INVALID_REPLAY_STATE");
75992
76000
  }
75993
76001
  function readReplayState(value) {
75994
76002
  if (typeof value !== "object" || value === null || Array.isArray(value)) return invalidReplay("expected a replay envelope");
@@ -76048,7 +76056,7 @@ function foreignAssistant(message) {
76048
76056
  });
76049
76057
  break;
76050
76058
  case "image":
76051
- throw new LlmError5("pi-ai chat history cannot represent structured assistant image output", "UNSUPPORTED_CONTENT");
76059
+ throw new LlmError6("pi-ai chat history cannot represent structured assistant image output", "UNSUPPORTED_CONTENT");
76052
76060
  default:
76053
76061
  break;
76054
76062
  }
@@ -76122,7 +76130,7 @@ function toPiAssistant(message, onDegrade) {
76122
76130
  try {
76123
76131
  return replayedAssistant(message, source, source.replayState);
76124
76132
  } catch (error) {
76125
- if (!(error instanceof LlmError5) || error.code !== "INVALID_REPLAY_STATE") throw error;
76133
+ if (!(error instanceof LlmError6) || error.code !== "INVALID_REPLAY_STATE") throw error;
76126
76134
  onDegrade?.(error.message);
76127
76135
  return foreignAssistant(message);
76128
76136
  }
@@ -76138,7 +76146,7 @@ function toolMessage(message) {
76138
76146
  function assertSupportedImageRoles(messages) {
76139
76147
  for (const message of messages) {
76140
76148
  if (message.role !== "user" && toolMessage(message) === void 0 && contentHasImage(message.content)) {
76141
- throw new LlmError6(`pi-ai cannot represent an image in an in-history ${message.role} message`, "UNSUPPORTED_CONTENT");
76149
+ throw new LlmError7(`pi-ai cannot represent an image in an in-history ${message.role} message`, "UNSUPPORTED_CONTENT");
76142
76150
  }
76143
76151
  }
76144
76152
  }
@@ -76186,7 +76194,7 @@ async function userContent(blocks, requestImages, resolveImageAccess) {
76186
76194
  if (block.type === "image") {
76187
76195
  const version = requestImages.get(block.attachment.attachmentId);
76188
76196
  if (version === void 0) {
76189
- throw new LlmError6(
76197
+ throw new LlmError7(
76190
76198
  "dshopencodego: an image in this request has no prepared bytes; image input requires the attachment service",
76191
76199
  "UNSUPPORTED_CONTENT"
76192
76200
  );
@@ -76210,7 +76218,7 @@ function projectImagesForRequest(messages, images, requestImages) {
76210
76218
  (block) => requestImages.get(block.attachment.attachmentId).bytes
76211
76219
  );
76212
76220
  if (over > 0) {
76213
- throw new LlmError6(
76221
+ throw new LlmError7(
76214
76222
  `request images exceed the ${images.maxRequestImageBytes}-byte base64 bound; ${over} more oldest occurrence(s) must be offloaded`,
76215
76223
  llm.IMAGE_OFFLOAD_REQUIRED_CODE,
76216
76224
  { offloadImages: over }
@@ -76243,7 +76251,13 @@ async function toPiContext(options, images, onReplayDegrade) {
76243
76251
  continue;
76244
76252
  }
76245
76253
  if (message.role === "system") {
76246
- messages.push({ role: "user", content: flattenText(message), timestamp: 0 });
76254
+ const text2 = flattenText(message);
76255
+ if (text2.length > 0) {
76256
+ const reminder = text2.replaceAll("</system-reminder>", "<\\/system-reminder>");
76257
+ messages.push({ role: "user", content: `<system-reminder>
76258
+ ${reminder}
76259
+ </system-reminder>`, timestamp: 0 });
76260
+ }
76247
76261
  continue;
76248
76262
  }
76249
76263
  if (message.role === "assistant") {
@@ -76272,7 +76286,7 @@ import {
76272
76286
  EMPTY_RESPONSE_CODE,
76273
76287
  isContextWindowExceededError,
76274
76288
  isQuotaExceededError,
76275
- LlmError as LlmError7
76289
+ LlmError as LlmError8
76276
76290
  } from "@deepseek-ai/dsh-llm";
76277
76291
 
76278
76292
  // node_modules/@earendil-works/pi-ai/dist/utils/overflow.js
@@ -76520,7 +76534,7 @@ async function* toStreamChunks(events, contextWindow, callerSignal, requestedMod
76520
76534
  return;
76521
76535
  }
76522
76536
  }
76523
- throw new LlmError7("pi-ai event stream ended without a terminal event", "STREAM_CLOSED");
76537
+ throw new LlmError8("pi-ai event stream ended without a terminal event", "STREAM_CLOSED");
76524
76538
  }
76525
76539
 
76526
76540
  // src/go-limits.ts
@@ -76723,7 +76737,7 @@ function withModelLimit(model, limits) {
76723
76737
  function stopSequencesFor(model, stop) {
76724
76738
  if (stop === void 0) return void 0;
76725
76739
  if (model.api === "openai-completions") return stop;
76726
- throw new LlmError8(
76740
+ throw new LlmError9(
76727
76741
  `opencode-go model "${model.id}" speaks ${model.api}, which has no stop-sequence parameter this adapter can reach; drop GenerateOptions.stop for this model`,
76728
76742
  "UNSUPPORTED_OPTION"
76729
76743
  );
@@ -76778,8 +76792,12 @@ var OpencodeGoAdapter = class extends LlmAdapter {
76778
76792
  baseURL: assertBaseURL(config.baseURL),
76779
76793
  refreshMs: config.refreshMinutes * 6e4,
76780
76794
  defaults: {
76781
- contextWindow: 262144,
76782
- maxTokens: 32768,
76795
+ // A guess for a model no source sizes, kept in step with the
76796
+ // llm-pi-ai route defaults: modern models are roomier than the
76797
+ // 2026-era numbers these replace, and undersizing one fails a
76798
+ // request the gateway would have served.
76799
+ contextWindow: 1e6,
76800
+ maxTokens: 128e3,
76783
76801
  input: ["text"]
76784
76802
  },
76785
76803
  overrides: config.modelProtocols,
@@ -76836,7 +76854,7 @@ var OpencodeGoAdapter = class extends LlmAdapter {
76836
76854
  const config = this.options.config();
76837
76855
  const snapshot2 = await this.catalogOf(config).forModel(model);
76838
76856
  const facts = snapshot2.facts.get(model);
76839
- if (facts === void 0) throw new LlmError8(`opencode-go has no model "${model}"`, "UNKNOWN_MODEL");
76857
+ if (facts === void 0) throw new LlmError9(`opencode-go has no model "${model}"`, "UNKNOWN_MODEL");
76840
76858
  return this.modelInfo(withModelLimit(toPiModel(facts, config.baseURL), config.modelLimits));
76841
76859
  }
76842
76860
  /** Describe one model: capacities plus the reasoning levels it really offers. */
@@ -76882,16 +76900,17 @@ var OpencodeGoAdapter = class extends LlmAdapter {
76882
76900
  if (effort === void 0 || effort === "off") return void 0;
76883
76901
  const supported = getSupportedThinkingLevels(model);
76884
76902
  if (supported.some((level) => level === effort)) return effort;
76885
- throw new LlmError8(
76903
+ throw new LlmError9(
76886
76904
  `opencode-go model "${model.id}" does not support reasoning effort "${effort}"`,
76887
76905
  "UNSUPPORTED_REASONING_EFFORT"
76888
76906
  );
76889
76907
  }
76890
76908
  async prepareCall(_provider, model, _signal) {
76891
76909
  const config = this.options.config();
76910
+ assertStreamIdleTimeoutMs(config.streamIdleTimeoutMs);
76892
76911
  const snapshot2 = await this.catalogOf(config).forModel(model);
76893
76912
  const facts = snapshot2.facts.get(model);
76894
- if (facts === void 0) throw new LlmError8(`opencode-go has no model "${model}"`, "UNKNOWN_MODEL");
76913
+ if (facts === void 0) throw new LlmError9(`opencode-go has no model "${model}"`, "UNKNOWN_MODEL");
76895
76914
  const prepared = this.modelInfo(withModelLimit(toPiModel(facts, config.baseURL), config.modelLimits));
76896
76915
  return {
76897
76916
  model: prepared,
@@ -76900,14 +76919,16 @@ var OpencodeGoAdapter = class extends LlmAdapter {
76900
76919
  }
76901
76920
  async *stream(options) {
76902
76921
  const config = this.options.config();
76922
+ assertStreamIdleTimeoutMs(config.streamIdleTimeoutMs);
76903
76923
  const snapshot2 = await this.catalogOf(config).forModel(options.model);
76904
76924
  yield* this.streamWithSnapshot(options, config, snapshot2);
76905
76925
  }
76906
76926
  async *streamWithSnapshot(options, config, snapshot2) {
76907
76927
  var _stack = [];
76908
76928
  try {
76929
+ assertStreamIdleTimeoutMs(config.streamIdleTimeoutMs);
76909
76930
  const facts = snapshot2.facts.get(options.model);
76910
- if (facts === void 0) throw new LlmError8(`opencode-go has no model "${options.model}"`, "UNKNOWN_MODEL");
76931
+ if (facts === void 0) throw new LlmError9(`opencode-go has no model "${options.model}"`, "UNKNOWN_MODEL");
76911
76932
  const model = withModelLimit(toPiModel(facts, config.baseURL), config.modelLimits);
76912
76933
  const rates2 = usableRates(facts.cost);
76913
76934
  const stop = stopSequencesFor(model, options.stop);
@@ -76915,7 +76936,7 @@ var OpencodeGoAdapter = class extends LlmAdapter {
76915
76936
  const maxTokens = options.maxTokens === void 0 || ceiling === null || ceiling === void 0 ? options.maxTokens : Math.min(options.maxTokens, ceiling);
76916
76937
  const apiKey = await this.options.resolveApiKey();
76917
76938
  if (apiKey === void 0 || apiKey.length === 0) {
76918
- throw new LlmError8("dshopencodego: no credential resolved for the opencode-go route", "MISSING_CREDENTIAL");
76939
+ throw new LlmError9("dshopencodego: no credential resolved for the opencode-go route", "MISSING_CREDENTIAL");
76919
76940
  }
76920
76941
  const reasoning = this.resolveReasoningLevel(model, options.reasoningEffort);
76921
76942
  const consumer = new AbortController();
@@ -76953,14 +76974,14 @@ var OpencodeGoAdapter = class extends LlmAdapter {
76953
76974
  };
76954
76975
  try {
76955
76976
  if (containsImage && !model.input.includes("image")) {
76956
- throw new LlmError8(`opencode-go model "${model.id}" does not support image input`, "UNSUPPORTED_CONTENT");
76977
+ throw new LlmError9(`opencode-go model "${model.id}" does not support image input`, "UNSUPPORTED_CONTENT");
76957
76978
  }
76958
76979
  let imageRequest;
76959
76980
  if (containsImage) {
76960
76981
  const access2 = this.options.imageAccess;
76961
76982
  const store = access2?.resolveAttachments();
76962
76983
  if (access2 === void 0 || store === void 0) {
76963
- throw new LlmError8("dshopencodego image input requires the durable attachment service", "UNSUPPORTED_CONTENT");
76984
+ throw new LlmError9("dshopencodego image input requires the durable attachment service", "UNSUPPORTED_CONTENT");
76964
76985
  }
76965
76986
  imageRequest = {
76966
76987
  attachments: store,
@@ -77004,7 +77025,7 @@ var OpencodeGoAdapter = class extends LlmAdapter {
77004
77025
  while (true) {
77005
77026
  const result = await watchdog.next(iterator);
77006
77027
  if (timeoutOf(watchdog.signal, "LLM_STREAM_IDLE_TIMEOUT") !== void 0) {
77007
- throw new LlmError8("opencode-go stream idle timeout", "TIMEOUT");
77028
+ throw new LlmError9("opencode-go stream idle timeout", "TIMEOUT");
77008
77029
  }
77009
77030
  if (result.done) {
77010
77031
  exhausted = true;
@@ -77056,13 +77077,13 @@ var OpencodeGoAdapter = class extends LlmAdapter {
77056
77077
  } catch (error) {
77057
77078
  if (timedOut || timeoutOf(watchdog.signal, "LLM_STREAM_IDLE_TIMEOUT") !== void 0) {
77058
77079
  span?.finish(false, "TIMEOUT");
77059
- throw new LlmError8("opencode-go stream idle timeout", "TIMEOUT", { cause: error });
77080
+ throw new LlmError9("opencode-go stream idle timeout", "TIMEOUT", { cause: error });
77060
77081
  }
77061
77082
  if (options.signal?.aborted) {
77062
77083
  span?.finish(false, "ABORTED");
77063
- throw new LlmError8("opencode-go request aborted by caller", "ABORTED", { cause: error });
77084
+ throw new LlmError9("opencode-go request aborted by caller", "ABORTED", { cause: error });
77064
77085
  }
77065
- span?.finish(false, error instanceof LlmError8 ? error.code : void 0);
77086
+ span?.finish(false, error instanceof LlmError9 ? error.code : void 0);
77066
77087
  throw error;
77067
77088
  } finally {
77068
77089
  consumer.abort("opencode-go stream consumer stopped");
@@ -77531,7 +77552,7 @@ function registerRemotes(ctx) {
77531
77552
 
77532
77553
  // src/catalog/service.ts
77533
77554
  import { RemoteError, TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol";
77534
- import { LlmError as LlmError9 } from "@deepseek-ai/dsh-llm";
77555
+ import { LlmError as LlmError10 } from "@deepseek-ai/dsh-llm";
77535
77556
 
77536
77557
  // src/catalog/reading.ts
77537
77558
  function catalogReading(snapshot2, visibility, listingFailure, now) {
@@ -77612,7 +77633,7 @@ var OpencodeGoCatalogService = class extends TypertRemoteService {
77612
77633
  const reading = catalogReading(
77613
77634
  snapshot2,
77614
77635
  visibility,
77615
- failure === void 0 ? void 0 : failure instanceof LlmError9 || failure instanceof Error ? failure.message : String(failure)
77636
+ failure === void 0 ? void 0 : failure instanceof LlmError10 || failure instanceof Error ? failure.message : String(failure)
77616
77637
  );
77617
77638
  this.reportUnadvertised(snapshot2, visibility);
77618
77639
  return reading;
@@ -78074,7 +78095,7 @@ function createUpdateChecker(deps) {
78074
78095
  }
78075
78096
 
78076
78097
  // src/update/version.ts
78077
- var PLUGIN_VERSION = true ? "0.1.74" : "0.0.0-dev";
78098
+ var PLUGIN_VERSION = true ? "0.1.76" : "0.0.0-dev";
78078
78099
 
78079
78100
  // src/update/service.ts
78080
78101
  import { TypertRemoteService as TypertRemoteService4 } from "@deepseek-ai/dsh-typert-protocol";
@@ -78103,7 +78124,7 @@ var OpencodeGoUpdateService = class extends TypertRemoteService4 {
78103
78124
  };
78104
78125
 
78105
78126
  // src/usage/windows.ts
78106
- import { attributionHeaders as attributionHeaders6, LlmError as LlmError10 } from "@deepseek-ai/dsh-llm";
78127
+ import { attributionHeaders as attributionHeaders6, LlmError as LlmError11 } from "@deepseek-ai/dsh-llm";
78107
78128
  var USAGE_MAX_BYTES = 1024 * 1024;
78108
78129
  var USAGE_TIMEOUT_MS = 1e4;
78109
78130
  function parseGoUsage(value) {
@@ -78121,7 +78142,7 @@ function parseGoUsage(value) {
78121
78142
  }
78122
78143
  async function readUsageWindows(options) {
78123
78144
  if (options.apiKey === void 0 || options.apiKey.length === 0) {
78124
- throw new LlmError10("dshopencodego: no credential is configured for the opencode-go route", "USAGE_UNAVAILABLE");
78145
+ throw new LlmError11("dshopencodego: no credential is configured for the opencode-go route", "USAGE_UNAVAILABLE");
78125
78146
  }
78126
78147
  const url = `${options.baseURL.replace(/\/+$/, "")}/usage`;
78127
78148
  const timeout = AbortSignal.timeout(USAGE_TIMEOUT_MS);
@@ -78138,12 +78159,12 @@ async function readUsageWindows(options) {
78138
78159
  signal: options.signal === void 0 ? timeout : AbortSignal.any([options.signal, timeout])
78139
78160
  });
78140
78161
  } catch (error) {
78141
- throw new LlmError10(`could not reach ${url}`, "USAGE_UNAVAILABLE", { cause: error });
78162
+ throw new LlmError11(`could not reach ${url}`, "USAGE_UNAVAILABLE", { cause: error });
78142
78163
  }
78143
78164
  if (!response.ok) {
78144
78165
  await response.body?.cancel().catch(() => {
78145
78166
  });
78146
- throw new LlmError10(`${url} answered HTTP ${response.status}`, "USAGE_UNAVAILABLE");
78167
+ throw new LlmError11(`${url} answered HTTP ${response.status}`, "USAGE_UNAVAILABLE");
78147
78168
  }
78148
78169
  const body = await readBoundedJson(response, url, USAGE_MAX_BYTES);
78149
78170
  try {
@@ -78152,16 +78173,16 @@ async function readUsageWindows(options) {
78152
78173
  ...options.source === void 0 ? {} : { source: options.source }
78153
78174
  };
78154
78175
  } catch (error) {
78155
- throw new LlmError10(`${url} returned an invalid usage document`, "USAGE_UNAVAILABLE", { cause: error });
78176
+ throw new LlmError11(`${url} returned an invalid usage document`, "USAGE_UNAVAILABLE", { cause: error });
78156
78177
  }
78157
78178
  }
78158
78179
 
78159
78180
  // src/usage/service.ts
78160
78181
  import { randomUUID as randomUUID3 } from "node:crypto";
78161
78182
  import { RemoteError as RemoteError2, TypertRemoteService as TypertRemoteService5 } from "@deepseek-ai/dsh-typert-protocol";
78162
- import { LlmError as LlmError11 } from "@deepseek-ai/dsh-llm";
78183
+ import { LlmError as LlmError12 } from "@deepseek-ai/dsh-llm";
78163
78184
  function usageFailure(error, source) {
78164
- const missing = error instanceof LlmError11 && error.code === "MISSING_CREDENTIAL";
78185
+ const missing = error instanceof LlmError12 && error.code === "MISSING_CREDENTIAL";
78165
78186
  return new RemoteError2(
78166
78187
  "dshopencodego/usage-unavailable",
78167
78188
  error instanceof Error ? error.message : "OpenCode Go usage is unavailable",
@@ -78188,7 +78209,7 @@ var OpencodeGoUsageService = class extends TypertRemoteService5 {
78188
78209
  }
78189
78210
  if (key === void 0 || key.length === 0) {
78190
78211
  this.identity = void 0;
78191
- throw usageFailure(new LlmError11("No OpenCode Go API key is configured", "MISSING_CREDENTIAL"), void 0);
78212
+ throw usageFailure(new LlmError12("No OpenCode Go API key is configured", "MISSING_CREDENTIAL"), void 0);
78192
78213
  }
78193
78214
  if (this.identity?.baseURL !== baseURL || this.identity.key !== key) {
78194
78215
  this.identity = { baseURL, key, source: randomUUID3() };
@@ -78237,7 +78258,7 @@ function apply(ctx, raw) {
78237
78258
  const credentials = ctx.get("credentials");
78238
78259
  const hit = credentials !== void 0 ? (await credentials.resolve(credentialRef(ref)))?.value : launchEnvironmentOf(ctx).get(ref)?.value;
78239
78260
  if (hit !== void 0 && hit.length > 0) return llm2.assertUsableApiKey(hit, name, ref);
78240
- throw new LlmError12(
78261
+ throw new LlmError13(
78241
78262
  `dshopencodego: no credential; the profile resolves ${ref}, which is not set \u2014 store ${ref} through the credentials service (the Web Models page writes it) or export it`,
78242
78263
  "MISSING_CREDENTIAL"
78243
78264
  );
@@ -78327,7 +78348,8 @@ function apply(ctx, raw) {
78327
78348
  };
78328
78349
  }, "dshopencodego: catalog warm-up");
78329
78350
  let registration;
78330
- let visibilityFacts = JSON.stringify(current2().modelVisibility);
78351
+ const registrationFacts = () => JSON.stringify({ visibility: current2().modelVisibility, retryPolicy: current2().retryPolicy ?? null });
78352
+ let registeredFacts = registrationFacts();
78331
78353
  const applyRoute = (credentialConfigured) => {
78332
78354
  const enabled = current2().enabled;
78333
78355
  if (enabled && credentialConfigured && registration === void 0) {
@@ -78348,9 +78370,9 @@ function apply(ctx, raw) {
78348
78370
  };
78349
78371
  const syncRoute = () => {
78350
78372
  try {
78351
- const visibility = JSON.stringify(current2().modelVisibility);
78352
- if (visibility !== visibilityFacts) {
78353
- visibilityFacts = visibility;
78373
+ const facts = registrationFacts();
78374
+ if (facts !== registeredFacts) {
78375
+ registeredFacts = facts;
78354
78376
  registration?.replace([PROVIDER_ID]);
78355
78377
  }
78356
78378
  const credentials = ctx.get("credentials");
@@ -78375,7 +78397,7 @@ function apply(ctx, raw) {
78375
78397
  settingsNs,
78376
78398
  async (request, signal) => {
78377
78399
  if (request.provider !== PROVIDER_ID && !(request.baseURL ?? "").includes("opencode.ai")) {
78378
- throw new LlmError12(
78400
+ throw new LlmError13(
78379
78401
  "dshopencodego discovers only OpenCode Go/Console endpoints; enter this provider's models by hand",
78380
78402
  "DISCOVERY_UNSUPPORTED"
78381
78403
  );
@@ -78416,6 +78438,7 @@ export {
78416
78438
  SESSION_HEADER,
78417
78439
  apply,
78418
78440
  assertBaseURL,
78441
+ assertStreamIdleTimeoutMs,
78419
78442
  discoverCatalogModels,
78420
78443
  fetchModelIds,
78421
78444
  inject,
@@ -121,6 +121,20 @@ export type LiveConfig = {
121
121
  };
122
122
  /** Runtime schema for {@link OpencodeGoConfig}; every field stays live. */
123
123
  export declare const Config: z<Partial<OpencodeGoConfig>, LiveConfig>;
124
+ /**
125
+ * Validate one request-time idle timeout the schema let through.
126
+ *
127
+ * The schema bounds the persisted profile, but a live reference hands back
128
+ * whatever it holds (and a programmatic mount hands back whatever it returns):
129
+ * `NaN` passes `z.number()`, and a non-positive or overflowing value would
130
+ * otherwise reach `idleWatchdog` mid-request — after the credential was read —
131
+ * as a bare `Error` from its own assertion. Failing here fails before any
132
+ * credential read or network wait, with the route's own message instead of
133
+ * the timer's. Mirrors the resolve-time guard `llm-pi-ai` applies to the same
134
+ * field (`llm-pi-ai/src/config.ts`, "must be a positive finite number").
135
+ * @param value - the configured idle timeout in milliseconds.
136
+ */
137
+ export declare function assertStreamIdleTimeoutMs(value: unknown): asserts value is number;
124
138
  /**
125
139
  * Keep the Loader's references: reparsing them would detach live updates.
126
140
  *
@@ -36,7 +36,7 @@ declare module '@deepseek-ai/cordis' {
36
36
  export { OpencodeGoAdapter } from './adapter.ts';
37
37
  export type { OpencodeGoAdapterOptions, OpencodeGoImageAccess } from './adapter.ts';
38
38
  export { DEFAULT_BASE_URL, CONSOLE_BASE_URL, DISPLAY_NAME, PROVIDER_ID, OpencodeGoCatalog, discoverCatalogModels, fetchModelIds } from './catalog/index.ts';
39
- export { Config, PlainConfig, assertBaseURL, DEFAULT_API_KEY_ENV } from './config.ts';
39
+ export { Config, PlainConfig, assertBaseURL, assertStreamIdleTimeoutMs, DEFAULT_API_KEY_ENV } from './config.ts';
40
40
  export type { OpencodeGoConfig } from './config.ts';
41
41
  export { SESSION_HEADER, SESSION_AFFINITY_HEADER, opencodeSessionValue, providerHeaders } from './session-header.ts';
42
42
  export { isModelEnabled, sortModels } from './models.ts';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dan-ai-studio/dshopencodego",
3
- "version": "0.1.74",
3
+ "version": "0.1.76",
4
4
  "description": "OpenCode Go provider for DeepSeek Harness: live gateway catalog, per-conversation session header, usage",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -123,30 +123,30 @@
123
123
  },
124
124
  "devDependencies": {
125
125
  "@deepseek-ai/cordis": "4.0.5",
126
- "@deepseek-ai/dsh-api-remotes": "0.2.1-rc.2",
127
- "@deepseek-ai/dsh-attachment": "0.2.1-rc.2",
128
- "@deepseek-ai/dsh-brand": "0.2.1-rc.2",
129
- "@deepseek-ai/dsh-client-locale": "0.2.1-rc.2",
130
- "@deepseek-ai/dsh-client-store": "0.2.1-rc.2",
131
- "@deepseek-ai/dsh-client-ui-conversation": "0.2.1-rc.2",
132
- "@deepseek-ai/dsh-client-ui-layout": "0.2.1-rc.2",
133
- "@deepseek-ai/dsh-client-ui-model-selection": "0.2.1-rc.2",
134
- "@deepseek-ai/dsh-client-ui-primitives": "0.2.1-rc.2",
135
- "@deepseek-ai/dsh-client-ui-renderer": "0.2.1-rc.2",
136
- "@deepseek-ai/dsh-client-ui-settings": "0.2.1-rc.2",
137
- "@deepseek-ai/dsh-client-ui-sidebar": "0.2.1-rc.2",
138
- "@deepseek-ai/dsh-client-ui-slots": "0.2.1-rc.2",
139
- "@deepseek-ai/dsh-credentials": "0.2.1-rc.2",
140
- "@deepseek-ai/dsh-fs": "0.2.1-rc.2",
141
- "@deepseek-ai/dsh-launch-environment": "0.2.1-rc.2",
142
- "@deepseek-ai/dsh-llm": "0.2.1-rc.2",
143
- "@deepseek-ai/dsh-sandbox": "0.2.1-rc.2",
144
- "@deepseek-ai/dsh-scope": "0.2.1-rc.2",
145
- "@deepseek-ai/dsh-session": "0.2.1-rc.2",
146
- "@deepseek-ai/dsh-settings": "0.2.1-rc.2",
147
- "@deepseek-ai/dsh-timeout": "0.2.1-rc.2",
148
- "@deepseek-ai/dsh-typert-protocol": "0.2.1-rc.2",
149
- "@deepseek-ai/dsh-typert-registry": "0.2.1-rc.2",
126
+ "@deepseek-ai/dsh-api-remotes": "0.2.1-rc.4",
127
+ "@deepseek-ai/dsh-attachment": "0.2.1-rc.4",
128
+ "@deepseek-ai/dsh-brand": "0.2.1-rc.4",
129
+ "@deepseek-ai/dsh-client-locale": "0.2.1-rc.4",
130
+ "@deepseek-ai/dsh-client-store": "0.2.1-rc.4",
131
+ "@deepseek-ai/dsh-client-ui-conversation": "0.2.1-rc.4",
132
+ "@deepseek-ai/dsh-client-ui-layout": "0.2.1-rc.4",
133
+ "@deepseek-ai/dsh-client-ui-model-selection": "0.2.1-rc.4",
134
+ "@deepseek-ai/dsh-client-ui-primitives": "0.2.1-rc.4",
135
+ "@deepseek-ai/dsh-client-ui-renderer": "0.2.1-rc.4",
136
+ "@deepseek-ai/dsh-client-ui-settings": "0.2.1-rc.4",
137
+ "@deepseek-ai/dsh-client-ui-sidebar": "0.2.1-rc.4",
138
+ "@deepseek-ai/dsh-client-ui-slots": "0.2.1-rc.4",
139
+ "@deepseek-ai/dsh-credentials": "0.2.1-rc.4",
140
+ "@deepseek-ai/dsh-fs": "0.2.1-rc.4",
141
+ "@deepseek-ai/dsh-launch-environment": "0.2.1-rc.4",
142
+ "@deepseek-ai/dsh-llm": "0.2.1-rc.4",
143
+ "@deepseek-ai/dsh-sandbox": "0.2.1-rc.4",
144
+ "@deepseek-ai/dsh-scope": "0.2.1-rc.4",
145
+ "@deepseek-ai/dsh-session": "0.2.1-rc.4",
146
+ "@deepseek-ai/dsh-settings": "0.2.1-rc.4",
147
+ "@deepseek-ai/dsh-timeout": "0.2.1-rc.4",
148
+ "@deepseek-ai/dsh-typert-protocol": "0.2.1-rc.4",
149
+ "@deepseek-ai/dsh-typert-registry": "0.2.1-rc.4",
150
150
  "@deepseek-ai/schemastery": "~3.18.5-alpha.2",
151
151
  "@earendil-works/pi-ai": "~1.4.0",
152
152
  "@testing-library/dom": "^10.4.1",