@stabgan/openrouter-mcp-multimodal 4.7.0 → 5.0.0
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/README.md +95 -41
- package/dist/errors.d.ts +5 -20
- package/dist/errors.js +1 -10
- package/dist/index.js +8 -2
- package/dist/logger.js +54 -24
- package/dist/model-cache.d.ts +13 -0
- package/dist/model-cache.js +62 -8
- package/dist/openrouter-api.d.ts +14 -15
- package/dist/openrouter-api.js +68 -22
- package/dist/tool-definitions.d.ts +24 -0
- package/dist/tool-definitions.js +280 -177
- package/dist/tool-descriptions.d.ts +0 -4
- package/dist/tool-descriptions.js +30 -21
- package/dist/tool-handlers/analyze-audio.js +4 -1
- package/dist/tool-handlers/analyze-image.js +11 -6
- package/dist/tool-handlers/analyze-video.js +9 -5
- package/dist/tool-handlers/async-chat.d.ts +17 -0
- package/dist/tool-handlers/async-chat.js +104 -30
- package/dist/tool-handlers/audio-utils.d.ts +19 -4
- package/dist/tool-handlers/audio-utils.js +170 -16
- package/dist/tool-handlers/cache.d.ts +3 -3
- package/dist/tool-handlers/cache.js +56 -4
- package/dist/tool-handlers/chat-completion.js +16 -7
- package/dist/tool-handlers/chat-request.d.ts +4 -1
- package/dist/tool-handlers/chat-request.js +29 -1
- package/dist/tool-handlers/completion-utils.d.ts +5 -11
- package/dist/tool-handlers/completion-utils.js +76 -47
- package/dist/tool-handlers/fetch-utils.d.ts +14 -0
- package/dist/tool-handlers/fetch-utils.js +329 -77
- package/dist/tool-handlers/generate-audio.d.ts +4 -15
- package/dist/tool-handlers/generate-audio.js +21 -53
- package/dist/tool-handlers/generate-image-dedicated.d.ts +1 -1
- package/dist/tool-handlers/generate-image-dedicated.js +50 -31
- package/dist/tool-handlers/generate-image.d.ts +1 -1
- package/dist/tool-handlers/generate-image.js +19 -22
- package/dist/tool-handlers/generate-video.d.ts +4 -3
- package/dist/tool-handlers/generate-video.js +42 -18
- package/dist/tool-handlers/get-model-info.js +1 -1
- package/dist/tool-handlers/health-check.js +39 -15
- package/dist/tool-handlers/image-utils.js +2 -2
- package/dist/tool-handlers/openrouter-errors.d.ts +2 -0
- package/dist/tool-handlers/openrouter-errors.js +138 -31
- package/dist/tool-handlers/path-safety.js +49 -17
- package/dist/tool-handlers/path-utils.d.ts +2 -0
- package/dist/tool-handlers/path-utils.js +13 -0
- package/dist/tool-handlers/provider-routing.d.ts +2 -0
- package/dist/tool-handlers/provider-routing.js +11 -1
- package/dist/tool-handlers/rerank.d.ts +1 -4
- package/dist/tool-handlers/rerank.js +44 -15
- package/dist/tool-handlers/search-models.js +3 -3
- package/dist/tool-handlers/speech-to-text.d.ts +1 -0
- package/dist/tool-handlers/speech-to-text.js +23 -56
- package/dist/tool-handlers/text-to-speech.d.ts +1 -1
- package/dist/tool-handlers/text-to-speech.js +33 -20
- package/dist/tool-handlers/tool-result-payload.js +11 -9
- package/dist/tool-handlers/validate-model.js +1 -1
- package/dist/tool-handlers.d.ts +9 -0
- package/dist/tool-handlers.js +17 -5
- package/dist/tts-defaults.d.ts +4 -0
- package/dist/tts-defaults.js +4 -0
- package/dist/version.d.ts +3 -2
- package/dist/version.js +4 -2
- package/package.json +11 -13
package/dist/tool-definitions.js
CHANGED
|
@@ -1,8 +1,84 @@
|
|
|
1
|
-
import { TOOL_DESCRIPTIONS } from './tool-descriptions.js';
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { TOOL_DESCRIPTIONS, TOOL_NAMES } from './tool-descriptions.js';
|
|
2
|
+
import { DEFAULT_TTS_MODEL, DEFAULT_TTS_RESPONSE_FORMAT, DEFAULT_TTS_VOICE, } from './tts-defaults.js';
|
|
3
|
+
/** Aspect ratios accepted by generate_image and generate_image_dedicated handlers. */
|
|
4
|
+
export const IMAGE_ASPECT_RATIOS = [
|
|
5
|
+
'1:1',
|
|
6
|
+
'2:3',
|
|
7
|
+
'3:2',
|
|
8
|
+
'3:4',
|
|
9
|
+
'4:3',
|
|
10
|
+
'4:5',
|
|
11
|
+
'5:4',
|
|
12
|
+
'9:16',
|
|
13
|
+
'16:9',
|
|
14
|
+
'21:9',
|
|
15
|
+
'1:4',
|
|
16
|
+
'4:1',
|
|
17
|
+
'1:8',
|
|
18
|
+
'8:1',
|
|
19
|
+
];
|
|
20
|
+
export const IMAGE_SIZES = ['0.5K', '1K', '2K', '4K'];
|
|
21
|
+
export const IMAGE_DEDICATED_RESOLUTIONS = ['512', '0.5K', '1K', '2K', '4K'];
|
|
22
|
+
export const IMAGE_DEDICATED_QUALITIES = ['auto', 'low', 'medium', 'high'];
|
|
23
|
+
export const IMAGE_OUTPUT_FORMATS = ['png', 'jpeg', 'webp', 'svg'];
|
|
24
|
+
/** generate_audio handler VALID_FORMATS */
|
|
25
|
+
export const GENERATE_AUDIO_FORMATS = ['wav', 'mp3', 'flac', 'opus', 'pcm16'];
|
|
26
|
+
/** text_to_speech handler VALID_FORMATS */
|
|
27
|
+
export const TTS_RESPONSE_FORMATS = ['mp3', 'pcm'];
|
|
28
|
+
/** speech_to_text handler VALID_RESPONSE_FORMATS */
|
|
29
|
+
export const STT_RESPONSE_FORMATS = ['json', 'text', 'srt', 'verbose_json', 'vtt'];
|
|
30
|
+
export const CHAT_MESSAGE_ROLES = ['system', 'user', 'assistant'];
|
|
31
|
+
export const PROVIDER_SORT_VALUES = ['price', 'throughput', 'latency'];
|
|
32
|
+
export const PROVIDER_DATA_COLLECTION = ['allow', 'deny'];
|
|
33
|
+
/** Tools whose handlers accept save_path (binary artifact output). */
|
|
34
|
+
export const TOOLS_WITH_SAVE_PATH = [
|
|
35
|
+
'generate_image',
|
|
36
|
+
'generate_image_dedicated',
|
|
37
|
+
'generate_audio',
|
|
38
|
+
'text_to_speech',
|
|
39
|
+
'generate_video',
|
|
40
|
+
'generate_video_from_image',
|
|
41
|
+
'get_video_status',
|
|
42
|
+
];
|
|
43
|
+
/** Shared save_path fragment for binary-output tools. */
|
|
44
|
+
export const SAVE_PATH_PROPERTY = {
|
|
4
45
|
type: 'string',
|
|
5
|
-
description: 'Write the artifact under OPENROUTER_OUTPUT_DIR (path-sandboxed). When set, the tool result is text-only with _meta.save_path — no inline media block.
|
|
46
|
+
description: 'Write the artifact under OPENROUTER_OUTPUT_DIR (path-sandboxed). When set, the tool result is text-only with _meta.save_path — no inline media block. ' +
|
|
47
|
+
'When unset, inline image/audio (default 1 MiB) or video (default 10 MiB) is returned only if under the per-kind ceiling: ' +
|
|
48
|
+
'OPENROUTER_IMAGE_INLINE_MAX_BYTES, OPENROUTER_AUDIO_INLINE_MAX_BYTES, OPENROUTER_VIDEO_INLINE_MAX_BYTES ' +
|
|
49
|
+
'(global fallback OPENROUTER_INLINE_MAX_BYTES). See .env.example.',
|
|
50
|
+
};
|
|
51
|
+
const SAVE_PATH_WITH_PREFIX = (prefix) => ({
|
|
52
|
+
...SAVE_PATH_PROPERTY,
|
|
53
|
+
description: `${prefix} ${SAVE_PATH_PROPERTY.description}`,
|
|
54
|
+
});
|
|
55
|
+
const CHAT_MESSAGE_SCHEMA = {
|
|
56
|
+
type: 'array',
|
|
57
|
+
minItems: 1,
|
|
58
|
+
items: {
|
|
59
|
+
type: 'object',
|
|
60
|
+
properties: {
|
|
61
|
+
role: { type: 'string', enum: [...CHAT_MESSAGE_ROLES] },
|
|
62
|
+
content: {
|
|
63
|
+
oneOf: [{ type: 'string' }, { type: 'array', items: { type: 'object' } }],
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
required: ['role', 'content'],
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
const CACHE_PROPERTIES = {
|
|
70
|
+
cache: {
|
|
71
|
+
type: 'boolean',
|
|
72
|
+
description: 'Enable OpenRouter response caching via `X-OpenRouter-Cache: true`. Server default: `OPENROUTER_CACHE_RESPONSES=1`.',
|
|
73
|
+
},
|
|
74
|
+
cache_ttl: {
|
|
75
|
+
type: 'string',
|
|
76
|
+
description: 'Cache TTL as integer seconds (1–86400) or a duration string such as "30s", "5m", or "1h". Sent upstream as seconds.',
|
|
77
|
+
},
|
|
78
|
+
cache_clear: {
|
|
79
|
+
type: 'boolean',
|
|
80
|
+
description: 'Bust the cache entry for this exact request.',
|
|
81
|
+
},
|
|
6
82
|
};
|
|
7
83
|
export const TOOL_DEFINITIONS = [
|
|
8
84
|
{
|
|
@@ -20,26 +96,10 @@ export const TOOL_DEFINITIONS = [
|
|
|
20
96
|
properties: {
|
|
21
97
|
model: {
|
|
22
98
|
type: 'string',
|
|
23
|
-
description: 'Model ID (optional, uses default). Append `:nitro`
|
|
24
|
-
'`:floor` for the cheapest, `:free` for the free tier, `:online` for web search, ' +
|
|
25
|
-
'or `:exacto` for the best tool-calling accuracy. ' +
|
|
26
|
-
'Example: `openai/gpt-4o:nitro`. Or pass `online: true` for programmatic web search control.',
|
|
99
|
+
description: 'Model ID (optional, uses server default). Append `:nitro` (fastest), `:floor` (cheapest), `:free`, `:online` (web search), or `:exacto` (tool accuracy). Example: `openai/gpt-4o:nitro`. Or pass `online: true` for programmatic web search.',
|
|
27
100
|
},
|
|
28
|
-
messages:
|
|
29
|
-
|
|
30
|
-
minItems: 1,
|
|
31
|
-
items: {
|
|
32
|
-
type: 'object',
|
|
33
|
-
properties: {
|
|
34
|
-
role: { type: 'string', enum: ['system', 'user', 'assistant'] },
|
|
35
|
-
content: {
|
|
36
|
-
oneOf: [{ type: 'string' }, { type: 'array', items: { type: 'object' } }],
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
required: ['role', 'content'],
|
|
40
|
-
},
|
|
41
|
-
},
|
|
42
|
-
temperature: { type: 'number', minimum: 0, maximum: 2 },
|
|
101
|
+
messages: CHAT_MESSAGE_SCHEMA,
|
|
102
|
+
temperature: { type: 'number', minimum: 0, maximum: 2, description: 'Default: 1.' },
|
|
43
103
|
max_tokens: {
|
|
44
104
|
type: 'number',
|
|
45
105
|
minimum: 1,
|
|
@@ -47,8 +107,7 @@ export const TOOL_DEFINITIONS = [
|
|
|
47
107
|
},
|
|
48
108
|
provider: {
|
|
49
109
|
type: 'object',
|
|
50
|
-
description: 'OpenRouter provider-routing overrides. Merges on top of `OPENROUTER_PROVIDER_*` env defaults. '
|
|
51
|
-
'See https://openrouter.ai/docs/features/provider-routing',
|
|
110
|
+
description: 'OpenRouter provider-routing overrides. Merges on top of `OPENROUTER_PROVIDER_*` env defaults. See https://openrouter.ai/docs/features/provider-routing',
|
|
52
111
|
properties: {
|
|
53
112
|
quantizations: {
|
|
54
113
|
type: 'array',
|
|
@@ -60,19 +119,16 @@ export const TOOL_DEFINITIONS = [
|
|
|
60
119
|
items: { type: 'string' },
|
|
61
120
|
description: 'Exclude these provider slugs.',
|
|
62
121
|
},
|
|
63
|
-
sort: {
|
|
64
|
-
type: 'string',
|
|
65
|
-
enum: ['price', 'throughput', 'latency'],
|
|
66
|
-
},
|
|
122
|
+
sort: { type: 'string', enum: [...PROVIDER_SORT_VALUES] },
|
|
67
123
|
order: { type: 'array', items: { type: 'string' } },
|
|
68
124
|
require_parameters: { type: 'boolean' },
|
|
69
|
-
data_collection: { type: 'string', enum: [
|
|
125
|
+
data_collection: { type: 'string', enum: [...PROVIDER_DATA_COLLECTION] },
|
|
70
126
|
allow_fallbacks: { type: 'boolean' },
|
|
71
127
|
},
|
|
72
128
|
},
|
|
73
129
|
include_reasoning: {
|
|
74
130
|
type: 'boolean',
|
|
75
|
-
description: "Surface the model's chain-of-thought on `_meta.reasoning` for R1 / Opus
|
|
131
|
+
description: "Surface the model's chain-of-thought on `_meta.reasoning` for R1 / Opus / Gemini Thinking models.",
|
|
76
132
|
},
|
|
77
133
|
online: {
|
|
78
134
|
type: 'boolean',
|
|
@@ -83,19 +139,7 @@ export const TOOL_DEFINITIONS = [
|
|
|
83
139
|
minimum: 1,
|
|
84
140
|
description: 'Max web-search results when `online: true` (default 5).',
|
|
85
141
|
},
|
|
86
|
-
|
|
87
|
-
type: 'boolean',
|
|
88
|
-
description: 'Enable OpenRouter response caching via `X-OpenRouter-Cache: true`. ' +
|
|
89
|
-
'Server-wide default settable via `OPENROUTER_CACHE_RESPONSES=1`.',
|
|
90
|
-
},
|
|
91
|
-
cache_ttl: {
|
|
92
|
-
type: 'string',
|
|
93
|
-
description: 'Cache TTL (e.g. `"5m"`, `"1h"`, `"24h"`; 1s-24h range).',
|
|
94
|
-
},
|
|
95
|
-
cache_clear: {
|
|
96
|
-
type: 'boolean',
|
|
97
|
-
description: 'Bust the cache entry for this exact request.',
|
|
98
|
-
},
|
|
142
|
+
...CACHE_PROPERTIES,
|
|
99
143
|
},
|
|
100
144
|
required: ['messages'],
|
|
101
145
|
},
|
|
@@ -113,30 +157,15 @@ export const TOOL_DEFINITIONS = [
|
|
|
113
157
|
inputSchema: {
|
|
114
158
|
type: 'object',
|
|
115
159
|
properties: {
|
|
116
|
-
model: { type: 'string', description: 'Model ID (same as chat_completion).' },
|
|
117
|
-
messages:
|
|
118
|
-
type: 'array',
|
|
119
|
-
minItems: 1,
|
|
120
|
-
items: {
|
|
121
|
-
type: 'object',
|
|
122
|
-
properties: {
|
|
123
|
-
role: { type: 'string', enum: ['system', 'user', 'assistant'] },
|
|
124
|
-
content: {
|
|
125
|
-
oneOf: [{ type: 'string' }, { type: 'array', items: { type: 'object' } }],
|
|
126
|
-
},
|
|
127
|
-
},
|
|
128
|
-
required: ['role', 'content'],
|
|
129
|
-
},
|
|
130
|
-
},
|
|
160
|
+
model: { type: 'string', description: 'Model ID (same options as chat_completion).' },
|
|
161
|
+
messages: CHAT_MESSAGE_SCHEMA,
|
|
131
162
|
temperature: { type: 'number', minimum: 0, maximum: 2 },
|
|
132
163
|
max_tokens: { type: 'number', minimum: 1 },
|
|
133
164
|
provider: { type: 'object' },
|
|
134
165
|
include_reasoning: { type: 'boolean' },
|
|
135
166
|
online: { type: 'boolean' },
|
|
136
167
|
web_max_results: { type: 'number', minimum: 1 },
|
|
137
|
-
|
|
138
|
-
cache_ttl: { type: 'string' },
|
|
139
|
-
cache_clear: { type: 'boolean' },
|
|
168
|
+
...CACHE_PROPERTIES,
|
|
140
169
|
},
|
|
141
170
|
required: ['messages'],
|
|
142
171
|
},
|
|
@@ -177,23 +206,21 @@ export const TOOL_DEFINITIONS = [
|
|
|
177
206
|
properties: {
|
|
178
207
|
image_path: {
|
|
179
208
|
type: 'string',
|
|
180
|
-
description: '
|
|
181
|
-
'Good: `"photo.jpg"`. Bad: `"url": "..."` (wrong key), `"/etc/passwd"` (UNSAFE_PATH).',
|
|
209
|
+
description: 'Local path (OPENROUTER_INPUT_DIR sandbox), https URL, or data URL. Good: `"photo.jpg"`. Bad: `"url": "..."` (wrong key), `"/etc/passwd"` (UNSAFE_PATH).',
|
|
182
210
|
},
|
|
183
211
|
question: {
|
|
184
212
|
type: 'string',
|
|
185
|
-
description: 'Optional question
|
|
186
|
-
|
|
213
|
+
description: 'Optional question. Default: "What\'s in this image?". Bad: using `prompt` (wrong key for this tool).',
|
|
214
|
+
},
|
|
215
|
+
model: {
|
|
216
|
+
type: 'string',
|
|
217
|
+
description: 'Vision model ID (optional; server default is a free multimodal model).',
|
|
187
218
|
},
|
|
188
|
-
model: { type: 'string' },
|
|
189
219
|
cache_input: {
|
|
190
220
|
type: 'boolean',
|
|
191
|
-
description: 'Attach `cache_control: ephemeral` to the image block
|
|
192
|
-
'Repeat questions about the same image save ~10x on Anthropic.',
|
|
221
|
+
description: 'Attach `cache_control: ephemeral` to the image block for Anthropic / Gemini prompt caching.',
|
|
193
222
|
},
|
|
194
|
-
|
|
195
|
-
cache_ttl: { type: 'string' },
|
|
196
|
-
cache_clear: { type: 'boolean' },
|
|
223
|
+
...CACHE_PROPERTIES,
|
|
197
224
|
},
|
|
198
225
|
required: ['image_path'],
|
|
199
226
|
},
|
|
@@ -213,18 +240,18 @@ export const TOOL_DEFINITIONS = [
|
|
|
213
240
|
properties: {
|
|
214
241
|
audio_path: {
|
|
215
242
|
type: 'string',
|
|
216
|
-
description: 'Local file path (sandboxed
|
|
217
|
-
'http(s) URL, or data URL (base64-encoded audio)',
|
|
243
|
+
description: 'Local file path (sandboxed), http(s) URL, or data URL (base64-encoded audio).',
|
|
218
244
|
},
|
|
219
245
|
question: {
|
|
220
246
|
type: 'string',
|
|
221
|
-
description: 'Question or instruction
|
|
247
|
+
description: 'Question or instruction. Default: "Please transcribe and analyze this audio file."',
|
|
248
|
+
},
|
|
249
|
+
model: {
|
|
250
|
+
type: 'string',
|
|
251
|
+
description: 'Multimodal model ID (default: google/gemini-2.5-flash).',
|
|
222
252
|
},
|
|
223
|
-
model: { type: 'string' },
|
|
224
253
|
cache_input: { type: 'boolean' },
|
|
225
|
-
|
|
226
|
-
cache_ttl: { type: 'string' },
|
|
227
|
-
cache_clear: { type: 'boolean' },
|
|
254
|
+
...CACHE_PROPERTIES,
|
|
228
255
|
},
|
|
229
256
|
required: ['audio_path'],
|
|
230
257
|
},
|
|
@@ -244,15 +271,18 @@ export const TOOL_DEFINITIONS = [
|
|
|
244
271
|
properties: {
|
|
245
272
|
video_path: {
|
|
246
273
|
type: 'string',
|
|
247
|
-
description: 'Local file path (sandboxed
|
|
248
|
-
|
|
274
|
+
description: 'Local file path (sandboxed), http(s) URL, or base64 data URL. Supported containers: mp4, mpeg, mov, webm.',
|
|
275
|
+
},
|
|
276
|
+
question: {
|
|
277
|
+
type: 'string',
|
|
278
|
+
description: 'Optional question. Default: "Describe what happens in this video, step by step."',
|
|
279
|
+
},
|
|
280
|
+
model: {
|
|
281
|
+
type: 'string',
|
|
282
|
+
description: 'Video-capable model ID (default: google/gemini-2.5-flash).',
|
|
249
283
|
},
|
|
250
|
-
question: { type: 'string' },
|
|
251
|
-
model: { type: 'string' },
|
|
252
284
|
cache_input: { type: 'boolean' },
|
|
253
|
-
|
|
254
|
-
cache_ttl: { type: 'string' },
|
|
255
|
-
cache_clear: { type: 'boolean' },
|
|
285
|
+
...CACHE_PROPERTIES,
|
|
256
286
|
},
|
|
257
287
|
required: ['video_path'],
|
|
258
288
|
},
|
|
@@ -270,8 +300,11 @@ export const TOOL_DEFINITIONS = [
|
|
|
270
300
|
inputSchema: {
|
|
271
301
|
type: 'object',
|
|
272
302
|
properties: {
|
|
273
|
-
query: { type: 'string' },
|
|
274
|
-
provider: {
|
|
303
|
+
query: { type: 'string', description: 'Substring match against model id or name.' },
|
|
304
|
+
provider: {
|
|
305
|
+
type: 'string',
|
|
306
|
+
description: 'Filter by provider slug prefix (e.g. `google`).',
|
|
307
|
+
},
|
|
275
308
|
capabilities: {
|
|
276
309
|
type: 'object',
|
|
277
310
|
properties: {
|
|
@@ -280,8 +313,13 @@ export const TOOL_DEFINITIONS = [
|
|
|
280
313
|
video: { type: 'boolean' },
|
|
281
314
|
},
|
|
282
315
|
},
|
|
283
|
-
limit: {
|
|
284
|
-
|
|
316
|
+
limit: {
|
|
317
|
+
type: 'number',
|
|
318
|
+
minimum: 1,
|
|
319
|
+
maximum: 50,
|
|
320
|
+
description: 'Page size (default 20, max 50).',
|
|
321
|
+
},
|
|
322
|
+
offset: { type: 'number', minimum: 0, description: 'Pagination offset (default 0).' },
|
|
285
323
|
},
|
|
286
324
|
},
|
|
287
325
|
outputSchema: {
|
|
@@ -309,7 +347,12 @@ export const TOOL_DEFINITIONS = [
|
|
|
309
347
|
},
|
|
310
348
|
inputSchema: {
|
|
311
349
|
type: 'object',
|
|
312
|
-
properties: {
|
|
350
|
+
properties: {
|
|
351
|
+
model: {
|
|
352
|
+
type: 'string',
|
|
353
|
+
description: 'Full OpenRouter model slug (e.g. `openai/gpt-4o`).',
|
|
354
|
+
},
|
|
355
|
+
},
|
|
313
356
|
required: ['model'],
|
|
314
357
|
},
|
|
315
358
|
outputSchema: {
|
|
@@ -335,7 +378,9 @@ export const TOOL_DEFINITIONS = [
|
|
|
335
378
|
},
|
|
336
379
|
inputSchema: {
|
|
337
380
|
type: 'object',
|
|
338
|
-
properties: {
|
|
381
|
+
properties: {
|
|
382
|
+
model: { type: 'string', description: 'Full OpenRouter model slug to check.' },
|
|
383
|
+
},
|
|
339
384
|
required: ['model'],
|
|
340
385
|
},
|
|
341
386
|
outputSchema: {
|
|
@@ -360,32 +405,33 @@ export const TOOL_DEFINITIONS = [
|
|
|
360
405
|
inputSchema: {
|
|
361
406
|
type: 'object',
|
|
362
407
|
properties: {
|
|
363
|
-
prompt: { type: 'string' },
|
|
364
|
-
model: {
|
|
408
|
+
prompt: { type: 'string', description: 'Text prompt describing the image to generate.' },
|
|
409
|
+
model: {
|
|
410
|
+
type: 'string',
|
|
411
|
+
description: 'Image model ID (default: google/gemini-2.5-flash-image). Chat-completions route.',
|
|
412
|
+
},
|
|
365
413
|
aspect_ratio: {
|
|
366
414
|
type: 'string',
|
|
367
|
-
enum: [
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
'16:9',
|
|
377
|
-
'21:9',
|
|
378
|
-
'1:4',
|
|
379
|
-
'4:1',
|
|
380
|
-
'1:8',
|
|
381
|
-
'8:1',
|
|
382
|
-
],
|
|
383
|
-
},
|
|
384
|
-
image_size: { type: 'string', enum: ['0.5K', '1K', '2K', '4K'] },
|
|
385
|
-
max_tokens: { type: 'number', minimum: 1 },
|
|
415
|
+
enum: [...IMAGE_ASPECT_RATIOS],
|
|
416
|
+
description: 'Optional aspect ratio (provider-dependent).',
|
|
417
|
+
},
|
|
418
|
+
image_size: {
|
|
419
|
+
type: 'string',
|
|
420
|
+
enum: [...IMAGE_SIZES],
|
|
421
|
+
description: 'Optional resolution tier for supported models.',
|
|
422
|
+
},
|
|
423
|
+
max_tokens: { type: 'number', minimum: 1, description: 'Optional completion token cap.' },
|
|
386
424
|
save_path: SAVE_PATH_PROPERTY,
|
|
387
|
-
input_images: {
|
|
388
|
-
|
|
425
|
+
input_images: {
|
|
426
|
+
type: 'array',
|
|
427
|
+
items: { type: 'string' },
|
|
428
|
+
description: 'Reference images (local path, URL, or data URL) for style/identity conditioning.',
|
|
429
|
+
},
|
|
430
|
+
modalities: {
|
|
431
|
+
type: 'array',
|
|
432
|
+
items: { type: 'string' },
|
|
433
|
+
description: 'Response modalities (default: `["image","text"]`).',
|
|
434
|
+
},
|
|
389
435
|
},
|
|
390
436
|
required: ['prompt'],
|
|
391
437
|
},
|
|
@@ -409,49 +455,45 @@ export const TOOL_DEFINITIONS = [
|
|
|
409
455
|
},
|
|
410
456
|
model: {
|
|
411
457
|
type: 'string',
|
|
412
|
-
description: 'Image model ID. Default: google/gemini-2.5-flash-image. Browse
|
|
458
|
+
description: 'Image model ID. Default: google/gemini-2.5-flash-image. Browse: https://openrouter.ai/collections/image-models',
|
|
413
459
|
},
|
|
414
460
|
resolution: {
|
|
415
461
|
type: 'string',
|
|
416
|
-
enum: [
|
|
462
|
+
enum: [...IMAGE_DEDICATED_RESOLUTIONS],
|
|
417
463
|
description: 'Normalized resolution tier. Provider maps to closest supported size.',
|
|
418
464
|
},
|
|
419
465
|
aspect_ratio: {
|
|
420
466
|
type: 'string',
|
|
421
|
-
|
|
467
|
+
enum: [...IMAGE_ASPECT_RATIOS],
|
|
468
|
+
description: 'Aspect ratio (same enum as generate_image).',
|
|
422
469
|
},
|
|
423
470
|
quality: {
|
|
424
471
|
type: 'string',
|
|
425
|
-
enum: [
|
|
426
|
-
description: 'Image quality level.',
|
|
472
|
+
enum: [...IMAGE_DEDICATED_QUALITIES],
|
|
473
|
+
description: 'Image quality level (default: auto).',
|
|
427
474
|
},
|
|
428
475
|
output_format: {
|
|
429
476
|
type: 'string',
|
|
430
|
-
enum: [
|
|
477
|
+
enum: [...IMAGE_OUTPUT_FORMATS],
|
|
431
478
|
description: 'Output image format.',
|
|
432
479
|
},
|
|
433
480
|
n: {
|
|
434
481
|
type: 'number',
|
|
435
482
|
minimum: 1,
|
|
436
483
|
maximum: 10,
|
|
437
|
-
description: 'Number of images to
|
|
484
|
+
description: 'Number of images to request (default 1; only images[0] is saved/inlined).',
|
|
438
485
|
},
|
|
439
486
|
input_references: {
|
|
440
487
|
type: 'array',
|
|
441
488
|
items: { type: 'string' },
|
|
442
|
-
description: 'Reference images for image-to-image
|
|
443
|
-
},
|
|
444
|
-
save_path: {
|
|
445
|
-
...SAVE_PATH_PROPERTY,
|
|
446
|
-
description: 'Save generated image to this path. ' + SAVE_PATH_PROPERTY.description,
|
|
489
|
+
description: 'Reference images for image-to-image. Each entry: local path, http(s) URL, or data URL.',
|
|
447
490
|
},
|
|
491
|
+
save_path: SAVE_PATH_WITH_PREFIX('Save generated image to this path.'),
|
|
448
492
|
provider: {
|
|
449
493
|
type: 'object',
|
|
450
494
|
description: 'Provider routing overrides (order, sort, allow_fallbacks, etc.).',
|
|
451
495
|
},
|
|
452
|
-
|
|
453
|
-
cache_ttl: { type: 'string' },
|
|
454
|
-
cache_clear: { type: 'boolean' },
|
|
496
|
+
...CACHE_PROPERTIES,
|
|
455
497
|
},
|
|
456
498
|
required: ['prompt'],
|
|
457
499
|
},
|
|
@@ -469,10 +511,20 @@ export const TOOL_DEFINITIONS = [
|
|
|
469
511
|
inputSchema: {
|
|
470
512
|
type: 'object',
|
|
471
513
|
properties: {
|
|
472
|
-
prompt: { type: 'string' },
|
|
473
|
-
model: {
|
|
474
|
-
|
|
475
|
-
|
|
514
|
+
prompt: { type: 'string', description: 'Text prompt for speech or music generation.' },
|
|
515
|
+
model: {
|
|
516
|
+
type: 'string',
|
|
517
|
+
description: 'Chat-completions audio model (default: openai/gpt-audio).',
|
|
518
|
+
},
|
|
519
|
+
voice: {
|
|
520
|
+
type: 'string',
|
|
521
|
+
description: 'Voice ID (default: alloy). Model-specific.',
|
|
522
|
+
},
|
|
523
|
+
format: {
|
|
524
|
+
type: 'string',
|
|
525
|
+
enum: [...GENERATE_AUDIO_FORMATS],
|
|
526
|
+
description: 'Output audio format (default: pcm16, auto-wrapped as WAV when needed).',
|
|
527
|
+
},
|
|
476
528
|
save_path: SAVE_PATH_PROPERTY,
|
|
477
529
|
},
|
|
478
530
|
required: ['prompt'],
|
|
@@ -497,34 +549,29 @@ export const TOOL_DEFINITIONS = [
|
|
|
497
549
|
},
|
|
498
550
|
model: {
|
|
499
551
|
type: 'string',
|
|
500
|
-
description:
|
|
552
|
+
description: `TTS model for OpenRouter POST /audio/speech. Default: ${DEFAULT_TTS_MODEL}. Discover current models with GET /api/v1/models?output_modalities=speech.`,
|
|
501
553
|
},
|
|
502
554
|
voice: {
|
|
503
555
|
type: 'string',
|
|
504
|
-
description:
|
|
556
|
+
description: `Voice ID (model-specific). Default: ${DEFAULT_TTS_VOICE} for ${DEFAULT_TTS_MODEL}; pass a voice supported by another model.`,
|
|
505
557
|
},
|
|
506
558
|
response_format: {
|
|
507
559
|
type: 'string',
|
|
508
|
-
enum: [
|
|
509
|
-
description:
|
|
560
|
+
enum: [...TTS_RESPONSE_FORMATS],
|
|
561
|
+
description: `Output audio format (mp3 or pcm). Default: ${DEFAULT_TTS_RESPONSE_FORMAT}.`,
|
|
510
562
|
},
|
|
511
563
|
speed: {
|
|
512
564
|
type: 'number',
|
|
513
565
|
minimum: 0.25,
|
|
514
566
|
maximum: 4.0,
|
|
515
|
-
description: 'Speed of speech (0.25
|
|
567
|
+
description: 'Speed of speech (0.25–4.0). Default: 1.0.',
|
|
516
568
|
},
|
|
517
569
|
instructions: {
|
|
518
570
|
type: 'string',
|
|
519
571
|
description: 'Tone/style instructions (e.g. "speak in a warm, friendly tone"). OpenAI models only.',
|
|
520
572
|
},
|
|
521
|
-
save_path:
|
|
522
|
-
|
|
523
|
-
description: 'Save audio to this path. ' + SAVE_PATH_PROPERTY.description,
|
|
524
|
-
},
|
|
525
|
-
cache: { type: 'boolean' },
|
|
526
|
-
cache_ttl: { type: 'string' },
|
|
527
|
-
cache_clear: { type: 'boolean' },
|
|
573
|
+
save_path: SAVE_PATH_WITH_PREFIX('Save audio to this path.'),
|
|
574
|
+
...CACHE_PROPERTIES,
|
|
528
575
|
},
|
|
529
576
|
required: ['input'],
|
|
530
577
|
},
|
|
@@ -544,7 +591,7 @@ export const TOOL_DEFINITIONS = [
|
|
|
544
591
|
properties: {
|
|
545
592
|
audio_path: {
|
|
546
593
|
type: 'string',
|
|
547
|
-
description: 'Audio file: local path (sandboxed), http(s) URL, or base64 data URL. Formats: mp3, wav, flac, ogg, webm, mp4.',
|
|
594
|
+
description: 'Audio file: local path (sandboxed), http(s) URL, or base64 data URL. Formats: mp3, wav, flac, ogg, webm, mp4, m4a.',
|
|
548
595
|
},
|
|
549
596
|
model: {
|
|
550
597
|
type: 'string',
|
|
@@ -556,18 +603,16 @@ export const TOOL_DEFINITIONS = [
|
|
|
556
603
|
},
|
|
557
604
|
response_format: {
|
|
558
605
|
type: 'string',
|
|
559
|
-
enum: [
|
|
606
|
+
enum: [...STT_RESPONSE_FORMATS],
|
|
560
607
|
description: 'Output format for transcription. Default: json.',
|
|
561
608
|
},
|
|
562
609
|
temperature: {
|
|
563
610
|
type: 'number',
|
|
564
611
|
minimum: 0,
|
|
565
612
|
maximum: 1,
|
|
566
|
-
description: 'Sampling temperature for transcription (0
|
|
613
|
+
description: 'Sampling temperature for transcription (0–1).',
|
|
567
614
|
},
|
|
568
|
-
|
|
569
|
-
cache_ttl: { type: 'string' },
|
|
570
|
-
cache_clear: { type: 'boolean' },
|
|
615
|
+
...CACHE_PROPERTIES,
|
|
571
616
|
},
|
|
572
617
|
required: ['audio_path'],
|
|
573
618
|
},
|
|
@@ -585,19 +630,50 @@ export const TOOL_DEFINITIONS = [
|
|
|
585
630
|
inputSchema: {
|
|
586
631
|
type: 'object',
|
|
587
632
|
properties: {
|
|
588
|
-
prompt: { type: 'string' },
|
|
589
|
-
model: {
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
633
|
+
prompt: { type: 'string', description: 'Text prompt describing the video to generate.' },
|
|
634
|
+
model: {
|
|
635
|
+
type: 'string',
|
|
636
|
+
description: 'Video model ID (default: google/veo-3.1). Passed through to provider.',
|
|
637
|
+
},
|
|
638
|
+
resolution: {
|
|
639
|
+
type: 'string',
|
|
640
|
+
description: 'Provider-specific resolution (e.g. "720p", "1080p"). No server-side enum.',
|
|
641
|
+
},
|
|
642
|
+
aspect_ratio: {
|
|
643
|
+
type: 'string',
|
|
644
|
+
description: 'Provider-specific aspect ratio (e.g. "16:9", "9:16"). No server-side enum.',
|
|
645
|
+
},
|
|
646
|
+
duration: {
|
|
647
|
+
type: 'number',
|
|
648
|
+
minimum: 1,
|
|
649
|
+
description: 'Clip duration in seconds (provider-dependent).',
|
|
650
|
+
},
|
|
651
|
+
seed: { type: 'number', description: 'Optional reproducibility seed.' },
|
|
652
|
+
first_frame_image: {
|
|
653
|
+
type: 'string',
|
|
654
|
+
description: 'Optional first-frame image (path, URL, or data URL).',
|
|
655
|
+
},
|
|
656
|
+
last_frame_image: {
|
|
657
|
+
type: 'string',
|
|
658
|
+
description: 'Optional last-frame image (path, URL, or data URL).',
|
|
659
|
+
},
|
|
660
|
+
reference_images: {
|
|
661
|
+
type: 'array',
|
|
662
|
+
items: { type: 'string' },
|
|
663
|
+
description: 'Optional reference images for style/subject guidance.',
|
|
664
|
+
},
|
|
665
|
+
provider: { type: 'object', description: 'Provider routing overrides.' },
|
|
598
666
|
save_path: SAVE_PATH_PROPERTY,
|
|
599
|
-
max_wait_ms: {
|
|
600
|
-
|
|
667
|
+
max_wait_ms: {
|
|
668
|
+
type: 'number',
|
|
669
|
+
minimum: 100,
|
|
670
|
+
description: 'Max time to poll before returning JOB_STILL_RUNNING (ms). Default: 600000 (10 min) via OPENROUTER_VIDEO_MAX_WAIT_MS.',
|
|
671
|
+
},
|
|
672
|
+
poll_interval_ms: {
|
|
673
|
+
type: 'number',
|
|
674
|
+
minimum: 50,
|
|
675
|
+
description: 'Poll interval while waiting (ms). Default: 15000 via OPENROUTER_VIDEO_POLL_INTERVAL_MS.',
|
|
676
|
+
},
|
|
601
677
|
},
|
|
602
678
|
required: ['prompt'],
|
|
603
679
|
},
|
|
@@ -619,15 +695,23 @@ export const TOOL_DEFINITIONS = [
|
|
|
619
695
|
type: 'string',
|
|
620
696
|
description: 'First-frame image (path, URL, or data URL). Required.',
|
|
621
697
|
},
|
|
622
|
-
prompt: { type: 'string' },
|
|
623
|
-
model: { type: 'string' },
|
|
624
|
-
resolution: { type: 'string' },
|
|
625
|
-
aspect_ratio: { type: 'string' },
|
|
626
|
-
duration: { type: 'number', minimum: 1 },
|
|
627
|
-
seed: { type: 'number' },
|
|
698
|
+
prompt: { type: 'string', description: 'Motion/scene prompt describing the video.' },
|
|
699
|
+
model: { type: 'string', description: 'Video model ID (default: google/veo-3.1).' },
|
|
700
|
+
resolution: { type: 'string', description: 'Provider-specific resolution.' },
|
|
701
|
+
aspect_ratio: { type: 'string', description: 'Provider-specific aspect ratio.' },
|
|
702
|
+
duration: { type: 'number', minimum: 1, description: 'Clip duration in seconds.' },
|
|
703
|
+
seed: { type: 'number', description: 'Optional reproducibility seed.' },
|
|
628
704
|
save_path: SAVE_PATH_PROPERTY,
|
|
629
|
-
max_wait_ms: {
|
|
630
|
-
|
|
705
|
+
max_wait_ms: {
|
|
706
|
+
type: 'number',
|
|
707
|
+
minimum: 100,
|
|
708
|
+
description: 'Max poll wait (ms) before JOB_STILL_RUNNING. Default: 600000.',
|
|
709
|
+
},
|
|
710
|
+
poll_interval_ms: {
|
|
711
|
+
type: 'number',
|
|
712
|
+
minimum: 50,
|
|
713
|
+
description: 'Poll interval (ms). Default: 15000.',
|
|
714
|
+
},
|
|
631
715
|
},
|
|
632
716
|
required: ['image', 'prompt'],
|
|
633
717
|
},
|
|
@@ -645,7 +729,10 @@ export const TOOL_DEFINITIONS = [
|
|
|
645
729
|
inputSchema: {
|
|
646
730
|
type: 'object',
|
|
647
731
|
properties: {
|
|
648
|
-
video_id: {
|
|
732
|
+
video_id: {
|
|
733
|
+
type: 'string',
|
|
734
|
+
description: 'Video job id from generate_video / generate_video_from_image.',
|
|
735
|
+
},
|
|
649
736
|
save_path: SAVE_PATH_PROPERTY,
|
|
650
737
|
},
|
|
651
738
|
required: ['video_id'],
|
|
@@ -664,11 +751,17 @@ export const TOOL_DEFINITIONS = [
|
|
|
664
751
|
inputSchema: {
|
|
665
752
|
type: 'object',
|
|
666
753
|
properties: {
|
|
667
|
-
query: { type: 'string' },
|
|
754
|
+
query: { type: 'string', description: 'Search query to rank documents against.' },
|
|
668
755
|
documents: { type: 'array', items: { type: 'string' }, minItems: 1 },
|
|
669
|
-
model: {
|
|
670
|
-
|
|
671
|
-
|
|
756
|
+
model: {
|
|
757
|
+
type: 'string',
|
|
758
|
+
description: 'Reranker model (default: cohere/rerank-v3.5).',
|
|
759
|
+
},
|
|
760
|
+
top_n: { type: 'number', minimum: 1, description: 'Return only the top N results.' },
|
|
761
|
+
return_documents: {
|
|
762
|
+
type: 'boolean',
|
|
763
|
+
description: 'When true, include original document text in each result.',
|
|
764
|
+
},
|
|
672
765
|
},
|
|
673
766
|
required: ['query', 'documents'],
|
|
674
767
|
},
|
|
@@ -717,3 +810,13 @@ export const TOOL_DEFINITIONS = [
|
|
|
717
810
|
},
|
|
718
811
|
},
|
|
719
812
|
];
|
|
813
|
+
/** Tool names from definitions — must match TOOL_NAMES in tool-descriptions.ts. */
|
|
814
|
+
export const TOOL_DEFINITION_NAMES = TOOL_DEFINITIONS.map((t) => t.name);
|
|
815
|
+
if (TOOL_DEFINITION_NAMES.length !== TOOL_NAMES.length) {
|
|
816
|
+
throw new Error(`Tool count mismatch: definitions=${TOOL_DEFINITION_NAMES.length} descriptions=${TOOL_NAMES.length}`);
|
|
817
|
+
}
|
|
818
|
+
for (const name of TOOL_NAMES) {
|
|
819
|
+
if (!TOOL_DEFINITION_NAMES.includes(name)) {
|
|
820
|
+
throw new Error(`Missing tool definition for ${name}`);
|
|
821
|
+
}
|
|
822
|
+
}
|