(config: Config, flags: GlobalFlags)
| 29 | 'mmx vision describe --file-id file-123456789 --prompt "Extract the text"', |
| 30 | ], |
| 31 | async run(config: Config, flags: GlobalFlags) { |
| 32 | let image = (flags.image ?? flags.file ?? flags.path ?? (flags._positional as string[]|undefined)?.[0]) as string | undefined; |
| 33 | let fileId = flags.fileId as string | undefined; |
| 34 | const prompt = (flags.prompt as string) || 'Describe the image.'; |
| 35 | |
| 36 | // Mutually exclusive: must provide one, cannot provide both |
| 37 | if (!image && !fileId) { |
| 38 | if (isInteractive({ nonInteractive: config.nonInteractive })) { |
| 39 | const hint = await promptText({ |
| 40 | message: 'Enter image path, URL, or File ID:', |
| 41 | }); |
| 42 | if (!hint) { |
| 43 | process.stderr.write('Vision describe cancelled.\n'); |
| 44 | process.exit(1); |
| 45 | } |
| 46 | // Simple heuristic: if no extension and not http(s), treat as fileId |
| 47 | if (!hint.includes('.') && !hint.startsWith('http')) { |
| 48 | fileId = hint; |
| 49 | } else { |
| 50 | image = hint; |
| 51 | } |
| 52 | } else { |
| 53 | throw new CLIError( |
| 54 | 'Missing required argument. Must provide either --image or --file-id.', |
| 55 | ExitCode.USAGE, |
| 56 | 'mmx vision describe --image <path> OR --file-id <id>', |
| 57 | ); |
| 58 | } |
| 59 | } else if (image && fileId) { |
| 60 | throw new CLIError( |
| 61 | 'Conflicting arguments: cannot provide both --image and --file-id.', |
| 62 | ExitCode.USAGE, |
| 63 | ); |
| 64 | } |
| 65 | |
| 66 | if (dryRun(config, { prompt, image, fileId })) return; |
| 67 | |
| 68 | const format = detectOutputFormat(config.output); |
| 69 | const url = vlmEndpoint(config.baseUrl); |
| 70 | const body: Record<string, unknown> = { prompt }; |
| 71 | |
| 72 | if (fileId) { |
| 73 | // Skip base64: pass fileId directly to the API |
| 74 | body.file_id = fileId; |
| 75 | } else if (image) { |
| 76 | // Fallback to base64 encoding for local/HTTP images |
| 77 | const imageUrl = await toDataUri(image); |
| 78 | body.image_url = imageUrl; |
| 79 | } |
| 80 | |
| 81 | const response = await requestJson<VlmResponse>(config, { |
| 82 | url, |
| 83 | method: 'POST', |
| 84 | body, |
| 85 | }); |
| 86 | |
| 87 | if (format !== 'text') { |
| 88 | process.stdout.write(formatOutput(response, format) + '\n'); |
nothing calls this directly
no test coverage detected