Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
- **fix(translator): inject a placeholder message when the Responses API `input[]` is empty** — a `POST /v1/responses` with `input: []` translated to `messages: []`, which every upstream Chat-Completions provider rejects (surfaced as a confusing 406); a single placeholder user message is now injected, mirroring the existing empty-string handling. ([#4393](https://github.com/diegosouzapw/OmniRoute/pull/4393) — thanks @diegosouzapw)
- **fix(providers): serve the api.airforce live `/models` catalog instead of the stale seed** — the api.airforce provider listed a stale hard-coded seed; it now serves the upstream live `/models` catalog. ([#4395](https://github.com/diegosouzapw/OmniRoute/pull/4395) — thanks @diegosouzapw)
- **fix(cli): non-interactive-safe prompts + `context` alias** — the CLI's `confirm()`/prompt helpers no longer hang in non-interactive (piped/CI) contexts, and a singular `context` alias is accepted alongside `contexts`; the contexts workflow is documented. ([#4439](https://github.com/diegosouzapw/OmniRoute/pull/4439), [#4397](https://github.com/diegosouzapw/OmniRoute/pull/4397) — thanks @diegosouzapw)
- **fix(cli): `omniroute update` no longer reports a stale "latest" version from npm's cache** — `getLatestVersion()` ran `npm view omniroute version` without `--prefer-online`, so npm could serve a cached value from its HTTP cache and tell users on an older build (e.g. 3.8.30) they were already "running the latest version" even after a newer one (3.8.31) was published. The version check now passes `--prefer-online` to force npm to revalidate against the registry. ([#4376](https://github.com/diegosouzapw/OmniRoute/issues/4376) — thanks @akbardwi)
- **fix(sse): `web_search_20250305` no longer 400s on MiniMax's Anthropic-compatible endpoint** — PR #2960 added a Claude→Claude bypass that forwards Anthropic's typed server tool `web_search_20250305` untouched, assuming the Claude-format upstream implements Anthropic server tools. MiniMax's `/anthropic` endpoint does not, so `claude → minimax` requests carrying that tool got `HTTP 400 "invalid params, function name or parameters is empty (2013)"`. `supportsNativeWebSearchFallbackBypass` now consults the (already-plumbed) `provider` and excludes providers known not to implement server tools (currently `minimax`) from the bypass, so the built-in web-search tool is converted to the `omniroute_web_search` function fallback — which MiniMax accepts as a normal function tool. ([#4481](https://github.com/diegosouzapw/OmniRoute/issues/4481) — thanks @shafqatevo)

### 🔒 Security
Expand Down
8 changes: 6 additions & 2 deletions bin/cli/commands/update.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,13 @@ export async function getCurrentVersion() {
}
}

async function getLatestVersion() {
// `--prefer-online` forces npm to revalidate its HTTP cache against the registry.
// Without it `npm view` can return a stale cached version (e.g. report 3.8.30 as
// "latest" after 3.8.31 was published), so the updater told users on an old build
// they were already on the latest version (#4376). `execFn` is injectable for tests.
export async function getLatestVersion(execFn = execFileAsync) {
try {
const { stdout } = await execFileAsync("npm", ["view", "omniroute", "version"], {
const { stdout } = await execFn("npm", ["view", "omniroute", "version", "--prefer-online"], {
timeout: 15000,
});
return stdout.trim();
Expand Down
36 changes: 36 additions & 0 deletions tests/unit/cli-update-prefer-online-4376.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import test from "node:test";
import assert from "node:assert/strict";

const update = await import("../../bin/cli/commands/update.mjs");

// #4376: `omniroute update` reported "Latest version: 3.8.30" while npm's `latest`
// dist-tag was already 3.8.31, so it told users on an old build they were "running
// the latest version". Root cause: getLatestVersion() ran `npm view omniroute version`
// without `--prefer-online`, so npm served a stale value from its HTTP cache.
// The fix forces npm to revalidate the cache against the registry.
test("getLatestVersion passes --prefer-online to bypass the stale npm cache (#4376)", async () => {
let capturedArgs = null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Under strict TypeScript configuration (strictNullChecks: true), initializing capturedArgs to null without an explicit type annotation infers its type as null. This will cause a compilation error when assigning an object to it on line 14. Specifying an explicit union type resolves this issue.

  let capturedArgs: { cmd: string; args: string[] } | null = null;

const fakeExec = async (cmd: string, args: string[]) => {
capturedArgs = { cmd, args };
return { stdout: "3.8.31\n" };
};
const latest = await update.getLatestVersion(fakeExec);
assert.equal(latest, "3.8.31");
assert.ok(capturedArgs, "exec must be invoked");
assert.equal(capturedArgs.cmd, "npm");
assert.ok(
capturedArgs.args.includes("--prefer-online"),
`expected --prefer-online in npm args, got: ${JSON.stringify(capturedArgs.args)}`
);
// still the right query
assert.ok(capturedArgs.args.includes("view"));
assert.ok(capturedArgs.args.includes("omniroute"));
assert.ok(capturedArgs.args.includes("version"));
});

test("getLatestVersion returns null when npm is unavailable (#4376)", async () => {
const latest = await update.getLatestVersion(async () => {
throw new Error("npm not found");
});
assert.equal(latest, null);
});
Loading