mobile-device-mcp 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.
Files changed (74) hide show
  1. package/README.md +181 -0
  2. package/dist/ai/analyzer.d.ts +98 -0
  3. package/dist/ai/analyzer.d.ts.map +1 -0
  4. package/dist/ai/analyzer.js +451 -0
  5. package/dist/ai/analyzer.js.map +1 -0
  6. package/dist/ai/client.d.ts +92 -0
  7. package/dist/ai/client.d.ts.map +1 -0
  8. package/dist/ai/client.js +281 -0
  9. package/dist/ai/client.js.map +1 -0
  10. package/dist/ai/element-search.d.ts +12 -0
  11. package/dist/ai/element-search.d.ts.map +1 -0
  12. package/dist/ai/element-search.js +387 -0
  13. package/dist/ai/element-search.js.map +1 -0
  14. package/dist/ai/prompts.d.ts +27 -0
  15. package/dist/ai/prompts.d.ts.map +1 -0
  16. package/dist/ai/prompts.js +153 -0
  17. package/dist/ai/prompts.js.map +1 -0
  18. package/dist/drivers/android/adb.d.ts +21 -0
  19. package/dist/drivers/android/adb.d.ts.map +1 -0
  20. package/dist/drivers/android/adb.js +122 -0
  21. package/dist/drivers/android/adb.js.map +1 -0
  22. package/dist/drivers/android/index.d.ts +70 -0
  23. package/dist/drivers/android/index.d.ts.map +1 -0
  24. package/dist/drivers/android/index.js +529 -0
  25. package/dist/drivers/android/index.js.map +1 -0
  26. package/dist/index.d.ts +3 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +131 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/server.d.ts +13 -0
  31. package/dist/server.d.ts.map +1 -0
  32. package/dist/server.js +41 -0
  33. package/dist/server.js.map +1 -0
  34. package/dist/tools/ai-tools.d.ts +11 -0
  35. package/dist/tools/ai-tools.d.ts.map +1 -0
  36. package/dist/tools/ai-tools.js +238 -0
  37. package/dist/tools/ai-tools.js.map +1 -0
  38. package/dist/tools/app-tools.d.ts +4 -0
  39. package/dist/tools/app-tools.d.ts.map +1 -0
  40. package/dist/tools/app-tools.js +222 -0
  41. package/dist/tools/app-tools.js.map +1 -0
  42. package/dist/tools/device-tools.d.ts +4 -0
  43. package/dist/tools/device-tools.d.ts.map +1 -0
  44. package/dist/tools/device-tools.js +104 -0
  45. package/dist/tools/device-tools.js.map +1 -0
  46. package/dist/tools/index.d.ts +21 -0
  47. package/dist/tools/index.d.ts.map +1 -0
  48. package/dist/tools/index.js +30 -0
  49. package/dist/tools/index.js.map +1 -0
  50. package/dist/tools/interaction-tools.d.ts +4 -0
  51. package/dist/tools/interaction-tools.d.ts.map +1 -0
  52. package/dist/tools/interaction-tools.js +304 -0
  53. package/dist/tools/interaction-tools.js.map +1 -0
  54. package/dist/tools/log-tools.d.ts +4 -0
  55. package/dist/tools/log-tools.d.ts.map +1 -0
  56. package/dist/tools/log-tools.js +60 -0
  57. package/dist/tools/log-tools.js.map +1 -0
  58. package/dist/tools/screen-tools.d.ts +4 -0
  59. package/dist/tools/screen-tools.d.ts.map +1 -0
  60. package/dist/tools/screen-tools.js +105 -0
  61. package/dist/tools/screen-tools.js.map +1 -0
  62. package/dist/types.d.ts +219 -0
  63. package/dist/types.d.ts.map +1 -0
  64. package/dist/types.js +19 -0
  65. package/dist/types.js.map +1 -0
  66. package/dist/utils/discovery.d.ts +20 -0
  67. package/dist/utils/discovery.d.ts.map +1 -0
  68. package/dist/utils/discovery.js +156 -0
  69. package/dist/utils/discovery.js.map +1 -0
  70. package/dist/utils/image.d.ts +46 -0
  71. package/dist/utils/image.d.ts.map +1 -0
  72. package/dist/utils/image.js +170 -0
  73. package/dist/utils/image.js.map +1 -0
  74. package/package.json +69 -0
