@extentos/mcp-server 0.0.67 → 0.0.68

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.
@@ -1 +1 @@
1
- {"version":3,"file":"capabilityPatterns.d.ts","sourceRoot":"","sources":["../../../src/tools/data/capabilityPatterns.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAySD,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAS7D,CAAC;AAEF,eAAO,MAAM,yBAAyB,UAAwC,CAAC"}
1
+ {"version":3,"file":"capabilityPatterns.d.ts","sourceRoot":"","sources":["../../../src/tools/data/capabilityPatterns.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAiTD,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAS7D,CAAC;AAEF,eAAO,MAAM,yBAAyB,UAAwC,CAAC"}
@@ -11,16 +11,22 @@ const CAPTURE_PHOTO = {
11
11
  feature: "capture_photo",
12
12
  summary: "One-shot still photo from the glasses camera. Returns a Photo with `uri` (transport-shaped — data: in BrowserSim, file: in RealMeta / LocalSim), width, height, format.",
13
13
  kotlin: `import com.extentos.glasses.core.PhotoConfig
14
+ import com.extentos.glasses.core.PhotoFormat
14
15
  import com.extentos.glasses.core.Photos
16
+ import com.extentos.glasses.core.Resolution
15
17
  import com.extentos.glasses.core.valueOrNull
16
18
 
17
19
  val photo = glasses.camera.capturePhoto(
18
- PhotoConfig(resolution = "MEDIUM", format = "jpeg")
20
+ PhotoConfig(resolution = Resolution.MEDIUM, format = PhotoFormat.JPEG)
19
21
  ).valueOrNull() ?: return // ExtentosResult.Err — see Errors.kt for failure shapes
20
22
 
21
- // Pass to a vision LLM (Anthropic Claude Vision / OpenAI GPT-4V):
22
- val base64 = Photos.loadBase64(photo.uri)
23
- val mediaType = Photos.mediaTypeFromUri(photo.uri) // "image/jpeg"`,
23
+ // Photo.uri is nullable (library shape a successful capture can still
24
+ // return a Photo whose URI got dropped at the transport boundary). Null-
25
+ // check before passing to the Photos helpers; loadBase64 / mediaTypeFromUri
26
+ // both require non-null String.
27
+ val uri = photo.uri ?: return
28
+ val base64 = Photos.loadBase64(uri)
29
+ val mediaType = Photos.mediaTypeFromUri(uri) // "image/jpeg"`,
24
30
  swift: `let result = await glasses.camera.capturePhoto(
25
31
  config: PhotoConfig(resolution: .medium, format: .jpeg)
26
32
  )
@@ -34,6 +40,8 @@ let image = await photo.loadImage()
34
40
  let base64 = image?.jpegData(compressionQuality: 0.85)?.base64EncodedString()
35
41
  let mediaType = "image/jpeg"`,
36
42
  gotchas: [
43
+ "PhotoConfig takes TYPED ENUMS, not strings: `PhotoConfig(resolution = Resolution.MEDIUM, format = PhotoFormat.JPEG)`. Resolution enum: LOW, MEDIUM, HIGH. PhotoFormat enum: JPEG, HEIC. Both live in com.extentos.glasses.core (flat package — see library_api topic).",
44
+ "Photo.uri is `String?` (nullable). The Photos helpers (loadBase64 / loadBytes / loadBitmap / mediaTypeFromUri) require non-null String. Null-check `photo.uri` before passing.",
37
45
  "Photo URI shape varies by transport (data: vs file:). Use Photos.loadBase64(uri) helpers to bridge — don't try to AsyncImage / URL.init() the URI directly.",
38
46
  "Resolution HIGH adds ~400ms latency on Gen 1 hardware vs MEDIUM. MEDIUM is the right default; only use HIGH for downstream models that genuinely need detail.",
39
47
  "Capture blocks while outgoing_video_stream is active (camera exclusivity). If both are needed, set audio_video_coexistence_policy = prefer_video.",
@@ -1 +1 @@
1
- {"version":3,"file":"capabilityPatterns.js","sourceRoot":"","sources":["../../../src/tools/data/capabilityPatterns.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,iEAAiE;AACjE,+DAA+D;AAC/D,iCAAiC;AACjC,EAAE;AACF,iEAAiE;AACjE,qEAAqE;AACrE,mEAAmE;AACnE,0CAA0C;AAW1C,MAAM,aAAa,GAAoB;IACrC,OAAO,EAAE,eAAe;IACxB,OAAO,EACL,yKAAyK;IAC3K,MAAM,EAAE;;;;;;;;;;oEAU0D;IAClE,KAAK,EAAE;;;;;;;;;;;6BAWoB;IAC3B,OAAO,EAAE;QACP,6JAA6J;QAC7J,+JAA+J;QAC/J,mJAAmJ;QACnJ,kJAAkJ;KACnJ;IACD,eAAe,EAAE,CAAC,sBAAsB,CAAC;CAC1C,CAAC;AAEF,MAAM,YAAY,GAAoB;IACpC,OAAO,EAAE,cAAc;IACvB,OAAO,EACL,qPAAqP;IACvP,MAAM,EAAE;;;;;;;;;;;yDAW+C;IACvD,KAAK,EAAE;;;;;;;;;gCASuB;IAC9B,OAAO,EAAE;QACP,kJAAkJ;QAClJ,wIAAwI;QACxI,iJAAiJ;QACjJ,oIAAoI;QACpI,wFAAwF;KACzF;IACD,eAAe,EAAE,CAAC,oBAAoB,EAAE,aAAa,CAAC;CACvD,CAAC;AAEF,MAAM,yBAAyB,GAAoB;IACjD,OAAO,EAAE,2BAA2B;IACpC,OAAO,EACL,wIAAwI;IAC1I,MAAM,EAAE;;;;;;;;;;;;EAYR;IACA,KAAK,EAAE;;;;;;;;;EASP;IACA,OAAO,EAAE;QACP,kQAAkQ;QAClQ,qOAAqO;QACrO,uKAAuK;QACvK,4MAA4M;QAC5M,8JAA8J;KAC/J;IACD,eAAe,EAAE,CAAC,oBAAoB,EAAE,uBAAuB,EAAE,aAAa,EAAE,sBAAsB,CAAC;CACxG,CAAC;AAEF,MAAM,gBAAgB,GAAoB;IACxC,OAAO,EAAE,OAAO;IAChB,OAAO,EACL,2KAA2K;IAC7K,MAAM,EAAE;;;;;;;aAOG;IACX,KAAK,EAAE;;;;;;;;cAQK;IACZ,OAAO,EAAE;QACP,gJAAgJ;QAChJ,wKAAwK;QACxK,+LAA+L;QAC/L,kHAAkH;KACnH;IACD,eAAe,EAAE,CAAC,oBAAoB,EAAE,gBAAgB,EAAE,aAAa,EAAE,sBAAsB,CAAC;CACjG,CAAC;AAEF,MAAM,YAAY,GAAoB;IACpC,OAAO,EAAE,cAAc;IACvB,OAAO,EACL,4LAA4L;IAC9L,MAAM,EAAE;;;;;;;;;EASR;IACA,KAAK,EAAE;;;;;;;;;EASP;IACA,OAAO,EAAE;QACP,+LAA+L;QAC/L,+IAA+I;QAC/I,+HAA+H;QAC/H,gHAAgH;KACjH;IACD,eAAe,EAAE,EAAE;CACpB,CAAC;AAEF,MAAM,YAAY,GAAoB;IACpC,OAAO,EAAE,cAAc;IACvB,OAAO,EACL,yJAAyJ;IAC3J,MAAM,EAAE;;;;;;;EAOR;IACA,KAAK,EAAE;;;;;;;EAOP;IACA,OAAO,EAAE;QACP,kJAAkJ;QAClJ,sHAAsH;QACtH,2GAA2G;QAC3G,uJAAuJ;KACxJ;IACD,eAAe,EAAE,EAAE;CACpB,CAAC;AAEF,MAAM,gBAAgB,GAAoB;IACxC,OAAO,EAAE,kBAAkB;IAC3B,OAAO,EACL,2MAA2M;IAC7M,MAAM,EAAE;;;;;;;;;EASR;IACA,KAAK,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8BP;IACA,OAAO,EAAE;QACP,2JAA2J;QAC3J,uPAAuP;KACxP;IACD,eAAe,EAAE,CAAC,uBAAuB,CAAC;CAC3C,CAAC;AAEF,MAAM,OAAO,GAAoB;IAC/B,OAAO,EAAE,SAAS;IAClB,OAAO,EACL,0SAA0S;IAC5S,MAAM,EAAE;;;;;;mFAMyE;IACjF,KAAK,EAAE;;;;;;;;;;;;;;;;;;;;;EAqBP;IACA,OAAO,EAAE;QACP,6MAA6M;QAC7M,4JAA4J;QAC5J,kHAAkH;QAClH,4JAA4J;KAC7J;IACD,eAAe,EAAE,EAAE;CACpB,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAoC;IAChE,aAAa,EAAE,aAAa;IAC5B,YAAY,EAAE,YAAY;IAC1B,yBAAyB,EAAE,yBAAyB;IACpD,KAAK,EAAE,gBAAgB;IACvB,YAAY,EAAE,YAAY;IAC1B,YAAY,EAAE,YAAY;IAC1B,gBAAgB,EAAE,gBAAgB;IAClC,OAAO,EAAE,OAAO;CACjB,CAAC;AAEF,MAAM,CAAC,MAAM,yBAAyB,GAAG,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,IAAI,EAAE,CAAC"}
1
+ {"version":3,"file":"capabilityPatterns.js","sourceRoot":"","sources":["../../../src/tools/data/capabilityPatterns.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"codeExamples.d.ts","sourceRoot":"","sources":["../../../src/tools/data/codeExamples.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE;QACJ,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAqoBD,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAQrD,CAAC;AAEF,eAAO,MAAM,qBAAqB,UAAoC,CAAC"}
1
+ {"version":3,"file":"codeExamples.d.ts","sourceRoot":"","sources":["../../../src/tools/data/codeExamples.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE;QACJ,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AA6zBD,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAQrD,CAAC;AAEF,eAAO,MAAM,qBAAqB,UAAoC,CAAC"}
@@ -196,12 +196,15 @@ const PHOTO_DESCRIBE_VOICE = {
196
196
  code: {
197
197
  kotlin: `import com.extentos.glasses.core.ExtentosGlasses
198
198
  import com.extentos.glasses.core.PhotoConfig
199
+ import com.extentos.glasses.core.PhotoFormat
200
+ import com.extentos.glasses.core.Photos
201
+ import com.extentos.glasses.core.Resolution
199
202
  import com.extentos.glasses.core.Transcript
200
203
  import com.extentos.glasses.core.valueOrNull
201
204
 
202
205
  class VisionHandler(
203
206
  private val glasses: ExtentosGlasses,
204
- private val vision: VisionClient, // USER PROVIDES — your vision-LLM wrapper
207
+ private val vision: VisionClient, // USER PROVIDES — see getCodeExample('byok_anthropic') for the canonical Vision client
205
208
  ) {
206
209
  private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
207
210
 
@@ -211,14 +214,24 @@ class VisionHandler(
211
214
  if ("describe what you see" !in t.text.lowercase()) return@collect
212
215
 
213
216
  val photo = glasses.camera.capturePhoto(
214
- PhotoConfig(resolution = "MEDIUM", format = "jpeg")
217
+ PhotoConfig(resolution = Resolution.MEDIUM, format = PhotoFormat.JPEG)
215
218
  ).valueOrNull() ?: run {
216
219
  glasses.audio.speak("I couldn't take a photo.")
217
220
  return@collect
218
221
  }
222
+ val uri = photo.uri ?: run {
223
+ glasses.audio.speak("Photo had no URI.")
224
+ return@collect
225
+ }
226
+ val base64 = Photos.loadBase64(uri) ?: run {
227
+ glasses.audio.speak("Couldn't decode the photo.")
228
+ return@collect
229
+ }
230
+ val mediaType = Photos.mediaTypeFromUri(uri) ?: "image/jpeg"
219
231
 
220
232
  val description = vision.describe(
221
- imageUri = photo.uri,
233
+ imageBase64 = base64,
234
+ mediaType = mediaType,
222
235
  prompt = "Describe this scene briefly, conversationally.",
223
236
  )
224
237
  glasses.audio.speak(description.ifBlank { "I couldn't describe that one." })
@@ -274,9 +287,12 @@ class VisionHandler(
274
287
  },
275
288
  explanation: "Voice wake → photo capture → vision LLM → spoken response. The photo URL shape varies by transport (data: in BrowserSim, file: in RealMeta + LocalSim). Android consumers use Photos.loadBase64(uri) / Photos.mediaTypeFromUri(uri) helpers; iOS consumers use the bundled `photo.loadImage()` extension on Photo to materialize a UIImage from either scheme.",
276
289
  gotchas: [
290
+ "PhotoConfig takes TYPED ENUMS: `PhotoConfig(resolution = Resolution.MEDIUM, format = PhotoFormat.JPEG)`. Not strings. Same enum types live in com.extentos.glasses.core — see getCapabilityGuide('capture_photo') for the full call shape.",
291
+ "Photo.uri is nullable — guard before passing to Photos.loadBase64 / mediaTypeFromUri. A successful capture can still return a Photo with no URI at the transport boundary.",
277
292
  "capturePhoto blocks until the photo is captured (~300-500ms on Meta DAT). Don't call it on a UI thread.",
278
293
  "Android: Photos.loadBase64(uri) bridges both data: and file: URIs into bytes ready for Claude Vision / GPT-4V request bodies. iOS: `photo.loadImage()` (extension on Photo) returns a UIImage; for base64 you encode the JPEG/PNG data yourself via Data.base64EncodedString().",
279
- "Vision LLM response time is 2-8 seconds p95; the user is staring at the glasses waiting. Consider an earcon at capture time so they know it worked.",
294
+ "Vision LLM response time is 2-8 seconds p95; the user is staring at the glasses waiting. Consider an earcon (`glasses.audio.earcon(EarconSound.START)`) at capture time so they know it worked.",
295
+ "VisionClient is a USER-PROVIDED stub — see getCodeExample('byok_anthropic') for the canonical Anthropic Claude Vision wrapper (request shape: content blocks with type:image / source:base64 + type:text). The byok_anthropic pattern is paste-ready in both Kotlin and Swift.",
280
296
  ],
281
297
  relatedFeatures: ["capture_photo", "voice_command", "transcription_incremental"],
282
298
  };
@@ -510,13 +526,15 @@ struct ContentView: View {
510
526
  };
511
527
  const BYOK_ANTHROPIC = {
512
528
  pattern: "byok_anthropic",
513
- title: "BYOK Anthropic Claude API client (minimal OkHttp / URLSession)",
514
- description: "Minimal AnthropicClient that voice_qa_assistant and photo_describe_voice reference. There is no first-party Anthropic Kotlin SDK; this is the canonical OkHttp + kotlinx.serialization wrapper around POST /v1/messages. iOS uses URLSession + Codable. Paste, then wire the API key through resValue (Android) / Info.plist (iOS) per getCredentialGuide.",
529
+ title: "BYOK Anthropic Claude API client (text + Vision, OkHttp / URLSession)",
530
+ description: "Minimal AnthropicClient that voice_qa_assistant and photo_describe_voice reference. Two methods: `ask(question, history)` for text-only Q&A, `describe(imageBase64, mediaType, prompt)` for Claude Vision (image content blocks). There is no first-party Anthropic Kotlin SDK; this is the canonical OkHttp + kotlinx.serialization wrapper around POST /v1/messages. iOS uses URLSession + Codable. Paste, then wire the API key through resValue (Android) / Info.plist (iOS) per getCredentialGuide.",
515
531
  code: {
516
532
  kotlin: `import kotlinx.coroutines.Dispatchers
517
533
  import kotlinx.coroutines.withContext
534
+ import kotlinx.serialization.SerialName
518
535
  import kotlinx.serialization.Serializable
519
536
  import kotlinx.serialization.json.Json
537
+ import kotlinx.serialization.json.JsonClassDiscriminator
520
538
  import okhttp3.MediaType.Companion.toMediaType
521
539
  import okhttp3.OkHttpClient
522
540
  import okhttp3.Request
@@ -533,20 +551,83 @@ class AnthropicClient(
533
551
  private val maxTokens: Int = 1024,
534
552
  private val client: OkHttpClient = OkHttpClient(),
535
553
  ) {
536
- private val json = Json { ignoreUnknownKeys = true }
554
+ private val json = Json { ignoreUnknownKeys = true; encodeDefaults = true }
555
+
556
+ // ---- Wire schema ----
557
+
558
+ @Serializable
559
+ private data class ImageSource(
560
+ val type: String = "base64",
561
+ @SerialName("media_type") val mediaType: String,
562
+ val data: String,
563
+ )
564
+
565
+ @OptIn(kotlinx.serialization.ExperimentalSerializationApi::class)
566
+ @JsonClassDiscriminator("type")
567
+ @Serializable
568
+ private sealed interface ContentBlock {
569
+ @Serializable @SerialName("text") data class Text(val text: String) : ContentBlock
570
+ @Serializable @SerialName("image") data class Image(val source: ImageSource) : ContentBlock
571
+ }
572
+
573
+ @Serializable
574
+ private data class Message(val role: String, val content: List<ContentBlock>)
575
+
576
+ @Serializable
577
+ private data class Req(
578
+ val model: String,
579
+ @SerialName("max_tokens") val maxTokens: Int,
580
+ val messages: List<Message>,
581
+ val system: String? = null,
582
+ )
537
583
 
538
- @Serializable private data class Msg(val role: String, val content: String)
539
- @Serializable private data class Req(val model: String, val max_tokens: Int, val messages: List<Msg>)
540
584
  @Serializable private data class ResBlock(val type: String, val text: String? = null)
541
585
  @Serializable private data class Res(val content: List<ResBlock>)
542
586
 
587
+ // ---- Public API ----
588
+
589
+ /** Text-only Q&A. Anthropic's content field accepts either a bare String or a
590
+ * list of ContentBlock; we use the list shape so this client can also do Vision. */
543
591
  suspend fun ask(question: String, history: List<String> = emptyList()): String =
592
+ post(
593
+ messages = buildList {
594
+ for (turn in history) {
595
+ add(Message("user", listOf(ContentBlock.Text(turn))))
596
+ }
597
+ add(Message("user", listOf(ContentBlock.Text(question))))
598
+ },
599
+ )
600
+
601
+ /** Vision: send one image (base64) + a text prompt. Use Photos.loadBase64(uri) and
602
+ * Photos.mediaTypeFromUri(uri) (from com.extentos.glasses.core.Photos) to source
603
+ * the imageBase64 + mediaType from a Photo returned by glasses.camera.capturePhoto(). */
604
+ suspend fun describe(
605
+ imageBase64: String,
606
+ mediaType: String,
607
+ prompt: String,
608
+ system: String? = null,
609
+ ): String = post(
610
+ messages = listOf(
611
+ Message(
612
+ "user",
613
+ listOf(
614
+ ContentBlock.Image(ImageSource(mediaType = mediaType, data = imageBase64)),
615
+ ContentBlock.Text(prompt),
616
+ ),
617
+ ),
618
+ ),
619
+ system = system,
620
+ )
621
+
622
+ // ---- Transport ----
623
+
624
+ private suspend fun post(messages: List<Message>, system: String? = null): String =
544
625
  withContext(Dispatchers.IO) {
545
- val msgs = buildList {
546
- for (turn in history) add(Msg("user", turn))
547
- add(Msg("user", question))
548
- }
549
- val body = json.encodeToString(Req.serializer(), Req(model, maxTokens, msgs))
626
+ if (apiKey.isBlank()) return@withContext ""
627
+ val body = json.encodeToString(
628
+ Req.serializer(),
629
+ Req(model = model, maxTokens = maxTokens, messages = messages, system = system),
630
+ )
550
631
  val request = Request.Builder()
551
632
  .url("https://api.anthropic.com/v1/messages")
552
633
  .header("x-api-key", apiKey)
@@ -555,22 +636,36 @@ class AnthropicClient(
555
636
  .post(body.toRequestBody("application/json".toMediaType()))
556
637
  .build()
557
638
  client.newCall(request).execute().use { response ->
558
- val payload = response.body?.string() ?: error("empty response body")
559
- if (!response.isSuccessful) error("Anthropic HTTP \${response.code}: \$payload")
639
+ val payload = response.body?.string() ?: return@withContext ""
640
+ if (!response.isSuccessful) {
641
+ android.util.Log.w("AnthropicClient", "HTTP \${response.code}: \${payload.take(500)}")
642
+ return@withContext ""
643
+ }
560
644
  json.decodeFromString(Res.serializer(), payload)
561
- .content.firstOrNull { it.type == "text" }?.text ?: ""
645
+ .content.firstOrNull { it.type == "text" }?.text.orEmpty().trim()
562
646
  }
563
647
  }
564
648
  }
565
649
 
566
650
  // Wire-up — your handler retrieves the API key from the resource string
567
- // emitted by your build.gradle.kts (see getCredentialGuide for the
568
- // resValue pattern), then passes it to a single client instance held
569
- // at Application scope:
651
+ // emitted by your build.gradle.kts (see getCredentialGuide('anthropic')
652
+ // for the resValue pattern), then passes it to a single client instance
653
+ // held at Application scope:
570
654
  //
571
655
  // val apiKey = context.getString(R.string.anthropic_api_key)
572
656
  // val anthropic = AnthropicClient(apiKey)
573
- // val answer = anthropic.ask("How many bench reps did I do today?")`,
657
+ //
658
+ // // text:
659
+ // val answer = anthropic.ask("How many bench reps did I do today?")
660
+ //
661
+ // // vision (paired with capture_photo + Photos helpers):
662
+ // val photo = glasses.camera.capturePhoto(
663
+ // PhotoConfig(resolution = Resolution.MEDIUM, format = PhotoFormat.JPEG)
664
+ // ).valueOrNull() ?: return
665
+ // val uri = photo.uri ?: return
666
+ // val b64 = Photos.loadBase64(uri) ?: return
667
+ // val mt = Photos.mediaTypeFromUri(uri) ?: "image/jpeg"
668
+ // val answer = anthropic.describe(b64, mt, "What card is showing?")`,
574
669
  swift: `import Foundation
575
670
 
576
671
  actor AnthropicClient {
@@ -585,17 +680,88 @@ actor AnthropicClient {
585
680
  self.maxTokens = maxTokens
586
681
  }
587
682
 
588
- private struct Msg: Codable { let role: String; let content: String }
589
- private struct Req: Codable { let model: String; let max_tokens: Int; let messages: [Msg] }
683
+ // ---- Wire schema ----
684
+
685
+ private struct ImageSource: Codable {
686
+ let type: String // "base64"
687
+ let media_type: String
688
+ let data: String
689
+ }
690
+
691
+ private enum ContentBlock: Codable {
692
+ case text(String)
693
+ case image(ImageSource)
694
+
695
+ private struct TextWire: Codable { let type: String; let text: String }
696
+ private struct ImageWire: Codable { let type: String; let source: ImageSource }
697
+
698
+ func encode(to encoder: Encoder) throws {
699
+ switch self {
700
+ case .text(let t):
701
+ try TextWire(type: "text", text: t).encode(to: encoder)
702
+ case .image(let s):
703
+ try ImageWire(type: "image", source: s).encode(to: encoder)
704
+ }
705
+ }
706
+
707
+ init(from decoder: Decoder) throws {
708
+ // Anthropic responses don't echo image blocks; only text comes back.
709
+ let wire = try TextWire(from: decoder)
710
+ self = .text(wire.text)
711
+ }
712
+ }
713
+
714
+ private struct Message: Codable { let role: String; let content: [ContentBlock] }
715
+ private struct Req: Codable {
716
+ let model: String
717
+ let max_tokens: Int
718
+ let messages: [Message]
719
+ let system: String?
720
+ }
590
721
  private struct ResBlock: Codable { let type: String; let text: String? }
591
722
  private struct Res: Codable { let content: [ResBlock] }
592
723
 
724
+ // ---- Public API ----
725
+
726
+ /// Text-only Q&A.
593
727
  func ask(question: String, history: [String] = []) async throws -> String {
594
- var msgs = history.map { Msg(role: "user", content: $0) }
595
- msgs.append(Msg(role: "user", content: question))
728
+ var messages = history.map {
729
+ Message(role: "user", content: [.text($0)])
730
+ }
731
+ messages.append(Message(role: "user", content: [.text(question)]))
732
+ return try await post(messages: messages, system: nil)
733
+ }
734
+
735
+ /// Vision: one image (base64) + a text prompt. Source the imageBase64 +
736
+ /// mediaType from a Photo returned by glasses.camera.capturePhoto() and
737
+ /// the photo.loadImage() / data extraction helpers in com.extentos.glasses.core.
738
+ func describe(
739
+ imageBase64: String,
740
+ mediaType: String,
741
+ prompt: String,
742
+ system: String? = nil,
743
+ ) async throws -> String {
744
+ let messages = [
745
+ Message(
746
+ role: "user",
747
+ content: [
748
+ .image(ImageSource(type: "base64", media_type: mediaType, data: imageBase64)),
749
+ .text(prompt),
750
+ ],
751
+ ),
752
+ ]
753
+ return try await post(messages: messages, system: system)
754
+ }
755
+
756
+ // ---- Transport ----
757
+
758
+ private func post(messages: [Message], system: String?) async throws -> String {
759
+ guard !apiKey.isEmpty else { return "" }
596
760
  var request = URLRequest(url: endpoint)
597
761
  request.httpMethod = "POST"
598
- request.httpBody = try JSONEncoder().encode(Req(model: model, max_tokens: maxTokens, messages: msgs))
762
+ request.httpBody = try JSONEncoder().encode(
763
+ Req(model: model, max_tokens: maxTokens, messages: messages, system: system)
764
+ )
599
765
  request.setValue(apiKey, forHTTPHeaderField: "x-api-key")
600
766
  request.setValue("2023-06-01", forHTTPHeaderField: "anthropic-version")
601
767
  request.setValue("application/json", forHTTPHeaderField: "content-type")
@@ -620,17 +786,35 @@ actor AnthropicClient {
620
786
  //
621
787
  // let key = Bundle.main.object(forInfoDictionaryKey: "ANTHROPIC_API_KEY") as? String ?? ""
622
788
  // let anthropic = AnthropicClient(apiKey: key)
623
- // let answer = try await anthropic.ask(question: "How many bench reps today?")`,
789
+ //
790
+ // // text:
791
+ // let answer = try await anthropic.ask(question: "How many bench reps today?")
792
+ //
793
+ // // vision (paired with capture_photo + photo.loadImage helpers):
794
+ // let result = await glasses.camera.capturePhoto(
795
+ // config: PhotoConfig(resolution: .medium, format: .jpeg)
796
+ // )
797
+ // guard case .success(let photo) = result else { return }
798
+ // guard let image = await photo.loadImage(),
799
+ // let jpeg = image.jpegData(compressionQuality: 0.85) else { return }
800
+ // let b64 = jpeg.base64EncodedString()
801
+ // let answer = try await anthropic.describe(
802
+ // imageBase64: b64,
803
+ // mediaType: "image/jpeg",
804
+ // prompt: "What's the next blackjack move?"
805
+ // )`,
624
806
  },
625
- explanation: "Minimal direct client. There's no first-party Anthropic Kotlin SDK; this is the wire-protocol wrapper voice_qa_assistant and photo_describe_voice patterns reference as `AnthropicClient`. Kotlin uses OkHttp + kotlinx-serialization (both small, both already common in Android apps). Swift uses URLSession + Codable (no external dependencies). The customer holds one instance at Application scope and passes it to handlers via DI.",
807
+ explanation: "Minimal direct client supporting BOTH text Q&A (`ask`) and Claude Vision (`describe`). There's no first-party Anthropic Kotlin SDK; this is the wire-protocol wrapper voice_qa_assistant and photo_describe_voice patterns reference as `AnthropicClient`. Kotlin uses OkHttp + kotlinx-serialization with a `JsonClassDiscriminator(\"type\")` sealed ContentBlock that mirrors Anthropic's polymorphic content shape (text + image). Swift uses URLSession + Codable with manual encode/decode for the same polymorphism. The customer holds one instance at Application scope and passes it to handlers via DI.",
626
808
  gotchas: [
627
809
  "API key MUST come from a build-injected resource (resValue on Android, xcconfig on iOS). Don't paste literals — they leak into git. See getCredentialGuide for the storage pattern.",
628
810
  "Anthropic-version header is required and version-pinned — bump '2023-06-01' when Anthropic releases a new API version that adds features you need.",
629
- "max_tokens defaults to 1024 here bump for longer answers, but the glasses TTS engine will speak whatever comes back, so consider trimming on your side before speak() rather than asking for unbounded length.",
630
- "history is a list of prior user turns. For real multi-turn you'll likely want to interleave 'user' and 'assistant' roles extend Msg's role enum and pass alternating turns.",
631
- "OkHttp's .execute() blocks the calling thread wrapping in withContext(Dispatchers.IO) keeps it off the main dispatcher. Don't call ask() from the UI thread directly.",
811
+ "Vision content-block shape: each user message's `content` is a LIST of blocks. Image block: `{ type: \"image\", source: { type: \"base64\", media_type, data } }`. Text block: `{ type: \"text\", text }`. Image first, then text prompt Claude reads them in order. media_type must match what Photos.mediaTypeFromUri returned (image/jpeg, image/png, image/webp).",
812
+ "max_tokens defaults to 1024 here bump for longer answers, but the glasses TTS engine will speak whatever comes back, so consider trimming on your side before speak() rather than asking for unbounded length. For Vision specifically, 256 is often plenty (you typically want a short action: hit / stand / split, not paragraphs).",
813
+ "history is a list of prior user turns. For real multi-turn you'll likely want to interleave 'user' and 'assistant' roles — extend the schema's role enum and pass alternating turns.",
814
+ "OkHttp's .execute() blocks the calling thread — wrapping in withContext(Dispatchers.IO) keeps it off the main dispatcher. Don't call ask() / describe() from the UI thread directly.",
815
+ "Vision LLM response p95 is 2-8 seconds. Play an earcon (`glasses.audio.earcon(EarconSound.START)`) BEFORE the call so the user knows the request fired.",
632
816
  ],
633
- relatedFeatures: [],
817
+ relatedFeatures: ["capture_photo"],
634
818
  };
635
819
  export const CODE_EXAMPLES = {
636
820
  voice_qa_assistant: VOICE_QA_ASSISTANT,
@@ -1 +1 @@
1
- {"version":3,"file":"codeExamples.js","sourceRoot":"","sources":["../../../src/tools/data/codeExamples.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"codeExamples.js","sourceRoot":"","sources":["../../../src/tools/data/codeExamples.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@extentos/mcp-server",
3
- "version": "0.0.67",
3
+ "version": "0.0.68",
4
4
  "description": "Extentos MCP server — deterministic tools for building Meta-glasses apps.",
5
5
  "type": "module",
6
6
  "bin": {