@aggc/or-info 0.2.9 → 0.2.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.
package/bin/or-info.mjs CHANGED
@@ -108,7 +108,7 @@ program
108
108
 
109
109
  if (opts.json) {
110
110
  console.log(JSON.stringify({
111
- model: model.id,
111
+ id: model.id,
112
112
  pricing: model.pricing,
113
113
  context_length: contextLength(model),
114
114
  }, null, 2));
@@ -100,7 +100,17 @@ export function supportsFeature(model, feature) {
100
100
  const featureMap = {
101
101
  reasoning: ['include_reasoning', 'reasoning'],
102
102
  tools: ['tools', 'tool_choice'],
103
- vision: () => (model?.architecture?.input_modalities ?? []).includes('image'),
103
+ vision: () => {
104
+ // Prefer the canonical modality string (e.g. "text+image->text") because
105
+ // input_modalities is inconsistently populated by OpenRouter providers.
106
+ const modality = model?.architecture?.modality ?? '';
107
+ if (modality) {
108
+ return modality.split('->')[0].split('+').map((s) => s.trim()).includes('image');
109
+ }
110
+ const inputMods = model?.architecture?.input_modalities;
111
+ if (Array.isArray(inputMods)) return inputMods.includes('image');
112
+ return false;
113
+ },
104
114
  structured: ['structured_outputs'],
105
115
  };
106
116
  const check = featureMap[feature];
package/mcp/server.mjs CHANGED
@@ -347,20 +347,45 @@ function wireHandlers(server) {
347
347
  }
348
348
 
349
349
  export async function startMcp() {
350
+ // Track in-flight tool calls so we don't exit while a response is still being written.
351
+ // Race condition: stdin EOF fires before the async handleTool completes, causing
352
+ // process.exit(0) to kill the process before the MCP SDK writes the response to stdout.
353
+ let pending = 0;
354
+ let stdinEnded = false;
355
+ let resolveWhenDone;
356
+ const donePromise = new Promise((res) => { resolveWhenDone = res; });
357
+
358
+ function checkDone() {
359
+ if (stdinEnded && pending === 0) resolveWhenDone();
360
+ }
361
+
350
362
  const server = makeServer();
351
- wireHandlers(server);
363
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
364
+ server.setRequestHandler(CallToolRequestSchema, async (req) => {
365
+ const { name, arguments: args } = req.params;
366
+ pending++;
367
+ try {
368
+ return await handleTool(name, args ?? {});
369
+ } catch (err) {
370
+ const safe = err.message?.replace(/sk-[a-zA-Z0-9-]+/g, '[REDACTED]') ?? 'Unexpected error';
371
+ return errorContent(safe);
372
+ } finally {
373
+ pending--;
374
+ // Defer checkDone by one tick so the SDK's response-write microtask runs first.
375
+ setImmediate(checkDone);
376
+ }
377
+ });
352
378
 
353
379
  const transport = new StdioServerTransport();
354
380
  await server.connect(transport);
355
381
 
356
- // server.connect() returns immediately after wiring up the transport.
357
- // Block here until stdin closes so the process stays alive while serving.
358
382
  if (!process.stdin.destroyed) {
359
- await new Promise((resolve) => {
360
- process.stdin.once('close', resolve);
361
- process.stdin.once('end', resolve);
362
- });
383
+ process.stdin.once('close', () => { stdinEnded = true; checkDone(); });
384
+ process.stdin.once('end', () => { stdinEnded = true; checkDone(); });
385
+ await donePromise;
363
386
  }
387
+ // One extra tick for any buffered stdout writes before the caller calls process.exit().
388
+ await new Promise((resolve) => setImmediate(resolve));
364
389
  }
365
390
 
366
391
  export async function startHttpMcp() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aggc/or-info",
3
- "version": "0.2.9",
3
+ "version": "0.2.10",
4
4
  "description": "CLI + MCP server for OpenRouter models: prices, benchmarks, context and comparisons",
5
5
  "type": "module",
6
6
  "engines": {