@yanickxia/agent-vision 0.1.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image.js","sourceRoot":"","sources":["../src/image.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ export declare function validateRemoteUrl(rawUrl: string, allowPrivateUrls: boolean): Promise<URL>;
2
+ export declare function fetchRemoteBuffer(options: {
3
+ url: string;
4
+ maxBytes: number;
5
+ timeoutMs: number;
6
+ allowPrivateUrls: boolean;
7
+ }): Promise<{
8
+ buffer: Buffer;
9
+ contentType?: string;
10
+ }>;
11
+ export declare function downloadRemoteFile(options: {
12
+ url: string;
13
+ destination: string;
14
+ maxBytes: number;
15
+ timeoutMs: number;
16
+ allowPrivateUrls: boolean;
17
+ }): Promise<number>;
18
+ //# sourceMappingURL=network.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../src/network.ts"],"names":[],"mappings":"AAmCA,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,MAAM,EACd,gBAAgB,EAAE,OAAO,GACxB,OAAO,CAAC,GAAG,CAAC,CA4Bd;AAqDD,wBAAsB,iBAAiB,CAAC,OAAO,EAAE;IAC/C,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,OAAO,CAAC;CAC3B,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAqCpD;AAED,wBAAsB,kBAAkB,CAAC,OAAO,EAAE;IAChD,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,OAAO,CAAC;CAC3B,GAAG,OAAO,CAAC,MAAM,CAAC,CAmClB"}
@@ -0,0 +1,169 @@
1
+ import { lookup } from "node:dns/promises";
2
+ import { isIP } from "node:net";
3
+ import { open } from "node:fs/promises";
4
+ import { VisionError } from "./errors.js";
5
+ function isPrivateIpv4(address) {
6
+ const parts = address.split(".").map(Number);
7
+ const first = parts[0];
8
+ const second = parts[1];
9
+ if (parts.length !== 4 || first === undefined || second === undefined) {
10
+ return false;
11
+ }
12
+ return (first === 0 ||
13
+ first === 10 ||
14
+ first === 127 ||
15
+ (first === 100 && second >= 64 && second <= 127) ||
16
+ (first === 169 && second === 254) ||
17
+ (first === 172 && second >= 16 && second <= 31) ||
18
+ (first === 192 && second === 168) ||
19
+ first >= 224);
20
+ }
21
+ function isPrivateAddress(address) {
22
+ if (isIP(address) === 4)
23
+ return isPrivateIpv4(address);
24
+ if (isIP(address) !== 6)
25
+ return false;
26
+ const normalized = address.toLowerCase();
27
+ if (normalized === "::" || normalized === "::1")
28
+ return true;
29
+ if (normalized.startsWith("fc") || normalized.startsWith("fd"))
30
+ return true;
31
+ if (/^fe[89ab]/.test(normalized) || normalized.startsWith("ff"))
32
+ return true;
33
+ const mapped = normalized.match(/^::ffff:(\d+\.\d+\.\d+\.\d+)$/);
34
+ return mapped?.[1] ? isPrivateIpv4(mapped[1]) : false;
35
+ }
36
+ export async function validateRemoteUrl(rawUrl, allowPrivateUrls) {
37
+ let url;
38
+ try {
39
+ url = new URL(rawUrl);
40
+ }
41
+ catch {
42
+ throw new VisionError("INVALID_SOURCE", `Invalid URL: ${rawUrl}`);
43
+ }
44
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
45
+ throw new VisionError("INVALID_SOURCE", "Only HTTP(S) URLs are supported");
46
+ }
47
+ if (allowPrivateUrls)
48
+ return url;
49
+ if (url.hostname.toLowerCase() === "localhost") {
50
+ throw new VisionError("PRIVATE_URL_BLOCKED", "Private source URLs are blocked");
51
+ }
52
+ let addresses;
53
+ try {
54
+ addresses = await lookup(url.hostname, { all: true });
55
+ }
56
+ catch (error) {
57
+ throw new VisionError("DOWNLOAD_ERROR", `Cannot resolve ${url.hostname}`, { cause: error });
58
+ }
59
+ if (addresses.length === 0 || addresses.some(({ address }) => isPrivateAddress(address))) {
60
+ throw new VisionError("PRIVATE_URL_BLOCKED", "Private source URLs are blocked");
61
+ }
62
+ return url;
63
+ }
64
+ async function fetchFollowingRedirects(rawUrl, allowPrivateUrls, signal) {
65
+ let current = rawUrl;
66
+ for (let redirects = 0; redirects <= 3; redirects += 1) {
67
+ const url = await validateRemoteUrl(current, allowPrivateUrls);
68
+ let response;
69
+ try {
70
+ response = await fetch(url, { redirect: "manual", signal });
71
+ }
72
+ catch (error) {
73
+ if (signal.aborted) {
74
+ throw new VisionError("DOWNLOAD_TIMEOUT", `Timed out downloading ${rawUrl}`);
75
+ }
76
+ throw new VisionError("DOWNLOAD_ERROR", `Failed to download ${rawUrl}`, {
77
+ cause: error,
78
+ });
79
+ }
80
+ if (response.status >= 300 && response.status < 400) {
81
+ const location = response.headers.get("location");
82
+ if (!location) {
83
+ throw new VisionError("DOWNLOAD_ERROR", "Redirect has no Location header");
84
+ }
85
+ await response.body?.cancel();
86
+ current = new URL(location, url).toString();
87
+ continue;
88
+ }
89
+ if (!response.ok) {
90
+ throw new VisionError("DOWNLOAD_ERROR", `Source returned HTTP ${response.status}`);
91
+ }
92
+ return response;
93
+ }
94
+ throw new VisionError("DOWNLOAD_ERROR", "Too many redirects (maximum 3)");
95
+ }
96
+ function assertContentLength(response, maxBytes) {
97
+ const raw = response.headers.get("content-length");
98
+ if (!raw)
99
+ return;
100
+ const length = Number(raw);
101
+ if (Number.isFinite(length) && length > maxBytes) {
102
+ throw new VisionError("SOURCE_TOO_LARGE", `Remote source is ${(length / 1024 / 1024).toFixed(1)} MB; limit is ${(maxBytes / 1024 / 1024).toFixed(1)} MB`);
103
+ }
104
+ }
105
+ export async function fetchRemoteBuffer(options) {
106
+ const controller = new AbortController();
107
+ const timer = setTimeout(() => controller.abort(), options.timeoutMs);
108
+ try {
109
+ const response = await fetchFollowingRedirects(options.url, options.allowPrivateUrls, controller.signal);
110
+ assertContentLength(response, options.maxBytes);
111
+ if (!response.body) {
112
+ throw new VisionError("DOWNLOAD_ERROR", "Remote source has an empty body");
113
+ }
114
+ const chunks = [];
115
+ let total = 0;
116
+ const reader = response.body.getReader();
117
+ while (true) {
118
+ const { done, value } = await reader.read();
119
+ if (done)
120
+ break;
121
+ total += value.byteLength;
122
+ if (total > options.maxBytes) {
123
+ await reader.cancel();
124
+ throw new VisionError("SOURCE_TOO_LARGE", `Remote source exceeds ${(options.maxBytes / 1024 / 1024).toFixed(1)} MB`);
125
+ }
126
+ chunks.push(Buffer.from(value));
127
+ }
128
+ const contentType = response.headers.get("content-type")?.split(";", 1)[0]?.trim();
129
+ return {
130
+ buffer: Buffer.concat(chunks, total),
131
+ ...(contentType ? { contentType } : {}),
132
+ };
133
+ }
134
+ finally {
135
+ clearTimeout(timer);
136
+ }
137
+ }
138
+ export async function downloadRemoteFile(options) {
139
+ const controller = new AbortController();
140
+ const timer = setTimeout(() => controller.abort(), options.timeoutMs);
141
+ let file;
142
+ try {
143
+ const response = await fetchFollowingRedirects(options.url, options.allowPrivateUrls, controller.signal);
144
+ assertContentLength(response, options.maxBytes);
145
+ if (!response.body) {
146
+ throw new VisionError("DOWNLOAD_ERROR", "Remote source has an empty body");
147
+ }
148
+ file = await open(options.destination, "w");
149
+ const reader = response.body.getReader();
150
+ let total = 0;
151
+ while (true) {
152
+ const { done, value } = await reader.read();
153
+ if (done)
154
+ break;
155
+ total += value.byteLength;
156
+ if (total > options.maxBytes) {
157
+ await reader.cancel();
158
+ throw new VisionError("SOURCE_TOO_LARGE", `Remote source exceeds ${(options.maxBytes / 1024 / 1024).toFixed(1)} MB`);
159
+ }
160
+ await file.write(value);
161
+ }
162
+ return total;
163
+ }
164
+ finally {
165
+ clearTimeout(timer);
166
+ await file?.close();
167
+ }
168
+ }
169
+ //# sourceMappingURL=network.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"network.js","sourceRoot":"","sources":["../src/network.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { VisionConfig } from "./config.js";
2
+ export interface VisionInputImage {
3
+ dataUrl: string;
4
+ label?: string;
5
+ }
6
+ export interface VisionCompletion {
7
+ text: string;
8
+ model: string;
9
+ usage?: Record<string, unknown>;
10
+ }
11
+ export declare function requestVisionCompletion(options: {
12
+ config: VisionConfig;
13
+ prompt: string;
14
+ images: VisionInputImage[];
15
+ }): Promise<VisionCompletion>;
16
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAIhD,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAiBD,wBAAsB,uBAAuB,CAAC,OAAO,EAAE;IACrD,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,gBAAgB,EAAE,CAAC;CAC5B,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAwG5B"}
@@ -0,0 +1,115 @@
1
+ import { chatCompletionsUrl, requireModel } from "./config.js";
2
+ import { VisionError } from "./errors.js";
3
+ function responseText(content) {
4
+ if (typeof content === "string" && content.trim())
5
+ return content.trim();
6
+ if (!Array.isArray(content))
7
+ return undefined;
8
+ const parts = content
9
+ .map((part) => {
10
+ if (!part || typeof part !== "object")
11
+ return undefined;
12
+ const value = part;
13
+ return value.type === "text" && typeof value.text === "string"
14
+ ? value.text
15
+ : undefined;
16
+ })
17
+ .filter((part) => Boolean(part));
18
+ return parts.length > 0 ? parts.join("\n").trim() : undefined;
19
+ }
20
+ export async function requestVisionCompletion(options) {
21
+ requireModel(options.config);
22
+ if (options.images.length === 0) {
23
+ throw new VisionError("INVALID_SOURCE", "At least one image is required");
24
+ }
25
+ const content = [
26
+ { type: "text", text: options.prompt },
27
+ ];
28
+ for (const [index, image] of options.images.entries()) {
29
+ if (image.label) {
30
+ content.push({ type: "text", text: `Image ${index + 1}: ${image.label}` });
31
+ }
32
+ content.push({
33
+ type: "image_url",
34
+ image_url: { url: image.dataUrl, detail: "high" },
35
+ });
36
+ }
37
+ const headers = new Headers(options.config.headers);
38
+ headers.set("content-type", "application/json");
39
+ if (options.config.apiKey && !headers.has("authorization")) {
40
+ headers.set("authorization", `Bearer ${options.config.apiKey}`);
41
+ }
42
+ const controller = new AbortController();
43
+ const timer = setTimeout(() => controller.abort(), options.config.timeoutMs);
44
+ let response;
45
+ let raw;
46
+ try {
47
+ response = await fetch(chatCompletionsUrl(options.config.baseUrl), {
48
+ method: "POST",
49
+ headers,
50
+ body: JSON.stringify({
51
+ model: options.config.model,
52
+ messages: [{ role: "user", content }],
53
+ max_tokens: options.config.maxTokens,
54
+ stream: false,
55
+ }),
56
+ signal: controller.signal,
57
+ });
58
+ raw = await response.text();
59
+ }
60
+ catch (error) {
61
+ if (controller.signal.aborted) {
62
+ throw new VisionError("API_TIMEOUT", `Vision API timed out after ${options.config.timeoutMs} ms`);
63
+ }
64
+ throw new VisionError("API_ERROR", "Could not reach the vision API", {
65
+ cause: error,
66
+ });
67
+ }
68
+ finally {
69
+ clearTimeout(timer);
70
+ }
71
+ let payload;
72
+ try {
73
+ payload = raw ? JSON.parse(raw) : {};
74
+ }
75
+ catch {
76
+ payload = undefined;
77
+ }
78
+ if (!response.ok) {
79
+ const record = payload && typeof payload === "object"
80
+ ? payload
81
+ : undefined;
82
+ const error = record?.error;
83
+ const apiMessage = error && typeof error === "object"
84
+ ? error.message
85
+ : undefined;
86
+ const detail = typeof apiMessage === "string"
87
+ ? apiMessage
88
+ : raw.slice(0, 500) || response.statusText;
89
+ throw new VisionError("API_ERROR", `Vision API returned HTTP ${response.status}: ${detail}`);
90
+ }
91
+ if (!payload || typeof payload !== "object") {
92
+ throw new VisionError("API_RESPONSE_ERROR", "Vision API returned invalid JSON");
93
+ }
94
+ const record = payload;
95
+ const choices = record.choices;
96
+ const firstChoice = Array.isArray(choices) ? choices[0] : undefined;
97
+ const message = firstChoice && typeof firstChoice === "object"
98
+ ? firstChoice.message
99
+ : undefined;
100
+ const contentValue = message && typeof message === "object"
101
+ ? message.content
102
+ : undefined;
103
+ const text = responseText(contentValue);
104
+ if (!text) {
105
+ throw new VisionError("API_RESPONSE_ERROR", "Vision API response is missing choices[0].message.content");
106
+ }
107
+ return {
108
+ text,
109
+ model: typeof record.model === "string" ? record.model : options.config.model,
110
+ ...(record.usage && typeof record.usage === "object"
111
+ ? { usage: record.usage }
112
+ : {}),
113
+ };
114
+ }
115
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare const SERVER_VERSION = "0.1.0";
3
+ export declare function createServer(): McpServer;
4
+ export declare function startStdioServer(): Promise<void>;
5
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMpE,eAAO,MAAM,cAAc,UAAU,CAAC;AAStC,wBAAgB,YAAY,IAAI,SAAS,CAsDxC;AAED,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAItD"}
package/dist/server.js ADDED
@@ -0,0 +1,62 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { z } from "zod";
4
+ import { analyzeImage, analyzeVideo } from "./analyze.js";
5
+ import { errorMessage } from "./errors.js";
6
+ export const SERVER_VERSION = "0.1.0";
7
+ function failure(error) {
8
+ return {
9
+ content: [{ type: "text", text: errorMessage(error) }],
10
+ isError: true,
11
+ };
12
+ }
13
+ export function createServer() {
14
+ const server = new McpServer({
15
+ name: "agent-vision",
16
+ version: SERVER_VERSION,
17
+ });
18
+ server.registerTool("analyze_image", {
19
+ title: "Analyze image",
20
+ description: "Analyze an image from a local path, HTTP(S) URL, or base64 data URI. Use this for screenshots, UI, OCR, diagrams, photos, and visual debugging.",
21
+ inputSchema: z.object({
22
+ source: z.string().min(1).describe("Local path, HTTP(S) URL, or data:image/... URI"),
23
+ prompt: z.string().optional().describe("The user's specific question about the image"),
24
+ }),
25
+ }, async ({ source, prompt }) => {
26
+ try {
27
+ const result = await analyzeImage({ source, ...(prompt ? { prompt } : {}) });
28
+ return { content: [{ type: "text", text: result.text }] };
29
+ }
30
+ catch (error) {
31
+ return failure(error);
32
+ }
33
+ });
34
+ server.registerTool("analyze_video", {
35
+ title: "Analyze video",
36
+ description: "Analyze a local or remote video by extracting evenly spaced keyframes. Use this for screen recordings, UI flows, demos, and event summaries.",
37
+ inputSchema: z.object({
38
+ source: z.string().min(1).describe("Local path or HTTP(S) URL"),
39
+ prompt: z.string().optional().describe("The user's specific question about the video"),
40
+ max_frames: z.number().int().min(1).max(16).optional().describe("Number of frames to sample; default 8"),
41
+ }),
42
+ }, async ({ source, prompt, max_frames }) => {
43
+ try {
44
+ const result = await analyzeVideo({
45
+ source,
46
+ ...(prompt ? { prompt } : {}),
47
+ ...(max_frames ? { maxFrames: max_frames } : {}),
48
+ });
49
+ return { content: [{ type: "text", text: result.text }] };
50
+ }
51
+ catch (error) {
52
+ return failure(error);
53
+ }
54
+ });
55
+ return server;
56
+ }
57
+ export async function startStdioServer() {
58
+ const server = createServer();
59
+ const transport = new StdioServerTransport();
60
+ await server.connect(transport);
61
+ }
62
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { VisionConfig } from "./config.js";
2
+ import type { VisionInputImage } from "./provider.js";
3
+ export interface VideoFrame extends VisionInputImage {
4
+ timestampSeconds: number;
5
+ }
6
+ export declare function ensureFfmpeg(): Promise<string>;
7
+ export declare function extractVideoFrames(options: {
8
+ source: string;
9
+ maxFrames: number;
10
+ config: VisionConfig;
11
+ tempRoot?: string;
12
+ }): Promise<VideoFrame[]>;
13
+ //# sourceMappingURL=video.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"video.d.ts","sourceRoot":"","sources":["../src/video.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD,MAAM,WAAW,UAAW,SAAQ,gBAAgB;IAClD,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAoCD,wBAAgB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAkC9C;AAmGD,wBAAsB,kBAAkB,CAAC,OAAO,EAAE;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,YAAY,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAyDxB"}