@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 +1 -1
- package/lib/openrouter.mjs +11 -1
- package/mcp/server.mjs +32 -7
- package/package.json +1 -1
package/bin/or-info.mjs
CHANGED
package/lib/openrouter.mjs
CHANGED
|
@@ -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: () =>
|
|
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
|
-
|
|
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
|
-
|
|
360
|
-
|
|
361
|
-
|
|
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() {
|