pi-multimodal-proxy 1.18.0 → 1.18.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 CHANGED
@@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
6
 
7
+ ## [1.18.1] - 2026-08-30
8
+
9
+ ### Fixed (post-release review of 1.18.0)
10
+
11
+ - **The stage-2 syntax gate was a silent no-op on Windows.** `tools/check-syntax.mjs` compared `walk()` paths (backslash separators) against TypeScript-normalized source-file names (forward slashes), so the `has()` filter dropped every diagnostic — a planted `await`-in-non-async probe passed the gate. Both sides are now normalized; the planted-probe test fails the gate as intended. (Linux CI paths happened to match, so releases were still protected — local/dev Windows runs were not.)
12
+ - **Default-substitution notice no longer fires when the proxy is `off`** — model resolution is irrelevant with media analysis disabled.
13
+ - **The substitution hint is now cause-aware**: when the substituted-from model is missing from the catalog the notice suggests updating pi / pinning a model, instead of the (wrong) `pi --login` key hint that only fits the no-API-key case.
14
+ - **`writePersisted`'s fire-and-forget status refresh gained a `.catch`** — a rejected key probe can no longer surface as an unhandled promise rejection in daemon processes.
15
+ - **`withModelFallback` skips the 5 async key probes for explicit configs** (`PI_VISION_PROXY_MODEL` or persisted `modelExplicit`), where resolution is a no-op by definition.
16
+
7
17
  ## [1.18.0] - 2026-08-30
8
18
 
9
19
  ### Added
@@ -667,9 +667,10 @@ function shouldStripImages(config: VisionConfig, model: ExtensionContext["model"
667
667
  * this runs on every prompt, tool result, and status refresh.
668
668
  */
669
669
  async function withModelFallback(config: VisionConfig, ctx: ExtensionContext): Promise<VisionConfig> {
670
- const hasModel = (p: string, m: string) => Boolean(ctx.modelRegistry.find(p, m));
671
- if (envFlags().model) return applyDefaultModelFallback(config, hasModel, true);
670
+ // Explicit choices are never rewritten skip the key probes entirely.
671
+ if (envFlags().model || config.modelExplicit === true) return config;
672
672
 
673
+ const hasModel = (p: string, m: string) => Boolean(ctx.modelRegistry.find(p, m));
673
674
  const state = getSessionState(ctx);
674
675
  state.keyProbe ??= new Map<string, boolean>();
675
676
  const probe = async (p: string, m: string): Promise<boolean> => {
@@ -708,6 +709,8 @@ async function withModelFallback(config: VisionConfig, ctx: ExtensionContext): P
708
709
  * configured model — e.g. no zai key → deepseek/deepseek-v4-flash-vision-exp.
709
710
  */
710
711
  function notifyDefaultSubstitution(config: VisionConfig, resolved: VisionConfig, ctx: ExtensionContext): void {
712
+ // Proxy disabled — model resolution is irrelevant, don't add noise.
713
+ if (resolved.mode === "off") return;
711
714
  const state = getSessionState(ctx);
712
715
  const before = `${config.provider}/${config.modelId}`;
713
716
  const after = `${resolved.provider}/${resolved.modelId}`;
@@ -715,11 +718,11 @@ function notifyDefaultSubstitution(config: VisionConfig, resolved: VisionConfig,
715
718
  const key = `${before}→${after}`;
716
719
  if (state.notifiedDefaultSub === key) return;
717
720
  state.notifiedDefaultSub = key;
718
- ctx.ui.notify(
719
- `[multimodal-proxy] Vision default resolved to ${after} (${before} not usable here). ` +
720
- `Pin a model with /multimodal-proxy model, or add a key: pi --login ${config.provider}`,
721
- "info",
722
- );
721
+ const missingFromCatalog = !ctx.modelRegistry.find(config.provider, config.modelId);
722
+ const hint = missingFromCatalog
723
+ ? "update pi (older model catalog), or pin a model with /multimodal-proxy model"
724
+ : `add a key: pi --login ${config.provider} — or pin a model with /multimodal-proxy model`;
725
+ ctx.ui.notify(`[multimodal-proxy] Vision default resolved to ${after} (${before} not usable here). ${hint}`, "info");
723
726
  }
724
727
 
725
728
  // ── Content sniffing (Pi ≥ 0.84.4) ───────────────────────────────────────
@@ -2814,9 +2817,13 @@ export default function (pi: ExtensionAPI) {
2814
2817
  const eff = resolveConfig(ctx.sessionManager.getEntries(), process.env, _fileConfig);
2815
2818
  // Fire-and-forget: writePersisted stays synchronous for its ~30 call
2816
2819
  // sites; the status refresh just needs the resolved model eventually.
2817
- void withModelFallback(eff, ctx).then((resolved) =>
2820
+ void withModelFallback(eff, ctx)
2821
+ .then((resolved) =>
2818
2822
  ctx.ui.setStatus("multimodal-proxy", steadyStatusText(resolved, ctx.modelRegistry)),
2819
- );
2823
+ )
2824
+ .catch(() => {
2825
+ // Key probing must never surface as an unhandled rejection in daemons.
2826
+ });
2820
2827
  return validated;
2821
2828
  };
2822
2829
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-multimodal-proxy",
3
- "version": "1.18.0",
3
+ "version": "1.18.1",
4
4
  "description": "Automatic image, video and audio description for any model in Pi. Routes media to a multimodal model and injects descriptions into context.",
5
5
  "keywords": [
6
6
  "pi-package"