@@ -0,0 +1,281 @@
1
+ // ============================================================
2
+ // AIClient — Multi-provider SDK wrapper for visual analysis
3
+ //
4
+ // Supports both Anthropic Claude and Google Gemini, providing
5
+ // a unified interface so callers never deal with provider
6
+ // specifics.
7
+ // ============================================================
8
+ import Anthropic from "@anthropic-ai/sdk";
9
+ import { GoogleGenerativeAI } from "@google/generative-ai";
10
+ /** Default delay (ms) before a manual retry for retryable errors. */
11
+ const RETRY_DELAY_MS = 2_000;
12
+ /** Maximum number of retries for rate-limit errors. */
13
+ const MAX_RETRIES = 3;
14
+ /** Per-request timeout in milliseconds. */
15
+ const REQUEST_TIMEOUT_MS = 60_000;
16
+ /**
17
+ * Wraps both the Anthropic and Google Generative AI SDKs for all
18
+ * AI visual-analysis features.
19
+ *
20
+ * Create one instance and reuse it — the underlying HTTP client is
21
+ * allocated once in the constructor.
22
+ */
23
+ export class AIClient {
24
+ anthropicClient;
25
+ geminiModel;
26
+ config;
27
+ constructor(config) {
28
+ this.config = config;
29
+ if (config.provider === "google") {
30
+ const genAI = new GoogleGenerativeAI(config.apiKey);
31
+ this.geminiModel = genAI.getGenerativeModel({ model: config.model });
32
+ }
33
+ else {
34
+ // Default: Anthropic
35
+ this.anthropicClient = new Anthropic({
36
+ apiKey: config.apiKey || undefined,
37
+ maxRetries: 1,
38
+ timeout: REQUEST_TIMEOUT_MS,
39
+ });
40
+ }
41
+ }
42
+ // ------------------------------------------------------------------
43
+ // Public API
44
+ // ------------------------------------------------------------------
45
+ /**
46
+ * Returns `true` when a non-empty API key has been configured,
47
+ * meaning AI features can be used.
48
+ */
49
+ isAvailable() {
50
+ return typeof this.config.apiKey === "string" && this.config.apiKey.length > 0;
51
+ }
52
+ /**
53
+ * Send a prompt (with an optional screenshot) to the configured
54
+ * AI provider and return the plain-text response.
55
+ */
56
+ async analyze(options) {
57
+ this.assertAvailable();
58
+ if (this.config.provider === "google") {
59
+ return this.analyzeWithGemini(options);
60
+ }
61
+ return this.analyzeWithAnthropic(options);
62
+ }
63
+ /**
64
+ * Convenience wrapper: call {@link analyze}, then parse the response
65
+ * as JSON. Handles responses wrapped in markdown code fences.
66
+ */
67
+ async analyzeJSON(options) {
68
+ const raw = await this.analyze(options);
69
+ return this.parseJSON(raw);
70
+ }
71
+ // ------------------------------------------------------------------
72
+ // Anthropic implementation
73
+ // ------------------------------------------------------------------
74
+ async analyzeWithAnthropic(options) {
75
+ const { systemPrompt, userPrompt, screenshot, screenshotMimeType = "image/png", maxTokens = this.config.maxTokens, } = options;
76
+ const content = this.buildAnthropicContent(userPrompt, screenshot, screenshotMimeType);
77
+ const request = {
78
+ model: this.config.model,
79
+ max_tokens: maxTokens,
80
+ system: systemPrompt,
81
+ messages: [{ role: "user", content }],
82
+ };
83
+ const response = await this.createWithRetryAnthropic(request);
84
+ return this.extractAnthropicText(response);
85
+ }
86
+ /**
87
+ * Build the `content` array for the Anthropic user message.
88
+ */
89
+ buildAnthropicContent(text, screenshot, mimeType) {
90
+ if (!screenshot) {
91
+ return [{ type: "text", text }];
92
+ }
93
+ return [
94
+ {
95
+ type: "image",
96
+ source: {
97
+ type: "base64",
98
+ media_type: mimeType,
99
+ data: screenshot,
100
+ },
101
+ },
102
+ { type: "text", text },
103
+ ];
104
+ }
105
+ /**
106
+ * Call `messages.create` with a single manual retry for 429 / 529.
107
+ */
108
+ async createWithRetryAnthropic(request) {
109
+ const client = this.anthropicClient;
110
+ try {
111
+ return await client.messages.create(request);
112
+ }
113
+ catch (error) {
114
+ if (this.isRetryableAnthropic(error)) {
115
+ await this.delay(RETRY_DELAY_MS);
116
+ return await client.messages.create(request);
117
+ }
118
+ throw this.wrapError(error);
119
+ }
120
+ }
121
+ /**
122
+ * Determine whether an Anthropic error is a retryable 429 or 529.
123
+ */
124
+ isRetryableAnthropic(error) {
125
+ if (error instanceof Anthropic.APIError) {
126
+ const status = error.status;
127
+ return status === 429 || status === 529;
128
+ }
129
+ return false;
130
+ }
131
+ /**
132
+ * Extract the text content from the first Anthropic content block.
133
+ */
134
+ extractAnthropicText(response) {
135
+ if (!response.content || response.content.length === 0) {
136
+ throw new Error("AI returned an empty response with no content blocks.");
137
+ }
138
+ const block = response.content[0];
139
+ if (block.type === "text") {
140
+ return block.text;
141
+ }
142
+ throw new Error(`Expected a text content block but received type "${block.type}".`);
143
+ }
144
+ // ------------------------------------------------------------------
145
+ // Google Gemini implementation
146
+ // ------------------------------------------------------------------
147
+ async analyzeWithGemini(options) {
148
+ const { systemPrompt, userPrompt, screenshot, screenshotMimeType = "image/png", } = options;
149
+ const parts = [];
150
+ if (screenshot) {
151
+ parts.push({
152
+ inlineData: { mimeType: screenshotMimeType, data: screenshot },
153
+ });
154
+ }
155
+ parts.push({ text: userPrompt });
156
+ return this.createWithRetryGemini(systemPrompt, parts);
157
+ }
158
+ /**
159
+ * Call Gemini generateContent with retries for 429 / 503 errors.
160
+ * Parses the RetryInfo delay from Google API error messages.
161
+ */
162
+ async createWithRetryGemini(systemPrompt, parts) {
163
+ const model = this.geminiModel;
164
+ const request = {
165
+ systemInstruction: systemPrompt,
166
+ contents: [{ role: "user", parts }],
167
+ };
168
+ let lastError;
169
+ for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
170
+ try {
171
+ const result = await model.generateContent(request);
172
+ return result.response.text();
173
+ }
174
+ catch (error) {
175
+ lastError = error;
176
+ if (attempt < MAX_RETRIES && this.isRetryableGemini(error)) {
177
+ const retryDelay = this.extractRetryDelay(error) || RETRY_DELAY_MS * (attempt + 1);
178
+ await this.delay(retryDelay);
179
+ continue;
180
+ }
181
+ throw this.wrapError(error);
182
+ }
183
+ }
184
+ throw this.wrapError(lastError);
185
+ }
186
+ /**
187
+ * Determine whether a Google API error is retryable (429 / 503).
188
+ */
189
+ isRetryableGemini(error) {
190
+ if (error instanceof Error) {
191
+ const message = error.message || "";
192
+ // Google SDK errors include status codes in the message
193
+ return message.includes("429") || message.includes("503");
194
+ }
195
+ return false;
196
+ }
197
+ /**
198
+ * Extract the retry delay (in ms) from a Google API error message.
199
+ * Looks for patterns like 'retryDelay":"23s"' or 'Please retry in 23.2s'.
200
+ */
201
+ extractRetryDelay(error) {
202
+ if (!(error instanceof Error))
203
+ return null;
204
+ const msg = error.message || "";
205
+ // Try "Please retry in Xs" pattern
206
+ const retryInMatch = msg.match(/Please retry in (\d+(?:\.\d+)?)s/);
207
+ if (retryInMatch) {
208
+ return Math.ceil(parseFloat(retryInMatch[1]) * 1000) + 1000; // add 1s buffer
209
+ }
210
+ // Try "retryDelay":"Xs" pattern
211
+ const retryDelayMatch = msg.match(/"retryDelay"\s*:\s*"(\d+)s"/);
212
+ if (retryDelayMatch) {
213
+ return parseInt(retryDelayMatch[1], 10) * 1000 + 1000;
214
+ }
215
+ return null;
216
+ }
217
+ // ------------------------------------------------------------------
218
+ // Shared internals
219
+ // ------------------------------------------------------------------
220
+ /**
221
+ * Throw immediately when the API key is absent so callers get a
222
+ * clear message instead of an opaque 401.
223
+ */
224
+ assertAvailable() {
225
+ if (!this.isAvailable()) {
226
+ throw new Error("AI API key not set. AI features require a valid API key.");
227
+ }
228
+ }
229
+ /**
230
+ * Parse a string as JSON, stripping markdown code fences if present.
231
+ */
232
+ parseJSON(raw) {
233
+ // First, try a direct parse — covers well-behaved responses.
234
+ try {
235
+ return JSON.parse(raw);
236
+ }
237
+ catch {
238
+ // Fall through to extraction attempts.
239
+ }
240
+ // Try extracting from fenced code blocks: ```json ... ``` or ``` ... ```
241
+ const fenceMatch = raw.match(/```(?:json)?\s*\n?([\s\S]*?)```/);
242
+ if (fenceMatch) {
243
+ try {
244
+ return JSON.parse(fenceMatch[1].trim());
245
+ }
246
+ catch {
247
+ // Fall through.
248
+ }
249
+ }
250
+ // Last resort: look for the first { ... } or [ ... ] block.
251
+ const objectMatch = raw.match(/(\{[\s\S]*\}|\[[\s\S]*\])/);
252
+ if (objectMatch) {
253
+ try {
254
+ return JSON.parse(objectMatch[1]);
255
+ }
256
+ catch {
257
+ // Fall through.
258
+ }
259
+ }
260
+ throw new Error(`Failed to parse AI response as JSON. Raw response:\n${raw.slice(0, 500)}`);
261
+ }
262
+ /**
263
+ * Wrap unknown errors into Error instances with descriptive messages.
264
+ */
265
+ wrapError(error) {
266
+ if (error instanceof Anthropic.APIError) {
267
+ return new Error(`Anthropic API error (${error.status}): ${error.message}`);
268
+ }
269
+ if (error instanceof Error) {
270
+ return error;
271
+ }
272
+ return new Error(`Unexpected AI client error: ${String(error)}`);
273
+ }
274
+ /**
275
+ * Promise-based delay helper.
276
+ */
277
+ delay(ms) {
278
+ return new Promise((resolve) => setTimeout(resolve, ms));
279
+ }
280
+ }
281
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/ai/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { UIElement, ElementMatch } from "../types.js";
2
+ /**
3
+ * Search UI elements locally by text matching.
4
+ * This is INSTANT and FREE — no AI API call needed.
5
+ * Falls back to AI only when local search fails (returns found: false).
6
+ *
7
+ * @param elements - The UI element tree from the device
8
+ * @param query - Natural language query like "the number 7 button"
9
+ * @returns An ElementMatch result compatible with AI findElement output
10
+ */
11
+ export declare function searchElementsLocally(elements: UIElement[], query: string): ElementMatch;
12
+ //# sourceMappingURL=element-search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"element-search.d.ts","sourceRoot":"","sources":["../../src/ai/element-search.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAmB,MAAM,aAAa,CAAC;AAgY5E;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,SAAS,EAAE,EACrB,KAAK,EAAE,MAAM,GACZ,YAAY,CAiDd"}