@mcowger/opencode-plexus 1.3.9 → 1.3.10

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.
Files changed (2) hide show
  1. package/dist/index.js +26 -11
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -120,22 +120,28 @@ function isChatModel(model) {
120
120
  return !NON_CHAT_PATTERN.test(`${model.id} ${model.name ?? ""} ${apiHints}`);
121
121
  }
122
122
  var DEFAULT_MODELS_FETCH_TIMEOUT_MS = 1e4;
123
- async function fetchPlexusModels(apiKey, modelsUrl, timeoutMs = DEFAULT_MODELS_FETCH_TIMEOUT_MS) {
123
+ async function fetchPlexusModels(apiKey, modelsUrl, timeoutMs = DEFAULT_MODELS_FETCH_TIMEOUT_MS, etag) {
124
124
  const controller = new AbortController;
125
125
  const timer = setTimeout(() => controller.abort(), timeoutMs);
126
126
  try {
127
127
  const headers = { Accept: "application/json" };
128
128
  if (apiKey)
129
129
  headers.Authorization = `Bearer ${apiKey}`;
130
+ if (etag)
131
+ headers["If-None-Match"] = etag;
130
132
  const res = await fetch(modelsUrl, {
131
133
  headers,
132
134
  signal: controller.signal
133
135
  });
136
+ if (res.status === 304) {
137
+ return { models: [], notModified: true };
138
+ }
134
139
  if (!res.ok) {
135
140
  throw new Error(`Plexus models fetch failed: ${res.status} ${res.statusText}`);
136
141
  }
137
142
  const raw = await res.json();
138
- return { models: raw.data ?? [], raw };
143
+ const responseEtag = res.headers.get("etag") ?? undefined;
144
+ return { models: raw.data ?? [], raw, etag: responseEtag };
139
145
  } catch (err) {
140
146
  if (err instanceof Error && err.name === "AbortError") {
141
147
  throw new Error(`Plexus models fetch timed out after ${timeoutMs}ms`);
@@ -178,18 +184,21 @@ async function readCachedModels(_client, suppress) {
178
184
  const content = await readFile(join(dir, CACHE_FILE), "utf8");
179
185
  const parsed = JSON.parse(content);
180
186
  if (parsed && typeof parsed.models === "object" && !Array.isArray(parsed.models)) {
181
- return filterCachedModels(parsed.models, suppress);
187
+ return {
188
+ models: filterCachedModels(parsed.models, suppress),
189
+ etag: typeof parsed.etag === "string" ? parsed.etag : undefined
190
+ };
182
191
  }
183
192
  return null;
184
193
  } catch {
185
194
  return null;
186
195
  }
187
196
  }
188
- async function writeCache(_client, models, raw) {
197
+ async function writeCache(_client, models, raw, etag) {
189
198
  try {
190
199
  const dir = getDir();
191
200
  await mkdir(dir, { recursive: true });
192
- const cache = { models, timestamp: Date.now() };
201
+ const cache = { models, timestamp: Date.now(), etag };
193
202
  await writeFile(join(dir, CACHE_FILE), JSON.stringify(cache, null, 2) + `
194
203
  `, "utf8");
195
204
  if (raw !== undefined) {
@@ -581,7 +590,13 @@ function refreshModels(client, baseURL, log, apiKey, force = false, suppress) {
581
590
  return inFlightRefresh;
582
591
  const run = async () => {
583
592
  const url = modelsUrl(baseURL);
584
- const { models: apiModels, raw } = await fetchPlexusModels(apiKey ?? "", url);
593
+ const cached = await readCachedModels(client, suppress);
594
+ const { models: apiModels, raw, etag, notModified } = await fetchPlexusModels(apiKey ?? "", url, undefined, cached?.etag);
595
+ if (notModified && cached?.models) {
596
+ log.info(`Plexus models not modified (etag: ${cached.etag})`);
597
+ lastRefresh = { at: Date.now(), models: cached.models };
598
+ return cached.models;
599
+ }
585
600
  const built = buildModels(apiModels, apiBase(baseURL), suppress);
586
601
  for (const [id, model] of Object.entries(built)) {
587
602
  const providerNpm = model.provider?.npm ?? OPENAI_COMPATIBLE_NPM;
@@ -589,7 +604,7 @@ function refreshModels(client, baseURL, log, apiKey, force = false, suppress) {
589
604
  log.info(`Model mapping ${id}: npm=${providerNpm} api=${providerApi}`);
590
605
  }
591
606
  lastRefresh = { at: Date.now(), models: built };
592
- writeCache(client, built, raw).catch(() => {});
607
+ writeCache(client, built, raw, etag).catch(() => {});
593
608
  return built;
594
609
  };
595
610
  inFlightRefresh = run().finally(() => {
@@ -614,7 +629,7 @@ var PlexusProviderPlugin = async (ctx) => {
614
629
  }
615
630
  const cachedAsync = await readCachedModels(client, suppress);
616
631
  if (cachedAsync) {
617
- log.info(`Loaded plexus cache with ${Object.keys(cachedAsync).length} models`);
632
+ log.info(`Loaded plexus cache with ${Object.keys(cachedAsync.models).length} models`);
618
633
  }
619
634
  const effectiveExistingModels = existingModels ? filterCachedModels(existingModels, suppress) : null;
620
635
  const merged = {
@@ -626,7 +641,7 @@ var PlexusProviderPlugin = async (ctx) => {
626
641
  ...baseURL ? { [PLEXUS_BASE_URL_OPTION]: baseURL } : {},
627
642
  ...apiKey ? { apiKey } : {}
628
643
  },
629
- models: (effectiveExistingModels && Object.keys(effectiveExistingModels).length > 0 ? effectiveExistingModels : null) ?? (cachedAsync ? toConfigModels(cachedAsync) : null) ?? {
644
+ models: (effectiveExistingModels && Object.keys(effectiveExistingModels).length > 0 ? effectiveExistingModels : null) ?? (cachedAsync ? toConfigModels(cachedAsync.models) : null) ?? {
630
645
  [PLACEHOLDER_MODEL_ID]: {
631
646
  id: PLACEHOLDER_MODEL_ID,
632
647
  name: "Plexus (run /connect to configure)",
@@ -668,7 +683,7 @@ var PlexusProviderPlugin = async (ctx) => {
668
683
  if (!baseURL) {
669
684
  log.info("Provider hook skipped live refresh; baseURL missing");
670
685
  const cached2 = await readCachedModels(client, suppress);
671
- return cached2 ? toRuntimeModels(cached2, provider) : {};
686
+ return cached2 ? toRuntimeModels(cached2.models, provider) : {};
672
687
  }
673
688
  const refreshPromise = refreshModels(client, baseURL, log, key, false, suppress);
674
689
  const race = await raceWithTimeout(refreshPromise, CONFIG_HOOK_REFRESH_BUDGET_MS);
@@ -685,7 +700,7 @@ var PlexusProviderPlugin = async (ctx) => {
685
700
  log.warn(`Background plexus model refresh failed: ${String(e)}`);
686
701
  });
687
702
  }
688
- return cached ? toRuntimeModels(cached, provider) : {};
703
+ return cached ? toRuntimeModels(cached.models, provider) : {};
689
704
  }
690
705
  },
691
706
  "command.execute.before": async (input) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcowger/opencode-plexus",
3
- "version": "1.3.9",
3
+ "version": "1.3.10",
4
4
  "description": "OpenCode plugin: Plexus provider with dynamic model discovery",
5
5
  "type": "module",
6
6
  "module": "./dist/index.js",