@aggc/or-info 0.2.15 → 0.2.17
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/bin/or-info.mjs +1 -1
- package/lib/formatter.mjs +14 -1
- package/lib/openrouter.mjs +7 -2
- package/mcp/server.mjs +2 -2
- package/package.json +1 -1
package/bin/or-info.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import { InvalidArgumentError, program } from 'commander';
|
|
|
4
4
|
import chalk from 'chalk';
|
|
5
5
|
|
|
6
6
|
const { version } = createRequire(import.meta.url)('../package.json');
|
|
7
|
-
import { fetchModels, findModel, pricePerMillion, contextLength } from '../lib/openrouter.mjs';
|
|
7
|
+
import { fetchModels, findModel, pricePerMillion, contextLength, isFree } from '../lib/openrouter.mjs';
|
|
8
8
|
import { getElo, getAllElo, loadLeaderboard } from '../lib/lmarena.mjs';
|
|
9
9
|
import { rankModels } from '../lib/scorer.mjs';
|
|
10
10
|
import { clearAll, status } from '../lib/cache.mjs';
|
package/lib/formatter.mjs
CHANGED
|
@@ -18,6 +18,15 @@ function fmtPrice(n) {
|
|
|
18
18
|
return RED(`$${n.toFixed(4)}`);
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
function maybeFreeWarning(model, price) {
|
|
22
|
+
// OpenRouter sometimes reports pricing="0" for non-free models (e.g. z-ai/glm-5.1).
|
|
23
|
+
// Show a warning so users don't get surprised by charges.
|
|
24
|
+
if (price.input === 0 && price.output === 0 && !model?.id?.endsWith(':free') && model?.id !== 'openrouter/free') {
|
|
25
|
+
return YELLOW(' ⚠ reported free — may incur charges on OpenRouter');
|
|
26
|
+
}
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
|
|
21
30
|
function fmtCtx(n) {
|
|
22
31
|
if (!n) return DIM('n/a');
|
|
23
32
|
if (n >= 1_000_000) return CYAN(`${(n / 1_000_000).toFixed(1)}M`);
|
|
@@ -46,8 +55,9 @@ export function modelTable(models, { showTags = false } = {}) {
|
|
|
46
55
|
const price = pricePerMillion(m);
|
|
47
56
|
const ctx = contextLength(m);
|
|
48
57
|
const tags = showTags ? modelTags(m) : [];
|
|
58
|
+
const idLabel = maybeFreeWarning(m, price) ? m.id + YELLOW(' ⚠') : m.id;
|
|
49
59
|
return {
|
|
50
|
-
id:
|
|
60
|
+
id: idLabel,
|
|
51
61
|
name: m.name ?? m.id,
|
|
52
62
|
input: fmtPrice(price.input),
|
|
53
63
|
output: fmtPrice(price.output),
|
|
@@ -95,6 +105,9 @@ export function modelDetail(model, bench = null) {
|
|
|
95
105
|
` Output ${fmtPrice(price.output)} per 1M tokens`,
|
|
96
106
|
];
|
|
97
107
|
|
|
108
|
+
const freeWarn = maybeFreeWarning(model, price);
|
|
109
|
+
if (freeWarn) lines.push(freeWarn);
|
|
110
|
+
|
|
98
111
|
if (price.image !== null) lines.push(` Image ${fmtPrice(price.image)} per 1M tokens`);
|
|
99
112
|
if (price.cacheRead !== null) lines.push(` Cache↓ ${fmtPrice(price.cacheRead)} per 1M tokens`);
|
|
100
113
|
if (price.cacheWrite !== null) lines.push(` Cache↑ ${fmtPrice(price.cacheWrite)} per 1M tokens`);
|
package/lib/openrouter.mjs
CHANGED
|
@@ -135,6 +135,11 @@ export function modelTags(model) {
|
|
|
135
135
|
}
|
|
136
136
|
|
|
137
137
|
export function isFree(model) {
|
|
138
|
-
|
|
139
|
-
|
|
138
|
+
// A model is genuinely free only if it carries the :free suffix
|
|
139
|
+
// or is a known free-tier model. OpenRouter sometimes reports
|
|
140
|
+
// pricing.prompt="0" & pricing.completion="0" for models that are NOT free
|
|
141
|
+
// (e.g. z-ai/glm-5.1) — a known API inconsistency.
|
|
142
|
+
if (model?.id?.endsWith(':free')) return true;
|
|
143
|
+
if (model?.id === 'openrouter/free') return true;
|
|
144
|
+
return false;
|
|
140
145
|
}
|
package/mcp/server.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
|
3
3
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
4
|
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
5
5
|
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
6
|
-
import { fetchModels, findModel, pricePerMillion, contextLength, modelTags } from '../lib/openrouter.mjs';
|
|
6
|
+
import { fetchModels, findModel, pricePerMillion, contextLength, modelTags, isFree } from '../lib/openrouter.mjs';
|
|
7
7
|
import { getElo, getAllElo, loadLeaderboard } from '../lib/lmarena.mjs';
|
|
8
8
|
import { rankModels } from '../lib/scorer.mjs';
|
|
9
9
|
import { getApiKey } from '../lib/secrets.mjs';
|
|
@@ -294,7 +294,7 @@ async function handleTool(name, args) {
|
|
|
294
294
|
|
|
295
295
|
let models = await fetchModels({ apiKey: key });
|
|
296
296
|
if (filter) models = models.filter((m) => m.id.toLowerCase().includes(filter) || (m.name ?? '').toLowerCase().includes(filter));
|
|
297
|
-
if (freeOnly) models = models.filter(
|
|
297
|
+
if (freeOnly) models = models.filter(isFree);
|
|
298
298
|
|
|
299
299
|
if (sortBy === 'price') models.sort((a, b) => (pricePerMillion(a).output ?? Infinity) - (pricePerMillion(b).output ?? Infinity));
|
|
300
300
|
else if (sortBy === 'context') models.sort((a, b) => (contextLength(b) ?? 0) - (contextLength(a) ?? 0));
|