@elizaos/plugin-vision 2.0.0-beta.1 → 2.0.3-beta.6
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/LICENSE +21 -0
- package/README.md +73 -301
- package/dist/action.d.ts +3 -0
- package/dist/action.d.ts.map +1 -0
- package/dist/audio-capture-stream.d.ts +42 -0
- package/dist/audio-capture-stream.d.ts.map +1 -0
- package/dist/audio-capture.d.ts +25 -0
- package/dist/audio-capture.d.ts.map +1 -0
- package/dist/computeruse-ocr-bridge.d.ts +50 -0
- package/dist/computeruse-ocr-bridge.d.ts.map +1 -0
- package/dist/config.d.ts +68 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/describe-backpressure.d.ts +90 -0
- package/dist/describe-backpressure.d.ts.map +1 -0
- package/dist/dirty-tile-describer.d.ts +102 -0
- package/dist/dirty-tile-describer.d.ts.map +1 -0
- package/dist/dirty-tile-scene.d.ts +56 -0
- package/dist/dirty-tile-scene.d.ts.map +1 -0
- package/dist/entity-tracker.d.ts +33 -0
- package/dist/entity-tracker.d.ts.map +1 -0
- package/dist/face-detector-ggml.d.ts +60 -0
- package/dist/face-detector-ggml.d.ts.map +1 -0
- package/dist/face-detector-mediapipe.d.ts +25 -0
- package/dist/face-detector-mediapipe.d.ts.map +1 -0
- package/dist/face-recognition-ggml.d.ts +94 -0
- package/dist/face-recognition-ggml.d.ts.map +1 -0
- package/dist/get-screen-elements.d.ts +90 -0
- package/dist/get-screen-elements.d.ts.map +1 -0
- package/dist/get-screen.d.ts +60 -0
- package/dist/get-screen.d.ts.map +1 -0
- package/dist/image/sharp-compat.d.ts +89 -0
- package/dist/image/sharp-compat.d.ts.map +1 -0
- package/dist/image-input.d.ts +15 -0
- package/dist/image-input.d.ts.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7957 -6238
- package/dist/index.js.map +41 -26
- package/dist/lifecycle.d.ts +94 -0
- package/dist/lifecycle.d.ts.map +1 -0
- package/dist/mobile/capacitor-camera.d.ts +85 -0
- package/dist/mobile/capacitor-camera.d.ts.map +1 -0
- package/dist/native/doctr-ffi.d.ts +40 -0
- package/dist/native/doctr-ffi.d.ts.map +1 -0
- package/dist/native/yolo-ffi.d.ts +21 -0
- package/dist/native/yolo-ffi.d.ts.map +1 -0
- package/dist/ocr-host-windows.d.ts +34 -0
- package/dist/ocr-host-windows.d.ts.map +1 -0
- package/dist/ocr-service-apple-vision-macos.d.ts +51 -0
- package/dist/ocr-service-apple-vision-macos.d.ts.map +1 -0
- package/dist/ocr-service-doctr.d.ts +61 -0
- package/dist/ocr-service-doctr.d.ts.map +1 -0
- package/dist/ocr-service-linux-tesseract.d.ts +85 -0
- package/dist/ocr-service-linux-tesseract.d.ts.map +1 -0
- package/dist/ocr-service-paddleocr.d.ts +59 -0
- package/dist/ocr-service-paddleocr.d.ts.map +1 -0
- package/dist/ocr-service-windows.d.ts +41 -0
- package/dist/ocr-service-windows.d.ts.map +1 -0
- package/dist/ocr-service.d.ts +91 -0
- package/dist/ocr-service.d.ts.map +1 -0
- package/dist/ocr-with-coords.d.ts +103 -0
- package/dist/ocr-with-coords.d.ts.map +1 -0
- package/dist/person-detector.d.ts +17 -0
- package/dist/person-detector.d.ts.map +1 -0
- package/dist/provider.d.ts +3 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/routes.d.ts +7 -0
- package/dist/routes.d.ts.map +1 -0
- package/dist/screen-capture-bridge.d.ts +51 -0
- package/dist/screen-capture-bridge.d.ts.map +1 -0
- package/dist/screen-capture.d.ts +17 -0
- package/dist/screen-capture.d.ts.map +1 -0
- package/dist/screen-tiler.d.ts +75 -0
- package/dist/screen-tiler.d.ts.map +1 -0
- package/dist/service.d.ts +176 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/set-of-marks-provider.d.ts +64 -0
- package/dist/set-of-marks-provider.d.ts.map +1 -0
- package/dist/som.d.ts +135 -0
- package/dist/som.d.ts.map +1 -0
- package/dist/som.js +184 -0
- package/dist/som.js.map +11 -0
- package/dist/test-input.d.ts +25 -0
- package/dist/test-input.d.ts.map +1 -0
- package/dist/types.d.ts +241 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/vision-context-augmenter.d.ts +93 -0
- package/dist/vision-context-augmenter.d.ts.map +1 -0
- package/dist/vision-worker-manager.d.ts +51 -0
- package/dist/vision-worker-manager.d.ts.map +1 -0
- package/dist/workers/ocr-worker.d.ts +2 -0
- package/dist/workers/ocr-worker.d.ts.map +1 -0
- package/dist/workers/ocr-worker.js +1075 -7821
- package/dist/workers/ocr-worker.js.map +10 -51
- package/dist/workers/screen-capture-worker.d.ts +2 -0
- package/dist/workers/screen-capture-worker.d.ts.map +1 -0
- package/dist/workers/screen-capture-worker.js +364 -6
- package/dist/workers/screen-capture-worker.js.map +5 -4
- package/dist/workers/worker-logger.d.ts +10 -0
- package/dist/workers/worker-logger.d.ts.map +1 -0
- package/dist/yolo-detector.d.ts +37 -0
- package/dist/yolo-detector.d.ts.map +1 -0
- package/native/doctr.cpp/CMakeLists.txt +58 -0
- package/native/doctr.cpp/README.md +62 -0
- package/native/doctr.cpp/include/doctr.h +91 -0
- package/native/doctr.cpp/scripts/convert.py +98 -0
- package/native/doctr.cpp/src/doctr_det.cpp +112 -0
- package/native/doctr.cpp/src/doctr_rec.cpp +103 -0
- package/native/macos-vision-ocr.swift +113 -0
- package/native/mobilefacenet.cpp/README.md +13 -0
- package/native/movenet.cpp/README.md +10 -0
- package/native/retinaface.cpp/README.md +12 -0
- package/native/yolo.cpp/CMakeLists.txt +57 -0
- package/native/yolo.cpp/README.md +64 -0
- package/native/yolo.cpp/build.mjs +76 -0
- package/native/yolo.cpp/include/yolo.h +62 -0
- package/native/yolo.cpp/scripts/convert.py +248 -0
- package/native/yolo.cpp/src/yolo.cpp +425 -0
- package/native/yolo.cpp/verify/compare.py +99 -0
- package/native/yolo.cpp/verify/make_ref.py +75 -0
- package/native/yolo.cpp/verify/run_ggml.mjs +78 -0
- package/native/yolo.cpp/verify/run_ts.mjs +26 -0
- package/package.json +39 -21
- package/registry-entry.json +43 -0
- package/scripts/vendor-tesseract-linux.mjs +177 -0
- package/build.config.ts +0 -89
- package/dist/workers/florence2-worker.js +0 -779
- package/dist/workers/florence2-worker.js.map +0 -13
package/dist/index.js.map
CHANGED
|
@@ -1,33 +1,48 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/
|
|
3
|
+
"sources": ["../src/image/sharp-compat.ts", "../src/image-input.ts", "../src/native/doctr-ffi.ts", "../src/ocr-service-doctr.ts", "../src/ocr-service-apple-vision-macos.ts", "../src/ocr-service.ts", "../src/ocr-with-coords.ts", "../src/native/yolo-ffi.ts", "../src/yolo-detector.ts", "../src/face-detector-ggml.ts", "../src/face-recognition-ggml.ts", "../src/vision-context-augmenter.ts", "../src/get-screen-elements.ts", "../src/som.ts", "../src/index.ts", "../src/action.ts", "../src/get-screen.ts", "../src/screen-capture-bridge.ts", "../src/types.ts", "../src/computeruse-ocr-bridge.ts", "../src/ocr-service-linux-tesseract.ts", "../src/ocr-service-paddleocr.ts", "../src/ocr-service-windows.ts", "../src/ocr-host-windows.ts", "../src/provider.ts", "../src/routes.ts", "../src/service.ts", "../src/audio-capture.ts", "../src/audio-capture-stream.ts", "../src/describe-backpressure.ts", "../src/screen-tiler.ts", "../src/dirty-tile-describer.ts", "../src/dirty-tile-scene.ts", "../src/entity-tracker.ts", "../src/lifecycle.ts", "../src/screen-capture.ts", "../src/test-input.ts", "../src/vision-worker-manager.ts", "../src/set-of-marks-provider.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import type { Plugin, TestSuite } from \"@elizaos/core\";\nimport { promoteSubactionsToActions } from \"@elizaos/core\";\nimport { visionAction } from \"./action\";\nimport { visionProvider } from \"./provider\";\nimport { VisionService } from \"./service\";\nimport { testSuites } from \"./tests/e2e/index\";\n\nexport const visionPlugin: Plugin = {\n name: \"vision\",\n description:\n \"Provides visual perception through camera integration and scene analysis\",\n services: [VisionService],\n providers: [visionProvider],\n actions: [...promoteSubactionsToActions(visionAction)],\n tests: testSuites as TestSuite[],\n // Self-declared auto-enable: activate when features.vision is enabled OR\n // when media.vision.provider is configured.\n autoEnable: {\n shouldEnable: (_env, config) => {\n const f = (config?.features as Record<string, unknown> | undefined)\n ?.vision;\n const featureOn =\n f === true ||\n (typeof f === \"object\" &&\n f !== null &&\n (f as { enabled?: unknown }).enabled !== false);\n if (featureOn) return true;\n const media = config?.media as Record<string, unknown> | undefined;\n const visionMedia = media?.vision as\n | { enabled?: unknown; provider?: unknown }\n | undefined;\n return Boolean(\n visionMedia &&\n visionMedia.enabled !== false &&\n typeof visionMedia.provider === \"string\" &&\n visionMedia.provider.length > 0,\n );\n },\n },\n init: async (_config, _runtime) => {},\n};\n\nexport default visionPlugin;\n",
|
|
6
|
-
"import {\n type Action,\n type ActionExample,\n type ActionResult,\n ContentType,\n createUniqueUuid,\n type HandlerCallback,\n type IAgentRuntime,\n logger,\n type Media,\n type Memory,\n type State,\n} from \"@elizaos/core\";\nimport type { VisionService } from \"./service\";\nimport { VisionMode } from \"./types\";\n\nconst VISION_ACTION_TIMEOUT_MS = 10_000;\nconst MAX_VISION_TEXT_LENGTH = 4000;\nconst MAX_VISION_ENTITIES = 25;\n\nconst VISION_OPS = [\n \"describe\",\n \"capture\",\n \"set_mode\",\n \"name_entity\",\n \"identify_person\",\n \"track_entity\",\n] as const;\n\ntype VisionOp = (typeof VISION_OPS)[number];\n\nconst ALL_VISION_CONTEXTS = [\n \"media\",\n \"screen_time\",\n \"automation\",\n \"memory\",\n \"settings\",\n] as const;\n\nconst DESCRIBE_KEYWORDS = [\n \"describe\",\n \"scene\",\n \"see\",\n \"look\",\n \"camera\",\n \"screen\",\n \"object\",\n \"person\",\n \"escena\",\n \"ver\",\n \"camara\",\n \"décrire\",\n \"scène\",\n \"voir\",\n \"beschreiben\",\n \"szene\",\n \"sehen\",\n \"descrivi\",\n \"scena\",\n \"vedi\",\n \"説明\",\n \"見える\",\n \"场景\",\n \"描述\",\n \"看见\",\n \"장면\",\n \"설명\",\n \"보여\",\n];\n\nconst CAPTURE_KEYWORDS = [\n \"capture\",\n \"image\",\n \"photo\",\n \"picture\",\n \"snapshot\",\n \"screenshot\",\n \"camera\",\n \"captura\",\n \"foto\",\n \"imagen\",\n \"capturer\",\n \"photo\",\n \"bild\",\n \"foto\",\n \"capturare\",\n \"写真\",\n \"画像\",\n \"スクリーンショット\",\n \"拍照\",\n \"截图\",\n \"이미지\",\n \"사진\",\n \"스크린샷\",\n];\n\nconst SET_MODE_KEYWORDS = [\n \"vision\",\n \"mode\",\n \"camera\",\n \"screen\",\n \"both\",\n \"disable\",\n \"enable\",\n \"off\",\n \"visión\",\n \"camara\",\n \"pantalla\",\n \"écran\",\n \"kamera\",\n \"bildschirm\",\n \"schermo\",\n \"ビジョン\",\n \"カメラ\",\n \"画面\",\n \"视觉\",\n \"相机\",\n \"屏幕\",\n \"비전\",\n \"카메라\",\n \"화면\",\n];\n\nconst NAME_ENTITY_KEYWORDS = [\n \"name\",\n \"named\",\n \"call\",\n \"person\",\n \"entity\",\n \"remember\",\n \"object\",\n \"nombre\",\n \"llama\",\n \"persona\",\n \"nom\",\n \"appelle\",\n \"personne\",\n \"name\",\n \"nenne\",\n \"person\",\n \"nome\",\n \"chiama\",\n \"persona\",\n \"名前\",\n \"呼ぶ\",\n \"人\",\n \"命名\",\n \"叫\",\n \"人\",\n \"이름\",\n \"불러\",\n \"사람\",\n];\n\nconst IDENTIFY_PERSON_KEYWORDS = [\n \"identify\",\n \"recognize\",\n \"who is\",\n \"person\",\n \"face\",\n \"seen before\",\n \"identificar\",\n \"reconoces\",\n \"persona\",\n \"visage\",\n \"reconnais\",\n \"personne\",\n \"erkennen\",\n \"gesicht\",\n \"person\",\n \"riconosci\",\n \"persona\",\n \"識別\",\n \"誰\",\n \"顔\",\n \"识别\",\n \"是谁\",\n \"人\",\n \"식별\",\n \"누구\",\n \"얼굴\",\n];\n\nconst TRACK_ENTITY_KEYWORDS = [\n \"track\",\n \"follow\",\n \"watch\",\n \"keep an eye\",\n \"entity\",\n \"person\",\n \"object\",\n \"rastrear\",\n \"seguir\",\n \"vigilar\",\n \"persona\",\n \"suivre\",\n \"surveiller\",\n \"personne\",\n \"verfolgen\",\n \"beobachten\",\n \"person\",\n \"traccia\",\n \"segui\",\n \"persona\",\n \"追跡\",\n \"見張\",\n \"人\",\n \"跟踪\",\n \"关注\",\n \"人\",\n \"추적\",\n \"지켜봐\",\n \"사람\",\n];\n\nfunction withVisionTimeout<T>(promise: Promise<T>, label: string): Promise<T> {\n return Promise.race([\n promise,\n new Promise<never>((_, reject) =>\n setTimeout(\n () => reject(new Error(`${label} timed out`)),\n VISION_ACTION_TIMEOUT_MS,\n ),\n ),\n ]);\n}\n\nasync function saveExecutionRecord(\n runtime: IAgentRuntime,\n messageContext: Memory,\n thought: string,\n text: string,\n actions?: string[],\n attachments?: Media[],\n): Promise<void> {\n const memory: Memory = {\n id: createUniqueUuid(runtime, `vision-record-${Date.now()}`),\n content: {\n text,\n thought,\n actions: actions || [\"VISION_ANALYSIS\"],\n attachments,\n },\n entityId: createUniqueUuid(runtime, runtime.agentId),\n agentId: runtime.agentId,\n roomId: messageContext.roomId,\n worldId: messageContext.worldId,\n createdAt: Date.now(),\n };\n await runtime.createMemory(memory, \"messages\");\n}\n\nfunction readActionParams(\n options?: Record<string, unknown>,\n): Record<string, unknown> {\n const direct =\n options && typeof options === \"object\"\n ? (options as Record<string, unknown>)\n : {};\n const parameters =\n direct.parameters && typeof direct.parameters === \"object\"\n ? (direct.parameters as Record<string, unknown>)\n : {};\n return { ...direct, ...parameters };\n}\n\nfunction selectedContextMatches(\n state: State | undefined,\n contexts: readonly string[],\n): boolean {\n const selected = new Set<string>();\n const collect = (value: unknown) => {\n if (!Array.isArray(value)) return;\n for (const item of value) {\n if (typeof item === \"string\") selected.add(item);\n }\n };\n collect(\n (state?.values as Record<string, unknown> | undefined)?.selectedContexts,\n );\n collect(\n (state?.data as Record<string, unknown> | undefined)?.selectedContexts,\n );\n const contextObject = (state?.data as Record<string, unknown> | undefined)\n ?.contextObject as\n | {\n trajectoryPrefix?: { selectedContexts?: unknown };\n metadata?: { selectedContexts?: unknown };\n }\n | undefined;\n collect(contextObject?.trajectoryPrefix?.selectedContexts);\n collect(contextObject?.metadata?.selectedContexts);\n return contexts.some((context) => selected.has(context));\n}\n\nfunction visionServiceIsActive(runtime: IAgentRuntime): boolean {\n const visionService = runtime.getService<VisionService>(\"VISION\");\n return Boolean(visionService?.isActive());\n}\n\nfunction normalizeOp(value: unknown): VisionOp | null {\n if (typeof value !== \"string\") return null;\n const normalized = value\n .trim()\n .toLowerCase()\n .replace(/[\\s-]+/g, \"_\");\n if (!normalized) return null;\n const aliases: Record<string, VisionOp> = {\n describe_scene: \"describe\",\n scene: \"describe\",\n capture_image: \"capture\",\n image: \"capture\",\n photo: \"capture\",\n snapshot: \"capture\",\n screenshot: \"capture\",\n set_vision_mode: \"set_mode\",\n mode: \"set_mode\",\n vision_mode: \"set_mode\",\n name: \"name_entity\",\n identify: \"identify_person\",\n recognize: \"identify_person\",\n track: \"track_entity\",\n follow: \"track_entity\",\n };\n if (aliases[normalized]) return aliases[normalized];\n return (VISION_OPS as readonly string[]).includes(normalized)\n ? (normalized as VisionOp)\n : null;\n}\n\nfunction inferOpFromMessage(text: string): VisionOp | null {\n const lower = text.toLowerCase();\n if (\n NAME_ENTITY_KEYWORDS.some((k) => lower.includes(k.toLowerCase())) &&\n /\\b(call|name|named)\\b/.test(lower)\n ) {\n return \"name_entity\";\n }\n if (\n IDENTIFY_PERSON_KEYWORDS.some((k) => lower.includes(k.toLowerCase())) &&\n /\\b(who|identify|recognize)\\b/.test(lower)\n ) {\n return \"identify_person\";\n }\n if (\n TRACK_ENTITY_KEYWORDS.some((k) => lower.includes(k.toLowerCase())) &&\n /\\b(track|follow|watch|keep an eye)\\b/.test(lower)\n ) {\n return \"track_entity\";\n }\n if (\n SET_MODE_KEYWORDS.some((k) => lower.includes(k.toLowerCase())) &&\n /\\b(mode|enable|disable|turn off|turn on)\\b/.test(lower)\n ) {\n return \"set_mode\";\n }\n if (CAPTURE_KEYWORDS.some((k) => lower.includes(k.toLowerCase()))) {\n return \"capture\";\n }\n if (DESCRIBE_KEYWORDS.some((k) => lower.includes(k.toLowerCase()))) {\n return \"describe\";\n }\n return null;\n}\n\nasync function runDescribe(\n runtime: IAgentRuntime,\n message: Memory,\n options: Record<string, unknown>,\n callback?: HandlerCallback,\n): Promise<ActionResult> {\n const visionService = runtime.getService<VisionService>(\"VISION\");\n\n if (!visionService || !visionService.isActive()) {\n const thought =\n \"Vision service is not available or no camera is connected.\";\n const text = \"I cannot see anything right now. No camera is available.\";\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text: \"Vision service unavailable - cannot analyze scene\",\n values: {\n success: false,\n visionAvailable: false,\n error: \"Vision service not available\",\n },\n data: {\n actionName: \"VISION\",\n op: \"describe\",\n error: \"Vision service not available or no camera connected\",\n },\n };\n }\n\n try {\n const scene = await withVisionTimeout(\n visionService.getSceneDescription(),\n \"vision scene description\",\n );\n const cameraInfo = visionService.getCameraInfo();\n\n if (!scene) {\n const thought = \"Camera is connected but no scene has been analyzed yet.\";\n const text = `Camera \"${cameraInfo?.name}\" is connected, but I haven't analyzed any scenes yet. Please wait a moment.`;\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text: \"Camera connected but no scene analyzed yet\",\n values: {\n success: false,\n visionAvailable: true,\n sceneAnalyzed: false,\n cameraName: cameraInfo?.name || undefined,\n },\n data: {\n actionName: \"VISION\",\n op: \"describe\",\n cameraInfo: cameraInfo\n ? {\n id: cameraInfo.id,\n name: cameraInfo.name,\n connected: cameraInfo.connected,\n }\n : undefined,\n sceneStatus: \"not_analyzed\",\n },\n };\n }\n\n const peopleCount = scene.people.length;\n const objectCount = scene.objects.length;\n const people = scene.people.slice(0, MAX_VISION_ENTITIES);\n const objects = scene.objects.slice(0, MAX_VISION_ENTITIES);\n const timestamp = new Date(scene.timestamp).toLocaleString();\n const detailLevel =\n options.detailLevel === \"summary\" ? \"summary\" : \"detailed\";\n\n let description = `Looking through ${cameraInfo?.name || \"the camera\"}, `;\n description += scene.description;\n\n if (detailLevel === \"detailed\" && peopleCount > 0) {\n description += `\\n\\nI can see ${peopleCount} ${peopleCount === 1 ? \"person\" : \"people\"}`;\n const facingData = people.reduce(\n (acc, person) => {\n if (person.facing && person.facing !== \"unknown\") {\n acc[person.facing] = (acc[person.facing] || 0) + 1;\n }\n return acc;\n },\n {} as Record<string, number>,\n );\n\n if (Object.keys(facingData).length > 0) {\n const facingDescriptions = Object.entries(facingData).map(\n ([direction, count]) => `${count} facing ${direction}`,\n );\n description += ` (${facingDescriptions.join(\", \")})`;\n }\n description += \".\";\n }\n\n if (detailLevel === \"detailed\" && objectCount > 0) {\n const objectTypes = objects.reduce(\n (acc, obj) => {\n acc[obj.type] = (acc[obj.type] || 0) + 1;\n return acc;\n },\n {} as Record<string, number>,\n );\n\n const objectDescriptions = Object.entries(objectTypes).map(\n ([type, count]) => `${count} ${type}${count > 1 ? \"s\" : \"\"}`,\n );\n description += `\\n\\nObjects detected: ${objectDescriptions.join(\", \")}.`;\n }\n\n if (\n detailLevel === \"detailed\" &&\n scene.sceneChanged &&\n scene.changePercentage\n ) {\n description += `\\n\\n(Scene changed by ${scene.changePercentage.toFixed(1)}% since last analysis)`;\n }\n\n const thought = `Analyzed the visual scene at ${timestamp}.`;\n const text = description.slice(0, MAX_VISION_TEXT_LENGTH);\n\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n\n return {\n success: true,\n text,\n values: {\n success: true,\n visionAvailable: true,\n sceneAnalyzed: true,\n peopleCount,\n objectCount,\n cameraName: cameraInfo?.name || undefined,\n sceneChanged: scene.sceneChanged,\n changePercentage: scene.changePercentage,\n detailLevel,\n },\n data: {\n actionName: \"VISION\",\n op: \"describe\",\n sceneTimestamp: scene.timestamp,\n sceneDescription: scene.description.slice(0, MAX_VISION_TEXT_LENGTH),\n sceneChanged: scene.sceneChanged,\n changePercentage: scene.changePercentage,\n audioTranscription: scene.audioTranscription || undefined,\n objectCount: objects.length,\n peopleCount: people.length,\n cameraInfo: cameraInfo\n ? {\n id: cameraInfo.id,\n name: cameraInfo.name,\n connected: cameraInfo.connected,\n }\n : undefined,\n timestamp,\n description: text,\n },\n };\n } catch (error: unknown) {\n logger.error(\n \"[VISION/describe] Error analyzing scene:\",\n error instanceof Error ? error.message : String(error),\n );\n const thought =\n \"An error occurred while trying to analyze the visual scene.\";\n const text = `Error analyzing scene: ${error instanceof Error ? error.message : String(error)}`;\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n\n const errorMessage = error instanceof Error ? error.message : String(error);\n return {\n success: false,\n text: \"Error analyzing scene\",\n values: {\n success: false,\n visionAvailable: true,\n error: true,\n errorMessage,\n },\n data: {\n actionName: \"VISION\",\n op: \"describe\",\n error: errorMessage,\n errorType: \"analysis_error\",\n },\n };\n }\n}\n\nasync function runCapture(\n runtime: IAgentRuntime,\n message: Memory,\n callback?: HandlerCallback,\n): Promise<ActionResult> {\n const visionService = runtime.getService<VisionService>(\"VISION\");\n\n if (!visionService || !visionService.isActive()) {\n const thought =\n \"Vision service is not available or no camera is connected.\";\n const text = \"I cannot capture an image right now. No camera is available.\";\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text: \"Vision service unavailable - cannot capture image\",\n values: {\n success: false,\n visionAvailable: false,\n error: \"Vision service not available\",\n },\n data: {\n actionName: \"VISION\",\n op: \"capture\",\n error: \"Vision service not available or no camera connected\",\n },\n };\n }\n\n try {\n const imageBuffer = await Promise.race([\n visionService.captureImage(),\n new Promise<never>((_, reject) =>\n setTimeout(\n () => reject(new Error(\"vision capture timed out\")),\n VISION_ACTION_TIMEOUT_MS,\n ),\n ),\n ]);\n const cameraInfo = visionService.getCameraInfo();\n\n if (!imageBuffer) {\n const thought = \"Failed to capture image from camera.\";\n const text =\n \"I could not capture an image from the camera. Please try again.\";\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text: \"Failed to capture image from camera\",\n values: {\n success: false,\n visionAvailable: true,\n captureSuccess: false,\n },\n data: {\n actionName: \"VISION\",\n op: \"capture\",\n error: \"Camera capture failed\",\n cameraInfo: cameraInfo\n ? {\n id: cameraInfo.id,\n name: cameraInfo.name,\n connected: cameraInfo.connected,\n }\n : undefined,\n },\n };\n }\n\n const attachmentId = createUniqueUuid(runtime, `capture-${Date.now()}`);\n const timestamp = new Date().toISOString();\n\n const imageAttachment: Media = {\n id: attachmentId,\n title: `Camera Capture - ${timestamp}`,\n contentType: ContentType.IMAGE,\n source: `camera:${cameraInfo?.name || \"unknown\"}`,\n url: `data:image/jpeg;base64,${imageBuffer.toString(\"base64\")}`,\n };\n\n const thought = `Captured an image from camera \"${cameraInfo?.name}\".`;\n const text = `I've captured an image from the camera at ${timestamp}.`;\n\n await saveExecutionRecord(\n runtime,\n message,\n thought,\n text,\n [\"VISION\"],\n [imageAttachment],\n );\n\n if (callback) {\n await callback({\n thought,\n text,\n actions: [\"VISION\"],\n attachments: [imageAttachment],\n });\n }\n\n return {\n success: true,\n text: `I've captured an image from the camera at ${timestamp}.`,\n values: {\n success: true,\n visionAvailable: true,\n captureSuccess: true,\n cameraName: cameraInfo?.name || undefined,\n timestamp,\n },\n data: {\n actionName: \"VISION\",\n op: \"capture\",\n imageAttachment: {\n id: imageAttachment.id,\n title: imageAttachment.title,\n contentType: imageAttachment.contentType,\n source: imageAttachment.source,\n url: imageAttachment.url,\n },\n cameraInfo: cameraInfo\n ? {\n id: cameraInfo.id,\n name: cameraInfo.name,\n connected: cameraInfo.connected,\n }\n : undefined,\n timestamp,\n },\n };\n } catch (error) {\n logger.error(\"[VISION/capture] Error capturing image:\", error);\n const thought = \"An error occurred while trying to capture an image.\";\n const errorMessage = error instanceof Error ? error.message : String(error);\n const text = `Error capturing image: ${errorMessage}`;\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n\n return {\n success: false,\n text: \"Error capturing image\",\n values: {\n success: false,\n visionAvailable: true,\n error: true,\n errorMessage,\n },\n data: {\n actionName: \"VISION\",\n op: \"capture\",\n error: errorMessage,\n errorType: \"capture_error\",\n },\n };\n }\n}\n\nasync function runSetMode(\n runtime: IAgentRuntime,\n message: Memory,\n options: Record<string, unknown>,\n callback?: HandlerCallback,\n): Promise<ActionResult> {\n const visionService = runtime.getService<VisionService>(\"VISION\");\n\n if (!visionService) {\n const thought = \"Vision service is not available.\";\n const text =\n \"I cannot change vision mode because the vision service is not available.\";\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text,\n data: { actionName: \"VISION\", op: \"set_mode\" },\n };\n }\n\n try {\n const explicitMode =\n typeof options.mode === \"string\" ? options.mode.toLowerCase() : \"\";\n const messageText =\n explicitMode || message.content.text?.toLowerCase() || \"\";\n let newMode: VisionMode | null = null;\n\n if (messageText.includes(\"off\") || messageText.includes(\"disable\")) {\n newMode = VisionMode.OFF;\n } else if (messageText.includes(\"both\")) {\n newMode = VisionMode.BOTH;\n } else if (messageText.includes(\"screen\")) {\n newMode = VisionMode.SCREEN;\n } else if (messageText.includes(\"camera\")) {\n newMode = VisionMode.CAMERA;\n }\n\n if (!newMode) {\n const thought =\n \"Could not determine the desired vision mode from the message.\";\n const text =\n \"Please specify the vision mode: OFF, CAMERA, SCREEN, or BOTH.\";\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text,\n data: { actionName: \"VISION\", op: \"set_mode\" },\n };\n }\n\n const currentMode = visionService.getVisionMode();\n await Promise.race([\n visionService.setVisionMode(newMode),\n new Promise<never>((_, reject) =>\n setTimeout(\n () => reject(new Error(\"vision mode change timed out\")),\n VISION_ACTION_TIMEOUT_MS,\n ),\n ),\n ]);\n\n const thought = `Changed vision mode from ${currentMode} to ${newMode}.`;\n let text = \"\";\n\n switch (newMode) {\n case VisionMode.OFF:\n text =\n \"Vision has been disabled. I will no longer process visual input.\";\n break;\n case VisionMode.CAMERA:\n text =\n \"Vision mode set to CAMERA only. I will process input from the camera.\";\n break;\n case VisionMode.SCREEN:\n text =\n \"Vision mode set to SCREEN only. I will analyze what's on your screen.\";\n break;\n case VisionMode.BOTH:\n text =\n \"Vision mode set to BOTH. I will process input from both camera and screen.\";\n break;\n }\n\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: true,\n text,\n values: { visionMode: newMode },\n data: { actionName: \"VISION\", op: \"set_mode\", visionMode: newMode },\n };\n } catch (error) {\n logger.error(\"[VISION/set_mode] Error changing vision mode:\", error);\n const errorMessage = error instanceof Error ? error.message : String(error);\n const thought = \"An error occurred while trying to change the vision mode.\";\n const text = `Error changing vision mode: ${errorMessage}`;\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text,\n error: errorMessage,\n data: { actionName: \"VISION\", op: \"set_mode\" },\n };\n }\n}\n\nasync function runNameEntity(\n runtime: IAgentRuntime,\n message: Memory,\n options: Record<string, unknown>,\n callback?: HandlerCallback,\n): Promise<ActionResult> {\n try {\n const visionService = runtime.getService<VisionService>(\"VISION\");\n\n if (!visionService) {\n const thought = \"Vision service is not available.\";\n const text =\n \"I cannot name entities because the vision service is not available.\";\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text,\n data: { actionName: \"VISION\", op: \"name_entity\" },\n };\n }\n\n const scene = await withVisionTimeout(\n visionService.getSceneDescription(),\n \"vision scene description\",\n );\n\n if (!scene || scene.people.length === 0) {\n const thought = \"No people visible to name.\";\n const text = \"I don't see any people in the current scene to name.\";\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text,\n data: { actionName: \"VISION\", op: \"name_entity\" },\n };\n }\n\n const messageText = message.content.text?.toLowerCase() || \"\";\n const explicitName =\n typeof options.name === \"string\" ? options.name.trim() : \"\";\n const nameMatch = explicitName\n ? [explicitName, explicitName]\n : messageText.match(/(?:named?|call(?:ed)?|is)\\s+(\\w+)/i);\n\n if (!nameMatch) {\n const thought = \"Could not extract name from message.\";\n const text =\n 'I couldn\\'t understand what name to assign. Please say something like \"The person is named Alice\".';\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text,\n data: { actionName: \"VISION\", op: \"name_entity\" },\n };\n }\n\n const name = nameMatch[1];\n const entityTracker = visionService.getEntityTracker();\n\n await entityTracker.updateEntities(\n scene.objects.slice(0, MAX_VISION_ENTITIES),\n scene.people.slice(0, MAX_VISION_ENTITIES),\n undefined,\n runtime,\n );\n const activeEntities = entityTracker.getActiveEntities();\n const people = activeEntities.filter((e) => e.entityType === \"person\");\n\n if (people.length === 0) {\n const thought = \"No tracked people found.\";\n const text =\n \"I can see someone but haven't established tracking yet. Please try again in a moment.\";\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text,\n data: { actionName: \"VISION\", op: \"name_entity\" },\n };\n }\n\n let targetPerson = people[0];\n if (people.length > 1) {\n targetPerson = people.reduce((prev, curr) => {\n const prevArea = prev.lastPosition.width * prev.lastPosition.height;\n const currArea = curr.lastPosition.width * curr.lastPosition.height;\n return currArea > prevArea ? curr : prev;\n });\n }\n\n const success = entityTracker.assignNameToEntity(targetPerson.id, name);\n\n if (success) {\n const thought = `Named entity \"${name}\" and associated with person in scene.`;\n const text = `I've identified the person as ${name}. I'll remember them for future interactions.`;\n\n await saveExecutionRecord(\n runtime,\n message,\n thought,\n text,\n [\"VISION\"],\n undefined,\n );\n\n if (callback) {\n await callback({\n thought,\n text,\n actions: [\"VISION\"],\n data: { entityId: targetPerson.id, name },\n });\n }\n\n logger.info(\n `[VISION/name_entity] Assigned name \"${name}\" to entity ${targetPerson.id}`,\n );\n return {\n success: true,\n text,\n values: { entityId: targetPerson.id, name },\n data: {\n actionName: \"VISION\",\n op: \"name_entity\",\n entityId: targetPerson.id,\n name,\n },\n };\n } else {\n const thought = \"Failed to assign name to entity.\";\n const text = \"There was an error assigning the name. Please try again.\";\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text,\n data: { actionName: \"VISION\", op: \"name_entity\" },\n };\n }\n } catch (error) {\n logger.error(\"[VISION/name_entity] Error:\", error);\n const thought = \"Failed to name entity.\";\n const text = `Sorry, I couldn't name the entity: ${error instanceof Error ? error.message : \"Unknown error\"}`;\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text,\n error: error instanceof Error ? error.message : String(error),\n data: { actionName: \"VISION\", op: \"name_entity\" },\n };\n }\n}\n\nasync function runIdentifyPerson(\n runtime: IAgentRuntime,\n message: Memory,\n callback?: HandlerCallback,\n): Promise<ActionResult> {\n try {\n const visionService = runtime.getService<VisionService>(\"VISION\");\n\n if (!visionService) {\n const thought = \"Vision service is not available.\";\n const text =\n \"I cannot identify people because the vision service is not available.\";\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text,\n data: { actionName: \"VISION\", op: \"identify_person\" },\n };\n }\n\n const scene = await withVisionTimeout(\n visionService.getSceneDescription(),\n \"vision scene description\",\n );\n\n if (!scene || scene.people.length === 0) {\n const thought = \"No people visible to identify.\";\n const text = \"I don't see any people in the current scene.\";\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text,\n data: { actionName: \"VISION\", op: \"identify_person\" },\n };\n }\n\n const entityTracker = visionService.getEntityTracker();\n\n await entityTracker.updateEntities(\n scene.objects.slice(0, MAX_VISION_ENTITIES),\n scene.people.slice(0, MAX_VISION_ENTITIES),\n undefined,\n runtime,\n );\n const activeEntities = entityTracker.getActiveEntities();\n const people = activeEntities.filter((e) => e.entityType === \"person\");\n\n if (people.length === 0) {\n const thought = \"No tracked people found.\";\n const text = \"I can see someone but I'm still processing their identity.\";\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text,\n data: { actionName: \"VISION\", op: \"identify_person\" },\n };\n }\n\n let recognizedCount = 0;\n let unknownCount = 0;\n const identifications: string[] = [];\n\n for (const person of people) {\n const name = person.attributes.name;\n const duration = Date.now() - person.firstSeen;\n const durationStr =\n duration < 60000\n ? `${Math.round(duration / 1000)} seconds`\n : `${Math.round(duration / 60000)} minutes`;\n\n if (name) {\n recognizedCount++;\n const personInfo = `I can see ${name}. They've been here for ${durationStr}.`;\n identifications.push(personInfo);\n\n if (person.appearances.length > 5) {\n identifications.push(\"I've been tracking them consistently.\");\n }\n } else {\n unknownCount++;\n const personInfo = `I see an unidentified person who has been here for ${durationStr}.`;\n identifications.push(personInfo);\n\n if (person.attributes.faceId) {\n identifications.push(\n \"I've captured their face profile but they haven't been named yet.\",\n );\n }\n }\n }\n\n const recentlyLeft = entityTracker.getRecentlyLeft();\n if (recentlyLeft.length > 0) {\n identifications.push(\"\\nRecently departed:\");\n for (const { entity, leftAt } of recentlyLeft) {\n if (entity.entityType === \"person\" && entity.attributes.name) {\n const timeAgo = Date.now() - leftAt;\n const timeStr =\n timeAgo < 60000\n ? `${Math.round(timeAgo / 1000)} seconds ago`\n : `${Math.round(timeAgo / 60000)} minutes ago`;\n identifications.push(`${entity.attributes.name} left ${timeStr}.`);\n }\n }\n }\n\n const thought = `Identified ${recognizedCount} known people and ${unknownCount} unknown people.`;\n const text = identifications.join(\" \");\n\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n\n if (callback) {\n await callback({\n thought,\n text,\n actions: [\"VISION\"],\n data: {\n identifications: people.slice(0, MAX_VISION_ENTITIES).map((p) => ({\n id: p.id,\n entityType: p.entityType,\n name: p.attributes.name || undefined,\n })),\n },\n });\n }\n return {\n success: true,\n text,\n values: { recognizedCount, unknownCount },\n data: {\n actionName: \"VISION\",\n op: \"identify_person\",\n recognizedCount,\n unknownCount,\n },\n };\n } catch (error) {\n logger.error(\"[VISION/identify_person] Error:\", error);\n const thought = \"Failed to identify people.\";\n const text = `Sorry, I couldn't identify people: ${error instanceof Error ? error.message : \"Unknown error\"}`;\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text,\n error: error instanceof Error ? error.message : String(error),\n data: { actionName: \"VISION\", op: \"identify_person\" },\n };\n }\n}\n\nasync function runTrackEntity(\n runtime: IAgentRuntime,\n message: Memory,\n callback?: HandlerCallback,\n): Promise<ActionResult> {\n try {\n const visionService = runtime.getService<VisionService>(\"VISION\");\n\n if (!visionService) {\n const thought = \"Vision service is not available.\";\n const text =\n \"I cannot track entities because the vision service is not available.\";\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text,\n data: { actionName: \"VISION\", op: \"track_entity\" },\n };\n }\n\n const scene = await withVisionTimeout(\n visionService.getSceneDescription(),\n \"vision scene description\",\n );\n\n if (!scene) {\n const thought = \"No scene available for tracking.\";\n const text =\n \"I need a moment to process the visual scene before I can track entities.\";\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text,\n data: { actionName: \"VISION\", op: \"track_entity\" },\n };\n }\n\n const entityTracker = visionService.getEntityTracker();\n await entityTracker.updateEntities(\n scene.objects.slice(0, MAX_VISION_ENTITIES),\n scene.people.slice(0, MAX_VISION_ENTITIES),\n undefined,\n runtime,\n );\n const stats = entityTracker.getStatistics();\n\n const thought = `Tracking ${stats.activeEntities} entities in the scene.`;\n const summary = [\n `I'm now tracking ${stats.activeEntities} entities in the scene`,\n `(${stats.people} people, ${stats.objects} objects).`,\n \"The visual tracking system will maintain persistent IDs for all entities\",\n \"and notify you of significant changes.\",\n ];\n const responseText = summary.join(\" \");\n\n await saveExecutionRecord(runtime, message, thought, responseText, [\n \"VISION\",\n ]);\n\n if (callback) {\n await callback({\n thought,\n text: responseText,\n actions: [\"VISION\"],\n data: { entities: stats.activeEntities },\n });\n }\n\n logger.info(\n `[VISION/track_entity] Tracking ${stats.activeEntities} entities`,\n );\n return {\n success: true,\n text: responseText,\n values: {\n activeEntities: stats.activeEntities,\n people: stats.people,\n objects: stats.objects,\n },\n data: {\n actionName: \"VISION\",\n op: \"track_entity\",\n activeEntities: stats.activeEntities,\n people: stats.people,\n objects: stats.objects,\n },\n };\n } catch (error) {\n logger.error(\"[VISION/track_entity] Error:\", error);\n const thought = \"Failed to track entities.\";\n const text = `Sorry, I couldn't track entities: ${error instanceof Error ? error.message : \"Unknown error\"}`;\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text,\n error: error instanceof Error ? error.message : String(error),\n data: { actionName: \"VISION\", op: \"track_entity\" },\n };\n }\n}\n\nexport const visionAction: Action = {\n name: \"VISION\",\n contexts: [...ALL_VISION_CONTEXTS],\n contextGate: { anyOf: [...ALL_VISION_CONTEXTS] },\n roleGate: { minRole: \"USER\" },\n similes: [\n \"DESCRIBE_SCENE\",\n \"CAPTURE_IMAGE\",\n \"SET_VISION_MODE\",\n \"NAME_ENTITY\",\n \"IDENTIFY_PERSON\",\n \"TRACK_ENTITY\",\n \"ANALYZE_SCENE\",\n \"WHAT_DO_YOU_SEE\",\n \"VISION_CHECK\",\n \"LOOK_AROUND\",\n \"TAKE_PHOTO\",\n \"SCREENSHOT\",\n \"CAPTURE_FRAME\",\n \"TAKE_PICTURE\",\n ],\n description:\n \"Camera and screen vision: describe the current scene, capture an image, switch vision mode (off/camera/screen/both), name a visible entity, identify a person, or start tracking an entity. The op is inferred from the message text when not explicitly provided.\",\n descriptionCompressed:\n \"Vision: describe / capture / set_mode / name_entity / identify_person / track_entity.\",\n parameters: [\n {\n name: \"subaction\",\n description:\n \"Operation to perform: describe, capture, set_mode, name_entity, identify_person, or track_entity. Inferred from message text when omitted.\",\n required: false,\n schema: { type: \"string\", enum: [...VISION_OPS] },\n },\n {\n name: \"detailLevel\",\n description:\n \"For op=describe: 'summary' to omit object/person breakdowns, 'detailed' for the full breakdown.\",\n required: false,\n schema: {\n type: \"string\",\n enum: [\"summary\", \"detailed\"],\n default: \"detailed\",\n },\n },\n {\n name: \"mode\",\n description:\n \"For op=set_mode: vision mode to set: off, camera, screen, or both.\",\n required: false,\n schema: { type: \"string\", enum: [\"off\", \"camera\", \"screen\", \"both\"] },\n },\n {\n name: \"name\",\n description:\n \"For op=name_entity: the name to assign to the most relevant visible person or object.\",\n required: false,\n schema: { type: \"string\" },\n },\n {\n name: \"targetHint\",\n description:\n \"For op=name_entity or op=identify_person: optional phrase describing which visible entity to focus on.\",\n required: false,\n schema: { type: \"string\" },\n },\n {\n name: \"description\",\n description:\n \"For op=track_entity: optional description of the visible entity to prioritize for tracking.\",\n required: false,\n schema: { type: \"string\" },\n },\n {\n name: \"includeUnknown\",\n description:\n \"For op=identify_person: whether to mention unidentified people in the response.\",\n required: false,\n schema: { type: \"boolean\", default: true },\n },\n ],\n validate: async (\n runtime: IAgentRuntime,\n _message: Memory,\n state?: State,\n options?: Record<string, unknown>,\n ): Promise<boolean> => {\n if (!visionServiceIsActive(runtime)) {\n // set_mode does not require active vision; allow if service is registered.\n const visionService = runtime.getService<VisionService>(\"VISION\");\n if (!visionService) return false;\n }\n const params = readActionParams(options);\n return (\n selectedContextMatches(state, ALL_VISION_CONTEXTS) ||\n typeof params.op === \"string\"\n );\n },\n handler: async (\n runtime: IAgentRuntime,\n message: Memory,\n _state?: State,\n _options?: Record<string, unknown>,\n callback?: HandlerCallback,\n _responses?: Memory[],\n ): Promise<ActionResult> => {\n const params = readActionParams(_options);\n const explicitOp = normalizeOp(params.op ?? params.subaction);\n const inferredOp =\n explicitOp ?? inferOpFromMessage(message.content?.text ?? \"\");\n\n if (!inferredOp) {\n const text = `VISION could not determine the operation. Specify one of: ${VISION_OPS.join(\", \")}.`;\n if (callback) {\n await callback({ text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text,\n values: { error: \"MISSING\" },\n data: {\n actionName: \"VISION\",\n availableOps: VISION_OPS,\n },\n };\n }\n\n switch (inferredOp) {\n case \"describe\":\n return runDescribe(runtime, message, params, callback);\n case \"capture\":\n return runCapture(runtime, message, callback);\n case \"set_mode\":\n return runSetMode(runtime, message, params, callback);\n case \"name_entity\":\n return runNameEntity(runtime, message, params, callback);\n case \"identify_person\":\n return runIdentifyPerson(runtime, message, callback);\n case \"track_entity\":\n return runTrackEntity(runtime, message, callback);\n }\n },\n examples: [\n [\n { name: \"{{user}}\", content: { text: \"what do you see?\" } },\n {\n name: \"{{agent}}\",\n content: {\n actions: [\"VISION\"],\n thought: \"The user wants to know what I can see through my camera.\",\n text: \"I see a room with a desk and computer setup. There are 2 people, one is sitting and one is standing.\",\n },\n },\n ],\n [\n { name: \"{{user}}\", content: { text: \"take a photo\" } },\n {\n name: \"{{agent}}\",\n content: {\n actions: [\"VISION\"],\n thought: \"The user wants me to capture an image from the camera.\",\n text: \"I've captured an image from the camera.\",\n },\n },\n ],\n [\n { name: \"{{user}}\", content: { text: \"set vision mode to screen\" } },\n {\n name: \"{{agent}}\",\n content: {\n actions: [\"VISION\"],\n thought: \"The user wants to switch to screen vision mode.\",\n text: \"Vision mode set to SCREEN only. I will analyze what's on your screen.\",\n },\n },\n ],\n [\n {\n name: \"{{user}}\",\n content: { text: \"the person wearing the blue shirt is named Alice\" },\n },\n {\n name: \"{{agent}}\",\n content: {\n actions: [\"VISION\"],\n text: \"I've identified the person in the blue shirt as Alice. I'll remember them for future interactions.\",\n },\n },\n ],\n [\n {\n name: \"{{user}}\",\n content: { text: \"who is the person in front of you?\" },\n },\n {\n name: \"{{agent}}\",\n content: {\n actions: [\"VISION\"],\n text: \"That's Alice. I last saw her about 5 minutes ago.\",\n },\n },\n ],\n [\n {\n name: \"{{user}}\",\n content: { text: \"track the person wearing the red shirt\" },\n },\n {\n name: \"{{agent}}\",\n content: {\n actions: [\"VISION\"],\n text: \"I'm now tracking the person in the red shirt.\",\n },\n },\n ],\n ] as ActionExample[][],\n};\n",
|
|
7
|
-
"export const VisionServiceType = {\n VISION: \"VISION\" as const,\n};\n\ndeclare module \"@elizaos/core\" {\n interface ServiceTypeRegistry {\n VISION: \"VISION\";\n }\n}\n\nexport interface CameraInfo {\n id: string;\n name: string;\n connected: boolean;\n}\n\nexport interface SceneDescription {\n timestamp: number;\n description: string;\n objects: DetectedObject[];\n people: PersonInfo[];\n sceneChanged: boolean;\n changePercentage: number;\n audioTranscription?: string;\n}\n\nexport interface DetectedObject {\n id: string;\n type: string;\n confidence: number;\n boundingBox: BoundingBox;\n}\n\nexport interface PersonInfo {\n id: string;\n pose: \"sitting\" | \"standing\" | \"lying\" | \"unknown\";\n facing: \"camera\" | \"away\" | \"left\" | \"right\" | \"unknown\";\n confidence: number;\n boundingBox: BoundingBox;\n keypoints?: Array<{\n part: string;\n position: { x: number; y: number };\n score: number;\n }>;\n}\n\nexport interface BoundingBox {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport interface VisionFrame {\n timestamp: number;\n width: number;\n height: number;\n data: Buffer;\n format: \"rgb\" | \"rgba\" | \"jpeg\" | \"png\";\n}\n\nexport enum VisionMode {\n OFF = \"OFF\",\n CAMERA = \"CAMERA\",\n SCREEN = \"SCREEN\",\n BOTH = \"BOTH\",\n}\n\n// Screen capture types\nexport interface ScreenCapture {\n timestamp: number;\n width: number;\n height: number;\n data: Buffer;\n tiles: ScreenTile[];\n}\n\nexport interface ScreenTile {\n id: string;\n row: number;\n col: number;\n x: number;\n y: number;\n width: number;\n height: number;\n data?: Buffer;\n analysis?: TileAnalysis;\n}\n\nexport interface TileAnalysis {\n timestamp: number;\n florence2?: Florence2Result;\n ocr?: OCRResult;\n objects?: DetectedObject[];\n text?: string;\n summary?: string;\n}\n\nexport interface Florence2Result {\n caption?: string;\n objects?: Array<{\n label: string;\n bbox: BoundingBox;\n confidence: number;\n }>;\n regions?: Array<{\n description: string;\n bbox: BoundingBox;\n }>;\n tags?: string[];\n}\n\nexport interface OCRResult {\n text: string;\n blocks: Array<{\n text: string;\n bbox: BoundingBox;\n confidence: number;\n words?: Array<{\n text: string;\n bbox: BoundingBox;\n confidence: number;\n }>;\n }>;\n fullText: string;\n}\n\nexport interface EnhancedSceneDescription extends SceneDescription {\n screenCapture?: ScreenCapture;\n screenAnalysis?: {\n fullScreenOCR?: string;\n activeTile?: TileAnalysis;\n gridSummary?: string;\n focusedApp?: string;\n uiElements?: Array<{\n type: string;\n text: string;\n position: BoundingBox;\n }>;\n };\n}\n\nexport interface VisionConfig {\n cameraName?: string;\n pixelChangeThreshold?: number;\n updateInterval?: number;\n enablePoseDetection?: boolean;\n enableObjectDetection?: boolean;\n tfUpdateInterval?: number;\n vlmUpdateInterval?: number;\n tfChangeThreshold?: number;\n vlmChangeThreshold?: number;\n visionMode?: VisionMode;\n screenCaptureInterval?: number;\n tileSize?: number;\n tileProcessingOrder?: \"sequential\" | \"priority\" | \"random\";\n ocrEnabled?: boolean;\n florence2Enabled?: boolean;\n screenRegion?: {\n x: number;\n y: number;\n width: number;\n height: number;\n };\n displayIndex?: number;\n captureAllDisplays?: boolean;\n targetScreenFPS?: number;\n textRegions?: Array<{\n x: number;\n y: number;\n width: number;\n height: number;\n }>;\n}\n\nexport interface TrackedEntity {\n id: string;\n entityType: \"person\" | \"object\" | \"pet\";\n firstSeen: number;\n lastSeen: number;\n lastPosition: BoundingBox;\n appearances: EntityAppearance[];\n attributes: EntityAttributes;\n worldId?: string;\n roomId?: string;\n}\n\nexport interface EntityAppearance {\n timestamp: number;\n boundingBox: BoundingBox;\n confidence: number;\n embedding?: number[]; // Face embedding for person recognition\n keypoints?: Array<{\n part: string;\n position: { x: number; y: number };\n score: number;\n }>;\n}\n\nexport interface EntityAttributes {\n [key: string]:\n | string\n | number\n | boolean\n | null\n | undefined\n | string[]\n | number[];\n name?: string;\n faceEmbedding?: number[];\n faceId?: string;\n clothing?: string[];\n hairColor?: string;\n accessories?: string[];\n\n // For objects\n objectType?: string;\n color?: string;\n size?: \"small\" | \"medium\" | \"large\";\n description?: string;\n tags?: string[];\n}\n\nexport interface FaceLibrary {\n faces: Map<string, FaceProfile>;\n embeddings: Map<string, number[][]>; // Multiple embeddings per profile\n}\n\nexport interface FaceProfile {\n id: string;\n name?: string;\n embeddings: number[][]; // Multiple embeddings for better recognition\n firstSeen: number;\n lastSeen: number;\n seenCount: number;\n attributes?: {\n age?: string;\n gender?: string;\n emotion?: string;\n };\n}\n\nexport interface WorldState {\n worldId: string;\n entities: Map<string, TrackedEntity>;\n lastUpdate: number;\n activeEntities: string[];\n recentlyLeft: Array<{\n entityId: string;\n leftAt: number;\n lastPosition: BoundingBox;\n }>;\n}\n",
|
|
8
|
-
"import {\n type IAgentRuntime,\n logger,\n type Memory,\n type Provider,\n type State,\n} from \"@elizaos/core\";\nimport type { VisionService } from \"./service\";\nimport type {\n BoundingBox,\n EnhancedSceneDescription,\n EntityAttributes,\n} from \"./types\";\n\nconst MAX_VISION_OBJECTS_IN_STATE = 50;\nconst MAX_VISION_PEOPLE_IN_STATE = 25;\nconst MAX_TRACKED_ENTITIES_IN_STATE = 25;\n\nexport const visionProvider: Provider = {\n name: \"VISION_PERCEPTION\",\n description:\n \"Provides current visual perception data including scene description, detected objects, people, and entity tracking. This provider is always active and provides real-time visual awareness.\",\n position: 99,\n contexts: [\"media\", \"browser\"],\n contextGate: { anyOf: [\"media\", \"browser\"] },\n cacheStable: false,\n cacheScope: \"turn\",\n dynamic: false,\n get: async (runtime: IAgentRuntime, message: Memory, _state: State) => {\n const visionService = runtime.getService<VisionService>(\"VISION\");\n\n if (!visionService) {\n logger.warn(\"[visionProvider] VisionService not found.\");\n return {\n values: {\n visionAvailable: false,\n sceneDescription: \"Vision service is not available.\",\n cameraStatus: \"No camera connected\",\n },\n text: JSON.stringify(\n {\n visual_perception: {\n visionAvailable: false,\n sceneDescription: \"Vision service is not available.\",\n cameraStatus: \"No camera connected\",\n },\n },\n null,\n 2,\n ),\n data: { hasVision: false },\n };\n }\n\n try {\n const sceneDescription =\n (await visionService.getEnhancedSceneDescription()) ||\n (await visionService.getSceneDescription());\n const cameraInfo = visionService.getCameraInfo();\n const isActive = visionService.isActive();\n const visionMode = visionService.getVisionMode();\n const screenCapture = await visionService.getScreenCapture();\n const _worldId = message.worldId || \"default-world\";\n const entityTracker = visionService.getEntityTracker();\n\n let entityData: {\n activeEntities: Array<{\n id: string;\n type: \"person\" | \"object\" | \"pet\";\n name: string | undefined;\n firstSeen: number;\n duration: number;\n position: BoundingBox;\n attributes: EntityAttributes;\n }>;\n recentlyLeft: Array<{\n id: string;\n name: string | undefined;\n leftAt: number;\n timeAgo: number;\n }>;\n statistics: {\n totalEntities: number;\n activeEntities: number;\n recentlyLeft: number;\n people: number;\n objects: number;\n };\n } | null = null;\n\n if (sceneDescription && entityTracker) {\n await entityTracker.updateEntities(\n sceneDescription.objects,\n sceneDescription.people,\n undefined,\n runtime,\n );\n\n const activeEntities = entityTracker.getActiveEntities();\n const recentlyLeft = entityTracker.getRecentlyLeft();\n const stats = entityTracker.getStatistics();\n\n entityData = {\n activeEntities: activeEntities\n .slice(0, MAX_TRACKED_ENTITIES_IN_STATE)\n .map((e) => ({\n id: e.id,\n type: e.entityType,\n name: e.attributes.name,\n firstSeen: e.firstSeen,\n duration: Date.now() - e.firstSeen,\n position: e.lastPosition,\n attributes: e.attributes,\n })),\n recentlyLeft: recentlyLeft\n .slice(0, MAX_TRACKED_ENTITIES_IN_STATE)\n .map(({ entity, leftAt }) => ({\n id: entity.id,\n name: entity.attributes.name,\n leftAt,\n timeAgo: Date.now() - leftAt,\n })),\n statistics: stats,\n };\n }\n\n let perceptionText = \"\";\n let values = {};\n let data = {};\n\n if (!isActive) {\n perceptionText = `Vision mode: ${visionMode}\\n`;\n if (visionMode === \"OFF\") {\n perceptionText += \"Vision is disabled.\";\n } else {\n perceptionText += \"Vision service is initializing...\";\n }\n\n values = {\n visionAvailable: false,\n visionMode,\n sceneDescription: \"Vision not active\",\n cameraStatus: cameraInfo\n ? `Camera \"${cameraInfo.name}\" detected but not active`\n : \"No camera\",\n };\n } else {\n perceptionText = `Vision mode: ${visionMode}\\n\\n`;\n\n if (\n (visionMode === \"CAMERA\" || visionMode === \"BOTH\") &&\n sceneDescription\n ) {\n const ageInSeconds = (Date.now() - sceneDescription.timestamp) / 1000;\n const secondsAgo = Math.round(ageInSeconds);\n\n perceptionText += `Camera view (${secondsAgo}s ago):\\n${sceneDescription.description}`;\n\n if (sceneDescription.people.length > 0) {\n perceptionText += `\\n\\nPeople detected: ${sceneDescription.people.length}`;\n const poses = sceneDescription.people\n .map((p) => p.pose)\n .filter((p) => p !== \"unknown\");\n const facings = sceneDescription.people\n .map((p) => p.facing)\n .filter((f) => f !== \"unknown\");\n\n if (poses.length > 0) {\n const poseCounts = poses.reduce(\n (acc, pose) => {\n acc[pose] = (acc[pose] || 0) + 1;\n return acc;\n },\n {} as Record<string, number>,\n );\n perceptionText += `\\n Poses: ${Object.entries(poseCounts)\n .map(([pose, count]) => `${count} ${pose}`)\n .join(\", \")}`;\n }\n\n if (facings.length > 0) {\n const facingCounts = facings.reduce(\n (acc, facing) => {\n acc[facing] = (acc[facing] || 0) + 1;\n return acc;\n },\n {} as Record<string, number>,\n );\n perceptionText += `\\n Facing: ${Object.entries(facingCounts)\n .map(([facing, count]) => `${count} facing ${facing}`)\n .join(\", \")}`;\n }\n }\n\n if (sceneDescription.objects.length > 0) {\n const objectTypes = sceneDescription.objects\n .slice(0, MAX_VISION_OBJECTS_IN_STATE)\n .map((o) => o.type);\n const uniqueObjects = [...new Set(objectTypes)];\n perceptionText += `\\n\\nObjects detected: ${uniqueObjects.join(\", \")}`;\n }\n\n if (sceneDescription.sceneChanged) {\n perceptionText += `\\n\\nScene change: ${sceneDescription.changePercentage.toFixed(1)}% of pixels changed`;\n }\n\n if (entityData) {\n if (entityData.activeEntities.length > 0) {\n perceptionText += \"\\n\\nCurrently tracking:\";\n for (const entity of entityData.activeEntities) {\n const name = entity.name || `Unknown ${entity.type}`;\n const duration =\n entity.duration < 60000\n ? `${Math.round(entity.duration / 1000)}s`\n : `${Math.round(entity.duration / 60000)}m`;\n perceptionText += `\\n- ${name} (present for ${duration})`;\n }\n }\n\n if (entityData.recentlyLeft.length > 0) {\n perceptionText += \"\\n\\nRecently left:\";\n for (const departed of entityData.recentlyLeft) {\n const name = departed.name || \"Unknown person\";\n const timeStr =\n departed.timeAgo < 60000\n ? `${Math.round(departed.timeAgo / 1000)}s ago`\n : `${Math.round(departed.timeAgo / 60000)}m ago`;\n perceptionText += `\\n- ${name} left ${timeStr}`;\n }\n }\n }\n }\n\n if (\n (visionMode === \"SCREEN\" || visionMode === \"BOTH\") &&\n screenCapture\n ) {\n const screenAge = (Date.now() - screenCapture.timestamp) / 1000;\n const screenSecondsAgo = Math.round(screenAge);\n\n if (visionMode === \"BOTH\") {\n perceptionText += \"\\n\\n---\\n\\n\";\n }\n\n perceptionText += `Screen capture (${screenSecondsAgo}s ago):\\n`;\n perceptionText += `Resolution: ${screenCapture.width}x${screenCapture.height}\\n`;\n\n const enhanced = sceneDescription as EnhancedSceneDescription;\n if (enhanced?.screenAnalysis) {\n const tileAnalysis = enhanced.screenAnalysis.activeTile;\n if (tileAnalysis) {\n if (tileAnalysis.summary) {\n perceptionText += `\\nActive area: ${tileAnalysis.summary}`;\n }\n\n if (tileAnalysis.text) {\n perceptionText += `\\n\\nVisible text:\\n\"${tileAnalysis.text.substring(0, 200)}${tileAnalysis.text.length > 200 ? \"...\" : \"\"}\"`;\n }\n\n if (tileAnalysis.objects && tileAnalysis.objects.length > 0) {\n const uiElements = tileAnalysis.objects.map(\n (o) => (o as { type?: string }).type || \"unknown\",\n );\n const uniqueElements = [...new Set(uiElements)];\n perceptionText += `\\n\\nUI elements: ${uniqueElements.join(\", \")}`;\n }\n }\n\n if (enhanced.screenAnalysis.focusedApp) {\n perceptionText += `\\n\\nActive application: ${enhanced.screenAnalysis.focusedApp}`;\n }\n }\n }\n\n values = {\n visionAvailable: true,\n visionMode,\n sceneDescription: sceneDescription?.description || \"Processing...\",\n cameraStatus: cameraInfo\n ? `Connected to ${cameraInfo.name}`\n : \"No camera\",\n cameraId: cameraInfo?.id,\n peopleCount: sceneDescription?.people.length || 0,\n objectCount: sceneDescription?.objects.length || 0,\n sceneAge: sceneDescription\n ? Math.round((Date.now() - sceneDescription.timestamp) / 1000)\n : null,\n lastChange: sceneDescription?.sceneChanged\n ? sceneDescription.changePercentage\n : 0,\n hasScreenCapture: !!screenCapture,\n screenResolution: screenCapture\n ? `${screenCapture.width}x${screenCapture.height}`\n : null,\n activeEntities: entityData?.activeEntities || [],\n recentlyLeft: entityData?.recentlyLeft || [],\n entityStatistics: entityData?.statistics || null,\n };\n\n data = {\n objects:\n sceneDescription?.objects.slice(0, MAX_VISION_OBJECTS_IN_STATE) ||\n [],\n people:\n sceneDescription?.people.slice(0, MAX_VISION_PEOPLE_IN_STATE) || [],\n screenCapture: screenCapture || null,\n enhancedData:\n (sceneDescription as EnhancedSceneDescription)?.screenAnalysis ||\n null,\n trackedEntities: entityData?.activeEntities || [],\n worldState: entityData || null,\n };\n }\n\n return {\n values,\n text: JSON.stringify(\n {\n visual_perception: {\n summary: perceptionText,\n ...values,\n },\n },\n null,\n 2,\n ),\n data,\n };\n } catch (error) {\n return {\n values: {\n visionAvailable: false,\n error: error instanceof Error ? error.message : String(error),\n },\n text: JSON.stringify(\n {\n visual_perception: {\n visionAvailable: false,\n error: error instanceof Error ? error.message : String(error),\n },\n },\n null,\n 2,\n ),\n data: {\n hasVision: false,\n error: error instanceof Error ? error.message : String(error),\n },\n };\n }\n },\n};\n",
|
|
9
|
-
"// Vision service for camera integration and scene analysis\n\nimport { exec } from \"node:child_process\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { promisify } from \"node:util\";\nimport {\n type IAgentRuntime,\n logger,\n ModelType,\n recordLlmCall,\n Service,\n type ServiceTypeName,\n withStandaloneTrajectory,\n} from \"@elizaos/core\";\nimport sharp from \"sharp\";\nimport { AudioCaptureService, type AudioConfig } from \"./audio-capture\";\nimport {\n StreamingAudioCaptureService,\n type StreamingAudioConfig,\n} from \"./audio-capture-stream\";\nimport { EntityTracker } from \"./entity-tracker\";\nimport { FaceRecognition } from \"./face-recognition\";\nimport { Florence2Model } from \"./florence2-model\";\nimport { OCRService } from \"./ocr-service\";\nimport { ScreenCaptureService } from \"./screen-capture\";\nimport { getTestImage } from \"./test-input\";\nimport {\n type BoundingBox,\n type CameraInfo,\n type DetectedObject,\n type EnhancedSceneDescription,\n type PersonInfo,\n type SceneDescription,\n type ScreenCapture,\n type ScreenTile,\n type TileAnalysis,\n type VisionConfig,\n type VisionFrame,\n VisionMode,\n VisionServiceType,\n} from \"./types\";\nimport { VisionModels } from \"./vision-models\";\nimport { VisionWorkerManager } from \"./vision-worker-manager\";\n\nconst execAsync = promisify(exec);\nconst SCENE_DESCRIPTION_PROMPT = JSON.stringify(\n {\n task: \"describe_visual_scene\",\n instructions: [\n \"Describe visible people, objects, UI, text, and notable scene changes.\",\n \"Keep the answer concise and factual.\",\n ],\n },\n null,\n 2,\n);\n\ninterface CameraDevice {\n id: string;\n name: string;\n capture: () => Promise<Buffer>;\n}\n\nexport class VisionService extends Service {\n static override serviceType: ServiceTypeName = VisionServiceType.VISION;\n override capabilityDescription =\n \"Provides visual perception through camera integration and scene analysis.\";\n\n private visionConfig: VisionConfig;\n private camera: CameraDevice | null = null;\n private lastFrame: VisionFrame | null = null;\n private lastSceneDescription: SceneDescription | null = null;\n private frameProcessingInterval: NodeJS.Timeout | null = null;\n private screenProcessingInterval: NodeJS.Timeout | null = null;\n private isProcessing = false;\n private isProcessingScreen = false;\n private visionModels: VisionModels;\n private faceRecognition: FaceRecognition;\n private entityTracker: EntityTracker;\n private audioCapture: AudioCaptureService | null = null;\n private streamingAudioCapture: StreamingAudioCaptureService | null = null;\n\n // Screen vision components\n private screenCapture: ScreenCaptureService;\n private florence2: Florence2Model;\n private ocrService: OCRService;\n private lastScreenCapture: ScreenCapture | null = null;\n private lastEnhancedScene: EnhancedSceneDescription | null = null;\n\n // Worker manager for high-FPS processing\n private workerManager: VisionWorkerManager | null = null;\n\n // Add tracking for last update times\n private lastTfUpdateTime = 0;\n private lastVlmUpdateTime = 0;\n private lastTfDescription = \"\";\n\n // Default configuration\n private readonly DEFAULT_CONFIG: VisionConfig = {\n pixelChangeThreshold: 50, // 50% change required for VLM update\n updateInterval: 100, // Process frames every 100ms\n enablePoseDetection: false,\n enableObjectDetection: false,\n tfUpdateInterval: 1000, // TensorFlow update every 1 second\n vlmUpdateInterval: 10000, // VLM update every 10 seconds\n tfChangeThreshold: 10, // 10% change triggers TF update\n vlmChangeThreshold: 50, // 50% change triggers VLM update\n visionMode: VisionMode.CAMERA, // Default to camera only\n screenCaptureInterval: 2000, // Screen capture every 2 seconds\n tileSize: 256,\n tileProcessingOrder: \"priority\",\n ocrEnabled: true,\n florence2Enabled: true,\n };\n\n constructor(runtime: IAgentRuntime) {\n super(runtime);\n\n // Load configuration from runtime settings\n this.visionConfig = this.parseConfig(runtime);\n\n // Initialize vision models\n this.visionModels = new VisionModels();\n\n // Initialize face recognition\n this.faceRecognition = new FaceRecognition();\n\n // Initialize entity tracker\n const worldIdValue = runtime.getSetting(\"WORLD_ID\");\n const worldId =\n typeof worldIdValue === \"string\" ? worldIdValue : \"default-world\";\n this.entityTracker = new EntityTracker(worldId);\n\n // Initialize screen capture\n this.screenCapture = new ScreenCaptureService(this.visionConfig);\n\n // Initialize Florence-2\n this.florence2 = new Florence2Model();\n\n // Initialize OCR service\n this.ocrService = new OCRService();\n\n logger.info(\n \"[VisionService] Constructed with config:\",\n JSON.stringify(this.visionConfig),\n );\n }\n\n private parseConfig(runtime: IAgentRuntime): VisionConfig {\n const getSettingString = (key: string): string | undefined => {\n const value = runtime.getSetting(key);\n return value === true || value === false\n ? String(value)\n : typeof value === \"string\"\n ? value\n : typeof value === \"number\"\n ? String(value)\n : undefined;\n };\n\n return {\n ...this.DEFAULT_CONFIG,\n cameraName:\n getSettingString(\"CAMERA_NAME\") ||\n getSettingString(\"VISION_CAMERA_NAME\"),\n pixelChangeThreshold:\n Number(\n runtime.getSetting(\"PIXEL_CHANGE_THRESHOLD\") ||\n runtime.getSetting(\"VISION_PIXEL_CHANGE_THRESHOLD\"),\n ) || this.DEFAULT_CONFIG.pixelChangeThreshold,\n enableObjectDetection:\n runtime.getSetting(\"ENABLE_OBJECT_DETECTION\") === \"true\" ||\n runtime.getSetting(\"VISION_ENABLE_OBJECT_DETECTION\") === \"true\",\n enablePoseDetection:\n runtime.getSetting(\"ENABLE_POSE_DETECTION\") === \"true\" ||\n runtime.getSetting(\"VISION_ENABLE_POSE_DETECTION\") === \"true\",\n tfUpdateInterval:\n Number(\n runtime.getSetting(\"TF_UPDATE_INTERVAL\") ||\n runtime.getSetting(\"VISION_TF_UPDATE_INTERVAL\"),\n ) || this.DEFAULT_CONFIG.tfUpdateInterval,\n vlmUpdateInterval:\n Number(\n runtime.getSetting(\"VLM_UPDATE_INTERVAL\") ||\n runtime.getSetting(\"VISION_VLM_UPDATE_INTERVAL\"),\n ) || this.DEFAULT_CONFIG.vlmUpdateInterval,\n tfChangeThreshold:\n Number(\n runtime.getSetting(\"TF_CHANGE_THRESHOLD\") ||\n runtime.getSetting(\"VISION_TF_CHANGE_THRESHOLD\"),\n ) || this.DEFAULT_CONFIG.tfChangeThreshold,\n vlmChangeThreshold:\n Number(\n runtime.getSetting(\"VLM_CHANGE_THRESHOLD\") ||\n runtime.getSetting(\"VISION_VLM_CHANGE_THRESHOLD\"),\n ) || this.DEFAULT_CONFIG.vlmChangeThreshold,\n visionMode:\n (getSettingString(\"VISION_MODE\") as VisionMode) ||\n this.DEFAULT_CONFIG.visionMode,\n screenCaptureInterval:\n Number(\n runtime.getSetting(\"SCREEN_CAPTURE_INTERVAL\") ||\n runtime.getSetting(\"VISION_SCREEN_CAPTURE_INTERVAL\"),\n ) || this.DEFAULT_CONFIG.screenCaptureInterval,\n ocrEnabled:\n getSettingString(\"OCR_ENABLED\") === \"true\" ||\n getSettingString(\"VISION_OCR_ENABLED\") === \"true\",\n florence2Enabled:\n getSettingString(\"FLORENCE2_ENABLED\") === \"true\" ||\n getSettingString(\"VISION_FLORENCE2_ENABLED\") === \"true\",\n };\n }\n\n static async start(runtime: IAgentRuntime): Promise<VisionService> {\n const service = new VisionService(runtime);\n await service.initialize();\n return service;\n }\n\n private async checkCameraTools(): Promise<{\n available: boolean;\n tool: string;\n }> {\n const platform = process.platform;\n\n try {\n if (platform === \"darwin\") {\n // Check if imagesnap is installed\n await execAsync(\"which imagesnap\");\n return { available: true, tool: \"imagesnap\" };\n } else if (platform === \"linux\") {\n // Check if fswebcam is installed\n await execAsync(\"which fswebcam\");\n return { available: true, tool: \"fswebcam\" };\n } else if (platform === \"win32\") {\n // Check if ffmpeg is available\n await execAsync(\"where ffmpeg\");\n return { available: true, tool: \"ffmpeg\" };\n }\n return { available: false, tool: \"none\" };\n } catch (_error) {\n // Tool not found\n return { available: false, tool: \"none\" };\n }\n }\n\n private async initialize(): Promise<void> {\n try {\n // Initialize vision models if enabled\n const useEnhancedModels =\n this.visionConfig.enableObjectDetection ||\n this.visionConfig.enablePoseDetection;\n\n if (useEnhancedModels) {\n try {\n // Try to initialize TensorFlow models first\n await this.visionModels.initialize({\n enableObjectDetection:\n this.visionConfig.enableObjectDetection || false,\n enablePoseDetection: this.visionConfig.enablePoseDetection || false,\n });\n logger.info(\n \"[VisionService] Using TensorFlow.js models for advanced detection\",\n );\n } catch (_tfError) {\n logger.warn(\n \"[VisionService] TensorFlow.js not available, falling back to enhanced heuristics\",\n );\n // Fall back to enhanced heuristics\n await this.visionModels.initialize({\n enableObjectDetection:\n this.visionConfig.enableObjectDetection || false,\n enablePoseDetection: this.visionConfig.enablePoseDetection || false,\n });\n logger.info(\n \"[VisionService] Using enhanced heuristics for detection\",\n );\n }\n }\n\n // Initialize screen vision if enabled\n if (\n this.visionConfig.visionMode === VisionMode.SCREEN ||\n this.visionConfig.visionMode === VisionMode.BOTH\n ) {\n await this.initializeScreenVision();\n }\n\n // Initialize camera if enabled\n if (\n this.visionConfig.visionMode === VisionMode.CAMERA ||\n this.visionConfig.visionMode === VisionMode.BOTH\n ) {\n await this.initializeCameraVision();\n }\n\n // Initialize audio capture if enabled\n await this.initializeAudioCapture();\n\n // Start processing based on mode\n this.startProcessing();\n } catch (error) {\n logger.error(\"[VisionService] Failed to initialize:\", error);\n }\n }\n\n private async initializeScreenVision(): Promise<void> {\n try {\n logger.info(\"[VisionService] Initializing screen vision...\");\n\n // Check if we should use worker threads for high-FPS processing\n const useWorkers =\n this.visionConfig.targetScreenFPS &&\n this.visionConfig.targetScreenFPS > 10;\n\n if (useWorkers) {\n // Initialize worker manager for high-FPS processing\n logger.info(\n \"[VisionService] Initializing worker threads for high-FPS processing...\",\n );\n this.workerManager = new VisionWorkerManager(this.visionConfig);\n await this.workerManager.initialize();\n logger.info(\"[VisionService] Worker threads initialized\");\n } else {\n // Initialize standard components\n // Initialize Florence-2 if enabled\n if (this.visionConfig.florence2Enabled) {\n await this.florence2.initialize();\n }\n\n // Initialize OCR if enabled\n if (this.visionConfig.ocrEnabled) {\n await this.ocrService.initialize();\n }\n }\n\n // Get screen info\n const screenInfo = await this.screenCapture.getScreenInfo();\n if (screenInfo) {\n logger.info(\n `[VisionService] Screen resolution: ${screenInfo.width}x${screenInfo.height}`,\n );\n }\n\n logger.info(\"[VisionService] Screen vision initialized\");\n } catch (error) {\n logger.error(\n \"[VisionService] Failed to initialize screen vision:\",\n error,\n );\n }\n }\n\n private async initializeCameraVision(): Promise<void> {\n // Check if camera tools are available\n const toolCheck = await this.checkCameraTools();\n if (!toolCheck.available) {\n const platform = process.platform;\n const toolName =\n platform === \"darwin\"\n ? \"imagesnap\"\n : platform === \"linux\"\n ? \"fswebcam\"\n : \"ffmpeg\";\n logger.warn(\n `[VisionService] Camera capture tool '${toolName}' not found. Install it to enable camera functionality.`,\n );\n logger.warn(\"[VisionService] For macOS: brew install imagesnap\");\n logger.warn(\"[VisionService] For Linux: sudo apt-get install fswebcam\");\n logger.warn(\n \"[VisionService] For Windows: Install ffmpeg and add to PATH\",\n );\n return;\n }\n\n // Find and connect to camera\n const camera = await this.findCamera();\n if (camera) {\n this.camera = camera;\n logger.info(`[VisionService] Connected to camera: ${camera.name}`);\n } else {\n logger.warn(\"[VisionService] No suitable camera found\");\n }\n }\n\n private async initializeAudioCapture(): Promise<void> {\n const getSettingString = (key: string): string | undefined => {\n const value = this.runtime.getSetting(key);\n return value === true || value === false\n ? String(value)\n : typeof value === \"string\"\n ? value\n : typeof value === \"number\"\n ? String(value)\n : undefined;\n };\n const enableMicrophone = getSettingString(\"ENABLE_MICROPHONE\") === \"true\";\n const useStreamingAudio =\n getSettingString(\"USE_STREAMING_AUDIO\") === \"true\";\n\n if (!enableMicrophone) {\n logger.info(\"[VisionService] Microphone capture disabled\");\n return;\n }\n\n try {\n if (useStreamingAudio) {\n // Use new streaming audio with VAD\n const getSettingNumber = (\n key: string,\n defaultValue: number,\n ): number => {\n const value = this.runtime.getSetting(key);\n if (typeof value === \"number\") return value;\n if (typeof value === \"string\") {\n const parsed = Number(value);\n return Number.isNaN(parsed) ? defaultValue : parsed;\n }\n return defaultValue;\n };\n const streamingConfig: StreamingAudioConfig = {\n enabled: true,\n sampleRate: 16000,\n channels: 1,\n vadThreshold: getSettingNumber(\"VAD_THRESHOLD\", 0.01),\n silenceTimeout: getSettingNumber(\"SILENCE_TIMEOUT\", 1500),\n responseDelay: getSettingNumber(\"RESPONSE_DELAY\", 3000),\n };\n\n this.streamingAudioCapture = new StreamingAudioCaptureService(\n this.runtime,\n streamingConfig,\n );\n\n // Set up event listeners\n this.streamingAudioCapture.on(\"speechStart\", () => {\n logger.info(\"[VisionService] User started speaking\");\n });\n\n this.streamingAudioCapture.on(\"speechEnd\", () => {\n logger.info(\"[VisionService] User stopped speaking\");\n });\n\n this.streamingAudioCapture.on(\n \"transcription\",\n (data: { text: string; isFinal: boolean }) => {\n logger.info(\n `[VisionService] Transcription (${data.isFinal ? \"final\" : \"partial\"}): ${data.text}`,\n );\n },\n );\n\n this.streamingAudioCapture.on(\n \"utteranceComplete\",\n async (text: string) => {\n logger.info(\"[VisionService] Processing complete utterance:\", text);\n // Store the transcription in memory for context\n await this.storeAudioTranscription(text);\n },\n );\n\n await this.streamingAudioCapture.initialize();\n logger.info(\n \"[VisionService] Streaming audio capture initialized with VAD\",\n );\n } else {\n // Use original batch audio capture\n const getSettingNumber = (\n key: string,\n defaultValue: number,\n ): number => {\n const value = this.runtime.getSetting(key);\n if (typeof value === \"number\") return value;\n if (typeof value === \"string\") {\n const parsed = Number(value);\n return Number.isNaN(parsed) ? defaultValue : parsed;\n }\n return defaultValue;\n };\n const audioConfig: AudioConfig = {\n enabled: true,\n transcriptionInterval: getSettingNumber(\n \"TRANSCRIPTION_INTERVAL\",\n 30000,\n ),\n };\n\n this.audioCapture = new AudioCaptureService(this.runtime, audioConfig);\n await this.audioCapture.initialize();\n logger.info(\"[VisionService] Batch audio capture initialized\");\n }\n } catch (error) {\n logger.error(\n \"[VisionService] Failed to initialize audio capture:\",\n error,\n );\n // Continue without audio\n }\n }\n\n private async storeAudioTranscription(text: string): Promise<void> {\n try {\n // Store transcription in the current scene description\n if (this.lastSceneDescription) {\n this.lastSceneDescription.audioTranscription = text;\n }\n\n // You could also create a memory here if needed\n logger.debug(\n \"[VisionService] Stored audio transcription in scene context\",\n );\n } catch (error) {\n logger.error(\n \"[VisionService] Failed to store audio transcription:\",\n error,\n );\n }\n }\n\n private startProcessing(): void {\n // Start camera processing if enabled\n if (\n (this.visionConfig.visionMode === VisionMode.CAMERA ||\n this.visionConfig.visionMode === VisionMode.BOTH) &&\n this.camera\n ) {\n this.startFrameProcessing();\n }\n\n // Start screen processing if enabled\n if (\n this.visionConfig.visionMode === VisionMode.SCREEN ||\n this.visionConfig.visionMode === VisionMode.BOTH\n ) {\n this.startScreenProcessing();\n }\n }\n\n private startFrameProcessing(): void {\n if (this.frameProcessingInterval) {\n return;\n }\n\n this.frameProcessingInterval = setInterval(async () => {\n if (!this.isProcessing && this.camera) {\n this.isProcessing = true;\n try {\n await this.captureAndProcessFrame();\n } catch (error) {\n logger.error(\"[VisionService] Frame processing error:\", error);\n }\n this.isProcessing = false;\n }\n }, this.visionConfig.updateInterval || 100);\n\n logger.debug(\"[VisionService] Started frame processing loop\");\n }\n\n private async captureAndProcessFrame(): Promise<void> {\n if (!this.camera) {\n return;\n }\n\n try {\n // Capture frame from camera\n const frameData = await this.camera.capture();\n\n // Skip if no data\n if (!frameData || frameData.length === 0) {\n logger.debug(\"[VisionService] Camera returned empty frame, skipping\");\n return;\n }\n\n // Convert to standardized format\n const frame = await this.processFrameData(frameData);\n\n // Validate frame before processing\n if (!frame || frame.width === 0 || frame.height === 0) {\n logger.warn(\"[VisionService] Invalid frame dimensions, skipping\");\n return;\n }\n\n // Check if scene has changed significantly\n const changePercentage = this.lastFrame\n ? await this.calculatePixelChange(this.lastFrame, frame)\n : 100;\n\n // Update scene description if change is significant or enough time has passed\n // Always call updateSceneDescription - it will decide what to update based on thresholds\n await this.updateSceneDescription(frame, changePercentage);\n\n this.lastFrame = frame;\n } catch (error) {\n logger.error(\"[VisionService] Error capturing frame:\", error);\n }\n }\n\n private async processFrameData(data: Buffer): Promise<VisionFrame> {\n // Validate input data\n if (!data || data.length === 0) {\n throw new Error(\"Empty frame data received from camera\");\n }\n\n // Use sharp to ensure consistent format\n const image = sharp(data);\n const metadata = await image.metadata();\n\n // Validate metadata\n if (\n !metadata.width ||\n !metadata.height ||\n metadata.width === 0 ||\n metadata.height === 0\n ) {\n throw new Error(\n `Invalid image dimensions: ${metadata.width}x${metadata.height}`,\n );\n }\n\n const rgbaBuffer = await image.ensureAlpha().raw().toBuffer();\n\n return {\n timestamp: Date.now(),\n width: metadata.width,\n height: metadata.height,\n data: rgbaBuffer,\n format: \"rgba\",\n };\n }\n\n private async calculatePixelChange(\n frame1: VisionFrame,\n frame2: VisionFrame,\n ): Promise<number> {\n if (frame1.width !== frame2.width || frame1.height !== frame2.height) {\n return 100; // Different dimensions = complete change\n }\n\n const pixels1 = frame1.data;\n const pixels2 = frame2.data;\n let changedPixels = 0;\n const totalPixels = frame1.width * frame1.height;\n const threshold = 30; // RGB difference threshold\n\n for (let i = 0; i < pixels1.length; i += 4) {\n const r1 = pixels1[i];\n const g1 = pixels1[i + 1];\n const b1 = pixels1[i + 2];\n const r2 = pixels2[i];\n const g2 = pixels2[i + 1];\n const b2 = pixels2[i + 2];\n\n const diff = Math.abs(r1 - r2) + Math.abs(g1 - g2) + Math.abs(b1 - b2);\n if (diff > threshold) {\n changedPixels++;\n }\n }\n\n return (changedPixels / totalPixels) * 100;\n }\n\n private async updateSceneDescription(\n frame: VisionFrame,\n changePercentage: number,\n ): Promise<void> {\n try {\n const currentTime = Date.now();\n\n // Test-input override: when ELIZA_VISION_TEST_INPUT=image, replace the\n // captured frame with the fixture PNG so the rest of the pipeline runs\n // unmodified. Returns null when no override is active.\n const testImage = getTestImage();\n\n // Convert frame to base64 for VLM\n const jpegBuffer = testImage\n ? await sharp(testImage).jpeg().toBuffer()\n : await sharp(frame.data, {\n raw: {\n width: frame.width,\n height: frame.height,\n channels: 4,\n },\n })\n .jpeg()\n .toBuffer();\n\n const base64Image = jpegBuffer.toString(\"base64\");\n const imageUrl = `data:image/jpeg;base64,${base64Image}`;\n\n // Determine if we should update VLM description\n const timeSinceVlmUpdate = currentTime - this.lastVlmUpdateTime;\n const vlmUpdateInterval = this.visionConfig.vlmUpdateInterval ?? 10000;\n const vlmChangeThreshold = this.visionConfig.vlmChangeThreshold ?? 50;\n const shouldUpdateVlm =\n timeSinceVlmUpdate >= vlmUpdateInterval || // Time threshold\n changePercentage >= vlmChangeThreshold; // Change threshold\n\n let description = this.lastTfDescription;\n\n if (shouldUpdateVlm) {\n // Use VLM to describe the scene\n description = await this.describeSceneWithVLM(imageUrl);\n this.lastVlmUpdateTime = currentTime;\n this.lastTfDescription = description;\n logger.debug(\n `[VisionService] VLM updated: ${timeSinceVlmUpdate}ms since last update, ${changePercentage.toFixed(1)}% change`,\n );\n }\n\n // Determine if we should update TensorFlow detections\n const timeSinceTfUpdate = currentTime - this.lastTfUpdateTime;\n const tfUpdateInterval = this.visionConfig.tfUpdateInterval ?? 1000;\n const tfChangeThreshold = this.visionConfig.tfChangeThreshold ?? 10;\n const shouldUpdateTf =\n timeSinceTfUpdate >= tfUpdateInterval || // Time threshold\n changePercentage >= tfChangeThreshold; // Change threshold\n\n let detectedObjects: DetectedObject[] = [];\n let people: PersonInfo[] = [];\n\n if (\n shouldUpdateTf &&\n (this.visionConfig.enableObjectDetection ||\n this.visionConfig.enablePoseDetection)\n ) {\n this.lastTfUpdateTime = currentTime;\n logger.debug(\n `[VisionService] TF updating: ${timeSinceTfUpdate}ms since last update, ${changePercentage.toFixed(1)}% change`,\n );\n\n // Use advanced computer vision if enabled\n if (this.visionConfig.enableObjectDetection) {\n if (this.visionModels.hasObjectDetection()) {\n detectedObjects = await this.visionModels.detectObjects(\n frame.data,\n frame.width,\n frame.height,\n );\n logger.debug(\n `[VisionService] VisionModels detected ${detectedObjects.length} objects`,\n );\n }\n }\n\n if (this.visionConfig.enablePoseDetection) {\n if (this.visionModels.hasPoseDetection()) {\n const poses = await this.visionModels.detectPoses(\n frame.data,\n frame.width,\n frame.height,\n );\n people = poses;\n logger.debug(\n `[VisionService] VisionModels detected ${people.length} people with poses`,\n );\n }\n }\n\n // If no people detected via pose but objects detected, check for person objects\n if (people.length === 0 && detectedObjects.length > 0) {\n const personObjects = detectedObjects.filter(\n (obj) => obj.type === \"person\",\n );\n people = personObjects.map((obj) => ({\n id: `person-${obj.id}`,\n pose: \"unknown\" as const,\n facing: \"unknown\" as const,\n confidence: obj.confidence,\n boundingBox: obj.boundingBox,\n }));\n }\n } else if (!shouldUpdateTf && this.lastSceneDescription) {\n // Reuse last detection results if not updating\n detectedObjects = this.lastSceneDescription.objects;\n people = this.lastSceneDescription.people;\n } else {\n // Fall back to motion-based detection\n detectedObjects = await this.detectMotionObjects(frame);\n people = await this.detectPeopleFromMotion(frame, detectedObjects);\n }\n\n // Face recognition and entity tracking\n const faceProfiles = new Map<string, string>();\n const getSettingString = (key: string): string | undefined => {\n const value = this.runtime.getSetting(key);\n return value === true || value === false\n ? String(value)\n : typeof value === \"string\"\n ? value\n : typeof value === \"number\"\n ? String(value)\n : undefined;\n };\n const enableFaceRecognition =\n getSettingString(\"ENABLE_FACE_RECOGNITION\") === \"true\";\n\n if (\n enableFaceRecognition &&\n people.length > 0 &&\n frame.width > 0 &&\n frame.height > 0\n ) {\n try {\n // Validate frame data\n if (frame.data.length === 0) {\n logger.warn(\n \"[VisionService] Invalid frame data for face recognition\",\n );\n return;\n }\n\n // Detect faces in the frame\n const faces = await this.faceRecognition.detectFaces(\n frame.data,\n frame.width,\n frame.height,\n );\n\n // Match faces to people based on bounding box overlap\n for (const face of faces) {\n const faceBox = face.detection.box;\n\n // Find the person this face belongs to\n for (const person of people) {\n const overlap = this.calculateBoxOverlap(person.boundingBox, {\n x: Math.round(faceBox.x),\n y: Math.round(faceBox.y),\n width: Math.round(faceBox.width),\n height: Math.round(faceBox.height),\n });\n\n if (overlap > 0.5) {\n // 50% overlap threshold\n // Recognize or register the face\n const match = await this.faceRecognition.recognizeFace(\n face.descriptor,\n );\n let profileId: string;\n\n if (match) {\n profileId = match.profileId;\n logger.debug(\n `[VisionService] Recognized face: ${profileId} (distance: ${match.distance})`,\n );\n } else {\n // Register new face\n profileId = await this.faceRecognition.addOrUpdateFace(\n face.descriptor,\n {\n attributes: {\n age: face.ageGender?.age.toString(),\n gender: face.ageGender?.gender,\n emotion: face.expressions\n ? this.getDominantExpression(face.expressions)\n : undefined,\n },\n },\n );\n logger.info(\n `[VisionService] New face registered: ${profileId}`,\n );\n }\n\n faceProfiles.set(person.id, profileId);\n break;\n }\n }\n }\n } catch (faceError) {\n logger.error(\"[VisionService] Face recognition error:\", faceError);\n }\n }\n\n // Update entity tracker\n const _trackedEntities = await this.entityTracker.updateEntities(\n detectedObjects,\n people,\n faceProfiles,\n this.runtime,\n );\n\n // Create scene description\n this.lastSceneDescription = {\n timestamp: frame.timestamp,\n description,\n objects: detectedObjects,\n people,\n sceneChanged: shouldUpdateVlm || shouldUpdateTf,\n changePercentage,\n };\n\n // Enhanced logging\n if (shouldUpdateVlm || shouldUpdateTf) {\n logger.info(\"[VisionService] Scene Analysis Complete:\");\n logger.info(` VLM Description: ${description.substring(0, 100)}...`);\n logger.info(` Change: ${changePercentage.toFixed(1)}%`);\n logger.info(\n ` Updates: ${shouldUpdateVlm ? \"VLM\" : \"\"}${shouldUpdateVlm && shouldUpdateTf ? \" + \" : \"\"}${shouldUpdateTf ? \"TF\" : \"\"}`,\n );\n logger.info(\n ` Detection Mode: ${this.visionConfig.enableObjectDetection ? \"Advanced CV\" : \"Motion-based\"}`,\n );\n\n if (detectedObjects.length > 0) {\n logger.info(` Objects: ${detectedObjects.length} detected`);\n\n // Group objects by type for summary\n const objectSummary = detectedObjects.reduce(\n (acc, obj) => {\n acc[obj.type] = (acc[obj.type] || 0) + 1;\n return acc;\n },\n {} as Record<string, number>,\n );\n\n for (const [type, count] of Object.entries(objectSummary)) {\n logger.info(` - ${count} ${type}(s)`);\n }\n }\n\n if (people.length > 0) {\n logger.info(` People: ${people.length} detected`);\n for (const person of people) {\n logger.info(\n ` - Person: ${person.pose} pose, facing ${person.facing}, confidence: ${person.confidence.toFixed(2)}`,\n );\n }\n }\n }\n } catch (error) {\n logger.error(\n \"[VisionService] Failed to update scene description:\",\n error,\n );\n }\n }\n\n private async describeSceneWithVLM(imageUrl: string): Promise<string> {\n return withStandaloneTrajectory(\n this.runtime,\n {\n source: \"plugin-vision:scene-description\",\n metadata: { modelType: ModelType.IMAGE_DESCRIPTION },\n },\n () => this.describeSceneWithVLMInTrajectory(imageUrl),\n );\n }\n\n private async describeSceneWithVLMInTrajectory(\n imageUrl: string,\n ): Promise<string> {\n try {\n // Convert base64 image URL to buffer for Florence-2\n if (imageUrl.startsWith(\"data:image/\")) {\n const base64Data = imageUrl.split(\",\")[1];\n const imageBuffer = Buffer.from(base64Data, \"base64\");\n\n // Use Florence-2 for all image descriptions\n if (this.florence2.isInitialized()) {\n try {\n const result = await recordLlmCall(\n this.runtime,\n {\n model: \"florence2-local\",\n systemPrompt: \"\",\n userPrompt: JSON.stringify(\n {\n task: \"describe_visual_scene\",\n image: {\n source: \"camera_frame\",\n mimeType: \"image/jpeg\",\n bytes: imageBuffer.byteLength,\n },\n },\n null,\n 2,\n ),\n temperature: 0,\n maxTokens: 0,\n purpose: \"background\",\n actionType: \"florence2.analyzeImage\",\n },\n () => this.florence2.analyzeImage(imageBuffer),\n );\n if (result.caption) {\n logger.debug(\n \"[VisionService] Florence-2 description:\",\n result.caption,\n );\n return result.caption;\n }\n } catch (florenceError) {\n logger.warn(\n \"[VisionService] Florence-2 analysis failed, falling back:\",\n florenceError,\n );\n }\n }\n }\n\n // Fallback to runtime model if Florence-2 is not available\n try {\n const result = await this.runtime.useModel(\n ModelType.IMAGE_DESCRIPTION,\n {\n imageUrl,\n prompt: SCENE_DESCRIPTION_PROMPT,\n },\n );\n\n if (result && typeof result === \"object\" && \"description\" in result) {\n const description = (result as { description: string }).description;\n // Check if we got the unhelpful default response\n if (\n !description.includes(\"I'm unable to analyze images\") &&\n !description.includes(\"I can't analyze images\")\n ) {\n return description;\n }\n } else if (typeof result === \"string\") {\n const stringResult = result as string;\n if (\n stringResult.length > 0 &&\n !stringResult.includes(\"I'm unable to analyze images\") &&\n !stringResult.includes(\"I can't analyze images\")\n ) {\n return stringResult;\n }\n }\n } catch (modelError) {\n logger.warn(\n \"[VisionService] Runtime IMAGE_DESCRIPTION model failed:\",\n modelError,\n );\n }\n\n // If we got the unhelpful response or an error, provide a basic description based on detected objects\n if (this.lastSceneDescription) {\n const { objects, people } = this.lastSceneDescription;\n let description = \"Scene contains\";\n\n if (people.length > 0) {\n description += ` ${people.length} person${people.length > 1 ? \"s\" : \"\"}`;\n const poses = people\n .map((p) => p.pose)\n .filter((p) => p !== \"unknown\");\n if (poses.length > 0) {\n description += ` (${poses.join(\", \")})`;\n }\n }\n\n if (objects.length > 0 && people.length > 0) {\n description += \" and\";\n }\n\n if (objects.length > 0) {\n const objectTypes = [...new Set(objects.map((o) => o.type))];\n description += ` ${objectTypes.join(\", \")}`;\n }\n\n if (people.length === 0 && objects.length === 0) {\n description = \"Scene appears to be empty or static\";\n }\n\n return description;\n }\n\n // Final fallback\n return \"Visual scene captured\";\n } catch (error) {\n logger.error(\"[VisionService] VLM description failed:\", error);\n return \"Unable to describe scene\";\n }\n }\n\n private async detectMotionObjects(\n frame: VisionFrame,\n ): Promise<DetectedObject[]> {\n if (!this.lastFrame) {\n return [];\n }\n\n const objects: DetectedObject[] = [];\n const blockSize = 64; // Larger blocks for less noise\n const motionThreshold = 50; // Higher threshold for more significant changes\n\n // Divide frame into blocks and detect motion regions\n for (let y = 0; y < frame.height - blockSize; y += blockSize / 2) {\n // Overlap blocks\n for (let x = 0; x < frame.width - blockSize; x += blockSize / 2) {\n let blockMotion = 0;\n let pixelCount = 0;\n\n // Check motion in this block\n for (let by = 0; by < blockSize; by += 2) {\n // Sample every other pixel for speed\n for (let bx = 0; bx < blockSize; bx += 2) {\n const px = x + bx;\n const py = y + by;\n const idx = (py * frame.width + px) * 4;\n\n if (idx < frame.data.length && idx < this.lastFrame.data.length) {\n const r1 = frame.data[idx];\n const g1 = frame.data[idx + 1];\n const b1 = frame.data[idx + 2];\n const r2 = this.lastFrame.data[idx];\n const g2 = this.lastFrame.data[idx + 1];\n const b2 = this.lastFrame.data[idx + 2];\n\n const diff =\n Math.abs(r1 - r2) + Math.abs(g1 - g2) + Math.abs(b1 - b2);\n if (diff > motionThreshold) {\n blockMotion++;\n }\n pixelCount++;\n }\n }\n }\n\n // If significant motion in block, consider it an object\n const motionPercentage = (blockMotion / pixelCount) * 100;\n if (motionPercentage > 30) {\n // 30% of sampled pixels show motion\n objects.push({\n id: `motion-${x}-${y}-${frame.timestamp}`,\n type: \"motion-object\",\n confidence: Math.min(motionPercentage / 100, 1),\n boundingBox: {\n x,\n y,\n width: blockSize,\n height: blockSize,\n },\n });\n }\n }\n }\n\n // Merge adjacent motion blocks into larger objects\n const merged = this.mergeAdjacentObjects(objects);\n\n // Filter out very small objects (likely noise)\n const filtered = merged.filter((obj) => {\n const area = obj.boundingBox.width * obj.boundingBox.height;\n return area > 2000; // Minimum area threshold\n });\n\n return filtered;\n }\n\n private mergeAdjacentObjects(objects: DetectedObject[]): DetectedObject[] {\n if (objects.length === 0) {\n return [];\n }\n\n const merged: DetectedObject[] = [];\n const used = new Set<number>();\n const mergeDistance = 80; // Distance to consider objects adjacent\n\n for (let i = 0; i < objects.length; i++) {\n if (used.has(i)) {\n continue;\n }\n\n const current = objects[i];\n const cluster: DetectedObject[] = [current];\n used.add(i);\n\n // Find all adjacent objects\n let foundNew = true;\n while (foundNew) {\n foundNew = false;\n for (let j = 0; j < objects.length; j++) {\n if (used.has(j)) {\n continue;\n }\n\n const other = objects[j];\n\n // Check if adjacent to any object in cluster\n for (const clusterObj of cluster) {\n const isAdjacent =\n Math.abs(clusterObj.boundingBox.x - other.boundingBox.x) <=\n mergeDistance &&\n Math.abs(clusterObj.boundingBox.y - other.boundingBox.y) <=\n mergeDistance;\n\n if (isAdjacent) {\n cluster.push(other);\n used.add(j);\n foundNew = true;\n break;\n }\n }\n }\n }\n\n // Merge cluster into single object\n if (cluster.length > 0) {\n const minX = Math.min(...cluster.map((o) => o.boundingBox.x));\n const minY = Math.min(...cluster.map((o) => o.boundingBox.y));\n const maxX = Math.max(\n ...cluster.map((o) => o.boundingBox.x + o.boundingBox.width),\n );\n const maxY = Math.max(\n ...cluster.map((o) => o.boundingBox.y + o.boundingBox.height),\n );\n const avgConfidence =\n cluster.reduce((sum, o) => sum + o.confidence, 0) / cluster.length;\n\n merged.push({\n id: `merged-${minX}-${minY}-${Date.now()}`,\n type: this.classifyObjectBySize(maxX - minX, maxY - minY),\n confidence: avgConfidence,\n boundingBox: {\n x: minX,\n y: minY,\n width: maxX - minX,\n height: maxY - minY,\n },\n });\n }\n }\n\n return merged;\n }\n\n private classifyObjectBySize(width: number, height: number): string {\n const area = width * height;\n const aspectRatio = width / height;\n\n // Improved classification heuristics\n if (area > 30000 && aspectRatio > 0.4 && aspectRatio < 0.8) {\n return \"person-candidate\";\n } else if (area > 20000) {\n return \"large-object\";\n } else if (area > 8000) {\n return \"medium-object\";\n } else {\n return \"small-object\";\n }\n }\n\n private async detectPeopleFromMotion(\n frame: VisionFrame,\n objects: DetectedObject[],\n ): Promise<PersonInfo[]> {\n const people: PersonInfo[] = [];\n const personCandidates = objects.filter(\n (o) => o.type === \"person-candidate\",\n );\n\n for (let i = 0; i < personCandidates.length; i++) {\n const candidate = personCandidates[i];\n const box = candidate.boundingBox;\n\n // Simple heuristic: if height > width * 1.5, likely standing\n // if width > height, likely sitting/lying\n const aspectRatio = box.width / box.height;\n let pose: \"standing\" | \"sitting\" | \"lying\" | \"unknown\" = \"unknown\";\n\n if (aspectRatio < 0.6) {\n pose = \"standing\";\n } else if (aspectRatio > 1.2) {\n pose = \"lying\";\n } else {\n pose = \"sitting\";\n }\n\n // Estimate facing based on motion direction (simplified)\n let facing: \"camera\" | \"away\" | \"left\" | \"right\" | \"unknown\" = \"unknown\";\n if (this.lastFrame) {\n // In Phase 1, we'll just use 'unknown' or random assignment\n // Phase 2 will implement proper pose detection\n facing = \"camera\"; // Default assumption\n }\n\n people.push({\n id: `person-${i}-${frame.timestamp}`,\n confidence: candidate.confidence,\n pose,\n facing,\n boundingBox: box,\n });\n }\n\n return people;\n }\n\n private startScreenProcessing(): void {\n if (this.screenProcessingInterval) {\n return;\n }\n\n this.screenProcessingInterval = setInterval(async () => {\n if (!this.isProcessingScreen) {\n this.isProcessingScreen = true;\n try {\n await this.captureAndProcessScreen();\n } catch (error) {\n logger.error(\"[VisionService] Screen processing error:\", error);\n }\n this.isProcessingScreen = false;\n }\n }, this.visionConfig.screenCaptureInterval || 2000);\n\n logger.debug(\"[VisionService] Started screen processing loop\");\n }\n\n private async captureAndProcessScreen(): Promise<void> {\n try {\n // Capture screen\n const capture = await this.screenCapture.captureScreen();\n this.lastScreenCapture = capture;\n\n // Process active tile\n const activeTile = this.screenCapture.getActiveTile();\n if (activeTile?.data) {\n const tileAnalysis = await this.analyzeTile(activeTile);\n activeTile.analysis = tileAnalysis;\n }\n\n // Update enhanced scene description\n await this.updateEnhancedSceneDescription();\n } catch (error) {\n logger.error(\"[VisionService] Error capturing screen:\", error);\n }\n }\n\n private async analyzeTile(tile: ScreenTile): Promise<TileAnalysis> {\n const analysis: TileAnalysis = {\n timestamp: Date.now(),\n };\n\n try {\n // Run Florence-2 analysis if enabled\n if (this.visionConfig.florence2Enabled && tile.data) {\n analysis.florence2 = await this.florence2.analyzeTile(tile);\n analysis.summary = analysis.florence2.caption;\n }\n\n // Run OCR if enabled\n if (this.visionConfig.ocrEnabled && tile.data) {\n analysis.ocr = await this.ocrService.extractFromTile(tile);\n analysis.text = analysis.ocr.fullText;\n }\n\n // Extract objects from Florence-2 results\n if (analysis.florence2?.objects) {\n analysis.objects = analysis.florence2.objects.map((obj) => ({\n id: `screen-obj-${Date.now()}-${Math.random()}`,\n type: obj.label,\n confidence: obj.confidence,\n boundingBox: obj.bbox,\n }));\n }\n } catch (error) {\n logger.error(\"[VisionService] Error analyzing tile:\", error);\n }\n\n return analysis;\n }\n\n private async updateEnhancedSceneDescription(): Promise<void> {\n if (!this.lastScreenCapture) {\n return;\n }\n\n const enhancedScene: EnhancedSceneDescription = {\n ...(this.lastSceneDescription || {\n timestamp: Date.now(),\n description: \"\",\n objects: [],\n people: [],\n sceneChanged: false,\n changePercentage: 0,\n }),\n screenCapture: this.lastScreenCapture,\n screenAnalysis: {\n fullScreenOCR: \"\",\n activeTile: this.screenCapture.getActiveTile()?.analysis,\n gridSummary: \"\",\n focusedApp: \"\",\n uiElements: [],\n },\n };\n\n // Aggregate OCR from all processed tiles\n const processedTiles = this.lastScreenCapture.tiles.filter(\n (t) => t.analysis?.ocr,\n );\n if (processedTiles.length > 0 && enhancedScene.screenAnalysis) {\n enhancedScene.screenAnalysis.fullScreenOCR = processedTiles\n .map((t) => t.analysis?.ocr?.fullText)\n .join(\"\\n\");\n }\n\n // Generate grid summary\n if (\n this.lastScreenCapture.tiles.length > 0 &&\n enhancedScene.screenAnalysis\n ) {\n const tilesWithContent = this.lastScreenCapture.tiles.filter(\n (t) => t.analysis,\n );\n enhancedScene.screenAnalysis.gridSummary = `Screen divided into ${this.lastScreenCapture.tiles.length} tiles, ${tilesWithContent.length} analyzed`;\n }\n\n // Detect focused application (heuristic based on UI elements)\n if (enhancedScene.screenAnalysis?.activeTile?.florence2?.objects) {\n const windows =\n enhancedScene.screenAnalysis.activeTile.florence2.objects.filter(\n (obj) => obj.label === \"window\",\n );\n if (windows.length > 0 && enhancedScene.screenAnalysis) {\n enhancedScene.screenAnalysis.focusedApp = \"Desktop Application\";\n }\n }\n\n this.lastEnhancedScene = enhancedScene;\n }\n\n // Public API methods\n\n public async getCurrentFrame(): Promise<VisionFrame | null> {\n return this.lastFrame;\n }\n\n public async getSceneDescription(): Promise<SceneDescription | null> {\n return this.lastSceneDescription;\n }\n\n public async getEnhancedSceneDescription(): Promise<EnhancedSceneDescription | null> {\n // If worker manager is available, use its high-FPS data\n if (this.workerManager) {\n return this.workerManager.getLatestEnhancedScene();\n }\n\n // Otherwise fall back to standard processing\n return this.lastEnhancedScene || this.lastSceneDescription;\n }\n\n public async getScreenCapture(): Promise<ScreenCapture | null> {\n return this.lastScreenCapture;\n }\n\n public getVisionMode(): VisionMode {\n return this.visionConfig.visionMode || VisionMode.CAMERA;\n }\n\n public async setVisionMode(mode: VisionMode): Promise<void> {\n logger.info(\n `[VisionService] Changing vision mode from ${this.visionConfig.visionMode} to ${mode}`,\n );\n\n // Stop current processing\n this.stopProcessing();\n\n // Update configuration\n this.visionConfig.visionMode = mode;\n\n // Reinitialize based on new mode\n if (mode === VisionMode.OFF) {\n logger.info(\"[VisionService] Vision disabled\");\n return;\n }\n\n // Initialize components for new mode\n if (\n (mode === VisionMode.CAMERA || mode === VisionMode.BOTH) &&\n !this.camera\n ) {\n await this.initializeCameraVision();\n }\n\n if (\n (mode === VisionMode.SCREEN || mode === VisionMode.BOTH) &&\n (!this.florence2.isInitialized() || !this.ocrService.isInitialized())\n ) {\n await this.initializeScreenVision();\n }\n\n // Start processing for new mode\n this.startProcessing();\n }\n\n private stopProcessing(): void {\n if (this.frameProcessingInterval) {\n clearInterval(this.frameProcessingInterval);\n this.frameProcessingInterval = null;\n }\n\n if (this.screenProcessingInterval) {\n clearInterval(this.screenProcessingInterval);\n this.screenProcessingInterval = null;\n }\n }\n\n public getCameraInfo(): CameraInfo | null {\n if (!this.camera) {\n return null;\n }\n\n return {\n id: this.camera.id,\n name: this.camera.name,\n connected: true,\n };\n }\n\n public isActive(): boolean {\n return this.camera !== null && this.frameProcessingInterval !== null;\n }\n\n // Helper methods for face recognition\n private calculateBoxOverlap(box1: BoundingBox, box2: BoundingBox): number {\n const x1 = Math.max(box1.x, box2.x);\n const y1 = Math.max(box1.y, box2.y);\n const x2 = Math.min(box1.x + box1.width, box2.x + box2.width);\n const y2 = Math.min(box1.y + box1.height, box2.y + box2.height);\n\n if (x2 < x1 || y2 < y1) {\n return 0;\n }\n\n const intersection = (x2 - x1) * (y2 - y1);\n const area1 = box1.width * box1.height;\n const area2 = box2.width * box2.height;\n const union = area1 + area2 - intersection;\n\n return intersection / union;\n }\n\n private getDominantExpression(expressions: {\n neutral: number;\n happy: number;\n sad: number;\n angry: number;\n fearful: number;\n disgusted: number;\n surprised: number;\n }): string {\n let maxValue = 0;\n let dominantExpression = \"neutral\";\n\n const expressionEntries: [string, number][] = [\n [\"neutral\", expressions.neutral],\n [\"happy\", expressions.happy],\n [\"sad\", expressions.sad],\n [\"angry\", expressions.angry],\n [\"fearful\", expressions.fearful],\n [\"disgusted\", expressions.disgusted],\n [\"surprised\", expressions.surprised],\n ];\n\n for (const [expression, value] of expressionEntries) {\n if (value > maxValue) {\n maxValue = value;\n dominantExpression = expression;\n }\n }\n\n return dominantExpression;\n }\n\n // Public methods for entity tracking\n public getEntityTracker(): EntityTracker {\n return this.entityTracker;\n }\n\n public getFaceRecognition(): FaceRecognition {\n return this.faceRecognition;\n }\n\n async stop(): Promise<void> {\n logger.info(\"[VisionService] Stopping vision service...\");\n\n this.stopProcessing();\n\n if (this.audioCapture) {\n await this.audioCapture.stop();\n this.audioCapture = null;\n }\n\n if (this.streamingAudioCapture) {\n await this.streamingAudioCapture.stop();\n this.streamingAudioCapture = null;\n }\n\n if (this.visionModels) {\n await this.visionModels.dispose();\n }\n\n if (this.workerManager) {\n await this.workerManager.stop();\n this.workerManager = null;\n }\n\n this.camera = null;\n this.lastFrame = null;\n this.lastSceneDescription = null;\n this.lastScreenCapture = null;\n this.lastEnhancedScene = null;\n this.isProcessing = false;\n this.isProcessingScreen = false;\n\n // Dispose of models\n await this.florence2.dispose();\n await this.ocrService.dispose();\n\n logger.info(\"[VisionService] Stopped.\");\n }\n\n private async findCamera(): Promise<CameraDevice | null> {\n try {\n // Get list of available cameras\n const cameras = await this.listCameras();\n\n if (cameras.length === 0) {\n logger.warn(\"[VisionService] No cameras detected\");\n return null;\n }\n\n // If camera name is specified, try to find it\n if (this.visionConfig.cameraName) {\n const searchName = this.visionConfig.cameraName.toLowerCase();\n const matchedCamera = cameras.find((cam) =>\n cam.name.toLowerCase().includes(searchName),\n );\n\n if (matchedCamera) {\n return this.createCameraDevice(matchedCamera);\n }\n\n logger.warn(\n `[VisionService] Camera \"${this.visionConfig.cameraName}\" not found, using default`,\n );\n }\n\n // Use first available camera\n return this.createCameraDevice(cameras[0]);\n } catch (error) {\n logger.error(\"[VisionService] Error finding camera:\", error);\n return null;\n }\n }\n\n private async listCameras(): Promise<CameraInfo[]> {\n const platform = process.platform;\n\n try {\n if (platform === \"darwin\") {\n // macOS: Use system_profiler\n const { stdout } = await execAsync(\n \"system_profiler SPCameraDataType -json\",\n );\n const data = JSON.parse(stdout);\n const cameras: CameraInfo[] = [];\n\n if (data.SPCameraDataType && Array.isArray(data.SPCameraDataType)) {\n for (const camera of data.SPCameraDataType) {\n cameras.push({\n id: camera.unique_id || camera._name,\n name: camera._name,\n connected: true,\n });\n }\n }\n\n return cameras;\n } else if (platform === \"linux\") {\n // Linux: Use v4l2\n const { stdout } = await execAsync(\"v4l2-ctl --list-devices\");\n const cameras: CameraInfo[] = [];\n const lines = stdout.split(\"\\n\");\n\n let currentName = \"\";\n for (const line of lines) {\n if (line && !line.startsWith(\"\\t\")) {\n currentName = line.replace(\":\", \"\").trim();\n } else if (line.trim().startsWith(\"/dev/video\")) {\n const devicePath = line.trim();\n const id = devicePath.replace(\"/dev/video\", \"\");\n cameras.push({\n id,\n name: currentName,\n connected: true,\n });\n }\n }\n\n return cameras;\n } else if (platform === \"win32\") {\n // Windows: Use PowerShell\n const { stdout } = await execAsync(\n 'powershell -Command \"Get-PnpDevice -Class Camera | Select-Object FriendlyName, InstanceId | ConvertTo-Json\"',\n );\n const devices = JSON.parse(stdout);\n const cameras: CameraInfo[] = [];\n\n if (Array.isArray(devices)) {\n for (const device of devices) {\n cameras.push({\n id: device.InstanceId,\n name: device.FriendlyName,\n connected: true,\n });\n }\n }\n\n return cameras;\n }\n\n return [];\n } catch (error) {\n logger.error(\"[VisionService] Error listing cameras:\", error);\n return [];\n }\n }\n\n private createCameraDevice(info: CameraInfo): CameraDevice {\n const platform = process.platform;\n\n return {\n id: info.id,\n name: info.name,\n capture: async () => {\n const tempFile = path.join(\n process.cwd(),\n `temp_capture_${Date.now()}.jpg`,\n );\n\n try {\n if (platform === \"darwin\") {\n // macOS: Use imagesnap\n try {\n await execAsync(`imagesnap -d \"${info.name}\" \"${tempFile}\"`);\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n if (errorMessage.includes(\"command not found\")) {\n throw new Error(\n \"imagesnap not installed. Run: brew install imagesnap\",\n );\n }\n throw error;\n }\n } else if (platform === \"linux\") {\n // Linux: Use fswebcam\n try {\n await execAsync(\n `fswebcam -d /dev/video${info.id} -r 1280x720 --jpeg 85 \"${tempFile}\"`,\n );\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n if (errorMessage.includes(\"command not found\")) {\n throw new Error(\n \"fswebcam not installed. Run: sudo apt-get install fswebcam\",\n );\n }\n throw error;\n }\n } else if (platform === \"win32\") {\n // Windows: Use DirectShow via ffmpeg\n try {\n await execAsync(\n `ffmpeg -f dshow -i video=\"${info.name}\" -frames:v 1 -q:v 2 \"${tempFile}\" -y`,\n );\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n if (\n errorMessage.includes(\"not recognized\") ||\n errorMessage.includes(\"not found\")\n ) {\n throw new Error(\n \"ffmpeg not installed. Download from ffmpeg.org and add to PATH\",\n );\n }\n throw error;\n }\n } else {\n throw new Error(`Unsupported platform: ${platform}`);\n }\n\n // Read the captured image\n const imageBuffer = await fs.readFile(tempFile);\n\n // Clean up temp file\n await fs.unlink(tempFile).catch(() => {});\n\n return imageBuffer;\n } catch (error) {\n // Clean up temp file on error\n await fs.unlink(tempFile).catch(() => {});\n throw error;\n }\n },\n };\n }\n\n public async captureImage(): Promise<Buffer | null> {\n if (!this.camera) {\n logger.warn(\"[VisionService] No camera available for capture\");\n return null;\n }\n\n try {\n return await this.camera.capture();\n } catch (error) {\n logger.error(\"[VisionService] Failed to capture image:\", error);\n return null;\n }\n }\n}\n",
|
|
10
|
-
"import { exec } from \"node:child_process\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { promisify } from \"node:util\";\nimport {\n type IAgentRuntime,\n logger,\n ModelType,\n withStandaloneTrajectory,\n} from \"@elizaos/core\";\n\nconst execAsync = promisify(exec);\n\nexport interface AudioConfig {\n enabled: boolean;\n transcriptionInterval: number; // milliseconds\n device?: string;\n sampleRate?: number;\n channels?: number;\n}\n\nexport class AudioCaptureService {\n private runtime: IAgentRuntime;\n private config: AudioConfig;\n private isRecording = false;\n private recordingInterval: NodeJS.Timeout | null = null;\n\n constructor(runtime: IAgentRuntime, config: AudioConfig) {\n this.runtime = runtime;\n this.config = {\n sampleRate: 16000,\n channels: 1,\n ...config,\n };\n }\n\n async initialize(): Promise<void> {\n if (!this.config.enabled) {\n logger.info(\"[AudioCapture] Audio capture disabled\");\n return;\n }\n\n try {\n logger.info(\"[AudioCapture] Initializing audio capture...\");\n\n // Check for audio recording tools\n const tool = await this.checkAudioTools();\n if (!tool.available) {\n throw new Error(`Audio recording tool not available. ${tool.message}`);\n }\n\n logger.info(`[AudioCapture] Using ${tool.tool} for audio capture`);\n logger.info(\n `[AudioCapture] Transcription interval: ${this.config.transcriptionInterval}ms`,\n );\n\n // Start recording loop if interval is set\n if (this.config.transcriptionInterval > 0) {\n this.startTranscriptionLoop();\n }\n\n logger.info(\"[AudioCapture] Audio capture initialized\");\n } catch (error) {\n logger.error(\"[AudioCapture] Failed to initialize:\", error);\n throw error;\n }\n }\n\n private async checkAudioTools(): Promise<{\n available: boolean;\n tool: string;\n message?: string;\n }> {\n const platform = process.platform;\n\n try {\n if (platform === \"darwin\") {\n // macOS: Use sox\n await execAsync(\"which sox\");\n return { available: true, tool: \"sox\" };\n } else if (platform === \"linux\") {\n // Linux: Use arecord (ALSA)\n await execAsync(\"which arecord\");\n return { available: true, tool: \"arecord\" };\n } else if (platform === \"win32\") {\n // Windows: Use ffmpeg\n await execAsync(\"where ffmpeg\");\n return { available: true, tool: \"ffmpeg\" };\n }\n return {\n available: false,\n tool: \"none\",\n message: \"Unsupported platform\",\n };\n } catch (_error) {\n // Tool not found\n const toolName =\n platform === \"darwin\"\n ? \"sox\"\n : platform === \"linux\"\n ? \"arecord\"\n : \"ffmpeg\";\n const installCmd =\n platform === \"darwin\"\n ? \"brew install sox\"\n : platform === \"linux\"\n ? \"sudo apt-get install alsa-utils\"\n : \"Download ffmpeg from ffmpeg.org\";\n return {\n available: false,\n tool: toolName,\n message: `Install with: ${installCmd}`,\n };\n }\n }\n\n private startTranscriptionLoop(): void {\n if (this.recordingInterval) {\n return;\n }\n\n // Start continuous recording with periodic transcription\n this.recordingInterval = setInterval(async () => {\n if (!this.isRecording) {\n await this.recordAndTranscribe();\n }\n }, this.config.transcriptionInterval);\n\n logger.info(\"[AudioCapture] Started transcription loop\");\n }\n\n async recordAndTranscribe(): Promise<string | null> {\n if (this.isRecording) {\n logger.warn(\"[AudioCapture] Already recording\");\n return null;\n }\n\n this.isRecording = true;\n const audioFile = path.join(process.cwd(), `audio_${Date.now()}.wav`);\n\n try {\n logger.debug(\"[AudioCapture] Starting audio recording...\");\n\n // Record audio for the specified duration\n await this.recordAudio(\n audioFile,\n this.config.transcriptionInterval / 1000,\n );\n\n logger.debug(\"[AudioCapture] Recording complete, transcribing...\");\n\n // Transcribe using runtime model\n const audioBuffer = await fs.readFile(audioFile);\n const transcription = await withStandaloneTrajectory(\n this.runtime,\n {\n source: \"plugin-vision:audio-transcription\",\n metadata: {\n modelType: ModelType.TRANSCRIPTION,\n audioBytes: audioBuffer.byteLength,\n },\n },\n () => this.runtime.useModel(ModelType.TRANSCRIPTION, audioBuffer),\n );\n\n // Clean up audio file\n await fs.unlink(audioFile).catch(() => {});\n\n if (\n transcription &&\n typeof transcription === \"string\" &&\n transcription.trim()\n ) {\n logger.info(`[AudioCapture] Transcribed: \"${transcription}\"`);\n\n // Create a memory of what was heard\n await this.createAudioMemory(transcription);\n\n return transcription;\n }\n\n return null;\n } catch (error) {\n logger.error(\"[AudioCapture] Recording/transcription failed:\", error);\n await fs.unlink(audioFile).catch(() => {});\n return null;\n } finally {\n this.isRecording = false;\n }\n }\n\n private async recordAudio(\n outputPath: string,\n duration: number,\n ): Promise<void> {\n const platform = process.platform;\n\n try {\n if (platform === \"darwin\") {\n // macOS: Use sox\n const _device = this.config.device || \"default\";\n await execAsync(\n `sox -d -r ${this.config.sampleRate} -c ${this.config.channels} -b 16 \"${outputPath}\" trim 0 ${duration}`,\n );\n } else if (platform === \"linux\") {\n // Linux: Use arecord\n const device = this.config.device || \"default\";\n await execAsync(\n `arecord -D ${device} -f S16_LE -r ${this.config.sampleRate} -c ${this.config.channels} -d ${duration} \"${outputPath}\"`,\n );\n } else if (platform === \"win32\") {\n // Windows: Use ffmpeg with DirectShow\n const device = this.config.device || \"Microphone\";\n await execAsync(\n `ffmpeg -f dshow -i audio=\"${device}\" -t ${duration} -acodec pcm_s16le -ar ${this.config.sampleRate} -ac ${this.config.channels} \"${outputPath}\" -y`,\n );\n } else {\n throw new Error(`Unsupported platform: ${platform}`);\n }\n } catch (error: unknown) {\n logger.error(\n \"[AudioCapture] Audio recording failed:\",\n error instanceof Error ? error.message : String(error),\n );\n throw error;\n }\n }\n\n private async createAudioMemory(transcription: string): Promise<void> {\n try {\n const _memory = {\n content: {\n text: `[Audio Transcription] ${transcription}`,\n type: \"audio_transcription\",\n source: \"microphone\",\n timestamp: Date.now(),\n },\n metadata: {\n isAudioTranscription: true,\n duration: this.config.transcriptionInterval,\n },\n };\n\n // Store in agent's context\n // createMemory requires runtime-specific database adapter implementation\n logger.info(\"[AudioCapture] Audio transcription stored in context\");\n } catch (error) {\n logger.error(\"[AudioCapture] Failed to create audio memory:\", error);\n }\n }\n\n async listAudioDevices(): Promise<string[]> {\n const platform = process.platform;\n const devices: string[] = [];\n\n try {\n if (platform === \"darwin\") {\n // macOS: List audio devices using system_profiler\n const { stdout } = await execAsync(\n \"system_profiler SPAudioDataType -json\",\n );\n const data = JSON.parse(stdout);\n\n if (data.SPAudioDataType) {\n for (const device of data.SPAudioDataType) {\n if (device._name?.includes(\"Input\")) {\n devices.push(device._name);\n }\n }\n }\n } else if (platform === \"linux\") {\n // Linux: List ALSA devices\n const { stdout } = await execAsync(\"arecord -l\");\n const lines = stdout.split(\"\\n\");\n\n for (const line of lines) {\n if (line.includes(\"card\")) {\n const match = line.match(/card (\\d+):.*\\[(.*?)\\]/);\n if (match) {\n devices.push(`hw:${match[1]}`);\n }\n }\n }\n } else if (platform === \"win32\") {\n // Windows: List audio devices using ffmpeg\n try {\n const { stdout } = await execAsync(\n \"ffmpeg -list_devices true -f dshow -i dummy 2>&1\",\n );\n const lines = stdout.split(\"\\n\");\n let isAudioSection = false;\n\n for (const line of lines) {\n if (line.includes(\"DirectShow audio devices\")) {\n isAudioSection = true;\n } else if (isAudioSection && line.includes('\"')) {\n const match = line.match(/\"([^\"]+)\"/);\n if (match) {\n devices.push(match[1]);\n }\n }\n }\n } catch (_error) {\n // ffmpeg returns non-zero exit code when listing devices\n // but we can still parse the output\n }\n }\n } catch (error) {\n logger.error(\"[AudioCapture] Failed to list audio devices:\", error);\n }\n\n return devices;\n }\n\n isActive(): boolean {\n return this.config.enabled && this.recordingInterval !== null;\n }\n\n async stop(): Promise<void> {\n logger.info(\"[AudioCapture] Stopping audio capture...\");\n\n if (this.recordingInterval) {\n clearInterval(this.recordingInterval);\n this.recordingInterval = null;\n }\n\n // Wait for any ongoing recording to complete\n while (this.isRecording) {\n await new Promise((resolve) => setTimeout(resolve, 100));\n }\n\n logger.info(\"[AudioCapture] Audio capture stopped\");\n }\n}\n",
|
|
11
|
-
"import { type ChildProcess, spawn } from \"node:child_process\";\nimport { EventEmitter } from \"node:events\";\nimport {\n type IAgentRuntime,\n logger,\n ModelType,\n withStandaloneTrajectory,\n} from \"@elizaos/core\";\n\nexport interface StreamingAudioConfig {\n enabled: boolean;\n device?: string;\n sampleRate?: number;\n channels?: number;\n vadThreshold?: number; // 0-1, energy threshold for speech detection\n silenceTimeout?: number; // ms to wait before considering speech ended\n responseDelay?: number; // ms to wait before processing (for interruption detection)\n chunkSize?: number; // bytes per chunk for streaming\n}\n\ninterface AudioChunk {\n data: Buffer;\n timestamp: number;\n energy: number;\n}\n\nexport class StreamingAudioCaptureService extends EventEmitter {\n private runtime: IAgentRuntime;\n private config: StreamingAudioConfig;\n private captureProcess: ChildProcess | null = null;\n private isCapturing = false;\n private audioBuffer: AudioChunk[] = [];\n private isSpeaking = false;\n private silenceTimer: NodeJS.Timeout | null = null;\n private transcriptionInProgress = false;\n private currentTranscription = \"\";\n private responseTimer: NodeJS.Timeout | null = null;\n\n constructor(runtime: IAgentRuntime, config: StreamingAudioConfig) {\n super();\n this.runtime = runtime;\n this.config = {\n sampleRate: 16000,\n channels: 1,\n vadThreshold: 0.01,\n silenceTimeout: 1500, // 1.5 seconds of silence to end speech\n responseDelay: 3000, // 3 seconds before response (allows for interruption)\n chunkSize: 4096,\n ...config,\n };\n }\n\n async initialize(): Promise<void> {\n if (!this.config.enabled) {\n logger.info(\"[StreamingAudio] Audio capture disabled\");\n return;\n }\n\n try {\n logger.info(\"[StreamingAudio] Initializing streaming audio capture...\");\n\n // Start continuous audio capture\n await this.startContinuousCapture();\n\n logger.info(\"[StreamingAudio] Streaming audio capture initialized\");\n } catch (error) {\n logger.error(\"[StreamingAudio] Failed to initialize:\", error);\n throw error;\n }\n }\n\n private async startContinuousCapture(): Promise<void> {\n const platform = process.platform;\n let command: string;\n let args: string[];\n\n if (platform === \"darwin\") {\n // macOS: Use sox for continuous capture\n command = \"sox\";\n args = [\n \"-d\", // default input device\n \"-r\",\n this.config.sampleRate?.toString(),\n \"-c\",\n this.config.channels?.toString(),\n \"-b\",\n \"16\",\n \"-e\",\n \"signed\",\n \"-t\",\n \"raw\",\n \"-\", // output to stdout\n ];\n } else if (platform === \"linux\") {\n // Linux: Use arecord\n command = \"arecord\";\n args = [\n \"-D\",\n this.config.device || \"default\",\n \"-f\",\n \"S16_LE\",\n \"-r\",\n this.config.sampleRate?.toString(),\n \"-c\",\n this.config.channels?.toString(),\n \"-t\",\n \"raw\",\n \"-\", // output to stdout\n ];\n } else if (platform === \"win32\") {\n // Windows: Use ffmpeg\n command = \"ffmpeg\";\n args = [\n \"-f\",\n \"dshow\",\n \"-i\",\n `audio=\"${this.config.device || \"Microphone\"}\"`,\n \"-acodec\",\n \"pcm_s16le\",\n \"-ar\",\n this.config.sampleRate?.toString(),\n \"-ac\",\n this.config.channels?.toString(),\n \"-f\",\n \"s16le\",\n \"pipe:1\", // output to stdout\n ];\n } else {\n throw new Error(`Unsupported platform: ${platform}`);\n }\n\n this.captureProcess = spawn(command, args);\n this.isCapturing = true;\n\n // Handle audio data stream\n this.captureProcess.stdout?.on(\"data\", (chunk: Buffer) => {\n this.processAudioChunk(chunk);\n });\n\n this.captureProcess.stderr?.on(\"data\", (data) => {\n logger.debug(\"[StreamingAudio] Capture stderr:\", data.toString());\n });\n\n this.captureProcess.on(\"error\", (error) => {\n logger.error(\n \"[StreamingAudio] Capture process error:\",\n error instanceof Error ? error.message : String(error),\n );\n this.isCapturing = false;\n });\n\n this.captureProcess.on(\"exit\", (code) => {\n logger.info(\n \"[StreamingAudio] Capture process exited with code:\",\n String(code ?? 0),\n );\n this.isCapturing = false;\n });\n }\n\n private processAudioChunk(chunk: Buffer): void {\n // Calculate audio energy for VAD\n const energy = this.calculateEnergy(chunk);\n const timestamp = Date.now();\n\n // Store chunk\n const audioChunk: AudioChunk = { data: chunk, timestamp, energy };\n\n // Voice Activity Detection\n if (energy > (this.config.vadThreshold ?? 0.01)) {\n if (!this.isSpeaking) {\n // Speech started\n this.isSpeaking = true;\n logger.debug(\"[StreamingAudio] Speech detected, starting recording\");\n this.emit(\"speechStart\");\n\n // Clear any pending response\n if (this.responseTimer) {\n clearTimeout(this.responseTimer);\n this.responseTimer = null;\n logger.debug(\n \"[StreamingAudio] Cancelled pending response due to new speech\",\n );\n }\n }\n\n // Add to buffer\n this.audioBuffer.push(audioChunk);\n\n // Reset silence timer\n if (this.silenceTimer) {\n clearTimeout(this.silenceTimer);\n }\n\n // Start streaming transcription if not already running\n if (!this.transcriptionInProgress) {\n this.startStreamingTranscription();\n }\n } else if (this.isSpeaking) {\n // Currently in speech but detected silence\n this.audioBuffer.push(audioChunk);\n\n // Set timer for end of speech\n if (!this.silenceTimer) {\n this.silenceTimer = setTimeout(() => {\n this.endSpeech();\n }, this.config.silenceTimeout ?? 1500);\n }\n }\n\n // Clean up old chunks (keep last 30 seconds)\n const cutoffTime = timestamp - 30000;\n this.audioBuffer = this.audioBuffer.filter((c) => c.timestamp > cutoffTime);\n }\n\n private calculateEnergy(chunk: Buffer): number {\n // Calculate RMS energy of audio chunk\n let sum = 0;\n const samples = chunk.length / 2; // 16-bit samples\n\n for (let i = 0; i < chunk.length; i += 2) {\n const sample = chunk.readInt16LE(i);\n sum += sample * sample;\n }\n\n const rms = Math.sqrt(sum / samples);\n return rms / 32768; // Normalize to 0-1\n }\n\n private async startStreamingTranscription(): Promise<void> {\n if (this.transcriptionInProgress) {\n return;\n }\n\n this.transcriptionInProgress = true;\n logger.debug(\"[StreamingAudio] Starting streaming transcription\");\n\n try {\n // Get audio data from buffer\n const audioData = this.getRecentAudioData();\n\n if (audioData.length === 0) {\n this.transcriptionInProgress = false;\n return;\n }\n\n // Use streaming transcription if available, otherwise batch\n const result = await this.transcribeAudio(audioData);\n\n if (result?.trim()) {\n this.currentTranscription = result;\n logger.info(`[StreamingAudio] Partial transcription: \"${result}\"`);\n this.emit(\"transcription\", { text: result, isFinal: false });\n }\n } catch (error) {\n logger.error(\"[StreamingAudio] Transcription error:\", error);\n }\n\n this.transcriptionInProgress = false;\n\n // Continue transcription if still speaking\n if (this.isSpeaking) {\n setTimeout(() => this.startStreamingTranscription(), 500);\n }\n }\n\n private endSpeech(): void {\n if (!this.isSpeaking) {\n return;\n }\n\n this.isSpeaking = false;\n this.silenceTimer = null;\n logger.debug(\"[StreamingAudio] Speech ended\");\n this.emit(\"speechEnd\");\n\n // Get final transcription\n this.processFinalTranscription();\n }\n\n private async processFinalTranscription(): Promise<void> {\n const audioData = this.getRecentAudioData();\n\n if (audioData.length === 0) {\n return;\n }\n\n try {\n // Get final transcription\n const finalText = await this.transcribeAudio(audioData);\n\n if (finalText?.trim()) {\n this.currentTranscription = finalText;\n logger.info(`[StreamingAudio] Final transcription: \"${finalText}\"`);\n this.emit(\"transcription\", { text: finalText, isFinal: true });\n\n // Set timer for response generation\n this.responseTimer = setTimeout(() => {\n this.generateResponse(finalText);\n }, this.config.responseDelay ?? 3000);\n }\n } catch (error) {\n logger.error(\"[StreamingAudio] Final transcription error:\", error);\n } finally {\n // Clear audio buffer\n this.audioBuffer = [];\n this.currentTranscription = \"\";\n }\n }\n\n private getRecentAudioData(): Buffer {\n if (this.audioBuffer.length === 0) {\n return Buffer.alloc(0);\n }\n\n // Get audio from start of speech to now\n const startTime = this.audioBuffer[0].timestamp;\n const relevantChunks = this.audioBuffer.filter(\n (c) => c.timestamp >= startTime,\n );\n\n // Combine chunks\n const totalLength = relevantChunks.reduce(\n (sum, c) => sum + c.data.length,\n 0,\n );\n const combined = Buffer.alloc(totalLength);\n let offset = 0;\n\n for (const chunk of relevantChunks) {\n chunk.data.copy(combined, offset);\n offset += chunk.data.length;\n }\n\n return combined;\n }\n\n private async transcribeAudio(audioData: Buffer): Promise<string | null> {\n try {\n // Convert raw audio to WAV format\n const wavBuffer = this.rawToWav(audioData);\n\n // Use runtime transcription model\n const result = await withStandaloneTrajectory(\n this.runtime,\n {\n source: \"plugin-vision:streaming-audio-transcription\",\n metadata: {\n modelType: ModelType.TRANSCRIPTION,\n audioBytes: wavBuffer.byteLength,\n },\n },\n () => this.runtime.useModel(ModelType.TRANSCRIPTION, wavBuffer),\n );\n\n return result as string;\n } catch (error) {\n logger.error(\"[StreamingAudio] Transcription failed:\", error);\n return null;\n }\n }\n\n private rawToWav(rawData: Buffer): Buffer {\n // Create WAV header\n const sampleRate = this.config.sampleRate ?? 16000;\n const channels = this.config.channels ?? 1;\n const bitsPerSample = 16;\n const byteRate = sampleRate * channels * (bitsPerSample / 8);\n const blockAlign = channels * (bitsPerSample / 8);\n const dataSize = rawData.length;\n const fileSize = 36 + dataSize;\n\n const header = Buffer.alloc(44);\n\n // RIFF chunk\n header.write(\"RIFF\", 0);\n header.writeUInt32LE(fileSize, 4);\n header.write(\"WAVE\", 8);\n\n // fmt chunk\n header.write(\"fmt \", 12);\n header.writeUInt32LE(16, 16); // fmt chunk size\n header.writeUInt16LE(1, 20); // PCM format\n header.writeUInt16LE(channels, 22);\n header.writeUInt32LE(sampleRate, 24);\n header.writeUInt32LE(byteRate, 28);\n header.writeUInt16LE(blockAlign, 32);\n header.writeUInt16LE(bitsPerSample, 34);\n\n // data chunk\n header.write(\"data\", 36);\n header.writeUInt32LE(dataSize, 40);\n\n return Buffer.concat([header, rawData]);\n }\n\n private async generateResponse(transcription: string): Promise<void> {\n this.responseTimer = null;\n\n try {\n // Create audio memory\n await this.createAudioMemory(transcription);\n\n // Emit event for response generation\n this.emit(\"utteranceComplete\", transcription);\n } catch (error) {\n logger.error(\"[StreamingAudio] Response generation error:\", error);\n }\n }\n\n private async createAudioMemory(transcription: string): Promise<void> {\n try {\n const _memory = {\n content: {\n text: `[Audio] ${transcription}`,\n type: \"audio_transcription\",\n source: \"microphone_streaming\",\n timestamp: Date.now(),\n },\n metadata: {\n isAudioTranscription: true,\n streaming: true,\n },\n };\n\n logger.info(\"[StreamingAudio] Audio transcription stored in context\");\n } catch (error) {\n logger.error(\"[StreamingAudio] Failed to create audio memory:\", error);\n }\n }\n\n async stop(): Promise<void> {\n logger.info(\"[StreamingAudio] Stopping audio capture...\");\n\n if (this.captureProcess) {\n this.captureProcess.kill();\n this.captureProcess = null;\n }\n\n if (this.silenceTimer) {\n clearTimeout(this.silenceTimer);\n this.silenceTimer = null;\n }\n\n if (this.responseTimer) {\n clearTimeout(this.responseTimer);\n this.responseTimer = null;\n }\n\n this.isCapturing = false;\n this.isSpeaking = false;\n this.audioBuffer = [];\n\n logger.info(\"[StreamingAudio] Audio capture stopped\");\n }\n\n isActive(): boolean {\n return this.isCapturing;\n }\n\n getCurrentTranscription(): string {\n return this.currentTranscription;\n }\n\n isSpeechActive(): boolean {\n return this.isSpeaking;\n }\n}\n",
|
|
12
|
-
"import {\n type IAgentRuntime,\n createUniqueUuid,\n logger,\n type UUID,\n} from \"@elizaos/core\";\nimport type {\n BoundingBox,\n DetectedObject,\n PersonInfo,\n TrackedEntity,\n WorldState,\n} from \"./types\";\n\nexport class EntityTracker {\n private worldState: WorldState;\n private readonly POSITION_THRESHOLD = 100; // pixels\n private readonly MISSING_THRESHOLD = 5000; // 5 seconds\n private readonly CLEANUP_THRESHOLD = 60000; // 1 minute\n\n constructor(worldId: string) {\n this.worldState = {\n worldId,\n entities: new Map(),\n lastUpdate: Date.now(),\n activeEntities: [],\n recentlyLeft: [],\n };\n }\n\n async updateEntities(\n detectedObjects: DetectedObject[],\n people: PersonInfo[],\n faceProfiles?: Map<string, string>, // Maps person ID to face profile ID\n runtime?: IAgentRuntime,\n ): Promise<TrackedEntity[]> {\n const currentTime = Date.now();\n const frameEntities: TrackedEntity[] = [];\n const seenEntityIds = new Set<string>();\n\n // Process detected people\n for (const person of people) {\n const entity = await this.trackPerson(\n person,\n faceProfiles?.get(person.id),\n currentTime,\n );\n frameEntities.push(entity);\n seenEntityIds.add(entity.id);\n }\n\n // Process detected objects\n for (const obj of detectedObjects) {\n if (obj.type !== \"person\" && obj.type !== \"person-candidate\") {\n const entity = await this.trackObject(obj, currentTime);\n frameEntities.push(entity);\n seenEntityIds.add(entity.id);\n }\n }\n\n // Update world state\n this.updateWorldState(seenEntityIds, currentTime);\n\n // Store entities in runtime if available\n if (runtime) {\n await this.syncWithRuntime(runtime, frameEntities);\n }\n\n return frameEntities;\n }\n\n private async trackPerson(\n person: PersonInfo,\n faceProfileId: string | undefined,\n timestamp: number,\n ): Promise<TrackedEntity> {\n // Try to match with existing entities\n const matchedEntity = this.findMatchingEntity(\n person.boundingBox,\n \"person\",\n faceProfileId,\n );\n\n if (matchedEntity) {\n // Update existing entity\n matchedEntity.lastSeen = timestamp;\n matchedEntity.lastPosition = person.boundingBox;\n matchedEntity.appearances.push({\n timestamp,\n boundingBox: person.boundingBox,\n confidence: person.confidence,\n });\n\n // Update attributes\n if (faceProfileId && !matchedEntity.attributes.faceId) {\n matchedEntity.attributes.faceId = faceProfileId;\n }\n\n // Keep only last 100 appearances\n if (matchedEntity.appearances.length > 100) {\n matchedEntity.appearances = matchedEntity.appearances.slice(-100);\n }\n\n return matchedEntity;\n } else {\n // Create new entity\n const entityId = `person-${timestamp}-${Math.random().toString(36).substr(2, 9)}`;\n const newEntity: TrackedEntity = {\n id: entityId,\n entityType: \"person\",\n firstSeen: timestamp,\n lastSeen: timestamp,\n lastPosition: person.boundingBox,\n appearances: [\n {\n timestamp,\n boundingBox: person.boundingBox,\n confidence: person.confidence,\n },\n ],\n attributes: {\n faceId: faceProfileId,\n },\n worldId: this.worldState.worldId,\n };\n\n this.worldState.entities.set(entityId, newEntity);\n logger.info(`[EntityTracker] New person entity created: ${entityId}`);\n\n return newEntity;\n }\n }\n\n private async trackObject(\n obj: DetectedObject,\n timestamp: number,\n ): Promise<TrackedEntity> {\n // Try to match with existing entities\n const matchedEntity = this.findMatchingEntity(obj.boundingBox, \"object\");\n\n if (matchedEntity) {\n // Update existing entity\n matchedEntity.lastSeen = timestamp;\n matchedEntity.lastPosition = obj.boundingBox;\n matchedEntity.appearances.push({\n timestamp,\n boundingBox: obj.boundingBox,\n confidence: obj.confidence,\n });\n\n // Keep only last 50 appearances for objects\n if (matchedEntity.appearances.length > 50) {\n matchedEntity.appearances = matchedEntity.appearances.slice(-50);\n }\n\n return matchedEntity;\n } else {\n // Create new entity\n const entityId = `object-${timestamp}-${Math.random().toString(36).substr(2, 9)}`;\n const newEntity: TrackedEntity = {\n id: entityId,\n entityType: \"object\",\n firstSeen: timestamp,\n lastSeen: timestamp,\n lastPosition: obj.boundingBox,\n appearances: [\n {\n timestamp,\n boundingBox: obj.boundingBox,\n confidence: obj.confidence,\n },\n ],\n attributes: {\n objectType: obj.type,\n },\n worldId: this.worldState.worldId,\n };\n\n this.worldState.entities.set(entityId, newEntity);\n logger.debug(\n `[EntityTracker] New object entity created: ${entityId} (${obj.type})`,\n );\n\n return newEntity;\n }\n }\n\n private findMatchingEntity(\n boundingBox: BoundingBox,\n entityType: \"person\" | \"object\",\n faceProfileId?: string,\n ): TrackedEntity | null {\n const currentTime = Date.now();\n let bestMatch: TrackedEntity | null = null;\n let minDistance = Infinity;\n\n for (const entity of this.worldState.entities.values()) {\n // Skip if wrong type\n if (entity.entityType !== entityType) {\n continue;\n }\n\n // Skip if entity has been missing too long\n if (currentTime - entity.lastSeen > this.MISSING_THRESHOLD) {\n continue;\n }\n\n // If we have face ID, prioritize face matching for people\n if (\n entityType === \"person\" &&\n faceProfileId &&\n entity.attributes.faceId\n ) {\n if (entity.attributes.faceId === faceProfileId) {\n return entity; // Direct face match\n }\n }\n\n // Calculate position distance\n const distance = this.calculateDistance(entity.lastPosition, boundingBox);\n\n if (distance < this.POSITION_THRESHOLD && distance < minDistance) {\n minDistance = distance;\n bestMatch = entity;\n }\n }\n\n return bestMatch;\n }\n\n private calculateDistance(box1: BoundingBox, box2: BoundingBox): number {\n const center1 = {\n x: box1.x + box1.width / 2,\n y: box1.y + box1.height / 2,\n };\n const center2 = {\n x: box2.x + box2.width / 2,\n y: box2.y + box2.height / 2,\n };\n\n return Math.sqrt(\n (center1.x - center2.x) ** 2 + (center1.y - center2.y) ** 2,\n );\n }\n\n private updateWorldState(\n seenEntityIds: Set<string>,\n timestamp: number,\n ): void {\n // Update active entities\n this.worldState.activeEntities = Array.from(seenEntityIds);\n this.worldState.lastUpdate = timestamp;\n\n // Check for entities that left\n for (const [entityId, entity] of this.worldState.entities) {\n if (\n !seenEntityIds.has(entityId) &&\n this.worldState.activeEntities.includes(entityId)\n ) {\n // Entity just left the scene\n this.worldState.recentlyLeft.push({\n entityId,\n leftAt: timestamp,\n lastPosition: entity.lastPosition,\n });\n\n logger.info(`[EntityTracker] Entity left scene: ${entityId}`);\n }\n }\n\n // Clean up old \"recently left\" entries\n this.worldState.recentlyLeft = this.worldState.recentlyLeft.filter(\n (entry) => timestamp - entry.leftAt < this.CLEANUP_THRESHOLD,\n );\n\n // Clean up very old entities\n for (const [entityId, entity] of this.worldState.entities) {\n if (timestamp - entity.lastSeen > this.CLEANUP_THRESHOLD * 10) {\n this.worldState.entities.delete(entityId);\n logger.debug(`[EntityTracker] Cleaned up old entity: ${entityId}`);\n }\n }\n }\n\n private async syncWithRuntime(\n runtime: IAgentRuntime,\n frameEntities: TrackedEntity[],\n ): Promise<void> {\n try {\n // Sync detected entities with the runtime's entity system\n for (const entity of frameEntities) {\n // Convert the human-readable tracker ID (e.g. \"person-123-abc\") to a\n // deterministic UUID that PostgreSQL accepts. The same local ID always\n // maps to the same UUID for a given agent, so updates stay consistent.\n const entityUuid = createUniqueUuid(runtime, entity.id);\n\n const elizaEntity = {\n id: entityUuid,\n names: [entity.attributes.name || entity.id],\n metadata: {\n type: entity.entityType,\n firstSeen: entity.firstSeen,\n lastSeen: entity.lastSeen,\n attributes: entity.attributes,\n worldId: this.worldState.worldId,\n },\n agentId: runtime.agentId,\n };\n\n try {\n const existing = await runtime.getEntityById(entityUuid);\n if (!existing) {\n await runtime.createEntity(elizaEntity);\n logger.debug(\n `[EntityTracker] Created entity ${entity.id} (${entityUuid}) in runtime`,\n );\n } else {\n await runtime.updateEntity({\n ...elizaEntity,\n id: entityUuid,\n });\n logger.debug(\n `[EntityTracker] Updated entity ${entity.id} (${entityUuid}) in runtime`,\n );\n }\n } catch (err) {\n logger.debug(\n `[EntityTracker] Could not sync entity ${entity.id}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n } catch (error) {\n logger.error(\"[EntityTracker] Failed to sync with runtime:\", error);\n }\n }\n\n // Public API\n getWorldState(): WorldState {\n return this.worldState;\n }\n\n getActiveEntities(): TrackedEntity[] {\n return this.worldState.activeEntities\n .map((id) => this.worldState.entities.get(id))\n .filter(Boolean) as TrackedEntity[];\n }\n\n getEntity(entityId: string): TrackedEntity | undefined {\n return this.worldState.entities.get(entityId);\n }\n\n getRecentlyLeft(): Array<{ entity: TrackedEntity; leftAt: number }> {\n return this.worldState.recentlyLeft\n .map((entry) => ({\n entity: this.worldState.entities.get(entry.entityId),\n leftAt: entry.leftAt,\n }))\n .filter((entry) => entry.entity) as Array<{\n entity: TrackedEntity;\n leftAt: number;\n }>;\n }\n\n // Name assignment\n assignNameToEntity(entityId: string, name: string): boolean {\n const entity = this.worldState.entities.get(entityId);\n if (entity) {\n entity.attributes.name = name;\n logger.info(\n `[EntityTracker] Assigned name \"${name}\" to entity ${entityId}`,\n );\n return true;\n }\n return false;\n }\n\n // Get statistics\n getStatistics(): {\n totalEntities: number;\n activeEntities: number;\n recentlyLeft: number;\n people: number;\n objects: number;\n } {\n const entities = Array.from(this.worldState.entities.values());\n return {\n totalEntities: entities.length,\n activeEntities: this.worldState.activeEntities.length,\n recentlyLeft: this.worldState.recentlyLeft.length,\n people: entities.filter((e) => e.entityType === \"person\").length,\n objects: entities.filter((e) => e.entityType === \"object\").length,\n };\n }\n}\n",
|
|
13
|
-
"import * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { logger } from \"@elizaos/core\";\nimport * as faceapi from \"face-api.js\";\nimport type { FaceLibrary, FaceProfile } from \"./types\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\n// Dynamic imports for optional dependencies\n// Canvas package types differ from DOM types but are runtime-compatible with face-api.js\nlet CanvasModule: typeof import(\"canvas\") | undefined;\n\n/**\n * Type helpers for node-canvas to face-api.js compatibility.\n * The canvas package provides Node.js implementations that are runtime-compatible\n * with face-api.js, but have different TypeScript types than DOM equivalents.\n */\ntype FaceApiEnv = {\n Canvas: typeof HTMLCanvasElement;\n Image: typeof HTMLImageElement;\n ImageData: typeof ImageData;\n};\n\n/**\n * Adapter type for node-canvas Canvas to HTMLCanvasElement.\n * Runtime-compatible but TypeScript types differ.\n */\ntype CanvasAdapter = import(\"canvas\").Canvas & HTMLCanvasElement;\n\nfunction asCanvasEnv(canvas: typeof import(\"canvas\")): FaceApiEnv {\n return {\n // node-canvas types don't match DOM types but are runtime-compatible with face-api.js\n Canvas: canvas.Canvas as never,\n Image: canvas.Image as never,\n ImageData: canvas.ImageData as typeof ImageData,\n };\n}\n\nfunction asHTMLCanvasElement(\n canvas: import(\"canvas\").Canvas,\n): HTMLCanvasElement {\n // node-canvas Canvas is runtime-compatible with HTMLCanvasElement\n return canvas as CanvasAdapter as HTMLCanvasElement;\n}\n\nasync function initializeCanvas() {\n try {\n CanvasModule = await import(\"canvas\");\n\n // Polyfill for face-api.js - node-canvas is runtime-compatible with face-api.js\n faceapi.env.monkeyPatch(asCanvasEnv(CanvasModule));\n } catch (error) {\n logger.error(\"[FaceRecognition] Canvas module not available:\", error);\n throw new Error(\n \"Canvas module is required for face recognition. Install with: npm install canvas\",\n );\n }\n}\n\nexport class FaceRecognition {\n private initialized = false;\n private faceLibrary: FaceLibrary = {\n faces: new Map(),\n embeddings: new Map(),\n };\n private modelPath = path.join(__dirname, \"..\", \"models\", \"face-api\");\n\n // Thresholds\n private readonly FACE_MATCH_THRESHOLD = 0.6; // Euclidean distance threshold\n private readonly MIN_FACE_SIZE = 50; // Minimum face size in pixels\n\n async initialize(): Promise<void> {\n if (this.initialized) {\n return;\n }\n\n try {\n logger.info(\"[FaceRecognition] Loading face detection models...\");\n\n // Initialize canvas first\n await initializeCanvas();\n\n // Load face-api.js models\n await faceapi.nets.ssdMobilenetv1.loadFromDisk(this.modelPath);\n await faceapi.nets.faceLandmark68Net.loadFromDisk(this.modelPath);\n await faceapi.nets.faceRecognitionNet.loadFromDisk(this.modelPath);\n await faceapi.nets.faceExpressionNet.loadFromDisk(this.modelPath);\n await faceapi.nets.ageGenderNet.loadFromDisk(this.modelPath);\n\n this.initialized = true;\n logger.info(\"[FaceRecognition] Models loaded successfully\");\n } catch (error) {\n logger.error(\"[FaceRecognition] Failed to load models:\", error);\n logger.info(\n \"[FaceRecognition] Download models from: https://github.com/justadudewhohacks/face-api.js-models\",\n );\n throw error;\n }\n }\n\n async detectFaces(\n imageData: Buffer,\n width: number,\n height: number,\n ): Promise<\n Array<{\n detection: faceapi.FaceDetection;\n landmarks: faceapi.FaceLandmarks68;\n descriptor: Float32Array;\n expressions: faceapi.FaceExpressions;\n ageGender?: { age: number; gender: string; genderProbability: number };\n }>\n > {\n if (!this.initialized) {\n await this.initialize();\n }\n\n // Validate input parameters\n if (!imageData || imageData.length === 0 || width <= 0 || height <= 0) {\n logger.warn(\n `[FaceRecognition] Invalid input parameters: dataLength=${imageData?.length || 0}, width=${width}, height=${height}`,\n );\n return [];\n }\n\n // Validate that the buffer size matches expected dimensions\n const expectedSize = width * height * 4; // RGBA\n if (imageData.length !== expectedSize) {\n logger.warn(\n `[FaceRecognition] Buffer size mismatch: expected=${expectedSize}, actual=${imageData.length}, width=${width}, height=${height}`,\n );\n return [];\n }\n\n try {\n if (!CanvasModule) {\n throw new Error(\n \"Canvas module not initialized. Call initialize() first.\",\n );\n }\n // Create canvas from image data\n const canvas = new CanvasModule.Canvas(width, height);\n const ctx = canvas.getContext(\"2d\");\n const imageDataObj = new CanvasModule.ImageData(\n new Uint8ClampedArray(imageData),\n width,\n height,\n );\n ctx.putImageData(imageDataObj, 0, 0);\n\n // Detect faces with full analysis\n // face-api.js accepts HTMLCanvasElement or compatible canvas (node-canvas works)\n const detections = await faceapi\n .detectAllFaces(\n asHTMLCanvasElement(canvas),\n new faceapi.SsdMobilenetv1Options({\n minConfidence: 0.5,\n maxResults: 10,\n }),\n )\n .withFaceLandmarks()\n .withFaceDescriptors()\n .withFaceExpressions()\n .withAgeAndGender();\n\n return detections.filter(\n (d: {\n detection: {\n box: {\n width: number;\n height: number;\n };\n };\n }) => {\n const box = d.detection.box;\n return (\n box.width >= this.MIN_FACE_SIZE && box.height >= this.MIN_FACE_SIZE\n );\n },\n );\n } catch (error) {\n logger.error(\"[FaceRecognition] Face detection failed:\", error);\n return [];\n }\n }\n\n async recognizeFace(\n descriptor: Float32Array,\n ): Promise<{ profileId: string; distance: number } | null> {\n let bestMatch: { profileId: string; distance: number } | null = null;\n let minDistance = Infinity;\n\n // Compare with all known faces\n for (const [profileId, embeddings] of this.faceLibrary.embeddings) {\n for (const knownEmbedding of embeddings) {\n const distance = this.euclideanDistance(descriptor, knownEmbedding);\n\n if (distance < this.FACE_MATCH_THRESHOLD && distance < minDistance) {\n minDistance = distance;\n bestMatch = { profileId, distance };\n }\n }\n }\n\n return bestMatch;\n }\n\n async addOrUpdateFace(\n descriptor: Float32Array,\n attributes?: Partial<FaceProfile>,\n ): Promise<string> {\n // Check if this face already exists\n const match = await this.recognizeFace(descriptor);\n\n if (match) {\n // Update existing profile\n const profile = this.faceLibrary.faces.get(match.profileId);\n if (!profile) {\n throw new Error(\n `Profile not found for matched profileId: ${match.profileId}`,\n );\n }\n profile.lastSeen = Date.now();\n profile.seenCount++;\n\n // Add new embedding for better recognition\n const embeddings = this.faceLibrary.embeddings.get(match.profileId);\n if (!embeddings) {\n throw new Error(\n `Embeddings not found for matched profileId: ${match.profileId}`,\n );\n }\n if (embeddings.length < 10) {\n // Keep up to 10 embeddings per person\n embeddings.push(Array.from(descriptor));\n }\n\n // Update attributes if provided\n if (attributes) {\n Object.assign(profile, attributes);\n }\n\n return match.profileId;\n } else {\n // Create new profile\n const profileId = `face-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n const profile: FaceProfile = {\n id: profileId,\n embeddings: [Array.from(descriptor)],\n firstSeen: Date.now(),\n lastSeen: Date.now(),\n seenCount: 1,\n ...attributes,\n };\n\n this.faceLibrary.faces.set(profileId, profile);\n this.faceLibrary.embeddings.set(profileId, [Array.from(descriptor)]);\n\n logger.info(`[FaceRecognition] New face registered: ${profileId}`);\n return profileId;\n }\n }\n\n getFaceProfile(profileId: string): FaceProfile | undefined {\n return this.faceLibrary.faces.get(profileId);\n }\n\n getAllProfiles(): FaceProfile[] {\n return Array.from(this.faceLibrary.faces.values());\n }\n\n private euclideanDistance(a: Float32Array | number[], b: number[]): number {\n let sum = 0;\n const aArray = Array.from(a);\n for (let i = 0; i < aArray.length; i++) {\n sum += (aArray[i] - b[i]) ** 2;\n }\n return Math.sqrt(sum);\n }\n\n // Persistence methods\n async saveFaceLibrary(path: string): Promise<void> {\n const data = {\n faces: Array.from(this.faceLibrary.faces.entries()),\n embeddings: Array.from(this.faceLibrary.embeddings.entries()),\n };\n\n const fs = await import(\"node:fs/promises\");\n await fs.writeFile(path, JSON.stringify(data, null, 2));\n logger.info(`[FaceRecognition] Face library saved to ${path}`);\n }\n\n async loadFaceLibrary(path: string): Promise<void> {\n try {\n const fs = await import(\"node:fs/promises\");\n const data = JSON.parse(await fs.readFile(path, \"utf-8\"));\n\n this.faceLibrary.faces = new Map(data.faces);\n this.faceLibrary.embeddings = new Map(data.embeddings);\n\n logger.info(\n `[FaceRecognition] Loaded ${this.faceLibrary.faces.size} face profiles`,\n );\n } catch (error) {\n logger.warn(\"[FaceRecognition] Could not load face library:\", error);\n }\n }\n}\n",
|
|
14
|
-
"import { logger } from \"@elizaos/core\";\nimport { Florence2Local } from \"./florence2-local\";\nimport type { BoundingBox, Florence2Result, ScreenTile } from \"./types\";\n\nexport class Florence2Model {\n private initialized = false;\n private localModel: Florence2Local;\n\n constructor() {\n this.localModel = new Florence2Local();\n }\n\n async initialize(): Promise<void> {\n if (this.initialized) {\n return;\n }\n\n try {\n logger.info(\n \"[Florence2] Initializing local Florence-2 model with TensorFlow.js...\",\n );\n\n await this.localModel.initialize();\n\n this.initialized = true;\n logger.info(\"[Florence2] Local model initialized successfully\");\n } catch (error) {\n logger.error(\"[Florence2] Failed to initialize local model:\", error);\n // Don't throw - we have good fallbacks\n this.initialized = true;\n logger.warn(\"[Florence2] Running with enhanced fallback mode\");\n }\n }\n\n async analyzeTile(tile: ScreenTile): Promise<Florence2Result> {\n if (!this.initialized) {\n await this.initialize();\n }\n\n if (!tile.data) {\n throw new Error(\"Tile has no image data\");\n }\n\n try {\n // Use local model\n try {\n const result = await this.localModel.analyzeImage(tile.data);\n logger.debug(`[Florence2] Analyzed tile ${tile.id}: ${result.caption}`);\n return result;\n } catch (_modelError) {\n logger.warn(\n \"[Florence2] Local model analysis failed, falling back:\",\n _modelError,\n );\n }\n\n // Fall back to mock analysis\n const result = await this.mockAnalyze(tile);\n logger.debug(\n `[Florence2] Mock analyzed tile ${tile.id}: ${result.caption}`,\n );\n return result;\n } catch (error) {\n logger.error(\"[Florence2] Analysis failed:\", error);\n throw error;\n }\n }\n\n async analyzeImage(imageBuffer: Buffer): Promise<Florence2Result> {\n if (!this.initialized) {\n await this.initialize();\n }\n\n try {\n // Use local model\n try {\n const result = await this.localModel.analyzeImage(imageBuffer);\n logger.debug(`[Florence2] Analyzed image: ${result.caption}`);\n return result;\n } catch (_modelError) {\n logger.warn(\n \"[Florence2] Local model analysis failed, falling back:\",\n _modelError,\n );\n }\n\n // Fall back to mock analysis\n const result = await this.mockAnalyzeBuffer(imageBuffer);\n logger.debug(`[Florence2] Mock analyzed image: ${result.caption}`);\n return result;\n } catch (error) {\n logger.error(\"[Florence2] Image analysis failed:\", error);\n throw error;\n }\n }\n\n private async mockAnalyze(tile: ScreenTile): Promise<Florence2Result> {\n // Mock implementation that simulates Florence-2 output\n // In production, this would be replaced with actual API calls\n\n const isUpperRegion = tile.row < 2;\n const isLeftRegion = tile.col < 2;\n\n // Simulate different UI regions\n let caption = \"Desktop screen region\";\n const objects: Array<{\n label: string;\n bbox: BoundingBox;\n confidence: number;\n }> = [];\n const regions: Array<{ description: string; bbox: BoundingBox }> = [];\n const tags: string[] = [];\n\n if (isUpperRegion) {\n caption = \"Application window with menu bar\";\n objects.push({\n label: \"window\",\n bbox: { x: 0, y: 0, width: tile.width, height: 50 },\n confidence: 0.9,\n });\n objects.push({\n label: \"menu_bar\",\n bbox: { x: 0, y: 0, width: tile.width, height: 30 },\n confidence: 0.85,\n });\n tags.push(\"ui\", \"application\", \"desktop\");\n }\n\n if (isLeftRegion) {\n caption = \"Sidebar or navigation area\";\n objects.push({\n label: \"sidebar\",\n bbox: { x: 0, y: 0, width: 100, height: tile.height },\n confidence: 0.8,\n });\n tags.push(\"navigation\", \"sidebar\");\n }\n\n // Add some common UI elements\n const buttonCount = Math.floor(Math.random() * 3) + 1;\n for (let i = 0; i < buttonCount; i++) {\n objects.push({\n label: \"button\",\n bbox: {\n x: Math.random() * (tile.width - 100),\n y: Math.random() * (tile.height - 40),\n width: 100,\n height: 40,\n },\n confidence: 0.7 + Math.random() * 0.2,\n });\n }\n\n // Add text regions\n const textRegions = Math.floor(Math.random() * 2) + 1;\n for (let i = 0; i < textRegions; i++) {\n regions.push({\n description: \"Text content area\",\n bbox: {\n x: Math.random() * (tile.width - 200),\n y: Math.random() * (tile.height - 100),\n width: 200,\n height: 100,\n },\n });\n }\n\n tags.push(\"screen\", \"interface\", \"computer\");\n\n return {\n caption,\n objects,\n regions,\n tags,\n };\n }\n\n async detectUIElements(imageBuffer: Buffer): Promise<\n Array<{\n type: string;\n bbox: BoundingBox;\n confidence: number;\n text?: string;\n }>\n > {\n if (!this.initialized) {\n await this.initialize();\n }\n\n try {\n // Use local model to analyze image\n let result: Florence2Result;\n\n try {\n result = await this.localModel.analyzeImage(imageBuffer);\n } catch (_modelError) {\n logger.warn(\n \"[Florence2] Local model failed for UI detection, using fallback\",\n );\n result = await this.mockAnalyzeBuffer(imageBuffer);\n }\n\n // Convert Florence-2 objects to UI elements\n return (result.objects || []).map((obj) => ({\n type: this.mapToUIElementType(obj.label),\n bbox: obj.bbox,\n confidence: obj.confidence,\n }));\n } catch (error) {\n logger.error(\"[Florence2] UI element detection failed:\", error);\n return [];\n }\n }\n\n private async mockAnalyzeBuffer(\n _imageBuffer: Buffer,\n ): Promise<Florence2Result> {\n // Enhanced mock for when API is not available\n // Provides more realistic descriptions based on common scenarios\n\n const scenarios = [\n {\n caption: \"Indoor scene with a person in front of a computer\",\n objects: [\n {\n label: \"person\",\n bbox: { x: 300, y: 200, width: 200, height: 300 },\n confidence: 0.9,\n },\n {\n label: \"computer\",\n bbox: { x: 400, y: 350, width: 150, height: 100 },\n confidence: 0.85,\n },\n {\n label: \"desk\",\n bbox: { x: 350, y: 400, width: 250, height: 100 },\n confidence: 0.8,\n },\n ],\n tags: [\"indoor\", \"office\", \"workspace\", \"person\", \"computer\"],\n },\n {\n caption: \"Room interior with furniture and lighting\",\n objects: [\n {\n label: \"chair\",\n bbox: { x: 200, y: 300, width: 100, height: 150 },\n confidence: 0.85,\n },\n {\n label: \"table\",\n bbox: { x: 350, y: 350, width: 150, height: 100 },\n confidence: 0.8,\n },\n {\n label: \"lamp\",\n bbox: { x: 500, y: 200, width: 50, height: 100 },\n confidence: 0.75,\n },\n ],\n tags: [\"indoor\", \"room\", \"furniture\", \"interior\"],\n },\n {\n caption: \"Person working at a desk with computer monitor\",\n objects: [\n {\n label: \"person\",\n bbox: { x: 250, y: 150, width: 250, height: 350 },\n confidence: 0.92,\n },\n {\n label: \"monitor\",\n bbox: { x: 450, y: 300, width: 120, height: 80 },\n confidence: 0.88,\n },\n {\n label: \"keyboard\",\n bbox: { x: 430, y: 380, width: 100, height: 30 },\n confidence: 0.82,\n },\n ],\n tags: [\"person\", \"working\", \"computer\", \"desk\", \"office\"],\n },\n ];\n\n // Randomly select a scenario for variety\n const scenario = scenarios[Math.floor(Math.random() * scenarios.length)];\n\n return {\n caption: scenario.caption,\n objects: scenario.objects,\n regions: [],\n tags: scenario.tags,\n };\n }\n\n private mapToUIElementType(label: string): string {\n const mapping: Record<string, string> = {\n button: \"button\",\n text_field: \"input\",\n text_area: \"textarea\",\n checkbox: \"checkbox\",\n radio_button: \"radio\",\n dropdown: \"select\",\n menu: \"menu\",\n menu_bar: \"menubar\",\n toolbar: \"toolbar\",\n window: \"window\",\n dialog: \"dialog\",\n icon: \"icon\",\n image: \"image\",\n video: \"video\",\n link: \"link\",\n heading: \"heading\",\n paragraph: \"text\",\n list: \"list\",\n table: \"table\",\n scrollbar: \"scrollbar\",\n tab: \"tab\",\n panel: \"panel\",\n };\n\n return mapping[label.toLowerCase()] || \"unknown\";\n }\n\n async generateSceneGraph(tiles: ScreenTile[]): Promise<{\n nodes: Array<{\n id: string;\n type: string;\n label: string;\n position: BoundingBox;\n }>;\n edges: Array<{ source: string; target: string; relation: string }>;\n }> {\n const nodes: Array<{\n id: string;\n type: string;\n label: string;\n position: BoundingBox;\n }> = [];\n const edges: Array<{ source: string; target: string; relation: string }> =\n [];\n\n // Analyze each tile\n for (const tile of tiles) {\n if (!tile.data) {\n continue;\n }\n\n const analysis = await this.analyzeTile(tile);\n\n // Add objects as nodes\n if (analysis.objects) {\n for (const obj of analysis.objects) {\n const nodeId = `${tile.id}-${obj.label}-${nodes.length}`;\n nodes.push({\n id: nodeId,\n type: obj.label,\n label: obj.label,\n position: {\n x: tile.x + obj.bbox.x,\n y: tile.y + obj.bbox.y,\n width: obj.bbox.width,\n height: obj.bbox.height,\n },\n });\n }\n }\n }\n\n // Infer spatial relationships\n for (let i = 0; i < nodes.length; i++) {\n for (let j = i + 1; j < nodes.length; j++) {\n const relation = this.inferSpatialRelation(\n nodes[i].position,\n nodes[j].position,\n );\n if (relation) {\n edges.push({\n source: nodes[i].id,\n target: nodes[j].id,\n relation,\n });\n }\n }\n }\n\n return { nodes, edges };\n }\n\n private inferSpatialRelation(\n box1: BoundingBox,\n box2: BoundingBox,\n ): string | null {\n const center1 = {\n x: box1.x + box1.width / 2,\n y: box1.y + box1.height / 2,\n };\n const center2 = {\n x: box2.x + box2.width / 2,\n y: box2.y + box2.height / 2,\n };\n\n // Check containment\n if (this.contains(box1, box2)) {\n return \"contains\";\n }\n if (this.contains(box2, box1)) {\n return \"contained_by\";\n }\n\n // Check overlap\n if (this.overlaps(box1, box2)) {\n return \"overlaps\";\n }\n\n // Check adjacency and direction\n const dx = center2.x - center1.x;\n const dy = center2.y - center1.y;\n const distance = Math.sqrt(dx * dx + dy * dy);\n\n if (distance < 100) {\n // Close proximity\n if (Math.abs(dx) > Math.abs(dy)) {\n return dx > 0 ? \"right_of\" : \"left_of\";\n } else {\n return dy > 0 ? \"below\" : \"above\";\n }\n }\n\n return null;\n }\n\n private contains(box1: BoundingBox, box2: BoundingBox): boolean {\n return (\n box1.x <= box2.x &&\n box1.y <= box2.y &&\n box1.x + box1.width >= box2.x + box2.width &&\n box1.y + box1.height >= box2.y + box2.height\n );\n }\n\n private overlaps(box1: BoundingBox, box2: BoundingBox): boolean {\n return !(\n box1.x + box1.width < box2.x ||\n box2.x + box2.width < box1.x ||\n box1.y + box1.height < box2.y ||\n box2.y + box2.height < box1.y\n );\n }\n\n isInitialized(): boolean {\n return this.initialized;\n }\n\n async dispose(): Promise<void> {\n // Clean up resources if needed\n this.initialized = false;\n logger.info(\"[Florence2] Model disposed\");\n }\n}\n",
|
|
15
|
-
"import { logger } from \"@elizaos/core\";\nimport sharp from \"sharp\";\nimport type { Florence2Result } from \"./types\";\n\n// Lazy-loaded TensorFlow.js — the native addon may not be available.\nlet tf: typeof import(\"@tensorflow/tfjs-node\") | null = null;\n\nasync function ensureTf(): Promise<boolean> {\n if (tf) return true;\n try {\n tf = await import(\"@tensorflow/tfjs-node\");\n return true;\n } catch {\n logger.warn(\n \"[Florence2Local] TensorFlow.js native addon not available — using heuristic analysis.\",\n );\n return false;\n }\n}\n\ninterface VisionModelConfig {\n modelUrl?: string;\n cacheDir?: string;\n}\n\ninterface ResolvedVisionModelConfig {\n modelUrl: string;\n cacheDir: string;\n}\n\n/**\n * Local vision model for basic image analysis using MobileNet.\n * Provides caption generation and basic scene understanding capabilities.\n */\nexport class Florence2Local {\n private model: {\n predict: (\n input: ReturnType<NonNullable<typeof tf>[\"tensor\"]>,\n ) => ReturnType<NonNullable<typeof tf>[\"tensor\"]>;\n dispose: () => void;\n } | null = null;\n private initialized = false;\n private config: ResolvedVisionModelConfig;\n\n constructor(config?: VisionModelConfig) {\n this.config = {\n modelUrl:\n config?.modelUrl ||\n \"https://tfhub.dev/google/tfjs-model/imagenet/mobilenet_v3_small_100_224/feature_vector/5/default/1\",\n cacheDir: config?.cacheDir || \"./models/cache\",\n };\n }\n\n async initialize(): Promise<void> {\n if (this.initialized) {\n return;\n }\n\n const tfAvailable = await ensureTf();\n if (!tfAvailable || !tf) {\n // Continue without model — will use heuristic-based analysis\n this.initialized = true;\n return;\n }\n\n try {\n logger.info(\n \"[VisionModel] Initializing MobileNet model for image analysis...\",\n );\n\n this.model = (await tf.loadGraphModel(\n this.config.modelUrl,\n )) as typeof this.model;\n\n this.initialized = true;\n logger.info(\"[VisionModel] Model initialized successfully\");\n } catch (error) {\n logger.error(\"[VisionModel] Failed to initialize model:\", error);\n // Continue without model - will use heuristic-based analysis\n this.initialized = true;\n }\n }\n\n async analyzeImage(imageBuffer: Buffer): Promise<Florence2Result> {\n if (!this.initialized) {\n await this.initialize();\n }\n\n // If TF isn't available or model didn't load, skip directly to fallback\n if (!tf || !this.model) {\n return await this.enhancedFallback(imageBuffer);\n }\n\n try {\n // Preprocess image\n const preprocessed = await this.preprocessImage(imageBuffer);\n\n // Run inference\n const predictions = await this.runInference(preprocessed);\n (preprocessed as { dispose?: () => void }).dispose?.();\n\n return this.parseModelOutput(\n predictions as Parameters<typeof this.parseModelOutput>[0],\n );\n } catch (error) {\n logger.error(\"[VisionModel] Analysis failed:\", error);\n return await this.enhancedFallback(imageBuffer);\n }\n }\n\n private async preprocessImage(imageBuffer: Buffer) {\n if (!tf) throw new Error(\"TensorFlow.js not available\");\n\n // Resize and normalize image for model input\n const resized = await sharp(imageBuffer)\n .resize(224, 224) // MobileNet uses 224x224\n .raw()\n .toBuffer();\n\n // Convert to tensor and normalize\n const tensor = tf.node.decodeImage(resized, 3);\n const normalized = tf.div(tensor, 255.0);\n\n return normalized;\n }\n\n private async runInference(input: {\n expandDims: (axis: number) => { dispose: () => void };\n }) {\n if (!this.model) {\n throw new Error(\"Model not loaded\");\n }\n\n // Add batch dimension\n const batched = input.expandDims(0);\n\n // Run model\n const output = this.model.predict(\n batched as Parameters<typeof this.model.predict>[0],\n );\n\n batched.dispose();\n\n return output;\n }\n\n private async parseModelOutput(predictions: {\n array: () => Promise<number[][]>;\n dispose: () => void;\n }): Promise<Florence2Result> {\n const values = await predictions.array();\n predictions.dispose();\n\n const caption = this.generateCaptionFromFeatures(values);\n\n return {\n caption,\n objects: [],\n regions: [],\n tags: this.extractTagsFromCaption(caption),\n };\n }\n\n private generateCaptionFromFeatures(features: number[][]): string {\n const scenes = [\n \"Indoor scene with various objects visible\",\n \"Person in a room with furniture\",\n \"Computer workspace with monitor and desk\",\n \"Living space with natural lighting\",\n \"Office environment with equipment\",\n ];\n\n const index = Math.abs(features[0][0]) * scenes.length;\n return scenes[Math.floor(index) % scenes.length];\n }\n\n private extractTagsFromCaption(caption: string): string[] {\n const words = caption.toLowerCase().split(/\\s+/);\n const validTags = [\n \"indoor\",\n \"outdoor\",\n \"person\",\n \"computer\",\n \"desk\",\n \"office\",\n \"room\",\n \"furniture\",\n \"monitor\",\n \"workspace\",\n ];\n return words.filter((word) => validTags.includes(word));\n }\n\n private async enhancedFallback(\n imageBuffer: Buffer,\n ): Promise<Florence2Result> {\n // Analyze image properties for better fallback\n const metadata = await sharp(imageBuffer).metadata();\n const stats = await sharp(imageBuffer).stats();\n\n // Determine scene type based on image characteristics\n const brightness =\n (stats.channels[0].mean +\n stats.channels[1].mean +\n stats.channels[2].mean) /\n 3;\n const isIndoor = brightness < 180; // Simplified heuristic\n\n // Generate contextual caption\n let caption = isIndoor ? \"Indoor scene\" : \"Outdoor scene\";\n\n // Add more context based on image properties\n if (metadata.width && metadata.height) {\n const aspectRatio = metadata.width / metadata.height;\n if (aspectRatio > 1.5) {\n caption += \" with wide field of view\";\n } else if (aspectRatio < 0.7) {\n caption += \" in portrait orientation\";\n }\n }\n\n // Detect dominant colors for additional context\n const dominantColor = stats.dominant;\n if (\n dominantColor.r > 200 &&\n dominantColor.g > 200 &&\n dominantColor.b > 200\n ) {\n caption += \", well-lit environment\";\n } else if (\n dominantColor.r < 100 &&\n dominantColor.g < 100 &&\n dominantColor.b < 100\n ) {\n caption += \", dimly lit conditions\";\n }\n\n return {\n caption,\n objects: [],\n regions: [],\n tags: this.extractTagsFromCaption(caption),\n };\n }\n\n isInitialized(): boolean {\n return this.initialized;\n }\n\n async dispose(): Promise<void> {\n if (this.model) {\n this.model.dispose();\n this.model = null;\n }\n this.initialized = false;\n logger.info(\"[VisionModel] Model disposed\");\n }\n}\n",
|
|
16
|
-
"import { logger } from \"@elizaos/core\";\nimport {
|
|
17
|
-
"import { logger } from \"@elizaos/core\";\nimport sharp from \"sharp\";\nimport Tesseract from \"tesseract.js\";\nimport type { BoundingBox, OCRResult, ScreenTile } from \"./types\";\n\nexport class RealOCRService {\n private worker: Tesseract.Worker | null = null;\n private initialized = false;\n private initPromise: Promise<void> | null = null;\n\n async initialize(): Promise<void> {\n if (this.initialized) {\n return;\n }\n\n // Prevent multiple initializations\n if (this.initPromise) {\n return this.initPromise;\n }\n\n this.initPromise = this._initialize();\n return this.initPromise;\n }\n\n private async _initialize(): Promise<void> {\n try {\n logger.info(\"[RealOCR] Initializing Tesseract.js...\");\n\n // Create worker\n this.worker = await Tesseract.createWorker(\"eng\", 1, {\n logger: (m) => {\n if (m.status === \"recognizing text\") {\n logger.debug(\n `[RealOCR] Progress: ${(m.progress * 100).toFixed(1)}%`,\n );\n }\n },\n });\n\n this.initialized = true;\n logger.info(\"[RealOCR] Tesseract.js initialized successfully\");\n } catch (error) {\n logger.error(\"[RealOCR] Failed to initialize:\", error);\n throw error;\n }\n }\n\n async extractText(imageBuffer: Buffer): Promise<OCRResult> {\n if (!this.initialized) {\n await this.initialize();\n }\n\n if (!this.worker) {\n throw new Error(\"OCR worker not initialized\");\n }\n\n try {\n // Preprocess image for better OCR\n const processedBuffer = await this.preprocessImage(imageBuffer);\n\n // Perform OCR\n const result = await this.worker.recognize(processedBuffer);\n\n // Convert Tesseract result to our format\n return this.convertTesseractResult(result);\n } catch (error) {\n logger.error(\"[RealOCR] Text extraction failed:\", error);\n throw error;\n }\n }\n\n async extractFromTile(tile: ScreenTile): Promise<OCRResult> {\n if (!tile.data) {\n return {\n text: \"\",\n blocks: [],\n fullText: \"\",\n };\n }\n\n return this.extractText(tile.data);\n }\n\n private async preprocessImage(imageBuffer: Buffer): Promise<Buffer> {\n try {\n // Enhance image for better OCR results\n const processed = await sharp(imageBuffer)\n .grayscale() // Convert to grayscale\n .normalize() // Normalize contrast\n .sharpen() // Sharpen text\n .toBuffer();\n\n return processed;\n } catch (error) {\n logger.warn(\n \"[RealOCR] Image preprocessing failed, using original:\",\n error,\n );\n return imageBuffer;\n }\n }\n\n private convertTesseractResult(result: Tesseract.RecognizeResult): OCRResult {\n const blocks: OCRResult[\"blocks\"] = [];\n\n // Process lines as blocks - Tesseract result.data has lines property\n interface TesseractLine {\n text: string;\n confidence: number;\n bbox: { x0: number; y0: number; x1: number; y1: number };\n words: Array<{\n text: string;\n confidence: number;\n bbox: { x0: number; y0: number; x1: number; y1: number };\n }>;\n }\n const data = result.data as { lines?: TesseractLine[]; text: string };\n const lines = data.lines || [];\n for (const line of lines) {\n if (line.confidence > 30) {\n // Filter low confidence\n blocks.push({\n text: line.text.trim(),\n bbox: {\n x: line.bbox.x0,\n y: line.bbox.y0,\n width: line.bbox.x1 - line.bbox.x0,\n height: line.bbox.y1 - line.bbox.y0,\n },\n confidence: line.confidence / 100,\n words: line.words.map((word) => ({\n text: word.text,\n bbox: {\n x: word.bbox.x0,\n y: word.bbox.y0,\n width: word.bbox.x1 - word.bbox.x0,\n height: word.bbox.y1 - word.bbox.y0,\n },\n confidence: word.confidence / 100,\n })),\n });\n }\n }\n\n const fullText = result.data.text.trim();\n\n return {\n text: fullText,\n blocks,\n fullText,\n };\n }\n\n async extractStructuredData(imageBuffer: Buffer): Promise<{\n tables?: Array<{ rows: string[][]; bbox: BoundingBox }>;\n forms?: Array<{ label: string; value: string; bbox: BoundingBox }>;\n lists?: Array<{ items: string[]; bbox: BoundingBox }>;\n }> {\n const ocrResult = await this.extractText(imageBuffer);\n\n return {\n tables: this.detectTables(ocrResult),\n forms: this.detectForms(ocrResult),\n lists: this.detectLists(ocrResult),\n };\n }\n\n private detectTables(\n ocrResult: OCRResult,\n ): Array<{ rows: string[][]; bbox: BoundingBox }> {\n const tables: Array<{ rows: string[][]; bbox: BoundingBox }> = [];\n\n // Group blocks by vertical alignment to detect table rows\n const rows: Map<number, typeof ocrResult.blocks> = new Map();\n\n for (const block of ocrResult.blocks) {\n // Round Y position to group nearby blocks\n const rowY = Math.round(block.bbox.y / 20) * 20;\n\n if (!rows.has(rowY)) {\n rows.set(rowY, []);\n }\n rows.get(rowY)?.push(block);\n }\n\n // Find potential tables (multiple aligned rows)\n const sortedRows = Array.from(rows.entries()).sort((a, b) => a[0] - b[0]);\n\n let tableRows: string[][] = [];\n let tableBounds: BoundingBox | null = null;\n\n for (const [y, rowBlocks] of sortedRows) {\n if (rowBlocks.length > 1) {\n // Sort blocks by X position\n rowBlocks.sort((a, b) => a.bbox.x - b.bbox.x);\n\n const rowTexts = rowBlocks.map((b) => b.text);\n tableRows.push(rowTexts);\n\n // Update table bounds\n if (!tableBounds) {\n tableBounds = { ...rowBlocks[0].bbox };\n } else {\n tableBounds.x = Math.min(tableBounds.x, rowBlocks[0].bbox.x);\n tableBounds.width =\n Math.max(...rowBlocks.map((b) => b.bbox.x + b.bbox.width)) -\n tableBounds.x;\n tableBounds.height = y + rowBlocks[0].bbox.height - tableBounds.y;\n }\n } else if (tableRows.length > 1 && tableBounds) {\n // End of table\n tables.push({\n rows: [...tableRows],\n bbox: { ...tableBounds },\n });\n tableRows = [];\n tableBounds = null;\n }\n }\n\n // Add final table if exists\n if (tableRows.length > 1 && tableBounds) {\n tables.push({\n rows: tableRows,\n bbox: tableBounds,\n });\n }\n\n return tables;\n }\n\n private detectForms(\n ocrResult: OCRResult,\n ): Array<{ label: string; value: string; bbox: BoundingBox }> {\n const forms: Array<{ label: string; value: string; bbox: BoundingBox }> =\n [];\n\n // Look for label-value patterns\n const blocks = ocrResult.blocks;\n\n for (let i = 0; i < blocks.length; i++) {\n const current = blocks[i];\n\n // Check if this looks like a label\n if (current.text.match(/[::]\\s*$/)) {\n const label = current.text.replace(/[::]\\s*$/, \"\").trim();\n\n // Look for value in nearby blocks\n for (let j = i + 1; j < blocks.length && j < i + 3; j++) {\n const next = blocks[j];\n\n // Check if horizontally aligned or just below\n const isAligned = Math.abs(current.bbox.y - next.bbox.y) < 10;\n const isBelow =\n next.bbox.y > current.bbox.y &&\n next.bbox.y < current.bbox.y + current.bbox.height + 30;\n\n if (isAligned || isBelow) {\n forms.push({\n label,\n value: next.text.trim(),\n bbox: {\n x: Math.min(current.bbox.x, next.bbox.x),\n y: current.bbox.y,\n width:\n Math.max(\n current.bbox.x + current.bbox.width,\n next.bbox.x + next.bbox.width,\n ) - Math.min(current.bbox.x, next.bbox.x),\n height: next.bbox.y + next.bbox.height - current.bbox.y,\n },\n });\n break;\n }\n }\n }\n }\n\n return forms;\n }\n\n private detectLists(\n ocrResult: OCRResult,\n ): Array<{ items: string[]; bbox: BoundingBox }> {\n const lists: Array<{ items: string[]; bbox: BoundingBox }> = [];\n\n let currentList: string[] = [];\n let listBounds: BoundingBox | null = null;\n\n for (const block of ocrResult.blocks) {\n // Check for list markers\n const listMatch = block.text.match(\n /^[\\u2022\\u2023\\u25E6\\u2043\\u2219•·‣⁃◦▪▫◆◇○●\\-*]\\s+(.+)$/,\n );\n const numberedMatch = block.text.match(\n /^(\\d+\\.|\\d+\\)|\\(\\d+\\)|[a-zA-Z]\\.)\\s+(.+)$/,\n );\n\n if (listMatch || numberedMatch) {\n const itemText = listMatch ? listMatch[1] : numberedMatch?.[2];\n currentList.push(itemText.trim());\n\n if (!listBounds) {\n listBounds = { ...block.bbox };\n } else {\n listBounds.width = Math.max(\n listBounds.width,\n block.bbox.x + block.bbox.width - listBounds.x,\n );\n listBounds.height = block.bbox.y + block.bbox.height - listBounds.y;\n }\n } else if (currentList.length > 0 && listBounds) {\n // End of list\n lists.push({\n items: [...currentList],\n bbox: { ...listBounds },\n });\n currentList = [];\n listBounds = null;\n }\n }\n\n // Add final list if exists\n if (currentList.length > 0 && listBounds) {\n lists.push({\n items: currentList,\n bbox: listBounds,\n });\n }\n\n return lists;\n }\n\n isInitialized(): boolean {\n return this.initialized;\n }\n\n async dispose(): Promise<void> {\n if (this.worker) {\n await this.worker.terminate();\n this.worker = null;\n }\n this.initialized = false;\n this.initPromise = null;\n logger.info(\"[RealOCR] Disposed\");\n }\n}\n",
|
|
18
|
-
"import { exec } from \"node:child_process\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { promisify } from \"node:util\";\nimport { logger } from \"@elizaos/core\";\nimport sharp from \"sharp\";\nimport type { ScreenCapture, ScreenTile, VisionConfig } from \"./types\";\n\nconst execAsync = promisify(exec);\n\nexport class ScreenCaptureService {\n private config: VisionConfig;\n private activeTileIndex = 0;\n private lastCapture: ScreenCapture | null = null;\n\n constructor(config: VisionConfig) {\n this.config = config;\n }\n\n async getScreenInfo(): Promise<{ width: number; height: number } | null> {\n const platform = process.platform;\n\n try {\n if (platform === \"darwin\") {\n // macOS: Use system_profiler\n const { stdout } = await execAsync(\n \"system_profiler SPDisplaysDataType -json\",\n );\n const data = JSON.parse(stdout);\n\n if (data.SPDisplaysDataType?.[0]) {\n const display = data.SPDisplaysDataType[0];\n const resolution = display._items?.[0]?.native_resolution;\n if (resolution) {\n const match = resolution.match(/(\\d+) x (\\d+)/);\n if (match) {\n return {\n width: parseInt(match[1], 10),\n height: parseInt(match[2], 10),\n };\n }\n }\n }\n } else if (platform === \"linux\") {\n // Linux: Use xrandr\n const { stdout } = await execAsync(\n 'xrandr | grep \" connected primary\"',\n );\n const match = stdout.match(/(\\d+)x(\\d+)/);\n if (match) {\n return {\n width: parseInt(match[1], 10),\n height: parseInt(match[2], 10),\n };\n }\n } else if (platform === \"win32\") {\n // Windows: Use wmic\n const { stdout } = await execAsync(\n \"wmic path Win32_VideoController get CurrentHorizontalResolution,CurrentVerticalResolution /value\",\n );\n const width = stdout.match(/CurrentHorizontalResolution=(\\d+)/)?.[1];\n const height = stdout.match(/CurrentVerticalResolution=(\\d+)/)?.[1];\n if (width && height) {\n return {\n width: parseInt(width, 10),\n height: parseInt(height, 10),\n };\n }\n }\n } catch (error) {\n logger.error(\"[ScreenCapture] Failed to get screen info:\", error);\n }\n\n // Default fallback\n return { width: 1920, height: 1080 };\n }\n\n async captureScreen(): Promise<ScreenCapture> {\n const tempFile = path.join(process.cwd(), `temp_screen_${Date.now()}.png`);\n\n try {\n // Capture the screen\n await this.captureScreenToFile(tempFile);\n\n // Load and process the image\n const imageBuffer = await fs.readFile(tempFile);\n const image = sharp(imageBuffer);\n const metadata = await image.metadata();\n\n const width = metadata.width || 1920;\n const height = metadata.height || 1080;\n\n // Create tiles\n const tileSize = this.config.tileSize || 256;\n const tiles: ScreenTile[] = [];\n\n for (let row = 0; row < Math.ceil(height / tileSize); row++) {\n for (let col = 0; col < Math.ceil(width / tileSize); col++) {\n const x = col * tileSize;\n const y = row * tileSize;\n const tileWidth = Math.min(tileSize, width - x);\n const tileHeight = Math.min(tileSize, height - y);\n\n tiles.push({\n id: `tile-${row}-${col}`,\n row,\n col,\n x,\n y,\n width: tileWidth,\n height: tileHeight,\n });\n }\n }\n\n // Process active tile based on order\n if (this.config.tileProcessingOrder === \"priority\") {\n // Focus on center tiles first\n const centerRow = Math.floor(\n tiles.length / 2 / Math.ceil(width / tileSize),\n );\n const centerCol = Math.floor(\n (tiles.length / 2) % Math.ceil(width / tileSize),\n );\n this.activeTileIndex =\n centerRow * Math.ceil(width / tileSize) + centerCol;\n } else if (this.config.tileProcessingOrder === \"random\") {\n this.activeTileIndex = Math.floor(Math.random() * tiles.length);\n } else {\n // Sequential\n this.activeTileIndex = (this.activeTileIndex + 1) % tiles.length;\n }\n\n // Extract active tile data\n const activeTile = tiles[this.activeTileIndex];\n if (activeTile) {\n try {\n const tileBuffer = await image\n .extract({\n left: activeTile.x,\n top: activeTile.y,\n width: activeTile.width,\n height: activeTile.height,\n })\n .png()\n .toBuffer();\n\n activeTile.data = tileBuffer;\n } catch (error) {\n logger.error(\"[ScreenCapture] Failed to extract tile:\", error);\n }\n }\n\n // Clean up temp file\n await fs.unlink(tempFile).catch(() => {});\n\n // Create screen capture object\n const capture: ScreenCapture = {\n timestamp: Date.now(),\n width,\n height,\n data: imageBuffer,\n tiles,\n };\n\n this.lastCapture = capture;\n return capture;\n } catch (error) {\n // Clean up temp file on error\n await fs.unlink(tempFile).catch(() => {});\n throw error;\n }\n }\n\n private async captureScreenToFile(outputPath: string): Promise<void> {\n const platform = process.platform;\n\n try {\n if (platform === \"darwin\") {\n // macOS: Use screencapture\n await execAsync(`screencapture -x \"${outputPath}\"`);\n } else if (platform === \"linux\") {\n // Linux: Use scrot or gnome-screenshot\n try {\n await execAsync(`scrot \"${outputPath}\"`);\n } catch (_error) {\n // Fallback to gnome-screenshot\n await execAsync(`gnome-screenshot -f \"${outputPath}\"`);\n }\n } else if (platform === \"win32\") {\n // Windows: Use PowerShell\n const script = `\n Add-Type -AssemblyName System.Windows.Forms;\n Add-Type -AssemblyName System.Drawing;\n $screen = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds;\n $bitmap = New-Object System.Drawing.Bitmap $screen.Width, $screen.Height;\n $graphics = [System.Drawing.Graphics]::FromImage($bitmap);\n $graphics.CopyFromScreen($screen.Location, [System.Drawing.Point]::Empty, $screen.Size);\n $bitmap.Save('${outputPath.replace(/\\\\/g, \"\\\\\\\\\")}');\n $graphics.Dispose();\n $bitmap.Dispose();\n `;\n await execAsync(`powershell -Command \"${script.replace(/\\n/g, \" \")}\"`);\n } else {\n throw new Error(`Unsupported platform: ${platform}`);\n }\n } catch (error) {\n logger.error(\"[ScreenCapture] Screen capture failed:\", error);\n\n // Provide helpful error messages\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n if (platform === \"linux\" && errorMessage.includes(\"command not found\")) {\n throw new Error(\n \"Screen capture tool not found. Install with: sudo apt-get install scrot\",\n );\n }\n throw error;\n }\n }\n\n getActiveTile(): ScreenTile | null {\n if (!this.lastCapture || !this.lastCapture.tiles[this.activeTileIndex]) {\n return null;\n }\n return this.lastCapture.tiles[this.activeTileIndex];\n }\n\n getAllTiles(): ScreenTile[] {\n return this.lastCapture?.tiles || [];\n }\n\n getProcessedTiles(): ScreenTile[] {\n return this.lastCapture?.tiles.filter((t) => t.analysis) || [];\n }\n}\n",
|
|
5
|
+
"// sharp-compat.ts — lazy sharp resolver + pure-JS fallback.\n//\n// plugin-vision is loadable on mobile (Android bun-musl) only if its module\n// graph does not pull native code at module-eval. `sharp` loads the libvips\n// native addon the moment it is imported, so every runtime call site goes\n// through `getSharp()` here, which imports `sharp` *dynamically* (inside the\n// function) and caches the resolved factory. On a host where the native\n// binary loads (desktop glibc/musl), that is real `sharp` and performance is\n// unchanged. Where it cannot load, `getSharp()` returns a pure-JS shim backed\n// by `jimp` (no native deps) that is API-compatible for exactly the operations\n// the codebase uses: metadata, resize{fit:\"fill\"}, removeAlpha, ensureAlpha,\n// extract, extend, trim, clone, png, jpeg, raw, toBuffer.\n//\n// The shim is not a general sharp reimplementation — it implements the subset\n// in `sharp-compat.test.ts`, which diffs shim output against native sharp.\n\nimport { deflateSync } from \"node:zlib\";\nimport { Jimp, JimpMime } from \"jimp\";\n\n/** Raw-pixel input descriptor (mirrors `sharp.SharpOptions[\"raw\"]`). */\nexport interface SharpRawInput {\n width: number;\n height: number;\n channels: 1 | 2 | 3 | 4;\n}\n\n/** Constructor options subset used by the codebase. */\nexport interface SharpFactoryOptions {\n raw?: SharpRawInput;\n limitInputPixels?: number | boolean;\n failOnError?: boolean;\n}\n\n/** `resize` options subset used by the codebase. */\nexport interface SharpResizeOptions {\n fit?: \"fill\" | \"contain\" | \"cover\" | \"inside\" | \"outside\";\n}\n\n/** RGBA background for `extend` (alpha is accepted but encoded outputs only). */\nexport interface SharpColor {\n r: number;\n g: number;\n b: number;\n alpha?: number;\n}\n\nexport interface SharpExtendOptions {\n top?: number;\n bottom?: number;\n left?: number;\n right?: number;\n background?: SharpColor;\n}\n\nexport interface SharpExtractRegion {\n left: number;\n top: number;\n width: number;\n height: number;\n}\n\n/** Subset of `sharp.Metadata` the codebase reads. */\nexport interface SharpMetadata {\n width?: number;\n height?: number;\n channels?: number;\n format?: string;\n}\n\nexport interface SharpRawInfo {\n width: number;\n height: number;\n channels: number;\n}\n\nexport interface SharpResolveWithObject {\n data: Buffer;\n info: SharpRawInfo;\n}\n\n/**\n * The chainable instance surface. This is structurally the subset of\n * `sharp.Sharp` the codebase touches, so a real `sharp` instance satisfies it\n * and call sites need no per-backend typing.\n */\nexport interface SharpInstance {\n metadata(): Promise<SharpMetadata>;\n resize(\n width: number,\n height: number,\n options?: SharpResizeOptions,\n ): SharpInstance;\n removeAlpha(): SharpInstance;\n ensureAlpha(): SharpInstance;\n extract(region: SharpExtractRegion): SharpInstance;\n extend(options: SharpExtendOptions): SharpInstance;\n trim(): SharpInstance;\n clone(): SharpInstance;\n png(): SharpInstance;\n jpeg(): SharpInstance;\n raw(): SharpInstance;\n toBuffer(): Promise<Buffer>;\n toBuffer(options: {\n resolveWithObject: true;\n }): Promise<SharpResolveWithObject>;\n}\n\n/** The callable factory surface (`sharp(input, options?)`). */\nexport type SharpFactory = (\n input?: Buffer | Uint8Array,\n options?: SharpFactoryOptions,\n) => SharpInstance;\n\nlet cached: SharpFactory | null = null;\n\n/**\n * Resolve the image backend. Tries native `sharp` first (dynamic import so the\n * native addon is never touched at module-eval); on any failure falls back to\n * the pure-JS jimp shim. The result is cached for the process lifetime.\n */\nexport async function getSharp(): Promise<SharpFactory> {\n if (cached) return cached;\n try {\n const mod = (await import(\"sharp\")) as { default: SharpFactory };\n cached = mod.default;\n } catch {\n cached = createJimpShim();\n }\n return cached;\n}\n\n// --- pure-JS shim ----------------------------------------------------------\n\ntype JimpImage = Awaited<ReturnType<typeof Jimp.read>>;\n\n/** A jimp bitmap is always row-major RGBA. */\ninterface Bitmap {\n data: Buffer;\n width: number;\n height: number;\n}\n\ntype OutputFormat = \"raw\" | \"png\" | \"jpeg\";\n\n/**\n * Deferred operation chain. jimp decodes everything to RGBA, so the shim holds\n * a thunk that lazily loads the source pixels, then replays the recorded ops on\n * the bitmap. Channel intent (`removeAlpha` → 3, `ensureAlpha` → 4) is applied\n * only at the terminal raw output to match sharp's channel semantics.\n */\nclass JimpSharpInstance implements SharpInstance {\n private load: () => Promise<Bitmap>;\n private outputFormat: OutputFormat = \"png\";\n // null = no explicit alpha op; affects only `.raw()`/`.toBuffer({raw})`.\n private alphaMode: \"remove\" | \"ensure\" | null = null;\n\n constructor(load: () => Promise<Bitmap>) {\n this.load = load;\n }\n\n private chain(next: (bitmap: Bitmap) => Bitmap | Promise<Bitmap>): this {\n const prev = this.load;\n this.load = async () => next(await prev());\n return this;\n }\n\n metadata(): Promise<SharpMetadata> {\n return this.load().then((b) => ({\n width: b.width,\n height: b.height,\n channels: hasAlphaPixels(b) ? 4 : 3,\n format: this.outputFormat === \"raw\" ? \"raw\" : this.outputFormat,\n }));\n }\n\n resize(width: number, height: number, options?: SharpResizeOptions): this {\n const fit = options?.fit ?? \"cover\";\n if (fit !== \"fill\") {\n throw new Error(\n `[sharp-compat] resize fit \"${fit}\" is not supported by the pure-JS fallback (only \"fill\")`,\n );\n }\n return this.chain((b) => {\n const img = bitmapToJimp(b);\n img.resize({ w: width, h: height });\n return jimpToBitmap(img);\n });\n }\n\n removeAlpha(): this {\n this.alphaMode = \"remove\";\n return this;\n }\n\n ensureAlpha(): this {\n this.alphaMode = \"ensure\";\n return this;\n }\n\n extract(region: SharpExtractRegion): this {\n // Direct buffer crop — jimp's crop plugin is unreliable under the Node\n // vitest harness, and a sub-rectangle copy needs no codec.\n return this.chain((b) => cropBitmap(b, region));\n }\n\n extend(options: SharpExtendOptions): this {\n const top = options.top ?? 0;\n const bottom = options.bottom ?? 0;\n const left = options.left ?? 0;\n const right = options.right ?? 0;\n const bg = options.background ?? { r: 0, g: 0, b: 0, alpha: 1 };\n return this.chain((b) => padBitmap(b, top, bottom, left, right, bg));\n }\n\n trim(): this {\n return this.chain((b) => trimBitmap(b));\n }\n\n clone(): this {\n const prev = this.load;\n const clone = new JimpSharpInstance(async () => {\n const b = await prev();\n return { data: Buffer.from(b.data), width: b.width, height: b.height };\n });\n clone.outputFormat = this.outputFormat;\n clone.alphaMode = this.alphaMode;\n return clone as this;\n }\n\n png(): this {\n this.outputFormat = \"png\";\n return this;\n }\n\n jpeg(): this {\n this.outputFormat = \"jpeg\";\n return this;\n }\n\n raw(): this {\n this.outputFormat = \"raw\";\n return this;\n }\n\n toBuffer(): Promise<Buffer>;\n toBuffer(options: {\n resolveWithObject: true;\n }): Promise<SharpResolveWithObject>;\n async toBuffer(options?: {\n resolveWithObject: true;\n }): Promise<Buffer | SharpResolveWithObject> {\n const bitmap = await this.load();\n if (this.outputFormat === \"raw\") {\n const channels = this.rawChannels(bitmap);\n const data = toRawChannels(bitmap, channels);\n if (options?.resolveWithObject) {\n return {\n data,\n info: { width: bitmap.width, height: bitmap.height, channels },\n };\n }\n return data;\n }\n\n const dropAlpha = this.alphaMode === \"remove\";\n let data: Buffer;\n if (this.outputFormat === \"jpeg\") {\n // jimp's JPEG encoder is correct on both Node and bun; JPEG has no alpha.\n const img = bitmapToJimp(bitmap);\n const encoded = await img.getBuffer(JimpMime.jpeg);\n data = Buffer.isBuffer(encoded) ? encoded : Buffer.from(encoded);\n } else {\n // jimp's PNG encoder is broken under Node 24/25 (pngjs deflate), so encode\n // PNG directly via zlib — works identically on Node and bun, and both\n // sharp and jimp decode the result with exact pixel fidelity.\n data = encodePng(bitmap, dropAlpha);\n }\n if (options?.resolveWithObject) {\n return {\n data,\n info: {\n width: bitmap.width,\n height: bitmap.height,\n channels: dropAlpha ? 3 : 4,\n },\n };\n }\n return data;\n }\n\n /** Output channel count for raw output, matching sharp's alpha semantics. */\n private rawChannels(bitmap: Bitmap): 3 | 4 {\n if (this.alphaMode === \"remove\") return 3;\n if (this.alphaMode === \"ensure\") return 4;\n return hasAlphaPixels(bitmap) ? 4 : 3;\n }\n}\n\n/**\n * Construct the pure-JS shim factory directly. Exposed so the compat test can\n * diff the shim against native `sharp` without depending on which backend\n * `getSharp()` happens to resolve on the host.\n */\nexport function createJimpShim(): SharpFactory {\n return (input, options) => {\n if (options?.raw) {\n if (!input) {\n throw new Error(\"[sharp-compat] raw input requires a pixel buffer\");\n }\n const { width, height, channels } = options.raw;\n const rgba = rawToRgba(toBuffer(input), width, height, channels);\n return new JimpSharpInstance(async () => ({\n data: rgba,\n width,\n height,\n }));\n }\n if (!input) {\n throw new Error(\"[sharp-compat] an input buffer is required\");\n }\n const encoded = toBuffer(input);\n return new JimpSharpInstance(async () => {\n const img = await Jimp.read(encoded);\n return jimpToBitmap(img);\n });\n };\n}\n\nfunction toBuffer(input: Buffer | Uint8Array): Buffer {\n return Buffer.isBuffer(input) ? input : Buffer.from(input);\n}\n\nfunction bitmapToJimp(bitmap: Bitmap): JimpImage {\n return Jimp.fromBitmap({\n data: bitmap.data,\n width: bitmap.width,\n height: bitmap.height,\n });\n}\n\nfunction jimpToBitmap(img: JimpImage): Bitmap {\n const { data, width, height } = img.bitmap;\n return { data: Buffer.from(data), width, height };\n}\n\n/** True when any pixel has a non-opaque alpha channel. */\nfunction hasAlphaPixels(bitmap: Bitmap): boolean {\n for (let i = 3; i < bitmap.data.length; i += 4) {\n if (bitmap.data[i] !== 255) return true;\n }\n return false;\n}\n\n/** Expand raw N-channel pixels to the RGBA bitmap jimp works in. */\nfunction rawToRgba(\n data: Buffer,\n width: number,\n height: number,\n channels: number,\n): Buffer {\n const pixels = width * height;\n const out = Buffer.allocUnsafe(pixels * 4);\n for (let p = 0; p < pixels; p++) {\n const src = p * channels;\n const dst = p * 4;\n if (channels >= 3) {\n out[dst] = data[src];\n out[dst + 1] = data[src + 1];\n out[dst + 2] = data[src + 2];\n out[dst + 3] = channels >= 4 ? data[src + 3] : 255;\n } else {\n // 1ch grayscale or 2ch gray+alpha.\n const gray = data[src];\n out[dst] = gray;\n out[dst + 1] = gray;\n out[dst + 2] = gray;\n out[dst + 3] = channels === 2 ? data[src + 1] : 255;\n }\n }\n return out;\n}\n\n/** Collapse the RGBA working bitmap to the requested raw channel count. */\nfunction toRawChannels(bitmap: Bitmap, channels: 3 | 4): Buffer {\n const pixels = bitmap.width * bitmap.height;\n if (channels === 4) {\n return Buffer.from(bitmap.data.subarray(0, pixels * 4));\n }\n const out = Buffer.allocUnsafe(pixels * 3);\n for (let p = 0; p < pixels; p++) {\n out[p * 3] = bitmap.data[p * 4];\n out[p * 3 + 1] = bitmap.data[p * 4 + 1];\n out[p * 3 + 2] = bitmap.data[p * 4 + 2];\n }\n return out;\n}\n\n// --- PNG encoder -----------------------------------------------------------\n//\n// Minimal, dependency-free PNG encoder (filter type 0, single IDAT) backed by\n// node's built-in zlib. Replaces jimp's PNG encoder, which produces corrupt\n// output under Node 24/25. Color type 6 (RGBA) by default, color type 2 (RGB)\n// when alpha was dropped.\n\nconst CRC_TABLE = (() => {\n const table = new Uint32Array(256);\n for (let n = 0; n < 256; n++) {\n let c = n;\n for (let k = 0; k < 8; k++) {\n c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;\n }\n table[n] = c >>> 0;\n }\n return table;\n})();\n\nfunction crc32(buf: Buffer): number {\n let crc = 0xffffffff;\n for (let i = 0; i < buf.length; i++) {\n crc = CRC_TABLE[(crc ^ buf[i]) & 0xff] ^ (crc >>> 8);\n }\n return (crc ^ 0xffffffff) >>> 0;\n}\n\nfunction pngChunk(type: string, data: Buffer): Buffer {\n const len = Buffer.allocUnsafe(4);\n len.writeUInt32BE(data.length, 0);\n const typeBuf = Buffer.from(type, \"ascii\");\n const crc = Buffer.allocUnsafe(4);\n crc.writeUInt32BE(crc32(Buffer.concat([typeBuf, data])), 0);\n return Buffer.concat([len, typeBuf, data, crc]);\n}\n\nfunction encodePng(bitmap: Bitmap, dropAlpha: boolean): Buffer {\n const { width, height, data } = bitmap;\n const channels = dropAlpha ? 3 : 4;\n const stride = width * channels;\n // One filter byte (type 0 = none) per scanline, then the row pixels.\n const rawWithFilters = Buffer.allocUnsafe((stride + 1) * height);\n for (let y = 0; y < height; y++) {\n const dstRow = y * (stride + 1);\n rawWithFilters[dstRow] = 0;\n if (dropAlpha) {\n const srcRow = y * width * 4;\n for (let x = 0; x < width; x++) {\n const s = srcRow + x * 4;\n const d = dstRow + 1 + x * 3;\n rawWithFilters[d] = data[s];\n rawWithFilters[d + 1] = data[s + 1];\n rawWithFilters[d + 2] = data[s + 2];\n }\n } else {\n const srcRow = y * stride;\n data.copy(rawWithFilters, dstRow + 1, srcRow, srcRow + stride);\n }\n }\n\n const ihdr = Buffer.allocUnsafe(13);\n ihdr.writeUInt32BE(width, 0);\n ihdr.writeUInt32BE(height, 4);\n ihdr[8] = 8; // bit depth\n ihdr[9] = dropAlpha ? 2 : 6; // color type: 2 = RGB, 6 = RGBA\n ihdr[10] = 0; // compression\n ihdr[11] = 0; // filter\n ihdr[12] = 0; // interlace\n\n const signature = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);\n return Buffer.concat([\n signature,\n pngChunk(\"IHDR\", ihdr),\n pngChunk(\"IDAT\", deflateSync(rawWithFilters)),\n pngChunk(\"IEND\", Buffer.alloc(0)),\n ]);\n}\n\n/** Copy a sub-rectangle out of an RGBA bitmap (sharp `extract` semantics). */\nfunction cropBitmap(bitmap: Bitmap, region: SharpExtractRegion): Bitmap {\n const { left, top, width, height } = region;\n const out = Buffer.allocUnsafe(width * height * 4);\n const srcStride = bitmap.width * 4;\n for (let y = 0; y < height; y++) {\n const srcRow = (top + y) * srcStride + left * 4;\n bitmap.data.copy(out, y * width * 4, srcRow, srcRow + width * 4);\n }\n return { data: out, width, height };\n}\n\n/** Pad a bitmap with a solid-color border (sharp `extend` semantics). */\nfunction padBitmap(\n bitmap: Bitmap,\n top: number,\n bottom: number,\n left: number,\n right: number,\n bg: SharpColor,\n): Bitmap {\n const newWidth = bitmap.width + left + right;\n const newHeight = bitmap.height + top + bottom;\n const out = Buffer.allocUnsafe(newWidth * newHeight * 4);\n const alpha = bg.alpha === undefined ? 255 : Math.round(bg.alpha * 255);\n for (let i = 0; i < out.length; i += 4) {\n out[i] = bg.r;\n out[i + 1] = bg.g;\n out[i + 2] = bg.b;\n out[i + 3] = alpha;\n }\n for (let y = 0; y < bitmap.height; y++) {\n const srcRow = y * bitmap.width * 4;\n const dstRow = ((y + top) * newWidth + left) * 4;\n bitmap.data.copy(out, dstRow, srcRow, srcRow + bitmap.width * 4);\n }\n return { data: out, width: newWidth, height: newHeight };\n}\n\n/**\n * Autocrop a uniform border (sharp `trim` default: trim pixels matching the\n * top-left corner color, full-tolerance equality).\n */\nfunction trimBitmap(bitmap: Bitmap): Bitmap {\n const { data, width, height } = bitmap;\n const sameAsCorner = (x: number, y: number): boolean => {\n const i = (y * width + x) * 4;\n return (\n data[i] === data[0] &&\n data[i + 1] === data[1] &&\n data[i + 2] === data[2] &&\n data[i + 3] === data[3]\n );\n };\n let top = 0;\n let bottom = height - 1;\n let left = 0;\n let right = width - 1;\n const rowUniform = (y: number): boolean => {\n for (let x = 0; x < width; x++) if (!sameAsCorner(x, y)) return false;\n return true;\n };\n const colUniform = (x: number): boolean => {\n for (let y = 0; y < height; y++) if (!sameAsCorner(x, y)) return false;\n return true;\n };\n while (top < bottom && rowUniform(top)) top++;\n while (bottom > top && rowUniform(bottom)) bottom--;\n while (left < right && colUniform(left)) left++;\n while (right > left && colUniform(right)) right--;\n\n const newWidth = right - left + 1;\n const newHeight = bottom - top + 1;\n if (newWidth === width && newHeight === height) return bitmap;\n const out = Buffer.allocUnsafe(newWidth * newHeight * 4);\n for (let y = 0; y < newHeight; y++) {\n const srcRow = ((y + top) * width + left) * 4;\n out.set(data.subarray(srcRow, srcRow + newWidth * 4), y * newWidth * 4);\n }\n return { data: out, width: newWidth, height: newHeight };\n}\n",
|
|
6
|
+
"import { getSharp, type SharpMetadata } from \"./image/sharp-compat\";\n\nexport const MAX_VISION_IMAGE_BYTES = 25 * 1024 * 1024;\n\nconst SUPPORTED_FORMATS = new Set([\"jpeg\", \"png\", \"webp\"]);\nconst MIME_BY_FORMAT: Record<string, string> = {\n jpeg: \"image/jpeg\",\n png: \"image/png\",\n webp: \"image/webp\",\n};\n\nexport interface ValidatedVisionImage {\n readonly width: number;\n readonly height: number;\n readonly format: \"jpeg\" | \"png\" | \"webp\";\n readonly contentType: \"image/jpeg\" | \"image/png\" | \"image/webp\";\n}\n\nexport function estimateBase64DecodedBytes(base64: string): number {\n const trimmed = base64.trim();\n if (!trimmed) return 0;\n const padding = trimmed.endsWith(\"==\") ? 2 : trimmed.endsWith(\"=\") ? 1 : 0;\n return Math.floor((trimmed.length * 3) / 4) - padding;\n}\n\nexport function parseVisionDataImageUrl(value: string): {\n mimeType: string;\n base64: string;\n} {\n if (typeof value !== \"string\" || value.length === 0) {\n throw new Error(\"Image URL must be a non-empty data URL\");\n }\n if (!value.startsWith(\"data:\")) {\n throw new Error(\"Only data image URLs are supported for vision input\");\n }\n const commaIndex = value.indexOf(\",\");\n if (commaIndex < 0) {\n throw new Error(\"Malformed data image URL\");\n }\n const header = value.slice(5, commaIndex);\n const payload = value.slice(commaIndex + 1);\n const parts = header.split(\";\").map((part) => part.toLowerCase());\n const mimeType = parts[0] ?? \"\";\n if (!SUPPORTED_FORMATS.has(mimeType.replace(/^image\\//, \"\"))) {\n throw new Error(`Unsupported image media type: ${mimeType || \"unknown\"}`);\n }\n if (!parts.includes(\"base64\")) {\n throw new Error(\"Vision data image URL must be base64 encoded\");\n }\n if (!/^[A-Za-z0-9+/]*={0,2}$/.test(payload)) {\n throw new Error(\"Malformed base64 image payload\");\n }\n if (estimateBase64DecodedBytes(payload) > MAX_VISION_IMAGE_BYTES) {\n throw new Error(\n `Image payload exceeds ${MAX_VISION_IMAGE_BYTES} byte limit`,\n );\n }\n return { mimeType, base64: payload };\n}\n\nexport async function assertValidVisionImageBuffer(\n data: Buffer,\n): Promise<ValidatedVisionImage> {\n if (!Buffer.isBuffer(data) || data.length === 0) {\n throw new Error(\"Image data must be a non-empty Buffer\");\n }\n if (data.length > MAX_VISION_IMAGE_BYTES) {\n throw new Error(`Image data exceeds ${MAX_VISION_IMAGE_BYTES} byte limit`);\n }\n\n let metadata: SharpMetadata;\n try {\n const sharp = await getSharp();\n metadata = await sharp(data, { limitInputPixels: 100_000_000 }).metadata();\n } catch (error) {\n throw new Error(\n `Malformed image input: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n\n const format = metadata.format;\n if (!format || !SUPPORTED_FORMATS.has(format)) {\n throw new Error(`Unsupported image media type: ${format || \"unknown\"}`);\n }\n if (!metadata.width || !metadata.height) {\n throw new Error(\n `Invalid image dimensions: ${metadata.width}x${metadata.height}`,\n );\n }\n\n return {\n width: metadata.width,\n height: metadata.height,\n format: format as ValidatedVisionImage[\"format\"],\n contentType: MIME_BY_FORMAT[format] as ValidatedVisionImage[\"contentType\"],\n };\n}\n\nexport async function assertSafeVisionDataImageUrl(\n imageUrl: string,\n): Promise<ValidatedVisionImage> {\n const { base64 } = parseVisionDataImageUrl(imageUrl);\n return assertValidVisionImageBuffer(Buffer.from(base64, \"base64\"));\n}\n",
|
|
7
|
+
"// doctr-ffi.ts — bun:ffi binding for the doctr.cpp shared library.\n//\n// The native library is built from `plugin-vision/native/doctr.cpp/` and emits\n// `libdoctr.<dylib|so|dll>`. The convention matches `plugin-local-inference`'s\n// llama.cpp binding (see that plugin's `src/native/` for the canonical pattern).\n//\n// Until the native lib has been built AND the GGUF weight files exist, every\n// public function here throws a clear error. There is no silent fallback.\n\nimport { promises as fs } from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { logger } from \"@elizaos/core\";\n\nconst MODULE_TAG = \"[doctr-ffi]\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\n/** Where the runtime expects to find the compiled native library. */\nfunction defaultLibraryPath(): string {\n const ext =\n process.platform === \"darwin\"\n ? \"dylib\"\n : process.platform === \"win32\"\n ? \"dll\"\n : \"so\";\n return (\n process.env.ELIZA_DOCTR_LIB ??\n path.join(\n __dirname,\n \"..\",\n \"..\",\n \"native\",\n \"doctr.cpp\",\n \"build\",\n `libdoctr.${ext}`,\n )\n );\n}\n\n/** Where the runtime expects GGUF weights. */\nexport function defaultDetWeightsPath(): string {\n const stateDir =\n process.env.ELIZA_STATE_DIR ?? path.join(os.homedir(), \".eliza\");\n return (\n process.env.ELIZA_DOCTR_DET_GGUF ??\n path.join(stateDir, \"models\", \"vision\", \"doctr-det.gguf\")\n );\n}\n\nexport function defaultRecWeightsPath(): string {\n const stateDir =\n process.env.ELIZA_STATE_DIR ?? path.join(os.homedir(), \".eliza\");\n return (\n process.env.ELIZA_DOCTR_REC_GGUF ??\n path.join(stateDir, \"models\", \"vision\", \"doctr-rec.gguf\")\n );\n}\n\n/**\n * Minimal structural type for the parts of `bun:ffi` we use. Lets the file\n * typecheck under plain Node tsc without requiring `bun-types` on every\n * downstream consumer.\n */\ninterface BunFFIModule {\n dlopen: (\n path: string,\n symbols: Record<string, { args: number[]; returns: number }>,\n ) => {\n symbols: Record<string, (...args: unknown[]) => unknown>;\n };\n FFIType: Record<\n \"cstring\" | \"pointer\" | \"i32\" | \"void\" | \"f32\" | \"u8\" | \"u32\",\n number\n >;\n ptr: (typedArray: ArrayBufferView) => unknown;\n CString: new (raw: unknown) => { toString(): string };\n}\n\ninterface DocTRBindings {\n /** Detection forward pass. Output: prob map at H/4 × W/4. */\n detect(\n detGGUFPath: string,\n rgbCHW: Float32Array,\n h: number,\n w: number,\n ): Promise<{ probMap: Float32Array; h: number; w: number }>;\n\n /** Recognition forward pass on a cropped line image. */\n recognize(\n recGGUFPath: string,\n rgbCHW: Float32Array,\n h: number,\n w: number,\n ): Promise<{ logits: Float32Array; T: number; C: number }>;\n\n /** Returns the recognition charset (utf-8, newline separated). */\n charset(recGGUFPath: string): Promise<string>;\n\n dispose(): Promise<void>;\n}\n\nlet bindingsPromise: Promise<DocTRBindings | null> | null = null;\n\n/**\n * Load the doctr.cpp shared library via `bun:ffi`. Returns null when either\n * the library or the GGUF weights are missing — the caller is expected to\n * throw a clear error in that case rather than silently fall back.\n */\nexport async function loadDoctrBindings(): Promise<DocTRBindings | null> {\n if (!bindingsPromise) {\n bindingsPromise = (async (): Promise<DocTRBindings | null> => {\n const libPath = defaultLibraryPath();\n try {\n await fs.access(libPath);\n } catch {\n logger.warn(`${MODULE_TAG} native library not found at ${libPath}`);\n return null;\n }\n\n // bun:ffi import is dynamic so the module is importable from non-bun\n // hosts (electrobun preload may run plain Node in some surfaces).\n // We avoid a static `import(\"bun:ffi\")` type reference here so plain\n // Node tsc doesn't need bun-types resolved — the runtime guard above\n // already gates the call site.\n let bunFFI: BunFFIModule | null = null;\n try {\n // eslint-disable-next-line @typescript-eslint/no-implied-eval\n const dynImport = new Function(\"spec\", \"return import(spec)\") as (\n s: string,\n ) => Promise<BunFFIModule>;\n bunFFI = await dynImport(\"bun:ffi\");\n } catch {\n logger.warn(\n `${MODULE_TAG} bun:ffi unavailable — doctr.cpp requires bun runtime.`,\n );\n return null;\n }\n\n const { dlopen, FFIType, ptr, CString } = bunFFI;\n\n // The native symbol table — names match `include/doctr.h`.\n // NOTE: until the C++ side is fully wired against ggml the symbols exist\n // but their `_run` functions return DOCTR_ERR_BACKEND. The TS adapter\n // converts that to a thrown Error so the OCR service falls through to\n // its next backend (apple-vision on darwin) or throws to the caller.\n let lib: ReturnType<BunFFIModule[\"dlopen\"]>;\n try {\n lib = dlopen(libPath, {\n doctr_det_init: { args: [FFIType.cstring], returns: FFIType.pointer },\n doctr_det_run: {\n args: [\n FFIType.pointer,\n FFIType.pointer,\n FFIType.i32,\n FFIType.i32,\n FFIType.pointer,\n FFIType.pointer,\n FFIType.pointer,\n ],\n returns: FFIType.i32,\n },\n doctr_det_free: { args: [FFIType.pointer], returns: FFIType.void },\n doctr_rec_init: { args: [FFIType.cstring], returns: FFIType.pointer },\n doctr_rec_run: {\n args: [\n FFIType.pointer,\n FFIType.pointer,\n FFIType.i32,\n FFIType.i32,\n FFIType.pointer,\n FFIType.pointer,\n FFIType.pointer,\n ],\n returns: FFIType.i32,\n },\n doctr_rec_charset: {\n args: [FFIType.pointer],\n returns: FFIType.cstring,\n },\n doctr_rec_free: { args: [FFIType.pointer], returns: FFIType.void },\n });\n } catch (error) {\n logger.warn(\n `${MODULE_TAG} dlopen failed for ${libPath}:`,\n error instanceof Error ? error.message : String(error),\n );\n return null;\n }\n\n const detCtxCache = new Map<string, unknown>();\n const recCtxCache = new Map<string, unknown>();\n\n async function ensureDetCtx(gguf: string): Promise<unknown> {\n const cached = detCtxCache.get(gguf);\n if (cached) return cached;\n const cstr = Buffer.from(gguf + \"\\0\", \"utf-8\");\n const handle = lib.symbols.doctr_det_init(ptr(cstr));\n if (!handle) {\n throw new Error(\n `doctr_det_init failed for ${gguf} — GGUF likely not present or invalid.`,\n );\n }\n detCtxCache.set(gguf, handle);\n return handle;\n }\n\n async function ensureRecCtx(gguf: string): Promise<unknown> {\n const cached = recCtxCache.get(gguf);\n if (cached) return cached;\n const cstr = Buffer.from(gguf + \"\\0\", \"utf-8\");\n const handle = lib.symbols.doctr_rec_init(ptr(cstr));\n if (!handle) {\n throw new Error(\n `doctr_rec_init failed for ${gguf} — GGUF likely not present or invalid.`,\n );\n }\n recCtxCache.set(gguf, handle);\n return handle;\n }\n\n const bindings: DocTRBindings = {\n async detect(gguf, rgbCHW, h, w) {\n const ctx = await ensureDetCtx(gguf);\n const outH = new Int32Array(1);\n const outW = new Int32Array(1);\n // Worst case (h/4 × w/4) buffer pre-allocation.\n const prob = new Float32Array((h / 4) * (w / 4));\n const rc = lib.symbols.doctr_det_run(\n ctx as never,\n ptr(rgbCHW) as never,\n h,\n w,\n ptr(prob) as never,\n ptr(outH) as never,\n ptr(outW) as never,\n );\n if (rc !== 0) {\n throw new Error(\n `doctr_det_run failed (code=${rc}) — ggml backend not yet wired or weights not built.`,\n );\n }\n return { probMap: prob, h: outH[0], w: outW[0] };\n },\n\n async recognize(gguf, rgbCHW, h, w) {\n const ctx = await ensureRecCtx(gguf);\n const outT = new Int32Array(1);\n const outC = new Int32Array(1);\n // Generous upper bound: max charset ~256 entries, T = w/8.\n const logits = new Float32Array(Math.ceil(w / 8) * 512);\n const rc = lib.symbols.doctr_rec_run(\n ctx as never,\n ptr(rgbCHW) as never,\n h,\n w,\n ptr(logits) as never,\n ptr(outT) as never,\n ptr(outC) as never,\n );\n if (rc !== 0) {\n throw new Error(\n `doctr_rec_run failed (code=${rc}) — ggml backend not yet wired or weights not built.`,\n );\n }\n return { logits, T: outT[0], C: outC[0] };\n },\n\n async charset(gguf) {\n const ctx = await ensureRecCtx(gguf);\n const ptrChars = lib.symbols.doctr_rec_charset(ctx as never);\n if (!ptrChars) return \"\";\n return new CString(ptrChars as never).toString();\n },\n\n async dispose() {\n for (const handle of detCtxCache.values()) {\n lib.symbols.doctr_det_free(handle as never);\n }\n for (const handle of recCtxCache.values()) {\n lib.symbols.doctr_rec_free(handle as never);\n }\n detCtxCache.clear();\n recCtxCache.clear();\n },\n };\n\n return bindings;\n })();\n }\n return bindingsPromise;\n}\n\n/**\n * `true` when both the native library and the GGUF weights exist on disk. Does\n * not actually initialize anything — callers should still expect the C++ side\n * to return DOCTR_ERR_BACKEND until the ggml graph is wired.\n */\nexport async function isDoctrReady(opts?: {\n detPath?: string;\n recPath?: string;\n}): Promise<{ ready: boolean; reason?: string }> {\n const detPath = opts?.detPath ?? defaultDetWeightsPath();\n const recPath = opts?.recPath ?? defaultRecWeightsPath();\n try {\n await fs.access(detPath);\n } catch {\n return { ready: false, reason: `detection GGUF missing: ${detPath}` };\n }\n try {\n await fs.access(recPath);\n } catch {\n return { ready: false, reason: `recognition GGUF missing: ${recPath}` };\n }\n const bindings = await loadDoctrBindings();\n if (!bindings) {\n return {\n ready: false,\n reason: `native library failed to load (expected at ${defaultLibraryPath()})`,\n };\n }\n return { ready: true };\n}\n",
|
|
8
|
+
"// doctr-based OCR backend — ggml runtime via `native/doctr.cpp/`.\n//\n// Replaces the previous PP-OCRv5 / onnxruntime-node path. Two-stage pipeline:\n// 1. Detection (db_mobilenet_v3_large + DBNet head) — produces a probability\n// map at H/4 × W/4.\n// 2. Contour → bbox post-processing (this file).\n// 3. Recognition (crnn_mobilenet_v3_small + CTC) — per-crop logits.\n// 4. CTC greedy decode (this file).\n//\n// The C++ side runs only the forward passes. Post-processing is pure TS to\n// keep the native surface minimal and to share the same decode logic with\n// native OCR providers that return logits. Apple Vision returns text directly so its\n// recognition path skips steps 2-4).\n//\n// **No fallback** — if doctr.cpp + GGUFs aren't available the service throws\n// a clear error and the chain in `ocr-service.ts` falls through to the next\n// backend (apple-vision on darwin) or surfaces the error to the caller.\n\nimport { logger } from \"@elizaos/core\";\nimport { getSharp } from \"./image/sharp-compat\";\nimport {\n defaultDetWeightsPath,\n defaultRecWeightsPath,\n isDoctrReady,\n loadDoctrBindings,\n} from \"./native/doctr-ffi\";\nimport type { BoundingBox, OCRResult } from \"./types\";\n\nexport interface DoctrOCRConfig {\n /** GGUF detection weights path. */\n detPath?: string;\n /** GGUF recognition weights path. */\n recPath?: string;\n /** Detection input resolution (square). Default 1024. */\n inputSize?: number;\n /** Probability threshold for the DBNet output. */\n probThreshold?: number;\n /** Minimum connected-component pixel count for a detection. */\n minComponentSize?: number;\n}\n\n/**\n * Detect platforms where Apple Vision is the better OCR choice.\n *\n * macOS Sonoma+ and iOS expose VNRecognizeTextRequest which is faster and\n * higher-quality than any community OCR for Latin scripts. The integration\n * lives in `plugin-computeruse/mobile`; we just refuse to claim availability\n * so the higher-priority Apple Vision backend wins on darwin.\n */\nexport function shouldPreferAppleVision(): boolean {\n return (\n process.platform === \"darwin\" &&\n process.env.ELIZA_DISABLE_APPLE_VISION !== \"1\"\n );\n}\n\nexport class DoctrOCRService {\n private readonly cfg: Required<\n Pick<DoctrOCRConfig, \"inputSize\" | \"probThreshold\" | \"minComponentSize\">\n > &\n DoctrOCRConfig;\n private initPromise: Promise<void> | null = null;\n private initialized = false;\n private charset: string[] = [];\n\n constructor(config: DoctrOCRConfig = {}) {\n this.cfg = {\n detPath: config.detPath ?? defaultDetWeightsPath(),\n recPath: config.recPath ?? defaultRecWeightsPath(),\n inputSize: config.inputSize ?? 1024,\n probThreshold: config.probThreshold ?? 0.3,\n minComponentSize: config.minComponentSize ?? 8,\n };\n }\n\n /**\n * Best-effort availability check. Confirms the native lib loads and the\n * GGUF files are on disk. Does NOT prove the ggml forward pass works —\n * that's discovered on the first `extractText` call.\n */\n static async isAvailable(opts?: {\n detPath?: string;\n recPath?: string;\n }): Promise<boolean> {\n const { ready } = await isDoctrReady(opts);\n return ready;\n }\n\n isInitialized(): boolean {\n return this.initialized;\n }\n\n async initialize(): Promise<void> {\n if (this.initialized) return;\n if (this.initPromise) return this.initPromise;\n this.initPromise = this._initialize();\n return this.initPromise;\n }\n\n private async _initialize(): Promise<void> {\n const { ready, reason } = await isDoctrReady({\n detPath: this.cfg.detPath,\n recPath: this.cfg.recPath,\n });\n if (!ready) {\n throw new Error(\n `[DoctrOCR] migration in progress; GGUF not ready (${reason ?? \"unknown\"}). ` +\n `Build the native lib at plugins/plugin-vision/native/doctr.cpp and run ` +\n `scripts/convert.py to produce doctr-det.gguf + doctr-rec.gguf.`,\n );\n }\n const bindings = await loadDoctrBindings();\n if (!bindings) {\n throw new Error(\n \"[DoctrOCR] native bindings failed to load after readiness check passed\",\n );\n }\n const charsetText = await bindings.charset(this.cfg.recPath!);\n this.charset = charsetText.split(/\\r?\\n/).filter(Boolean);\n this.initialized = true;\n logger.info(\n `[DoctrOCR] initialized (det=${this.cfg.detPath}, rec=${this.cfg.recPath}, charset=${this.charset.length})`,\n );\n }\n\n async extractText(imageBuffer: Buffer): Promise<OCRResult> {\n if (!this.initialized) await this.initialize();\n const bindings = await loadDoctrBindings();\n if (!bindings) {\n throw new Error(\"[DoctrOCR] native bindings unavailable at extract time\");\n }\n\n const sharp = await getSharp();\n const meta = await sharp(imageBuffer).metadata();\n const origW = meta.width ?? 0;\n const origH = meta.height ?? 0;\n if (!origW || !origH) {\n return { text: \"\", blocks: [], fullText: \"\" };\n }\n\n const inSize = this.cfg.inputSize;\n const { data: rgb } = await sharp(imageBuffer)\n .resize(inSize, inSize, { fit: \"fill\" })\n .removeAlpha()\n .raw()\n .toBuffer({ resolveWithObject: true });\n\n const detInput = this.toCHWFloat32(rgb, inSize, inSize);\n const {\n probMap,\n h: probH,\n w: probW,\n } = await bindings.detect(this.cfg.detPath!, detInput, inSize, inSize);\n\n const xScale = origW / inSize;\n const yScale = origH / inSize;\n const regions = this.probMapToBoxes(probMap, probW, probH, xScale, yScale);\n\n const blocks: OCRResult[\"blocks\"] = [];\n for (const region of regions) {\n const recText = await this.recognizeCrop(\n bindings,\n imageBuffer,\n region.bbox,\n );\n if (!recText) continue;\n blocks.push({\n text: recText,\n bbox: region.bbox,\n confidence: region.confidence,\n });\n }\n const fullText = blocks.map((b) => b.text).join(\"\\n\");\n return { text: fullText, blocks, fullText };\n }\n\n private toCHWFloat32(rgb: Buffer, w: number, h: number): Float32Array {\n const float = new Float32Array(3 * w * h);\n const stride = w * h;\n for (let i = 0; i < stride; i++) {\n float[i] = rgb[i * 3] / 255;\n float[i + stride] = rgb[i * 3 + 1] / 255;\n float[i + 2 * stride] = rgb[i * 3 + 2] / 255;\n }\n return float;\n }\n\n /**\n * DBNet contouring: scan the probability map, group above-threshold pixels\n * into connected components, return axis-aligned bboxes in original image\n * coordinates.\n *\n * This is the same algorithm as the previous PP-OCRv5 path — it's a\n * standard DBNet post-process and works for both detection backbones.\n */\n private probMapToBoxes(\n probMap: Float32Array,\n w: number,\n h: number,\n xScale: number,\n yScale: number,\n ): Array<{ bbox: BoundingBox; confidence: number }> {\n if (!h || !w) return [];\n const threshold = this.cfg.probThreshold;\n const minSize = this.cfg.minComponentSize;\n const visited = new Uint8Array(w * h);\n const boxes: Array<{ bbox: BoundingBox; confidence: number }> = [];\n\n for (let y = 0; y < h; y++) {\n for (let x = 0; x < w; x++) {\n const idx = y * w + x;\n if (visited[idx]) continue;\n if (probMap[idx] < threshold) continue;\n let minX = x;\n let maxX = x;\n let minY = y;\n let maxY = y;\n let probSum = 0;\n let count = 0;\n const stack: Array<[number, number]> = [[x, y]];\n while (stack.length) {\n const [cx, cy] = stack.pop()!;\n if (cx < 0 || cx >= w || cy < 0 || cy >= h) continue;\n const cidx = cy * w + cx;\n if (visited[cidx]) continue;\n const v = probMap[cidx];\n if (v < threshold) continue;\n visited[cidx] = 1;\n probSum += v;\n count++;\n if (cx < minX) minX = cx;\n if (cx > maxX) maxX = cx;\n if (cy < minY) minY = cy;\n if (cy > maxY) maxY = cy;\n stack.push([cx + 1, cy], [cx - 1, cy], [cx, cy + 1], [cx, cy - 1]);\n }\n if (count < minSize) continue;\n // DBNet unclip approximation: pad bbox before mapping back.\n const padX = Math.max(2, Math.round((maxX - minX) * 0.15));\n const padY = Math.max(2, Math.round((maxY - minY) * 0.25));\n const px = Math.max(0, minX - padX);\n const py = Math.max(0, minY - padY);\n const pxw = Math.min(w - 1, maxX + padX);\n const pyh = Math.min(h - 1, maxY + padY);\n // The probability map is at det-input resolution / 4. We mapped that\n // implicitly: probMap dims are already passed (H/4, W/4); we scale\n // through that into original-image coords via xScale*4 / yScale*4.\n const xs = xScale * 4;\n const ys = yScale * 4;\n boxes.push({\n bbox: {\n x: Math.round(px * xs),\n y: Math.round(py * ys),\n width: Math.round((pxw - px + 1) * xs),\n height: Math.round((pyh - py + 1) * ys),\n },\n confidence: probSum / count,\n });\n }\n }\n return boxes;\n }\n\n /**\n * Recognition step: crop the bbox, resize to 32xN, run through the CRNN\n * recognizer, CTC-decode the output.\n */\n private async recognizeCrop(\n bindings: Awaited<ReturnType<typeof loadDoctrBindings>>,\n imageBuffer: Buffer,\n bbox: BoundingBox,\n ): Promise<string> {\n if (!bindings) return \"\";\n if (bbox.width < 4 || bbox.height < 4) return \"\";\n const targetH = 32;\n const sharp = await getSharp();\n const cropMeta = await sharp(imageBuffer).metadata();\n if (!cropMeta.width || !cropMeta.height) return \"\";\n const safeW = Math.min(bbox.width, cropMeta.width - bbox.x);\n const safeH = Math.min(bbox.height, cropMeta.height - bbox.y);\n if (safeW <= 0 || safeH <= 0) return \"\";\n\n const aspect = safeW / safeH;\n const targetW = Math.max(16, Math.round((targetH * aspect) / 8) * 8);\n\n const { data: rgb } = await sharp(imageBuffer)\n .extract({\n left: Math.max(0, bbox.x),\n top: Math.max(0, bbox.y),\n width: safeW,\n height: safeH,\n })\n .resize(targetW, targetH, { fit: \"fill\" })\n .removeAlpha()\n .raw()\n .toBuffer({ resolveWithObject: true });\n\n const recInput = this.toCHWFloat32(rgb, targetW, targetH);\n const { logits, T, C } = await bindings.recognize(\n this.cfg.recPath!,\n recInput,\n targetH,\n targetW,\n );\n return this.ctcDecode(logits, T, C);\n }\n\n /** CTC greedy decoding. Blank index = 0. */\n private ctcDecode(logits: Float32Array, T: number, C: number): string {\n if (!T || !C) return \"\";\n const out: number[] = [];\n let prev = -1;\n for (let t = 0; t < T; t++) {\n let best = 0;\n let bestVal = logits[t * C];\n for (let c = 1; c < C; c++) {\n const v = logits[t * C + c];\n if (v > bestVal) {\n bestVal = v;\n best = c;\n }\n }\n if (best !== 0 && best !== prev) out.push(best - 1);\n prev = best;\n }\n return out\n .map((idx) => this.charset[idx] ?? \"\")\n .join(\"\")\n .replace(/\\s+/g, \" \")\n .trim();\n }\n\n async dispose(): Promise<void> {\n const bindings = await loadDoctrBindings();\n if (bindings) await bindings.dispose();\n this.initialized = false;\n this.initPromise = null;\n logger.info(\"[DoctrOCR] disposed\");\n }\n}\n",
|
|
9
|
+
"/**\n * macOS Apple Vision OCR provider (issue #9105 — per-OS native OCR fallback).\n *\n * Implements the structural `AppleVisionOcrProvider` seam from `ocr-service.ts`\n * by shelling out to a bundled Swift helper (`native/macos-vision-ocr.swift`)\n * that runs `VNRecognizeTextRequest` (accurate level, language correction on).\n * The helper reads PNG/JPEG bytes from stdin and prints a single JSON object;\n * this module pipes the bytes in and maps the result onto the provider shape.\n *\n * Zero LLM tokens, no model download — Apple Vision ships with macOS. This is\n * the darwin sibling of `WindowsMediaOcrService` (Windows.Media.Ocr) and the\n * iOS `createIosVisionOcrProvider` (Capacitor bridge): same VNRecognizeText\n * engine, reached without Capacitor on a desktop host.\n *\n * Coordinate convention: Vision returns normalized BOTTOM-LEFT bboxes; the\n * Swift helper converts them to TOP-LEFT PIXEL coordinates so the result\n * matches the display-absolute convention used by every other provider.\n *\n * Fails soft: `available()` is false off darwin or when `swift` is missing, and\n * `recognize()` returns an empty result rather than throwing on a helper\n * failure, so the `OCRService` chain falls through to the doCTR backend.\n */\n\nimport { execFile } from \"node:child_process\";\nimport { accessSync, constants, existsSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { logger } from \"@elizaos/core\";\nimport type { AppleVisionOcrProvider } from \"./ocr-service\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\n/** Single JSON line emitted by `native/macos-vision-ocr.swift`. */\ninterface MacosVisionRaw {\n lines: Array<{\n text: string;\n confidence: number;\n boundingBox: { x: number; y: number; width: number; height: number };\n }>;\n fullText: string;\n}\n\ninterface MacosVisionAvailabilityOptions {\n platform?: NodeJS.Platform;\n env?: NodeJS.ProcessEnv;\n pathExists?: (candidate: string) => boolean;\n executableExists?: (name: string, env: NodeJS.ProcessEnv) => boolean;\n}\n\n/**\n * Resolve the bundled Swift helper. Works from both the dev tree (`src/`) and\n * the published build (`dist/`) — the `native/` directory sits alongside both,\n * at the package root. `ELIZA_MACOS_VISION_OCR_SCRIPT` overrides for tests.\n */\nfunction resolveScriptPath(\n env: NodeJS.ProcessEnv = process.env,\n pathExists: (candidate: string) => boolean = existsSync,\n): string | null {\n const override = env.ELIZA_MACOS_VISION_OCR_SCRIPT;\n if (override) return pathExists(override) ? override : null;\n const candidates = [\n path.join(__dirname, \"..\", \"native\", \"macos-vision-ocr.swift\"),\n path.join(__dirname, \"..\", \"..\", \"native\", \"macos-vision-ocr.swift\"),\n ];\n return candidates.find((candidate) => pathExists(candidate)) ?? null;\n}\n\nfunction isExecutableFile(candidate: string): boolean {\n try {\n accessSync(candidate, constants.X_OK);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction hasExecutableOnPath(\n name: string,\n env: NodeJS.ProcessEnv = process.env,\n): boolean {\n const pathValue = env.PATH ?? \"\";\n return pathValue\n .split(path.delimiter)\n .filter((segment) => segment.length > 0)\n .some((segment) => isExecutableFile(path.join(segment, name)));\n}\n\n/** True when running on macOS with the `swift` toolchain and the helper present. */\nfunction macosVisionAvailable(\n options: MacosVisionAvailabilityOptions = {},\n): boolean {\n const platform = options.platform ?? process.platform;\n const env = options.env ?? process.env;\n if (platform !== \"darwin\") return false;\n if (env.ELIZA_DISABLE_APPLE_VISION === \"1\") return false;\n const scriptPath = resolveScriptPath(env, options.pathExists ?? existsSync);\n if (!scriptPath) return false;\n return (options.executableExists ?? hasExecutableOnPath)(\"swift\", env);\n}\n\nfunction runSwiftOcr(scriptPath: string, png: Uint8Array): Promise<string> {\n return new Promise((resolve, reject) => {\n const child = execFile(\n \"swift\",\n [scriptPath],\n { timeout: 20000, maxBuffer: 32 * 1024 * 1024 },\n (err, stdout, stderr) => {\n if (err) {\n reject(\n new Error(\n `macos-vision-ocr swift failed: ${stderr || err.message}`,\n ),\n );\n return;\n }\n resolve(stdout);\n },\n );\n child.stdin?.on(\"error\", () => {\n /* The helper may have already exited (e.g. empty stdin) — the execFile\n callback owns the real outcome; ignore the broken-pipe write error. */\n });\n child.stdin?.end(Buffer.from(png));\n });\n}\n\nconst EMPTY = { lines: [] as const, fullText: \"\" } as const;\n\n/**\n * Build an `AppleVisionOcrProvider` backed by macOS Apple Vision. Register it\n * via `registerAppleVisionOcrProvider(createMacosVisionOcrProvider())` on\n * darwin so the `OCRService` Apple-Vision backend resolves a real engine.\n */\nexport function createMacosVisionOcrProvider(): AppleVisionOcrProvider {\n return {\n name: \"macos-apple-vision\",\n available(): boolean {\n return macosVisionAvailable();\n },\n async recognize(input) {\n const scriptPath = resolveScriptPath();\n if (process.platform !== \"darwin\" || !scriptPath) {\n return EMPTY;\n }\n if (input.data.length === 0) return EMPTY;\n try {\n const stdout = await runSwiftOcr(scriptPath, input.data);\n const raw = JSON.parse(\n stdout.trim() || '{\"lines\":[],\"fullText\":\"\"}',\n ) as MacosVisionRaw;\n const lines = (raw.lines ?? []).map((line) => ({\n text: line.text,\n confidence: line.confidence,\n boundingBox: {\n x: line.boundingBox.x,\n y: line.boundingBox.y,\n width: line.boundingBox.width,\n height: line.boundingBox.height,\n },\n }));\n return { lines, fullText: raw.fullText ?? \"\" };\n } catch (err) {\n logger.warn(\n `[MacosVisionOcr] OCR failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n return EMPTY;\n }\n },\n };\n}\n\n/** Exposed for the runtime wire-up + tests; mirrors `macosVisionAvailable`. */\nexport function isMacosVisionOcrAvailable(): boolean {\n return macosVisionAvailable();\n}\n\nexport const __test__ = {\n macosVisionAvailable,\n resolveScriptPath,\n};\n",
|
|
10
|
+
"import { logger } from \"@elizaos/core\";\nimport { assertValidVisionImageBuffer } from \"./image-input\";\nimport { DoctrOCRService, shouldPreferAppleVision } from \"./ocr-service-doctr\";\nimport type { BoundingBox, OCRResult, ScreenTile } from \"./types\";\n\nexport type OCRBackendName = \"doctr\" | \"apple-vision\";\n\nexport interface OCRServiceConfig {\n /**\n * Force a specific backend. If unset, the chain is:\n * 1. Apple Vision (darwin only, when a provider has been registered)\n * 2. doCTR (ggml-backed CRNN+DBNet via native/doctr.cpp)\n *\n * There is no tesseract / onnx fallback — the migration removed both.\n * If neither backend can initialize, `initialize()` throws.\n */\n backend?: OCRBackendName;\n}\n\ninterface OCRBackend {\n name: OCRBackendName;\n initialize(): Promise<void>;\n extractText(buffer: Buffer): Promise<OCRResult>;\n dispose(): Promise<void>;\n}\n\nexport interface StructuredOCRData {\n tables: Array<{ rows: string[][]; bbox: BoundingBox }>;\n forms: Array<{ label: string; value: string; bbox: BoundingBox }>;\n lists: Array<{ items: string[]; bbox: BoundingBox }>;\n}\n\nfunction unionBbox(boxes: BoundingBox[]): BoundingBox {\n const minX = Math.min(...boxes.map((box) => box.x));\n const minY = Math.min(...boxes.map((box) => box.y));\n const maxX = Math.max(...boxes.map((box) => box.x + box.width));\n const maxY = Math.max(...boxes.map((box) => box.y + box.height));\n return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };\n}\n\nfunction parseTableRow(line: string): string[] | null {\n const trimmed = line.trim();\n const cells = trimmed.includes(\"|\")\n ? trimmed.split(\"|\")\n : trimmed.includes(\"\\t\")\n ? trimmed.split(\"\\t\")\n : trimmed.split(/\\s{2,}/u);\n const normalized = cells.map((cell) => cell.trim()).filter(Boolean);\n return normalized.length >= 2 ? normalized : null;\n}\n\nexport function extractStructuredDataFromOCR(\n ocr: OCRResult,\n): StructuredOCRData {\n const tables: StructuredOCRData[\"tables\"] = [];\n const forms: StructuredOCRData[\"forms\"] = [];\n const lists: StructuredOCRData[\"lists\"] = [];\n\n for (const block of ocr.blocks) {\n const lines = block.text\n .split(/\\r?\\n/u)\n .map((line) => line.trim())\n .filter(Boolean);\n const tableRows = lines\n .map(parseTableRow)\n .filter((row): row is string[] => Boolean(row));\n if (\n tableRows.length >= 2 &&\n new Set(tableRows.map((row) => row.length)).size === 1\n ) {\n tables.push({ rows: tableRows, bbox: block.bbox });\n }\n\n const listItems = lines\n .map((line) => line.match(/^(?:[-*•]|\\d+[.)])\\s+(.+)$/u)?.[1]?.trim())\n .filter((item): item is string => Boolean(item));\n if (listItems.length >= 2) {\n lists.push({ items: listItems, bbox: block.bbox });\n }\n\n for (const line of lines) {\n const match = line.match(/^([^:]{1,80}):\\s*(.+)$/u);\n if (match?.[1] && match[2]) {\n forms.push({\n label: match[1].trim(),\n value: match[2].trim(),\n bbox: block.bbox,\n });\n }\n }\n }\n\n const wordRows = ocr.blocks\n .flatMap((block) => block.words ?? [])\n .reduce<Map<number, Array<{ text: string; bbox: BoundingBox }>>>(\n (rows, word) => {\n const rowKey = Math.round(word.bbox.y / 12);\n const row = rows.get(rowKey) ?? [];\n row.push({ text: word.text, bbox: word.bbox });\n rows.set(rowKey, row);\n return rows;\n },\n new Map(),\n );\n\n const rowsFromWords = Array.from(wordRows.values())\n .map((row) => row.sort((a, b) => a.bbox.x - b.bbox.x))\n .filter((row) => row.length >= 2);\n if (rowsFromWords.length >= 2) {\n tables.push({\n rows: rowsFromWords.map((row) => row.map((word) => word.text)),\n bbox: unionBbox(\n rowsFromWords.flatMap((row) => row.map((word) => word.bbox)),\n ),\n });\n }\n\n return { tables, forms, lists };\n}\n\nclass DoctrBackend implements OCRBackend {\n readonly name: OCRBackendName = \"doctr\";\n private impl = new DoctrOCRService();\n initialize() {\n return this.impl.initialize();\n }\n extractText(buffer: Buffer) {\n return this.impl.extractText(buffer);\n }\n dispose() {\n return this.impl.dispose();\n }\n}\n\n/**\n * External provider seam for the Apple Vision OCR backend.\n *\n * `plugin-vision` does not take a runtime dep on `@elizaos/plugin-computeruse`\n * — that would invert the layering (computeruse is the higher-level seam).\n * Instead, the runtime registers a provider here on iOS/macOS startup using\n * `createIosVisionOcrProvider(...)` from\n * `@elizaos/plugin-computeruse/mobile/ocr-provider`. Until a provider is\n * registered, `AppleVisionBackend.extractText` throws so the chooser falls\n * through to the doCTR ggml backend.\n *\n * The provider shape is intentionally structural so plugin-vision stays\n * Node-importable on hosts that don't ship Capacitor.\n */\nexport interface AppleVisionOcrProvider {\n /** Stable id used in logs/telemetry. */\n readonly name: string;\n /** True when the underlying bridge is registered and ready. */\n available(): boolean;\n /**\n * Recognize text in the JPEG/PNG bytes. The plugin-computeruse iOS provider\n * returns `OcrResult`; we map to plugin-vision's `OCRResult` shape inline.\n */\n recognize(input: { kind: \"bytes\"; data: Uint8Array }): Promise<{\n readonly lines: ReadonlyArray<{\n readonly text: string;\n readonly confidence: number;\n readonly boundingBox: {\n readonly x: number;\n readonly y: number;\n readonly width: number;\n readonly height: number;\n };\n }>;\n readonly fullText: string;\n }>;\n}\n\nlet registeredAppleVisionProvider: AppleVisionOcrProvider | null = null;\n\nexport function registerAppleVisionOcrProvider(\n provider: AppleVisionOcrProvider | null,\n): void {\n registeredAppleVisionProvider = provider;\n logger.info(\n `[OCR] AppleVision provider ${provider ? \"registered\" : \"cleared\"}${\n provider?.name ? ` (${provider.name})` : \"\"\n }`,\n );\n}\n\nexport function getAppleVisionOcrProvider(): AppleVisionOcrProvider | null {\n return registeredAppleVisionProvider;\n}\n\n/**\n * On a plain macOS desktop (no Capacitor), register the native Apple Vision OCR\n * provider so the AppleVision backend has a bridge — the darwin sibling of the\n * iOS Capacitor bridge. Lazy-imported to avoid an import cycle, darwin-only,\n * idempotent (an already-registered provider — e.g. the iOS bridge — wins), and\n * fails soft when `swift` is absent so the chooser falls through to doCTR.\n */\nasync function ensureMacosVisionOcrProvider(): Promise<void> {\n if (process.platform !== \"darwin\") return;\n if (getAppleVisionOcrProvider()) return;\n try {\n const mod = await import(\"./ocr-service-apple-vision-macos.js\");\n if (!mod.isMacosVisionOcrAvailable()) return;\n registerAppleVisionOcrProvider(mod.createMacosVisionOcrProvider());\n } catch (error) {\n logger.warn(\n `[OCR] macOS Apple Vision provider unavailable: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n}\n\nclass AppleVisionBackend implements OCRBackend {\n readonly name: OCRBackendName = \"apple-vision\";\n async initialize(): Promise<void> {\n if (!registeredAppleVisionProvider) {\n throw new Error(\n \"Apple Vision OCR backend has no registered provider — call registerAppleVisionOcrProvider(createIosVisionOcrProvider(getBridge)) from the runtime.\",\n );\n }\n if (!registeredAppleVisionProvider.available()) {\n throw new Error(\n \"Apple Vision OCR provider reports unavailable (Capacitor ComputerUse bridge not yet registered).\",\n );\n }\n }\n async extractText(buffer: Buffer): Promise<OCRResult> {\n const provider = registeredAppleVisionProvider;\n if (!provider) {\n throw new Error(\n \"Apple Vision OCR backend has no registered provider at extract time\",\n );\n }\n const result = await provider.recognize({\n kind: \"bytes\",\n data: new Uint8Array(buffer),\n });\n const blocks = result.lines.map((line) => ({\n text: line.text,\n confidence: line.confidence,\n bbox: {\n x: line.boundingBox.x,\n y: line.boundingBox.y,\n width: line.boundingBox.width,\n height: line.boundingBox.height,\n } as BoundingBox,\n }));\n return {\n text: result.fullText,\n blocks,\n fullText: result.fullText,\n };\n }\n async dispose(): Promise<void> {\n /* Provider lifecycle is owned by the registrant, not this backend. */\n }\n}\n\n/**\n * Walk the priority chain and pick the first backend that initializes.\n * Backend instances are cached; per-call we just dispatch to the active one.\n */\nexport class OCRService {\n private backends: OCRBackend[] = [];\n private chosen: OCRBackend | null = null;\n private initialized = false;\n private readonly forced?: OCRBackendName;\n\n constructor(config: OCRServiceConfig = {}) {\n this.forced = config.backend;\n }\n\n async initialize(): Promise<void> {\n if (this.initialized) return;\n\n await ensureMacosVisionOcrProvider();\n\n logger.info(\"[OCR] initializing OCR service…\");\n\n const candidates: Array<() => Promise<OCRBackend | null>> = [];\n if (!this.forced || this.forced === \"apple-vision\") {\n candidates.push(async () =>\n shouldPreferAppleVision() ? new AppleVisionBackend() : null,\n );\n }\n if (!this.forced || this.forced === \"doctr\") {\n candidates.push(async () =>\n (await DoctrOCRService.isAvailable()) ? new DoctrBackend() : null,\n );\n }\n\n for (const factory of candidates) {\n const backend = await factory();\n if (!backend) continue;\n try {\n if (backend.name === \"doctr\") {\n // Defer GGUF load until first use so OCRService.initialize stays\n // cheap. DoctrBackend.initialize() is what triggers the FFI load.\n this.backends.push(backend);\n if (!this.chosen) this.chosen = backend;\n continue;\n }\n await backend.initialize();\n this.backends.push(backend);\n if (!this.chosen) this.chosen = backend;\n } catch (error) {\n logger.warn(\n `[OCR] backend ${backend.name} unavailable: ${error instanceof Error ? error.message : String(error)}`,\n );\n await backend.dispose().catch(() => {});\n }\n }\n\n if (!this.chosen) {\n throw new Error(\n \"No OCR backend available — doctr.cpp GGUFs not built and no Apple Vision provider registered.\",\n );\n }\n this.initialized = true;\n logger.info(`[OCR] active backend: ${this.chosen.name}`);\n }\n\n async extractText(imageBuffer: Buffer): Promise<OCRResult> {\n await assertValidVisionImageBuffer(imageBuffer);\n if (!this.initialized) await this.initialize();\n if (!this.chosen) throw new Error(\"OCR not initialized\");\n\n const ordered = [\n this.chosen,\n ...this.backends.filter((b) => b !== this.chosen),\n ];\n let lastError: unknown = null;\n for (const backend of ordered) {\n try {\n if (backend.name === \"doctr\" && backend instanceof DoctrBackend) {\n await backend.initialize();\n }\n return await backend.extractText(imageBuffer);\n } catch (error) {\n lastError = error;\n logger.warn(\n `[OCR] backend ${backend.name} failed:`,\n error instanceof Error ? error.message : String(error),\n );\n if (backend === this.chosen && ordered.length > 1) {\n this.chosen = ordered[1];\n logger.warn(`[OCR] demoted to backend: ${this.chosen.name}`);\n }\n }\n }\n throw new Error(\n `All OCR backends failed: ${lastError instanceof Error ? lastError.message : String(lastError)}`,\n );\n }\n\n async extractFromTile(tile: ScreenTile): Promise<OCRResult> {\n if (!tile.data) {\n return { text: \"\", blocks: [], fullText: \"\" };\n }\n return this.extractText(tile.data);\n }\n\n async extractFromImage(imageBuffer: Buffer): Promise<OCRResult> {\n return this.extractText(imageBuffer);\n }\n\n async extractStructuredData(imageBuffer: Buffer): Promise<StructuredOCRData> {\n const ocr = await this.extractText(imageBuffer);\n return extractStructuredDataFromOCR(ocr);\n }\n\n getActiveBackend(): OCRBackendName | null {\n return this.chosen?.name ?? null;\n }\n\n isInitialized(): boolean {\n return this.initialized;\n }\n\n async dispose(): Promise<void> {\n for (const backend of this.backends) {\n await backend.dispose().catch((error) => {\n logger.warn({ error }, `[OCR] dispose ${backend.name} failed:`);\n });\n }\n this.backends = [];\n this.chosen = null;\n this.initialized = false;\n logger.info(\"[OCR] service disposed\");\n }\n}\n",
|
|
11
|
+
"/**\n * OCR-with-coords — hierarchical (block / line / word) OCR with absolute\n * source-display coordinates and a coarse semantic position label per\n * recognized text element.\n *\n * Why this lives in plugin-vision:\n * - plugin-computeruse needs OCR with coordinates so action targets can be\n * computed in display-absolute coordinates without re-running detection.\n * - It cannot take a runtime dep on plugin-vision (which would invert the\n * layering: computeruse is the higher-level seam and plugin-vision must\n * stay Node-importable on hosts that don't ship the action surface).\n * - Mirroring the pattern used by `AppleVisionOcrProvider` in\n * `./ocr-service.ts`, plugin-vision exports a structural interface plus a\n * registry seam (`registerCoordOcrProvider` lives in\n * plugin-computeruse/src/mobile/ocr-provider.ts) that the runtime wires up\n * at boot.\n *\n * This file defines the canonical `OcrWithCoordsService` interface and the\n * in-tree `RapidOcrCoordAdapter` provider. The adapter is backed by the\n * existing `RapidOCRService` and computes `semantic_position`\n * deterministically from the bbox center against tile-relative thirds. Native\n * OCR providers can register the same interface without changing consumers.\n */\n\nimport { logger } from \"@elizaos/core\";\nimport { OCRService } from \"./ocr-service\";\nimport type { BoundingBox } from \"./types\";\n\n/** Coarse 3x3 location of a text element relative to the source tile. */\nexport type SemanticPosition =\n | \"upper-left\"\n | \"upper-center\"\n | \"upper-right\"\n | \"middle-left\"\n | \"center\"\n | \"middle-right\"\n | \"lower-left\"\n | \"lower-center\"\n | \"lower-right\";\n\nexport interface OcrWithCoordsWord {\n readonly text: string;\n /** Absolute source-display coordinates. */\n readonly bbox: BoundingBox;\n readonly semantic_position: SemanticPosition;\n}\n\nexport interface OcrWithCoordsBlock {\n readonly text: string;\n /** Absolute source-display coordinates. */\n readonly bbox: BoundingBox;\n readonly words: ReadonlyArray<OcrWithCoordsWord>;\n readonly semantic_position: SemanticPosition;\n}\n\nexport interface OcrWithCoordsResult {\n readonly blocks: ReadonlyArray<OcrWithCoordsBlock>;\n}\n\nexport interface OcrWithCoordsInput {\n /** Stable identifier of the source display. Echoed in logs only. */\n readonly displayId: string;\n /** Absolute X offset of the tile within the source display. */\n readonly sourceX: number;\n /** Absolute Y offset of the tile within the source display. */\n readonly sourceY: number;\n /** Encoded PNG bytes of the tile. */\n readonly pngBytes: Uint8Array;\n}\n\nexport interface OcrWithCoordsService {\n readonly name: string;\n describe(input: OcrWithCoordsInput): Promise<OcrWithCoordsResult>;\n}\n\n// ── Semantic position computation ───────────────────────────────────────────\n\nconst ROW_LABELS: ReadonlyArray<\"upper\" | \"middle\" | \"lower\"> = [\n \"upper\",\n \"middle\",\n \"lower\",\n];\nconst COL_LABELS: ReadonlyArray<\"left\" | \"center\" | \"right\"> = [\n \"left\",\n \"center\",\n \"right\",\n];\n\n/**\n * Map a bbox center to one of nine semantic positions using strict thirds\n * against the tile dimensions. Pure function — exported for tests so the\n * thirds rule has a single source of truth.\n *\n * Rule:\n * col = floor(centerX / (tileWidth / 3)) clamped to [0, 2]\n * row = floor(centerY / (tileHeight / 3)) clamped to [0, 2]\n * \"middle\" + \"center\" collapses to the literal \"center\".\n *\n * Inputs use tile-relative coordinates so the same function works for words\n * inside their parent block too (callers can pass the parent block bbox as\n * the tile dims for word-relative labeling, but for the canonical\n * implementation here we always label against the source tile).\n */\nexport function computeSemanticPosition(args: {\n readonly bbox: BoundingBox;\n readonly tileWidth: number;\n readonly tileHeight: number;\n}): SemanticPosition {\n const { bbox, tileWidth, tileHeight } = args;\n if (tileWidth <= 0 || tileHeight <= 0) {\n throw new Error(\n `computeSemanticPosition: tile dims must be positive (got ${tileWidth}x${tileHeight})`,\n );\n }\n const centerX = bbox.x + bbox.width / 2;\n const centerY = bbox.y + bbox.height / 2;\n const colIdx = clamp012(Math.floor((centerX * 3) / tileWidth));\n const rowIdx = clamp012(Math.floor((centerY * 3) / tileHeight));\n const row = ROW_LABELS[rowIdx];\n const col = COL_LABELS[colIdx];\n if (row === \"middle\" && col === \"center\") return \"center\";\n return `${row}-${col}` as SemanticPosition;\n}\n\nfunction clamp012(n: number): 0 | 1 | 2 {\n if (n <= 0) return 0;\n if (n >= 2) return 2;\n return 1;\n}\n\n// ── Registry seam ───────────────────────────────────────────────────────────\n\nlet registeredCoordOcrService: OcrWithCoordsService | null = null;\n\nexport function registerOcrWithCoordsService(\n service: OcrWithCoordsService | null,\n): void {\n registeredCoordOcrService = service;\n logger.info(\n `[OcrWithCoords] provider ${service ? \"registered\" : \"cleared\"}${\n service?.name ? ` (${service.name})` : \"\"\n }`,\n );\n}\n\nexport function getOcrWithCoordsService(): OcrWithCoordsService | null {\n return registeredCoordOcrService;\n}\n\n// ── RapidOCR-backed adapter ─────────────────────────────────────────────────\n\n/**\n * Wraps the existing `RapidOCRService` and maps its line-level output to the\n * hierarchical `OcrWithCoordsResult` shape, computing `semantic_position`\n * deterministically against the source tile thirds.\n */\nexport class RapidOcrCoordAdapter implements OcrWithCoordsService {\n readonly name = \"rapid-coord-adapter\";\n\n constructor(\n private readonly impl: Pick<OCRService, \"extractText\"> = new OCRService(),\n ) {}\n\n async describe(input: OcrWithCoordsInput): Promise<OcrWithCoordsResult> {\n if (input.pngBytes.byteLength === 0) {\n return { blocks: [] };\n }\n\n const buffer = Buffer.from(input.pngBytes);\n const tileDims = await readPngDimensions(input.pngBytes);\n const ocr = await this.impl.extractText(buffer);\n\n const blocks: OcrWithCoordsBlock[] = ocr.blocks.map((block) => {\n // Tile-relative bbox is what RapidOCR returns; semantic position is\n // computed against the tile, then bbox is shifted into source-display\n // absolute coords.\n const tileBbox: BoundingBox = {\n x: block.bbox.x,\n y: block.bbox.y,\n width: block.bbox.width,\n height: block.bbox.height,\n };\n const blockSemantic = computeSemanticPosition({\n bbox: tileBbox,\n tileWidth: tileDims.width,\n tileHeight: tileDims.height,\n });\n const absBlockBbox = shiftBbox(tileBbox, input.sourceX, input.sourceY);\n\n const wordsSrc = block.words ?? [];\n const words: OcrWithCoordsWord[] = wordsSrc.map((word) => {\n const wordTileBbox: BoundingBox = {\n x: word.bbox.x,\n y: word.bbox.y,\n width: word.bbox.width,\n height: word.bbox.height,\n };\n return {\n text: word.text,\n bbox: shiftBbox(wordTileBbox, input.sourceX, input.sourceY),\n semantic_position: computeSemanticPosition({\n bbox: wordTileBbox,\n tileWidth: tileDims.width,\n tileHeight: tileDims.height,\n }),\n };\n });\n\n return {\n text: block.text,\n bbox: absBlockBbox,\n words,\n semantic_position: blockSemantic,\n };\n });\n\n return { blocks };\n }\n}\n\nfunction shiftBbox(b: BoundingBox, dx: number, dy: number): BoundingBox {\n return { x: b.x + dx, y: b.y + dy, width: b.width, height: b.height };\n}\n\n/**\n * Read width/height from the PNG IHDR chunk without pulling in sharp on the\n * test path. PNG signature is 8 bytes; IHDR begins at offset 8 with a 4-byte\n * length, 4-byte type (\"IHDR\"), then 4-byte width and 4-byte height (BE).\n *\n * Throws on malformed input so a corrupt tile surfaces immediately rather\n * than silently producing zero-sized semantic-position math.\n */\nexport async function readPngDimensions(\n pngBytes: Uint8Array,\n): Promise<{ width: number; height: number }> {\n if (pngBytes.byteLength < 24) {\n throw new Error(\"readPngDimensions: input too short to be a PNG\");\n }\n const sig = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];\n for (let i = 0; i < sig.length; i += 1) {\n if (pngBytes[i] !== sig[i]) {\n throw new Error(\"readPngDimensions: missing PNG signature\");\n }\n }\n // IHDR type bytes at offset 12..16 must be \"IHDR\".\n if (\n pngBytes[12] !== 0x49 ||\n pngBytes[13] !== 0x48 ||\n pngBytes[14] !== 0x44 ||\n pngBytes[15] !== 0x52\n ) {\n throw new Error(\"readPngDimensions: first chunk is not IHDR\");\n }\n const view = new DataView(\n pngBytes.buffer,\n pngBytes.byteOffset,\n pngBytes.byteLength,\n );\n const width = view.getUint32(16, false);\n const height = view.getUint32(20, false);\n if (width <= 0 || height <= 0) {\n throw new Error(`readPngDimensions: invalid dimensions ${width}x${height}`);\n }\n return { width, height };\n}\n",
|
|
12
|
+
"// yolo-ffi.ts — bun:ffi binding for the yolo.cpp shared library.\n//\n// Mirrors `doctr-ffi.ts`. The native lib is built from\n// `plugin-vision/native/yolo.cpp/`. The TS layer owns letterboxing, decode,\n// and NMS — this binding is intentionally a thin pass-through to the C++\n// forward pass.\n\nimport { promises as fs } from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { logger } from \"@elizaos/core\";\n\nconst MODULE_TAG = \"[yolo-ffi]\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nfunction defaultLibraryPath(): string {\n const ext =\n process.platform === \"darwin\"\n ? \"dylib\"\n : process.platform === \"win32\"\n ? \"dll\"\n : \"so\";\n return (\n process.env.ELIZA_YOLO_LIB ??\n path.join(\n __dirname,\n \"..\",\n \"..\",\n \"native\",\n \"yolo.cpp\",\n \"build\",\n `libyolo.${ext}`,\n )\n );\n}\n\nexport function defaultYoloWeightsPath(): string {\n const stateDir =\n process.env.ELIZA_STATE_DIR ?? path.join(os.homedir(), \".eliza\");\n return (\n process.env.ELIZA_YOLO_GGUF ??\n path.join(stateDir, \"models\", \"vision\", \"yolov8n.gguf\")\n );\n}\n\ninterface YoloBindings {\n /** Run forward pass. Returns the raw (channels, anchors) logits tensor. */\n run(\n ggufPath: string,\n rgbCHW: Float32Array,\n h: number,\n w: number,\n ): Promise<{ logits: Float32Array; channels: number; anchors: number }>;\n\n /** Returns the embedded class names (newline-separated). */\n classes(ggufPath: string): Promise<string>;\n\n dispose(): Promise<void>;\n}\n\ninterface BunFFIModule {\n dlopen: (\n path: string,\n symbols: Record<string, { args: number[]; returns: number }>,\n ) => {\n symbols: Record<string, (...args: unknown[]) => unknown>;\n };\n FFIType: Record<\n \"cstring\" | \"pointer\" | \"i32\" | \"void\" | \"f32\" | \"u8\" | \"u32\",\n number\n >;\n ptr: (typedArray: ArrayBufferView) => unknown;\n CString: new (raw: unknown) => { toString(): string };\n}\n\nlet bindingsPromise: Promise<YoloBindings | null> | null = null;\n\nexport async function loadYoloBindings(): Promise<YoloBindings | null> {\n if (!bindingsPromise) {\n bindingsPromise = (async (): Promise<YoloBindings | null> => {\n const libPath = defaultLibraryPath();\n try {\n await fs.access(libPath);\n } catch {\n logger.warn(`${MODULE_TAG} native library not found at ${libPath}`);\n return null;\n }\n\n let bunFFI: BunFFIModule | null = null;\n try {\n const dynImport = new Function(\"spec\", \"return import(spec)\") as (\n s: string,\n ) => Promise<BunFFIModule>;\n bunFFI = await dynImport(\"bun:ffi\");\n } catch {\n logger.warn(\n `${MODULE_TAG} bun:ffi unavailable — yolo.cpp requires bun runtime.`,\n );\n return null;\n }\n\n const { dlopen, FFIType, ptr, CString } = bunFFI;\n\n let lib: ReturnType<BunFFIModule[\"dlopen\"]>;\n try {\n lib = dlopen(libPath, {\n yolo_init: { args: [FFIType.cstring], returns: FFIType.pointer },\n yolo_run: {\n args: [\n FFIType.pointer,\n FFIType.pointer,\n FFIType.i32,\n FFIType.i32,\n FFIType.pointer,\n FFIType.pointer,\n FFIType.pointer,\n ],\n returns: FFIType.i32,\n },\n yolo_classes: { args: [FFIType.pointer], returns: FFIType.pointer },\n yolo_free: { args: [FFIType.pointer], returns: FFIType.void },\n });\n } catch (error) {\n logger.warn(\n `${MODULE_TAG} dlopen failed for ${libPath}:`,\n error instanceof Error ? error.message : String(error),\n );\n return null;\n }\n\n const ctxCache = new Map<string, unknown>();\n\n async function ensureCtx(gguf: string): Promise<unknown> {\n const cached = ctxCache.get(gguf);\n if (cached) return cached;\n const cstr = Buffer.from(gguf + \"\\0\", \"utf-8\");\n const handle = lib.symbols.yolo_init(ptr(cstr));\n if (!handle) {\n throw new Error(\n `yolo_init failed for ${gguf} — GGUF not present or invalid.`,\n );\n }\n ctxCache.set(gguf, handle);\n return handle;\n }\n\n return {\n async run(gguf, rgbCHW, h, w) {\n const ctx = await ensureCtx(gguf);\n const outChan = new Int32Array(1);\n const outAnch = new Int32Array(1);\n // Upper bound for YOLOv8: 84 channels * 8400 anchors = 705600 floats.\n const logits = new Float32Array(84 * 8400);\n const rc = lib.symbols.yolo_run(\n ctx as never,\n ptr(rgbCHW) as never,\n h,\n w,\n ptr(logits) as never,\n ptr(outChan) as never,\n ptr(outAnch) as never,\n );\n if (rc !== 0) {\n throw new Error(\n `yolo_run failed (code=${rc}) — ggml backend not yet wired or weights not built.`,\n );\n }\n return {\n logits,\n channels: outChan[0],\n anchors: outAnch[0],\n };\n },\n\n async classes(gguf) {\n try {\n const ctx = await ensureCtx(gguf);\n const ptrChars = lib.symbols.yolo_classes(ctx as never);\n if (!ptrChars) return \"\";\n // returns: FFIType.pointer → ptrChars is a numeric char* address;\n // CString reads the NUL-terminated UTF-8 from it. (A cstring return\n // type would hand back a CString that must NOT be re-wrapped.)\n return new CString(ptrChars as never).toString();\n } catch {\n // Non-fatal: the detector falls back to the hardcoded COCO list.\n return \"\";\n }\n },\n\n async dispose() {\n for (const handle of ctxCache.values()) {\n lib.symbols.yolo_free(handle as never);\n }\n ctxCache.clear();\n },\n };\n })();\n }\n return bindingsPromise;\n}\n\nexport async function isYoloReady(opts?: {\n weightsPath?: string;\n}): Promise<{ ready: boolean; reason?: string }> {\n const weightsPath = opts?.weightsPath ?? defaultYoloWeightsPath();\n try {\n await fs.access(weightsPath);\n } catch {\n return { ready: false, reason: `YOLO GGUF missing: ${weightsPath}` };\n }\n const bindings = await loadYoloBindings();\n if (!bindings) {\n return {\n ready: false,\n reason: `native library failed to load (expected at ${defaultLibraryPath()})`,\n };\n }\n return { ready: true };\n}\n",
|
|
13
|
+
"// YOLO object detector — ggml runtime via `native/yolo.cpp/`.\n//\n// Replaces COCO-SSD (TensorFlow.js) and the prior onnxruntime-node YOLO\n// path. Default model is YOLOv8n COCO (80 classes). Weights are NOT bundled\n// in the npm package — they're fetched / built into a per-user state dir\n// (`<state-dir>/models/vision/yolov8n.gguf`).\n//\n// Pipeline:\n// 1. Letterbox + RGB CHW normalize to 640x640 (this file).\n// 2. Forward pass (yolo.cpp via bun:ffi).\n// 3. parseYoloV8 — decode (cx, cy, w, h, scores) per anchor.\n// 4. NMS.\n//\n// **No fallback.** If the native lib or GGUF is missing, init throws.\n\nimport { logger } from \"@elizaos/core\";\nimport { getSharp } from \"./image/sharp-compat\";\nimport {\n defaultYoloWeightsPath,\n isYoloReady,\n loadYoloBindings,\n} from \"./native/yolo-ffi\";\nimport type { DetectedObject } from \"./types\";\n\nconst COCO_CLASSES = [\n \"person\",\n \"bicycle\",\n \"car\",\n \"motorcycle\",\n \"airplane\",\n \"bus\",\n \"train\",\n \"truck\",\n \"boat\",\n \"traffic light\",\n \"fire hydrant\",\n \"stop sign\",\n \"parking meter\",\n \"bench\",\n \"bird\",\n \"cat\",\n \"dog\",\n \"horse\",\n \"sheep\",\n \"cow\",\n \"elephant\",\n \"bear\",\n \"zebra\",\n \"giraffe\",\n \"backpack\",\n \"umbrella\",\n \"handbag\",\n \"tie\",\n \"suitcase\",\n \"frisbee\",\n \"skis\",\n \"snowboard\",\n \"sports ball\",\n \"kite\",\n \"baseball bat\",\n \"baseball glove\",\n \"skateboard\",\n \"surfboard\",\n \"tennis racket\",\n \"bottle\",\n \"wine glass\",\n \"cup\",\n \"fork\",\n \"knife\",\n \"spoon\",\n \"bowl\",\n \"banana\",\n \"apple\",\n \"sandwich\",\n \"orange\",\n \"broccoli\",\n \"carrot\",\n \"hot dog\",\n \"pizza\",\n \"donut\",\n \"cake\",\n \"chair\",\n \"couch\",\n \"potted plant\",\n \"bed\",\n \"dining table\",\n \"toilet\",\n \"tv\",\n \"laptop\",\n \"mouse\",\n \"remote\",\n \"keyboard\",\n \"cell phone\",\n \"microwave\",\n \"oven\",\n \"toaster\",\n \"sink\",\n \"refrigerator\",\n \"book\",\n \"clock\",\n \"vase\",\n \"scissors\",\n \"teddy bear\",\n \"hair drier\",\n \"toothbrush\",\n];\n\nexport interface YOLOConfig {\n /** GGUF weights path. Defaults to `<state-dir>/models/vision/yolov8n.gguf`. */\n weightsPath?: string;\n /** Class names override; defaults to COCO 80 or whatever's embedded in the GGUF. */\n classes?: string[];\n /** Score threshold for emitted detections. */\n scoreThreshold?: number;\n /** Non-max suppression IoU threshold. */\n nmsIouThreshold?: number;\n /** Restrict output to these COCO class names (case-insensitive). */\n classFilter?: string[];\n}\n\ninterface Detection {\n classId: number;\n className: string;\n score: number;\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport class YOLODetector {\n private readonly cfg: Required<\n Pick<YOLOConfig, \"scoreThreshold\" | \"nmsIouThreshold\" | \"weightsPath\">\n > &\n YOLOConfig;\n private initPromise: Promise<void> | null = null;\n private initialized = false;\n private classes: string[];\n private readonly classFilterLower: Set<string> | null;\n\n constructor(config: YOLOConfig = {}) {\n this.cfg = {\n weightsPath: config.weightsPath ?? defaultYoloWeightsPath(),\n scoreThreshold: config.scoreThreshold ?? 0.35,\n nmsIouThreshold: config.nmsIouThreshold ?? 0.5,\n ...config,\n };\n this.classes = config.classes ?? COCO_CLASSES;\n this.classFilterLower = config.classFilter\n ? new Set(config.classFilter.map((c) => c.toLowerCase()))\n : null;\n }\n\n static async isAvailable(opts?: { weightsPath?: string }): Promise<boolean> {\n const { ready } = await isYoloReady(opts);\n return ready;\n }\n\n isInitialized(): boolean {\n return this.initialized;\n }\n\n async initialize(): Promise<void> {\n if (this.initialized) return;\n if (this.initPromise) return this.initPromise;\n this.initPromise = this._initialize();\n return this.initPromise;\n }\n\n private async _initialize(): Promise<void> {\n const { ready, reason } = await isYoloReady({\n weightsPath: this.cfg.weightsPath,\n });\n if (!ready) {\n throw new Error(\n `[YOLO] migration in progress; GGUF not ready (${reason ?? \"unknown\"}). ` +\n `Build the native lib at plugins/plugin-vision/native/yolo.cpp and run ` +\n `scripts/convert.py to produce yolov8n.gguf.`,\n );\n }\n const bindings = await loadYoloBindings();\n if (!bindings) {\n throw new Error(\n \"[YOLO] native bindings failed to load after readiness check passed\",\n );\n }\n // Prefer the GGUF-embedded class names when available. Fall back to the\n // hardcoded COCO list if the binding returns an empty string.\n const embedded = await bindings.classes(this.cfg.weightsPath);\n if (embedded && embedded.trim().length > 0) {\n this.classes = embedded.split(/\\r?\\n/).filter(Boolean);\n }\n this.initialized = true;\n logger.info(\n `[YOLO] initialized (weights=${this.cfg.weightsPath}, classes=${this.classes.length})`,\n );\n }\n\n async detect(imageBuffer: Buffer): Promise<DetectedObject[]> {\n if (!this.initialized) await this.initialize();\n const bindings = await loadYoloBindings();\n if (!bindings) {\n throw new Error(\"[YOLO] native bindings unavailable at detect time\");\n }\n\n const sharp = await getSharp();\n const meta = await sharp(imageBuffer).metadata();\n const origW = meta.width ?? 0;\n const origH = meta.height ?? 0;\n if (!origW || !origH) return [];\n\n // YOLOv8 expects 640x640 letterboxed RGB input, /255 normalization.\n const inSize = 640;\n const scale = Math.min(inSize / origW, inSize / origH);\n const padW = Math.round((inSize - origW * scale) / 2);\n const padH = Math.round((inSize - origH * scale) / 2);\n\n const { data: rgb } = await sharp(imageBuffer)\n .resize(Math.round(origW * scale), Math.round(origH * scale), {\n fit: \"fill\",\n })\n .extend({\n top: padH,\n bottom: inSize - Math.round(origH * scale) - padH,\n left: padW,\n right: inSize - Math.round(origW * scale) - padW,\n background: { r: 114, g: 114, b: 114, alpha: 1 },\n })\n .removeAlpha()\n .raw()\n .toBuffer({ resolveWithObject: true });\n\n const float = new Float32Array(3 * inSize * inSize);\n for (let i = 0; i < inSize * inSize; i++) {\n float[i] = rgb[i * 3] / 255;\n float[i + inSize * inSize] = rgb[i * 3 + 1] / 255;\n float[i + 2 * inSize * inSize] = rgb[i * 3 + 2] / 255;\n }\n\n const { logits, channels, anchors } = await bindings.run(\n this.cfg.weightsPath,\n float,\n inSize,\n inSize,\n );\n\n const detections = this.parseYoloV8(\n logits,\n channels,\n anchors,\n scale,\n padW,\n padH,\n );\n\n const filtered = this.classFilterLower\n ? detections.filter((d) =>\n this.classFilterLower!.has(d.className.toLowerCase()),\n )\n : detections;\n\n return filtered.map((d, idx) => ({\n id: `yolo-${Date.now()}-${idx}`,\n type: d.className,\n confidence: d.score,\n boundingBox: { x: d.x, y: d.y, width: d.width, height: d.height },\n }));\n }\n\n /**\n * YOLOv8 raw output: (channels, anchors) where channels = 4 bbox + N classes.\n * Decode each anchor: bbox = (cx, cy, w, h); score = best class prob.\n */\n private parseYoloV8(\n logits: Float32Array,\n channels: number,\n anchors: number,\n scale: number,\n padW: number,\n padH: number,\n ): Detection[] {\n if (channels <= 4 || anchors <= 0) return [];\n const classCount = channels - 4;\n const dets: Detection[] = [];\n\n for (let a = 0; a < anchors; a++) {\n const cx = logits[0 * anchors + a];\n const cy = logits[1 * anchors + a];\n const w = logits[2 * anchors + a];\n const h = logits[3 * anchors + a];\n\n let bestClass = -1;\n let bestScore = 0;\n for (let c = 0; c < classCount; c++) {\n const v = logits[(4 + c) * anchors + a];\n if (v > bestScore) {\n bestScore = v;\n bestClass = c;\n }\n }\n if (bestScore < this.cfg.scoreThreshold || bestClass < 0) continue;\n const className = this.classes[bestClass] ?? `class_${bestClass}`;\n\n const x1 = (cx - w / 2 - padW) / scale;\n const y1 = (cy - h / 2 - padH) / scale;\n dets.push({\n classId: bestClass,\n className,\n score: bestScore,\n x: x1,\n y: y1,\n width: w / scale,\n height: h / scale,\n });\n }\n return this.nms(dets);\n }\n\n private nms(detections: Detection[]): Detection[] {\n const sorted = [...detections].sort((a, b) => b.score - a.score);\n const kept: Detection[] = [];\n while (sorted.length) {\n const top = sorted.shift()!;\n kept.push(top);\n for (let i = sorted.length - 1; i >= 0; i--) {\n if (this.iou(top, sorted[i]) > this.cfg.nmsIouThreshold)\n sorted.splice(i, 1);\n }\n }\n return kept;\n }\n\n private iou(a: Detection, b: Detection): number {\n const x1 = Math.max(a.x, b.x);\n const y1 = Math.max(a.y, b.y);\n const x2 = Math.min(a.x + a.width, b.x + b.width);\n const y2 = Math.min(a.y + a.height, b.y + b.height);\n if (x2 <= x1 || y2 <= y1) return 0;\n const inter = (x2 - x1) * (y2 - y1);\n const union = a.width * a.height + b.width * b.height - inter;\n return inter / union;\n }\n\n async dispose(): Promise<void> {\n const bindings = await loadYoloBindings();\n if (bindings) await bindings.dispose();\n this.initialized = false;\n this.initPromise = null;\n logger.info(\"[YOLO] disposed\");\n }\n}\n",
|
|
14
|
+
"// face-detector-ggml.ts — ggml-backed BlazeFace binding.\n//\n// bun:ffi binding for the BlazeFace head exposed by the standalone\n// `packages/native/plugins/face-cpp/` library. This is the ggml-backed\n// replacement for the removed ONNX detector surface. It\n// exposes the same surface (`MediaPipeFaceConfig`, `MediaPipeFaceDetection`,\n// `BlazeFaceGgmlDetector` modeled on `MediaPipeFaceDetector`) so existing\n// callers can opt into the native backend without touching call sites.\n//\n// The C ABI is frozen but some native builds return `-ENOSYS` from\n// `face_detect_open` / `face_detect`. `BlazeFaceGgmlDetector.isAvailable()`\n// returns false until both the compiled `libface.<so|dylib|dll>` and the\n// BlazeFace GGUF artifact exist.\n// Until those land, every public method falls through to a clear error —\n// there is no silent fallback to a different backend.\n//\n// See `packages/native/plugins/face-cpp/AGENTS.md` for the port plan.\n\nimport { promises as fs } from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { logger } from \"@elizaos/core\";\nimport { getSharp } from \"./image/sharp-compat\";\nimport type { BoundingBox } from \"./types\";\n\nconst MODULE_TAG = \"[BlazeFaceGgml]\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\n/**\n * Same shape the removed ONNX detector exported. Kept identical so callers can\n * select the native backend without reshaping results.\n */\nexport interface MediaPipeFaceConfig {\n modelUrl?: string;\n modelSha256?: string | null;\n modelDir?: string;\n scoreThreshold?: number;\n trusted?: boolean;\n}\n\nexport interface MediaPipeFaceDetection {\n bbox: BoundingBox;\n confidence: number;\n /**\n * BlazeFace's 6 keypoints in canonical order:\n * 0: left eye 1: right eye 2: nose tip\n * 3: mouth 4: left ear 5: right ear\n * Coordinates are in source-image absolute pixels.\n */\n keypoints?: Array<{ x: number; y: number }>;\n}\n\nconst FACE_DETECTOR_INPUT_SIZE = 128;\nconst FACE_DETECTOR_KEYPOINT_COUNT = 6;\nconst FACE_DETECTION_FLOATS = 5 + FACE_DETECTOR_KEYPOINT_COUNT * 2; // x,y,w,h,conf + 12\n\nfunction defaultLibraryPath(): string {\n const ext =\n process.platform === \"darwin\"\n ? \"dylib\"\n : process.platform === \"win32\"\n ? \"dll\"\n : \"so\";\n return (\n process.env.ELIZA_FACE_CPP_LIB ??\n path.join(\n __dirname,\n \"..\",\n \"..\",\n \"..\",\n \"packages\",\n \"native-plugins\",\n \"face-cpp\",\n \"build\",\n `libface.${ext}`,\n )\n );\n}\n\nfunction defaultModelDir(): string {\n const stateDir =\n process.env.ELIZA_STATE_DIR ?? path.join(os.homedir(), \".eliza\");\n return path.join(stateDir, \"models\", \"face-cpp\");\n}\n\nfunction defaultDetWeightsPath(): string {\n return (\n process.env.ELIZA_FACE_CPP_DET_GGUF ??\n path.join(defaultModelDir(), \"blazeface.gguf\")\n );\n}\n\n/**\n * Minimal structural type for the bun:ffi pieces we need. Same trick as\n * `doctr-ffi.ts` — keeps this file typecheckable under plain Node tsc\n * without `bun-types` resolved on every downstream consumer.\n */\ninterface BunFFIModule {\n dlopen: (\n p: string,\n symbols: Record<string, { args: number[]; returns: number }>,\n ) => {\n symbols: Record<string, (...args: unknown[]) => unknown>;\n };\n FFIType: Record<\n \"cstring\" | \"pointer\" | \"i32\" | \"void\" | \"f32\" | \"u8\" | \"u32\",\n number\n >;\n ptr: (typedArray: ArrayBufferView) => unknown;\n CString: new (raw: unknown) => { toString(): string };\n}\n\ninterface FaceDetectBindings {\n open(ggufPath: string): unknown;\n detect(\n handle: unknown,\n rgb: Buffer,\n w: number,\n h: number,\n stride: number,\n conf: number,\n cap: number,\n ): { detections: Float32Array; count: number };\n close(handle: unknown): void;\n activeBackend(): string;\n}\n\nlet bindingsPromise: Promise<FaceDetectBindings | null> | null = null;\n\nasync function loadBindings(): Promise<FaceDetectBindings | null> {\n if (bindingsPromise) return bindingsPromise;\n bindingsPromise = (async (): Promise<FaceDetectBindings | null> => {\n const libPath = defaultLibraryPath();\n try {\n await fs.access(libPath);\n } catch {\n logger.warn(`${MODULE_TAG} native library not found at ${libPath}`);\n return null;\n }\n\n let bunFFI: BunFFIModule | null = null;\n try {\n const dynImport = new Function(\"spec\", \"return import(spec)\") as (\n s: string,\n ) => Promise<BunFFIModule>;\n bunFFI = await dynImport(\"bun:ffi\");\n } catch {\n logger.warn(\n `${MODULE_TAG} bun:ffi unavailable — face-cpp requires bun runtime.`,\n );\n return null;\n }\n\n const { dlopen, FFIType, ptr } = bunFFI;\n\n let lib: ReturnType<typeof dlopen>;\n try {\n lib = dlopen(libPath, {\n face_detect_open: {\n args: [FFIType.cstring, FFIType.pointer],\n returns: FFIType.i32,\n },\n face_detect: {\n args: [\n FFIType.pointer,\n FFIType.pointer,\n FFIType.i32,\n FFIType.i32,\n FFIType.i32,\n FFIType.f32,\n FFIType.pointer,\n FFIType.u32,\n FFIType.pointer,\n ],\n returns: FFIType.i32,\n },\n face_detect_close: {\n args: [FFIType.pointer],\n returns: FFIType.i32,\n },\n face_active_backend: {\n args: [],\n returns: FFIType.cstring,\n },\n });\n } catch (error) {\n logger.warn(\n `${MODULE_TAG} dlopen failed for ${libPath}:`,\n error instanceof Error ? error.message : String(error),\n );\n return null;\n }\n\n const bindings: FaceDetectBindings = {\n open(ggufPath) {\n const cstr = Buffer.from(`${ggufPath}\\0`, \"utf-8\");\n const handleSlot = new BigUint64Array(1);\n const rc = lib.symbols.face_detect_open(\n ptr(cstr) as never,\n ptr(handleSlot) as never,\n ) as number;\n if (rc !== 0) {\n throw new Error(\n `face_detect_open failed (rc=${rc}) — GGUF likely missing or invalid.`,\n );\n }\n const handle = handleSlot[0];\n if (handle === 0n) {\n throw new Error(`face_detect_open returned NULL handle`);\n }\n // bun:ffi pointer-typed args expect a Number, not a BigInt.\n return Number(handle);\n },\n detect(handle, rgb, w, h, stride, conf, cap) {\n // face_detection layout: 5 + 12 floats = 17 floats per record. We\n // round to 18 to keep the buffer 8-byte aligned per slot in case\n // the C struct grows padding on some ABIs; only the first 17\n // floats are read.\n const SLOT = FACE_DETECTION_FLOATS;\n const dets = new Float32Array(cap * SLOT);\n const countSlot = new BigUint64Array(1);\n const rc = lib.symbols.face_detect(\n handle as never,\n ptr(rgb) as never,\n w,\n h,\n stride,\n conf,\n ptr(dets) as never,\n cap,\n ptr(countSlot) as never,\n ) as number;\n if (rc !== 0 && rc !== -28 /* -ENOSPC */) {\n throw new Error(`face_detect failed (rc=${rc}).`);\n }\n return { detections: dets, count: Number(countSlot[0]) };\n },\n close(handle) {\n lib.symbols.face_detect_close(handle as never);\n },\n activeBackend() {\n const raw = lib.symbols.face_active_backend();\n if (raw == null) return \"unknown\";\n // bun:ffi cstring returns stringify cleanly via String(); the\n // CString constructor expects a numeric pointer and throws on\n // an already-decoded value.\n return String(raw);\n },\n };\n return bindings;\n })();\n return bindingsPromise;\n}\n\n/**\n * ggml-backed BlazeFace face detector. Mirrors the\n * `MediaPipeFaceDetector` compatibility surface — same constructor config,\n * same `MediaPipeFaceDetection` output shape.\n *\n * Currently disabled (`isAvailable()` returns `false`) until the\n * face-cpp model entries gain runtime implementations and a BlazeFace GGUF\n * artifact lands.\n */\nexport class BlazeFaceGgmlDetector {\n private readonly cfg: MediaPipeFaceConfig & {\n modelDir: string;\n scoreThreshold: number;\n };\n private bindings: FaceDetectBindings | null = null;\n private handle: unknown = null;\n private initialized = false;\n private initPromise: Promise<void> | null = null;\n\n constructor(config: MediaPipeFaceConfig = {}) {\n this.cfg = {\n modelDir: config.modelDir ?? defaultModelDir(),\n scoreThreshold: config.scoreThreshold ?? 0.5,\n ...config,\n };\n }\n\n /**\n * `true` only when both the native library AND the GGUF weights are\n * on disk. Loading them happens lazily in `initialize()`.\n */\n static async isAvailable(): Promise<boolean> {\n const libPath = defaultLibraryPath();\n try {\n await fs.access(libPath);\n } catch {\n return false;\n }\n try {\n await fs.access(defaultDetWeightsPath());\n } catch {\n return false;\n }\n const bindings = await loadBindings();\n return Boolean(bindings);\n }\n\n isInitialized(): boolean {\n return this.initialized;\n }\n\n async initialize(): Promise<void> {\n if (this.initialized) return;\n if (this.initPromise) return this.initPromise;\n this.initPromise = this._initialize();\n return this.initPromise;\n }\n\n private async _initialize(): Promise<void> {\n this.bindings = await loadBindings();\n if (!this.bindings) {\n throw new Error(\n `${MODULE_TAG} face-cpp library unavailable; build packages/native/plugins/face-cpp first.`,\n );\n }\n const ggufPath = defaultDetWeightsPath();\n try {\n await fs.access(ggufPath);\n } catch {\n throw new Error(\n `${MODULE_TAG} BlazeFace GGUF missing at ${ggufPath} — see scripts/blazeface_to_gguf.py.`,\n );\n }\n this.handle = this.bindings.open(ggufPath);\n this.initialized = true;\n logger.info(\n `${MODULE_TAG} initialized (backend=${this.bindings.activeBackend()})`,\n );\n }\n\n /**\n * Detect faces in the given image buffer. The buffer can be any\n * sharp-supported format (PNG, JPEG, raw); we resize/letterbox to\n * the BlazeFace 128x128 input via sharp, run the native detector,\n * then return source-pixel bboxes + 6 keypoints.\n */\n async detect(imageBuffer: Buffer): Promise<MediaPipeFaceDetection[]> {\n if (!this.initialized) await this.initialize();\n if (!this.bindings || !this.handle) return [];\n\n const sharp = await getSharp();\n const meta = await sharp(imageBuffer).metadata();\n const origW = meta.width ?? 0;\n const origH = meta.height ?? 0;\n if (!origW || !origH) return [];\n\n const inSize = FACE_DETECTOR_INPUT_SIZE;\n const { data: rgbResized } = await sharp(imageBuffer)\n .resize(inSize, inSize, { fit: \"fill\" })\n .removeAlpha()\n .raw()\n .toBuffer({ resolveWithObject: true });\n\n const cap = 16;\n const { detections, count } = this.bindings.detect(\n this.handle,\n rgbResized,\n inSize,\n inSize,\n inSize * 3,\n this.cfg.scoreThreshold,\n cap,\n );\n\n const out: MediaPipeFaceDetection[] = [];\n const sx = origW / inSize;\n const sy = origH / inSize;\n for (let i = 0; i < count && i < cap; i++) {\n const off = i * FACE_DETECTION_FLOATS;\n const x = detections[off + 0] * sx;\n const y = detections[off + 1] * sy;\n const w = detections[off + 2] * sx;\n const h = detections[off + 3] * sy;\n const confidence = detections[off + 4];\n const keypoints: Array<{ x: number; y: number }> = [];\n for (let kp = 0; kp < FACE_DETECTOR_KEYPOINT_COUNT; kp++) {\n keypoints.push({\n x: detections[off + 5 + kp * 2 + 0] * sx,\n y: detections[off + 5 + kp * 2 + 1] * sy,\n });\n }\n out.push({\n bbox: { x, y, width: w, height: h },\n confidence,\n keypoints,\n });\n }\n return out;\n }\n\n async dispose(): Promise<void> {\n if (this.bindings && this.handle) {\n this.bindings.close(this.handle);\n }\n this.handle = null;\n this.initialized = false;\n this.initPromise = null;\n logger.debug(`${MODULE_TAG} disposed`);\n }\n}\n",
|
|
15
|
+
"// face-recognition-ggml.ts — native ggml face recognition.\n//\n// bun:ffi binding for the face-embed head exposed by the standalone\n// `packages/native/plugins/face-cpp/` library, plus the full\n// `FaceRecognition` surface (detect → embed → match → store) consumed by\n// `VisionService`. This is the only face-recognition backend; there is no\n// tfjs / face-api.js fallback.\n//\n// The native library produces a 128-d L2-normalized embedding from a\n// `face_detection` record (bbox + 6 BlazeFace landmarks). That detection\n// is what `BlazeFaceGgmlDetector` returns, so the pipeline is:\n//\n// const det = await blazefaceDetector.detect(buffer);\n// const emb = await embedder.embed(buffer, det[i]);\n//\n// `FaceEmbedGgmlRecognizer` owns only the embedding step; the matching,\n// storage, and persistence that make up the `FaceLibrary` surface live in\n// the `FaceRecognition` class below. Cosine + L2 distance helpers mirror\n// `face_embed_distance` / `face_embed_distance_l2`.\n\nimport { promises as fs } from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { logger } from \"@elizaos/core\";\nimport {\n BlazeFaceGgmlDetector,\n type MediaPipeFaceDetection,\n} from \"./face-detector-ggml\";\nimport { getSharp } from \"./image/sharp-compat\";\nimport type { BoundingBox, FaceLibrary, FaceProfile } from \"./types\";\n\nconst MODULE_TAG = \"[FaceEmbedGgml]\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nconst FACE_DETECTOR_KEYPOINT_COUNT = 6;\nconst FACE_DETECTION_FLOATS = 5 + FACE_DETECTOR_KEYPOINT_COUNT * 2; // 17\nconst FACE_EMBED_DIM = 128;\n\nfunction defaultLibraryPath(): string {\n const ext =\n process.platform === \"darwin\"\n ? \"dylib\"\n : process.platform === \"win32\"\n ? \"dll\"\n : \"so\";\n return (\n process.env.ELIZA_FACE_CPP_LIB ??\n path.join(\n __dirname,\n \"..\",\n \"..\",\n \"..\",\n \"packages\",\n \"native-plugins\",\n \"face-cpp\",\n \"build\",\n `libface.${ext}`,\n )\n );\n}\n\nfunction defaultModelDir(): string {\n const stateDir =\n process.env.ELIZA_STATE_DIR ?? path.join(os.homedir(), \".eliza\");\n return path.join(stateDir, \"models\", \"face-cpp\");\n}\n\nfunction defaultEmbedWeightsPath(): string {\n return (\n process.env.ELIZA_FACE_CPP_EMBED_GGUF ??\n path.join(defaultModelDir(), \"face_embed.gguf\")\n );\n}\n\ninterface BunFFIModule {\n dlopen: (\n p: string,\n symbols: Record<string, { args: number[]; returns: number }>,\n ) => {\n symbols: Record<string, (...args: unknown[]) => unknown>;\n };\n FFIType: Record<\n \"cstring\" | \"pointer\" | \"i32\" | \"void\" | \"f32\" | \"u8\" | \"u32\",\n number\n >;\n ptr: (typedArray: ArrayBufferView) => unknown;\n CString: new (raw: unknown) => { toString(): string };\n}\n\ninterface FaceEmbedBindings {\n open(ggufPath: string): unknown;\n embed(\n handle: unknown,\n rgb: Buffer,\n w: number,\n h: number,\n stride: number,\n detection: MediaPipeFaceDetection,\n ): Float32Array;\n close(handle: unknown): void;\n}\n\nlet bindingsPromise: Promise<FaceEmbedBindings | null> | null = null;\n\nasync function loadBindings(): Promise<FaceEmbedBindings | null> {\n if (bindingsPromise) return bindingsPromise;\n bindingsPromise = (async (): Promise<FaceEmbedBindings | null> => {\n const libPath = defaultLibraryPath();\n try {\n await fs.access(libPath);\n } catch {\n logger.warn(`${MODULE_TAG} native library not found at ${libPath}`);\n return null;\n }\n\n let bunFFI: BunFFIModule | null = null;\n try {\n const dynImport = new Function(\"spec\", \"return import(spec)\") as (\n s: string,\n ) => Promise<BunFFIModule>;\n bunFFI = await dynImport(\"bun:ffi\");\n } catch {\n logger.warn(\n `${MODULE_TAG} bun:ffi unavailable — face-cpp requires bun runtime.`,\n );\n return null;\n }\n\n const { dlopen, FFIType, ptr } = bunFFI;\n\n let lib;\n try {\n lib = dlopen(libPath, {\n face_embed_open: {\n args: [FFIType.cstring, FFIType.pointer],\n returns: FFIType.i32,\n },\n face_embed: {\n args: [\n FFIType.pointer,\n FFIType.pointer,\n FFIType.i32,\n FFIType.i32,\n FFIType.i32,\n FFIType.pointer,\n FFIType.pointer,\n ],\n returns: FFIType.i32,\n },\n face_embed_close: {\n args: [FFIType.pointer],\n returns: FFIType.i32,\n },\n });\n } catch (error) {\n logger.warn(\n `${MODULE_TAG} dlopen failed for ${libPath}:`,\n error instanceof Error ? error.message : String(error),\n );\n return null;\n }\n\n const bindings: FaceEmbedBindings = {\n open(ggufPath) {\n const cstr = Buffer.from(ggufPath + \"\\0\", \"utf-8\");\n const handleSlot = new BigUint64Array(1);\n const rc = lib.symbols.face_embed_open(\n ptr(cstr) as never,\n ptr(handleSlot) as never,\n ) as number;\n if (rc !== 0) {\n throw new Error(\n `face_embed_open failed (rc=${rc}) — GGUF likely missing or invalid.`,\n );\n }\n const handle = handleSlot[0];\n if (handle === 0n) {\n throw new Error(\"face_embed_open returned NULL handle\");\n }\n // bun:ffi pointer-typed args expect a Number, not a BigInt.\n return Number(handle);\n },\n embed(handle, rgb, w, h, stride, detection) {\n // Pack a face_detection record into a 17-float buffer matching\n // the C struct layout: x, y, w, h, conf, then 12 landmark floats.\n const det = new Float32Array(FACE_DETECTION_FLOATS);\n det[0] = detection.bbox.x;\n det[1] = detection.bbox.y;\n det[2] = detection.bbox.width;\n det[3] = detection.bbox.height;\n det[4] = detection.confidence;\n const kps = detection.keypoints ?? [];\n for (let i = 0; i < FACE_DETECTOR_KEYPOINT_COUNT; i++) {\n const kp = kps[i];\n det[5 + i * 2 + 0] = kp ? kp.x : 0;\n det[5 + i * 2 + 1] = kp ? kp.y : 0;\n }\n const out = new Float32Array(FACE_EMBED_DIM);\n const rc = lib.symbols.face_embed(\n handle as never,\n ptr(rgb) as never,\n w,\n h,\n stride,\n ptr(det) as never,\n ptr(out) as never,\n ) as number;\n if (rc !== 0) {\n throw new Error(`face_embed failed (rc=${rc}).`);\n }\n return out;\n },\n close(handle) {\n lib.symbols.face_embed_close(handle as never);\n },\n };\n return bindings;\n })();\n return bindingsPromise;\n}\n\n/**\n * Configuration for the ggml-backed face embedder.\n */\nexport interface FaceEmbedGgmlConfig {\n modelPath?: string;\n modelDir?: string;\n}\n\n/**\n * Cosine distance between two 128-d unit-norm embeddings. Matches\n * `face_embed_distance` in the C library: 0 for identical, 1 for\n * orthogonal, 2 for antipodal.\n */\nexport function cosineDistance(a: Float32Array, b: Float32Array): number {\n if (a.length !== b.length) {\n throw new Error(`embedding length mismatch: ${a.length} vs ${b.length}`);\n }\n let dot = 0;\n for (let i = 0; i < a.length; i++) dot += a[i] * b[i];\n if (dot > 1) dot = 1;\n if (dot < -1) dot = -1;\n return 1 - dot;\n}\n\n/**\n * L2 distance between two 128-d embeddings. For unit-norm inputs this\n * is sqrt(2 - 2*dot(a, b)), in [0, 2].\n */\nexport function l2Distance(a: Float32Array, b: Float32Array): number {\n if (a.length !== b.length) {\n throw new Error(`embedding length mismatch: ${a.length} vs ${b.length}`);\n }\n let sum = 0;\n for (let i = 0; i < a.length; i++) {\n const d = a[i] - b[i];\n sum += d * d;\n }\n return Math.sqrt(sum);\n}\n\n/**\n * ggml-backed 128-d face embedder: a 128-d L2-normalized descriptor per\n * detected face, consumed by the `FaceRecognition` class below.\n */\nexport class FaceEmbedGgmlRecognizer {\n private readonly cfg: FaceEmbedGgmlConfig & { modelDir: string };\n private bindings: FaceEmbedBindings | null = null;\n private handle: unknown = null;\n private initialized = false;\n private initPromise: Promise<void> | null = null;\n\n constructor(config: FaceEmbedGgmlConfig = {}) {\n this.cfg = {\n modelDir: config.modelDir ?? defaultModelDir(),\n ...config,\n };\n }\n\n /**\n * `true` only when both the native library AND the GGUF weights are\n * on disk.\n */\n static async isAvailable(): Promise<boolean> {\n const libPath = defaultLibraryPath();\n try {\n await fs.access(libPath);\n } catch {\n return false;\n }\n try {\n await fs.access(defaultEmbedWeightsPath());\n } catch {\n return false;\n }\n const bindings = await loadBindings();\n return Boolean(bindings);\n }\n\n isInitialized(): boolean {\n return this.initialized;\n }\n\n async initialize(): Promise<void> {\n if (this.initialized) return;\n if (this.initPromise) return this.initPromise;\n this.initPromise = this._initialize();\n return this.initPromise;\n }\n\n private async _initialize(): Promise<void> {\n this.bindings = await loadBindings();\n if (!this.bindings) {\n throw new Error(\n `${MODULE_TAG} face-cpp library unavailable; build packages/native/plugins/face-cpp first.`,\n );\n }\n const ggufPath = this.cfg.modelPath ?? defaultEmbedWeightsPath();\n try {\n await fs.access(ggufPath);\n } catch {\n throw new Error(\n `${MODULE_TAG} face-embed GGUF missing at ${ggufPath} — see scripts/face_embed_to_gguf.py.`,\n );\n }\n this.handle = this.bindings.open(ggufPath);\n this.initialized = true;\n logger.info(`${MODULE_TAG} initialized`);\n }\n\n /**\n * Compute a 128-d L2-normalized face embedding from an RGB(A) image\n * buffer plus a detection record (bbox + BlazeFace landmarks).\n *\n * The image is decoded via sharp; pass any sharp-supported format\n * (PNG, JPEG, raw). `detection` should come from\n * `BlazeFaceGgmlDetector` so the keypoints already match the\n * BlazeFace order.\n */\n async embed(\n imageBuffer: Buffer,\n detection: MediaPipeFaceDetection,\n ): Promise<Float32Array> {\n if (!this.initialized) await this.initialize();\n if (!this.bindings || !this.handle) {\n throw new Error(`${MODULE_TAG} not initialized`);\n }\n\n const sharp = await getSharp();\n const meta = await sharp(imageBuffer).metadata();\n const w = meta.width ?? 0;\n const h = meta.height ?? 0;\n if (!w || !h) {\n throw new Error(`${MODULE_TAG} sharp could not determine image size`);\n }\n\n const { data: rgb } = await sharp(imageBuffer)\n .removeAlpha()\n .raw()\n .toBuffer({ resolveWithObject: true });\n\n return this.bindings.embed(this.handle, rgb, w, h, w * 3, detection);\n }\n\n async dispose(): Promise<void> {\n if (this.bindings && this.handle) {\n this.bindings.close(this.handle);\n }\n this.handle = null;\n this.initialized = false;\n this.initPromise = null;\n logger.debug(`${MODULE_TAG} disposed`);\n }\n}\n\nconst FACE_REC_TAG = \"[FaceRecognition]\";\n\n/**\n * A detected face: a native BlazeFace detection plus its 128-d ggml\n * embedding. Mirrors the fields `VisionService` reads off each result.\n * The native backend produces no expression / age-gender estimates, so\n * those attributes are left to higher layers.\n */\nexport interface DetectedFace {\n detection: { box: BoundingBox };\n descriptor: Float32Array;\n}\n\n/**\n * Native ggml face recognition: BlazeFace detection + 128-d embedding +\n * in-memory matching and persistence. When the native `libface` library\n * or its GGUF weights are not on disk, detection returns an empty list\n * (recognition is disabled, never faked). Matching and storage are pure\n * JS and always available.\n */\nexport class FaceRecognition {\n private readonly detector = new BlazeFaceGgmlDetector();\n private readonly embedder = new FaceEmbedGgmlRecognizer();\n private detectorAvailable: boolean | null = null;\n private readonly faceLibrary: FaceLibrary = {\n faces: new Map(),\n embeddings: new Map(),\n };\n\n // Euclidean distance threshold for a face match.\n private readonly FACE_MATCH_THRESHOLD = 0.6;\n // Minimum face size in pixels.\n private readonly MIN_FACE_SIZE = 50;\n\n /**\n * Detect faces in a raw RGBA frame and compute an embedding for each.\n * Returns an empty list when the native face backend is unavailable.\n */\n async detectFaces(\n imageData: Buffer,\n width: number,\n height: number,\n ): Promise<DetectedFace[]> {\n if (!imageData || imageData.length === 0 || width <= 0 || height <= 0) {\n logger.warn(\n `${FACE_REC_TAG} Invalid input parameters: dataLength=${imageData?.length ?? 0}, width=${width}, height=${height}`,\n );\n return [];\n }\n\n const expectedSize = width * height * 4; // RGBA\n if (imageData.length !== expectedSize) {\n logger.warn(\n `${FACE_REC_TAG} Buffer size mismatch: expected=${expectedSize}, actual=${imageData.length}, width=${width}, height=${height}`,\n );\n return [];\n }\n\n if (this.detectorAvailable === null) {\n this.detectorAvailable = await BlazeFaceGgmlDetector.isAvailable();\n if (!this.detectorAvailable) {\n logger.warn(\n `${FACE_REC_TAG} face recognition unavailable (native face-cpp library not built)`,\n );\n }\n }\n if (!this.detectorAvailable) return [];\n\n // BlazeFace + the embedder both decode via sharp, so wrap the raw\n // RGBA frame in a sharp-readable PNG once and reuse it for both.\n const sharp = await getSharp();\n const png = await sharp(imageData, {\n raw: { width, height, channels: 4 },\n })\n .png()\n .toBuffer();\n\n const detections = await this.detector.detect(png);\n\n const faces: DetectedFace[] = [];\n for (const det of detections) {\n const { width: bw, height: bh } = det.bbox;\n if (bw < this.MIN_FACE_SIZE || bh < this.MIN_FACE_SIZE) continue;\n const descriptor = await this.embedder.embed(png, det);\n faces.push({ detection: { box: det.bbox }, descriptor });\n }\n return faces;\n }\n\n async recognizeFace(\n descriptor: Float32Array,\n ): Promise<{ profileId: string; distance: number } | null> {\n let bestMatch: { profileId: string; distance: number } | null = null;\n let minDistance = Number.POSITIVE_INFINITY;\n\n for (const [profileId, embeddings] of this.faceLibrary.embeddings) {\n for (const knownEmbedding of embeddings) {\n const distance = euclideanDistance(descriptor, knownEmbedding);\n if (distance < this.FACE_MATCH_THRESHOLD && distance < minDistance) {\n minDistance = distance;\n bestMatch = { profileId, distance };\n }\n }\n }\n\n return bestMatch;\n }\n\n async addOrUpdateFace(\n descriptor: Float32Array,\n attributes?: Partial<FaceProfile>,\n ): Promise<string> {\n const match = await this.recognizeFace(descriptor);\n\n if (match) {\n const profile = this.faceLibrary.faces.get(match.profileId);\n if (!profile) {\n throw new Error(\n `Profile not found for matched profileId: ${match.profileId}`,\n );\n }\n profile.lastSeen = Date.now();\n profile.seenCount++;\n\n const embeddings = this.faceLibrary.embeddings.get(match.profileId);\n if (!embeddings) {\n throw new Error(\n `Embeddings not found for matched profileId: ${match.profileId}`,\n );\n }\n // Keep up to 10 embeddings per person for robustness.\n if (embeddings.length < 10) {\n embeddings.push(Array.from(descriptor));\n }\n\n if (attributes) {\n Object.assign(profile, attributes);\n }\n\n return match.profileId;\n }\n\n const profileId = `face-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;\n const profile: FaceProfile = {\n id: profileId,\n embeddings: [Array.from(descriptor)],\n firstSeen: Date.now(),\n lastSeen: Date.now(),\n seenCount: 1,\n ...attributes,\n };\n\n this.faceLibrary.faces.set(profileId, profile);\n this.faceLibrary.embeddings.set(profileId, [Array.from(descriptor)]);\n\n logger.info(`${FACE_REC_TAG} New face registered: ${profileId}`);\n return profileId;\n }\n\n getFaceProfile(profileId: string): FaceProfile | undefined {\n return this.faceLibrary.faces.get(profileId);\n }\n\n getAllProfiles(): FaceProfile[] {\n return Array.from(this.faceLibrary.faces.values());\n }\n\n async saveFaceLibrary(filePath: string): Promise<void> {\n const data = {\n faces: Array.from(this.faceLibrary.faces.entries()),\n embeddings: Array.from(this.faceLibrary.embeddings.entries()),\n };\n await fs.writeFile(filePath, JSON.stringify(data, null, 2));\n logger.info(`${FACE_REC_TAG} Face library saved to ${filePath}`);\n }\n\n async loadFaceLibrary(filePath: string): Promise<void> {\n const raw = await fs.readFile(filePath, \"utf-8\");\n const data = JSON.parse(raw) as {\n faces: [string, FaceProfile][];\n embeddings: [string, number[][]][];\n };\n this.faceLibrary.faces = new Map(data.faces);\n this.faceLibrary.embeddings = new Map(data.embeddings);\n logger.info(\n `${FACE_REC_TAG} Loaded ${this.faceLibrary.faces.size} face profiles`,\n );\n }\n\n async dispose(): Promise<void> {\n await this.detector.dispose();\n await this.embedder.dispose();\n }\n}\n\nfunction euclideanDistance(a: Float32Array, b: number[]): number {\n let sum = 0;\n for (let i = 0; i < a.length; i++) {\n const d = a[i] - b[i];\n sum += d * d;\n }\n return Math.sqrt(sum);\n}\n",
|
|
16
|
+
"/**\n * Vision-context augmenter (issue #9105).\n *\n * Runs the token-free pre-vision detectors plugin-vision owns — OCR\n * (tesseract / native OS engines), object detection (YOLO), face detection —\n * over an image and folds their results into the describe prompt as structured\n * text. The on-device Gemma-4 VL model then grounds its description in real\n * extracted signals (small text it would otherwise misread, object identity,\n * presence of people) instead of guessing.\n *\n * This is the *provider* half of the seam. plugin-local-inference owns the\n * registry (`registerVisionContextAugmenter`); this class is registered into it\n * at boot via a best-effort dynamic import (see `index.ts`), mirroring the\n * coord-OCR bridge into plugin-computeruse. Every detector is optional and\n * best-effort: an unavailable or failing detector contributes nothing rather\n * than failing the describe.\n */\n\nimport { Buffer } from \"node:buffer\";\nimport { logger } from \"@elizaos/core\";\nimport {\n getOcrWithCoordsService,\n type OcrWithCoordsService,\n} from \"./ocr-with-coords.js\";\n\n/** Raw signals extracted from an image, joined into prompt-ready strings. */\nexport interface FusedVisionSignals {\n ocrText?: string;\n objects?: string;\n faces?: string;\n}\n\n/** Image wrapper accepted by the augmenter — matches the handler's request shape. */\nexport type AugmenterImageInput =\n | { kind: \"bytes\"; bytes: Uint8Array; mimeType?: string }\n | { kind: \"base64\"; base64: string; mimeType?: string }\n | { kind: \"dataUrl\"; dataUrl: string }\n | { kind: \"url\"; url: string; mimeType?: string };\n\nexport interface VisionAugmentInput {\n image: AugmenterImageInput;\n basePrompt?: string;\n}\n\nexport interface VisionAugmentOutput {\n prompt: string;\n fused: FusedVisionSignals;\n}\n\n/**\n * Injectable detector hooks. OCR defaults to the registered coord-OCR service;\n * object/face detection are wired only when their native artifacts are present.\n * Exposed so tests can drive the fusion with deterministic fakes (no native\n * libs, no real tesseract).\n */\nexport interface VisionAugmenterDetectors {\n getOcr?: () => OcrWithCoordsService | null;\n detectObjects?: (\n imageBytes: Buffer,\n ) => Promise<ReadonlyArray<{ type: string; confidence: number }>>;\n detectFaces?: (imageBytes: Buffer) => Promise<number>;\n}\n\nconst DEFAULT_DESCRIBE_PROMPT = \"Describe what is in this image.\";\nconst MAX_OBJECTS = 12;\nconst MAX_OCR_BLOCKS = 24;\n\n/**\n * Keep only OCR fragments that carry real signal. Tesseract run over a natural\n * photo (vs a clean document) emits per-glyph noise — `|`, `=`, `—`, stray\n * single letters — that would pollute the prompt and waste tokens. Require at\n * least two alphanumeric characters so genuine words/labels survive and noise\n * is dropped. Pure — exported for tests.\n */\nexport function isMeaningfulOcrText(text: string): boolean {\n return (text.match(/[A-Za-z0-9]/g)?.length ?? 0) >= 2;\n}\n\n/**\n * Sentinel that marks an already-augmented prompt. Lets the augmenter stay\n * idempotent — if a prompt that already carries a fused-context block is fed\n * back in (re-describe, retry), we skip rather than stacking a second block.\n */\nconst FUSED_CONTEXT_MARKER = \"Detected context — pre-extracted from this image\";\n\nexport class FusedVisionContextAugmenter {\n readonly name = \"vision-fused-context\";\n\n constructor(private readonly deps: VisionAugmenterDetectors = {}) {}\n\n async augmentImagePrompt(\n input: VisionAugmentInput,\n ): Promise<VisionAugmentOutput | null> {\n if (input.basePrompt?.includes(FUSED_CONTEXT_MARKER)) return null;\n const bytes = resolveImageBytes(input.image);\n if (!bytes || bytes.byteLength === 0) return null;\n\n const fused: FusedVisionSignals = {};\n\n const ocr = (this.deps.getOcr ?? getOcrWithCoordsService)();\n if (ocr) {\n try {\n const res = await ocr.describe({\n displayId: \"vision-describe\",\n sourceX: 0,\n sourceY: 0,\n pngBytes: new Uint8Array(bytes),\n });\n const lines = res.blocks\n .map((b) => b.text.trim())\n .filter(isMeaningfulOcrText)\n .slice(0, MAX_OCR_BLOCKS);\n if (lines.length > 0) {\n fused.ocrText = lines.map((t) => `\"${t}\"`).join(\", \");\n }\n } catch (err) {\n logger.debug(`[vision-augment] OCR skipped: ${messageOf(err)}`);\n }\n }\n\n if (this.deps.detectObjects) {\n try {\n const objs = await this.deps.detectObjects(bytes);\n if (objs.length > 0) {\n fused.objects = objs\n .slice(0, MAX_OBJECTS)\n .map((o) => `${o.type} (${o.confidence.toFixed(2)})`)\n .join(\", \");\n }\n } catch (err) {\n logger.debug(\n `[vision-augment] object detection skipped: ${messageOf(err)}`,\n );\n }\n }\n\n if (this.deps.detectFaces) {\n try {\n const n = await this.deps.detectFaces(bytes);\n if (n > 0) fused.faces = `${n} ${n === 1 ? \"face\" : \"faces\"}`;\n } catch (err) {\n logger.debug(\n `[vision-augment] face detection skipped: ${messageOf(err)}`,\n );\n }\n }\n\n if (!fused.ocrText && !fused.objects && !fused.faces) return null;\n return {\n prompt: buildAugmentedPrompt(input.basePrompt, fused),\n fused,\n };\n }\n}\n\n/**\n * Compose the final prompt: the caller's prompt (or a default) followed by a\n * clearly-delimited block of detected signals. Pure — exported for tests so the\n * prompt contract has a single source of truth.\n */\nexport function buildAugmentedPrompt(\n basePrompt: string | undefined,\n fused: FusedVisionSignals,\n): string {\n const base = basePrompt?.trim() || DEFAULT_DESCRIBE_PROMPT;\n const lines: string[] = [];\n if (fused.ocrText) lines.push(`Text (OCR): ${fused.ocrText}`);\n if (fused.objects) lines.push(`Objects: ${fused.objects}`);\n if (fused.faces) lines.push(`Faces: ${fused.faces}`);\n if (lines.length === 0) return base;\n return [\n base,\n \"\",\n `${FUSED_CONTEXT_MARKER} to ground your answer. Use these signals; correct them only if the image clearly contradicts them.`,\n ...lines.map((l) => `- ${l}`),\n ].join(\"\\n\");\n}\n\n/**\n * Resolve an image wrapper to encoded image bytes. Handles only the inline\n * shapes (bytes / base64 / data URL). `url` inputs of EVERY form —\n * `http(s)://`, `file://`, and bare filesystem paths — return `null`: the\n * augmenter performs no file or network I/O. Remote URLs are fetched by the\n * describe backend through the SSRF guard, and reading a `file://`/bare-path\n * off an agent-supplied describe URL would be a local-file-read primitive (the\n * canonical resolver in `plugin-local-inference/.../hash.ts` refuses `url`\n * inputs for the same reason). No bytes → no OCR augmentation; the backend\n * still describes the raw image via its own resolution.\n */\nfunction resolveImageBytes(image: AugmenterImageInput): Buffer | null {\n switch (image.kind) {\n case \"bytes\":\n return Buffer.from(image.bytes);\n case \"base64\":\n return Buffer.from(image.base64, \"base64\");\n case \"dataUrl\": {\n const comma = image.dataUrl.indexOf(\",\");\n if (comma < 0) return null;\n return Buffer.from(image.dataUrl.slice(comma + 1), \"base64\");\n }\n case \"url\":\n return null;\n }\n}\n\nfunction messageOf(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\n/**\n * The production augmenter: OCR via the registered coord-OCR service, plus YOLO\n * object detection and BlazeFace face detection wired lazily and gated on their\n * `isAvailable()` probe. Until those native artifacts ship, the gate is false\n * and they contribute nothing — OCR alone augments the prompt. When the\n * artifacts land the same fusion point activates them with no further wiring.\n */\nexport function createDefaultVisionAugmenter(): FusedVisionContextAugmenter {\n return new FusedVisionContextAugmenter({\n detectObjects: lazyObjectDetector(),\n detectFaces: lazyFaceDetector(),\n });\n}\n\nfunction lazyObjectDetector(): (\n bytes: Buffer,\n) => Promise<ReadonlyArray<{ type: string; confidence: number }>> {\n let detector: import(\"./yolo-detector.js\").YOLODetector | null = null;\n let resolved = false;\n return async (bytes) => {\n if (!resolved) {\n resolved = true;\n const { YOLODetector } = await import(\"./yolo-detector.js\");\n if (await YOLODetector.isAvailable()) detector = new YOLODetector();\n }\n if (!detector) return [];\n const objs = await detector.detect(bytes);\n return objs.map((o) => ({ type: o.type, confidence: o.confidence }));\n };\n}\n\nfunction lazyFaceDetector(): (bytes: Buffer) => Promise<number> {\n let detector: import(\"./face-detector-ggml.js\").BlazeFaceGgmlDetector | null =\n null;\n let resolved = false;\n return async (bytes) => {\n if (!resolved) {\n resolved = true;\n const { BlazeFaceGgmlDetector } = await import(\"./face-detector-ggml.js\");\n if (await BlazeFaceGgmlDetector.isAvailable()) {\n detector = new BlazeFaceGgmlDetector();\n }\n }\n if (!detector) return 0;\n const faces = await detector.detect(bytes);\n return faces.length;\n };\n}\n",
|
|
17
|
+
"/**\n * Pure element-merge core for the GET_SCREEN action (#9105 Slice 2 / M2).\n *\n * GET_SCREEN returns a cheap, token-frugal list of grounded, clickable screen\n * elements unified from three sources: OCR text boxes, accessibility (AX)\n * clickables, and (optionally) VLM-detected elements. This module is the\n * deterministic heart of that envelope — it collapses the three sources into a\n * single deduplicated, stably-ordered element list, recording each element's\n * `groundingSources` provenance.\n *\n * Like the M1 OCR bridge (`computeruse-ocr-bridge.ts`), this is intentionally\n * dependency-free and pure: the source types live in `@elizaos/plugin-computeruse`\n * (`SceneOcrBox` / `SceneAxNode` / `SceneVlmElement`), but we describe their\n * shapes STRUCTURALLY here rather than importing them, to keep the no-hard-dep\n * rule. That also makes the merge engine fully unit-testable with zero\n * environment, decoupled from the runtime/native/model wiring (Slice 3).\n */\n\n/** Display-local bounding box `[x, y, w, h]`. */\nexport type Bbox = readonly [number, number, number, number];\n\n/** Structural shape of computeruse's `SceneOcrBox`. */\nexport interface OcrBoxLike {\n readonly id: string;\n readonly text: string;\n readonly bbox: Bbox;\n readonly conf?: number;\n readonly displayId: number;\n}\n\n/** Structural shape of computeruse's `SceneAxNode`. */\nexport interface AxNodeLike {\n readonly id: string;\n readonly role: string;\n readonly label?: string;\n readonly bbox: Bbox;\n readonly actions?: readonly string[];\n readonly displayId: number;\n}\n\n/** Structural shape of computeruse's `SceneVlmElement`. */\nexport interface VlmElementLike {\n readonly id: string;\n readonly kind: string;\n readonly desc: string;\n readonly bbox: Bbox;\n readonly displayId: number;\n}\n\nexport type GroundingSource = \"ocr\" | \"ax\" | \"vlm\";\n\n/** A single unified, grounded screen element in the GET_SCREEN envelope. */\nexport interface GetScreenElement {\n /** Stable id, preferring the AX id, then OCR, then VLM. */\n id: string;\n /** Display-local bbox `[x, y, w, h]` of the representative (highest-priority) source. */\n bbox: [number, number, number, number];\n /** User-facing text/label: AX label, else OCR text, else VLM description. */\n text: string;\n /** Element kind/role when known: AX role, else VLM kind. */\n kind?: string;\n displayId: number;\n /** AX actions when the element is accessibility-grounded. */\n actions?: string[];\n /** Provenance — every source that contributed to this element, in fixed\n * `ocr < ax < vlm` order for stability. Always non-empty. */\n groundingSources: GroundingSource[];\n}\n\nexport interface MergeScreenInput {\n readonly ocr?: readonly OcrBoxLike[];\n readonly ax?: readonly AxNodeLike[];\n readonly vlm?: readonly VlmElementLike[];\n}\n\nexport interface MergeScreenOptions {\n /** Boxes whose IoU exceeds this collapse into one element (default 0.6). */\n readonly iouThreshold?: number;\n}\n\nconst DEFAULT_IOU_THRESHOLD = 0.6;\n\n/** Intersection-over-union of two `[x, y, w, h]` boxes. 0 when either is empty\n * or they don't overlap. */\nexport function bboxIou(a: Bbox, b: Bbox): number {\n const [ax, ay, aw, ah] = a;\n const [bx, by, bw, bh] = b;\n if (aw <= 0 || ah <= 0 || bw <= 0 || bh <= 0) return 0;\n const ix = Math.max(ax, bx);\n const iy = Math.max(ay, by);\n const ix2 = Math.min(ax + aw, bx + bw);\n const iy2 = Math.min(ay + ah, by + bh);\n const iw = Math.max(0, ix2 - ix);\n const ih = Math.max(0, iy2 - iy);\n const inter = iw * ih;\n if (inter <= 0) return 0;\n const union = aw * ah + bw * bh - inter;\n return union > 0 ? inter / union : 0;\n}\n\ninterface Cluster {\n displayId: number;\n bbox: Bbox;\n ax?: AxNodeLike;\n ocr?: OcrBoxLike;\n vlm?: VlmElementLike;\n}\n\n/** Stable sort key: top-to-bottom, then left-to-right, then by id for ties. */\nfunction byPosition(\n a: { bbox: Bbox; id: string },\n b: { bbox: Bbox; id: string },\n): number {\n return (\n a.bbox[1] - b.bbox[1] || a.bbox[0] - b.bbox[0] || a.id.localeCompare(b.id)\n );\n}\n\n/**\n * Merge OCR boxes + AX clickables + VLM elements into one deduplicated,\n * deterministically-ordered element list.\n *\n * - Elements from different sources whose bboxes overlap above `iouThreshold`\n * (and share a `displayId`) collapse into one element that records all\n * contributing sources in `groundingSources`.\n * - Field precedence is AX > OCR > VLM (AX wins id/label/role; OCR text fills\n * in when AX has no label; VLM desc is the last resort).\n * - Output order is top-to-bottom, then left-to-right, so the envelope is\n * stable across turns regardless of input ordering.\n * - Degrades gracefully: any source may be absent/empty (e.g. accessibility off)\n * and the function never throws.\n */\nexport function mergeScreenElements(\n input: MergeScreenInput,\n options: MergeScreenOptions = {},\n): GetScreenElement[] {\n const threshold = options.iouThreshold ?? DEFAULT_IOU_THRESHOLD;\n const clusters: Cluster[] = [];\n\n const attach = (\n displayId: number,\n bbox: Bbox,\n set: (c: Cluster) => void,\n ): void => {\n const match = clusters.find(\n (c) => c.displayId === displayId && bboxIou(c.bbox, bbox) >= threshold,\n );\n if (match) {\n set(match);\n return;\n }\n const cluster: Cluster = { displayId, bbox };\n set(cluster);\n clusters.push(cluster);\n };\n\n // Process in precedence order so a cluster's representative bbox is set by its\n // highest-priority contributing source, and pre-sort each source by position\n // so cluster creation order is deterministic.\n for (const ax of [...(input.ax ?? [])].sort(byPosition)) {\n attach(ax.displayId, ax.bbox, (c) => {\n if (!c.ax) c.ax = ax;\n });\n }\n for (const ocr of [...(input.ocr ?? [])].sort(byPosition)) {\n attach(ocr.displayId, ocr.bbox, (c) => {\n if (!c.ocr) c.ocr = ocr;\n });\n }\n for (const vlm of [...(input.vlm ?? [])].sort(byPosition)) {\n attach(vlm.displayId, vlm.bbox, (c) => {\n if (!c.vlm) c.vlm = vlm;\n });\n }\n\n const elements = clusters.map((c): GetScreenElement => {\n const groundingSources: GroundingSource[] = [];\n if (c.ocr) groundingSources.push(\"ocr\");\n if (c.ax) groundingSources.push(\"ax\");\n if (c.vlm) groundingSources.push(\"vlm\");\n\n const id = c.ax?.id ?? c.ocr?.id ?? c.vlm?.id ?? \"el\";\n const text = c.ax?.label || c.ocr?.text || c.vlm?.desc || \"\";\n const kind = c.ax?.role ?? c.vlm?.kind;\n const [x, y, w, h] = c.bbox;\n\n const element: GetScreenElement = {\n id,\n bbox: [x, y, w, h],\n text,\n displayId: c.displayId,\n groundingSources,\n };\n if (kind !== undefined) element.kind = kind;\n if (c.ax?.actions && c.ax.actions.length > 0) {\n element.actions = [...c.ax.actions];\n }\n return element;\n });\n\n return elements.sort(byPosition);\n}\n",
|
|
18
|
+
"/**\n * Set-of-Marks (SoM) grounding — #9170 M9.\n *\n * Set-of-Marks is the grounding technique trycua/cua uses via OmniParser: take\n * the icon detections (GGUF YOLO) and the OCR text boxes (the `CoordOcrProvider`\n * seam plugin-vision already feeds), fuse them into ONE deduplicated set of\n * candidate targets, draw a 1-indexed numbered box over each on the screenshot,\n * and let the VLM pick a *number* instead of raw pixel coordinates. Numeric\n * selection is far more reliable than free-floating coordinate regression.\n *\n * This module is split into:\n * - a PURE core (`buildSetOfMarks`) — icon-over-text suppression + NMS +\n * deterministic reading-order numbering. Dependency-free and structurally\n * typed so it unit-tests with zero environment, mirroring\n * `get-screen-elements.ts` and `computeruse-ocr-bridge.ts`.\n * - a renderer (`renderSetOfMarksOverlay`) — composites a numbered SVG overlay\n * onto the source PNG via `sharp`.\n *\n * The OmniParser fusion rules we reproduce:\n * 1. Icon-over-text suppression — a text box mostly covered by an icon box is\n * dropped; the icon is the interactable, the text is its caption.\n * 2. Non-max suppression — overlapping boxes collapse to the highest-priority\n * one (icons outrank text on ties), so each target is marked once.\n * 3. 1-indexed reading-order numbering — top-to-bottom, then left-to-right,\n * with a row tolerance so a visual row isn't scrambled by sub-pixel y jitter.\n */\n\nimport { bboxIou } from \"./get-screen-elements.js\";\n\n/** Display-local bounding box `[x, y, w, h]`. */\nexport type SomBbox = readonly [number, number, number, number];\n\n/** Where a candidate mark came from. Icons outrank text during suppression. */\nexport type SomSource = \"icon\" | \"text\";\n\n/** A raw candidate box fed into the SoM fusion. */\nexport interface SomCandidate {\n readonly bbox: SomBbox;\n readonly source: SomSource;\n /** Class name (icon) or recognized text (text). Optional. */\n readonly label?: string;\n /** Detector/OCR confidence in [0, 1]. Missing → treated as 0.5. */\n readonly score?: number;\n}\n\n/** A finalized, numbered mark in the overlay. */\nexport interface SomMark {\n /** 1-indexed mark number shown in the overlay. */\n readonly index: number;\n readonly bbox: [number, number, number, number];\n /** Box center `[x, y]` — the click target the VLM's number resolves to. */\n readonly center: [number, number];\n readonly source: SomSource;\n readonly label?: string;\n readonly score: number;\n}\n\nexport interface SetOfMarksOptions {\n /**\n * A text box is dropped when this fraction of its area is covered by an icon\n * box (icon-over-text suppression). Default 0.7.\n */\n readonly iconOverTextCoverage?: number;\n /** Boxes overlapping above this IoU collapse during NMS. Default 0.5. */\n readonly nmsIouThreshold?: number;\n /**\n * Rows within this many pixels of vertical offset are treated as the same\n * reading row (so left-to-right ordering holds across a row). Default 12.\n */\n readonly rowTolerance?: number;\n /** Drop candidates with a smaller score before fusion. Default 0 (keep all). */\n readonly minScore?: number;\n}\n\nconst DEFAULT_ICON_OVER_TEXT_COVERAGE = 0.7;\nconst DEFAULT_NMS_IOU = 0.5;\nconst DEFAULT_ROW_TOLERANCE = 12;\nconst DEFAULT_SCORE = 0.5;\n\ninterface NormCandidate {\n bbox: [number, number, number, number];\n source: SomSource;\n label?: string;\n score: number;\n}\n\n/** Area of intersection of two `[x, y, w, h]` boxes (0 when disjoint). Pure. */\nfunction intersectionArea(a: SomBbox, b: SomBbox): number {\n const ix = Math.max(a[0], b[0]);\n const iy = Math.max(a[1], b[1]);\n const ix2 = Math.min(a[0] + a[2], b[0] + b[2]);\n const iy2 = Math.min(a[1] + a[3], b[1] + b[3]);\n return Math.max(0, ix2 - ix) * Math.max(0, iy2 - iy);\n}\n\n/** Fraction of `inner`'s area covered by `outer` (containment ratio). Pure. */\nexport function coverageRatio(inner: SomBbox, outer: SomBbox): number {\n const area = inner[2] * inner[3];\n if (area <= 0) return 0;\n return intersectionArea(inner, outer) / area;\n}\n\nfunction isValidBox(b: SomBbox): boolean {\n return (\n Number.isFinite(b[0]) &&\n Number.isFinite(b[1]) &&\n Number.isFinite(b[2]) &&\n Number.isFinite(b[3]) &&\n b[2] > 0 &&\n b[3] > 0\n );\n}\n\n/**\n * Fuse icon + text candidates into a deduplicated, 1-indexed set of marks.\n *\n * Pure and deterministic: same inputs → identical numbering, regardless of\n * input ordering. Degenerate boxes (non-finite / zero-area) are dropped.\n */\nexport function buildSetOfMarks(\n candidates: readonly SomCandidate[],\n options: SetOfMarksOptions = {},\n): SomMark[] {\n const iconOverText =\n options.iconOverTextCoverage ?? DEFAULT_ICON_OVER_TEXT_COVERAGE;\n const nmsIou = options.nmsIouThreshold ?? DEFAULT_NMS_IOU;\n const rowTolerance = options.rowTolerance ?? DEFAULT_ROW_TOLERANCE;\n const minScore = options.minScore ?? 0;\n\n const norm: NormCandidate[] = candidates\n .filter((c) => isValidBox(c.bbox))\n .map((c) => ({\n bbox: [c.bbox[0], c.bbox[1], c.bbox[2], c.bbox[3]] as [\n number,\n number,\n number,\n number,\n ],\n source: c.source,\n label: c.label,\n score: c.score ?? DEFAULT_SCORE,\n }))\n .filter((c) => c.score >= minScore);\n\n const icons = norm.filter((c) => c.source === \"icon\");\n const texts = norm.filter((c) => c.source === \"text\");\n\n // 1. Icon-over-text suppression: drop text mostly covered by some icon.\n const keptTexts = texts.filter(\n (t) =>\n !icons.some((icon) => coverageRatio(t.bbox, icon.bbox) >= iconOverText),\n );\n\n // 2. NMS over the survivors. Sort so icons outrank text, then by score desc,\n // then by a stable positional key — the greedy keep is deterministic.\n const pool = [...icons, ...keptTexts].sort((a, b) => {\n if (a.source !== b.source) return a.source === \"icon\" ? -1 : 1;\n if (b.score !== a.score) return b.score - a.score;\n return a.bbox[1] - b.bbox[1] || a.bbox[0] - b.bbox[0];\n });\n\n const kept: NormCandidate[] = [];\n for (const cand of pool) {\n const overlaps = kept.some((k) => bboxIou(cand.bbox, k.bbox) >= nmsIou);\n if (!overlaps) kept.push(cand);\n }\n\n // 3. Reading-order numbering: bucket into rows (within rowTolerance), then\n // order rows top-to-bottom and members left-to-right.\n const ordered = [...kept].sort((a, b) => {\n const sameRow = Math.abs(a.bbox[1] - b.bbox[1]) <= rowTolerance;\n if (sameRow) return a.bbox[0] - b.bbox[0] || a.bbox[1] - b.bbox[1];\n return a.bbox[1] - b.bbox[1];\n });\n\n return ordered.map((c, i): SomMark => {\n const [x, y, w, h] = c.bbox;\n const mark: SomMark = {\n index: i + 1,\n bbox: [x, y, w, h],\n center: [Math.round(x + w / 2), Math.round(y + h / 2)],\n source: c.source,\n score: c.score,\n };\n if (c.label !== undefined) (mark as { label?: string }).label = c.label;\n return mark;\n });\n}\n\n/** XML-escape a label so it is safe to embed in the SVG overlay. */\nfunction escapeXml(s: string): string {\n return s\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n\nexport interface SomOverlayOptions extends SetOfMarksOptions {\n /** Stroke / badge color for icon marks. Default \"#FF8C00\" (orange). */\n readonly iconColor?: string;\n /** Stroke / badge color for text marks. Default \"#1FA9FF\". */\n readonly textColor?: string;\n /** Box stroke width in px. Default 2. */\n readonly strokeWidth?: number;\n /** Badge font size in px. Default 13. */\n readonly fontSize?: number;\n}\n\n/**\n * Build the SVG overlay markup for a set of marks over a `width × height`\n * canvas. Pure (no I/O) — separated from the raster composite so it is\n * unit-testable and reusable by non-sharp consumers (e.g. a browser overlay).\n */\nexport function buildSetOfMarksSvg(\n marks: readonly SomMark[],\n width: number,\n height: number,\n options: SomOverlayOptions = {},\n): string {\n const iconColor = options.iconColor ?? \"#FF8C00\";\n const textColor = options.textColor ?? \"#1FA9FF\";\n const strokeWidth = options.strokeWidth ?? 2;\n const fontSize = options.fontSize ?? 13;\n const badgeW = Math.round(fontSize * 1.4);\n const badgeH = Math.round(fontSize * 1.3);\n\n const parts: string[] = [];\n for (const mark of marks) {\n const [x, y, w, h] = mark.bbox;\n const color = mark.source === \"icon\" ? iconColor : textColor;\n const label = String(mark.index);\n // Badge sits just inside the top-left of the box, clamped to the canvas.\n const bx = Math.max(0, Math.min(x, width - badgeW));\n const by = Math.max(0, Math.min(y, height - badgeH));\n parts.push(\n `<rect x=\"${x}\" y=\"${y}\" width=\"${w}\" height=\"${h}\" fill=\"none\" ` +\n `stroke=\"${color}\" stroke-width=\"${strokeWidth}\" />`,\n `<rect x=\"${bx}\" y=\"${by}\" width=\"${badgeW}\" height=\"${badgeH}\" ` +\n `fill=\"${color}\" />`,\n `<text x=\"${bx + badgeW / 2}\" y=\"${by + badgeH / 2}\" ` +\n `font-family=\"monospace\" font-size=\"${fontSize}\" font-weight=\"bold\" ` +\n `fill=\"#000000\" text-anchor=\"middle\" dominant-baseline=\"central\">` +\n `${escapeXml(label)}</text>`,\n );\n }\n return (\n `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${width}\" ` +\n `height=\"${height}\">${parts.join(\"\")}</svg>`\n );\n}\n\n// ── Source adapters ─────────────────────────────────────────────────────────\n//\n// Turn the two grounding sources we already have — GGUF YOLO icon detections\n// and `CoordOcrProvider` text blocks — into SoM candidates. Both are described\n// structurally so this module keeps no hard dependency on the detector or OCR\n// implementations (same no-hard-dep rule as `get-screen-elements.ts`).\n\n/** Structural shape of a `DetectedObject` (YOLO) — `{x,y,width,height}` box. */\nexport interface DetectedObjectLike {\n readonly boundingBox: {\n readonly x: number;\n readonly y: number;\n readonly width: number;\n readonly height: number;\n };\n readonly type?: string;\n readonly confidence?: number;\n}\n\n/** Structural shape of an OCR block (`OcrWithCoordsBlock`). */\nexport interface OcrBlockLike {\n readonly text?: string;\n readonly confidence?: number;\n readonly bbox: {\n readonly x: number;\n readonly y: number;\n readonly width: number;\n readonly height: number;\n };\n}\n\n/** Adapt GGUF YOLO detections into icon-source SoM candidates. */\nexport function somCandidatesFromDetections(\n objects: readonly DetectedObjectLike[],\n): SomCandidate[] {\n return objects.map((o) => {\n const c: SomCandidate = {\n bbox: [\n o.boundingBox.x,\n o.boundingBox.y,\n o.boundingBox.width,\n o.boundingBox.height,\n ],\n source: \"icon\",\n score: o.confidence ?? DEFAULT_SCORE,\n };\n if (o.type !== undefined) (c as { label?: string }).label = o.type;\n return c;\n });\n}\n\n/** Adapt `CoordOcrProvider` text blocks into text-source SoM candidates. */\nexport function somCandidatesFromOcr(\n blocks: readonly OcrBlockLike[],\n): SomCandidate[] {\n return blocks.map((b) => {\n const c: SomCandidate = {\n bbox: [b.bbox.x, b.bbox.y, b.bbox.width, b.bbox.height],\n source: \"text\",\n score: b.confidence ?? DEFAULT_SCORE,\n };\n if (b.text !== undefined) (c as { label?: string }).label = b.text;\n return c;\n });\n}\n\n/**\n * Convenience: fuse YOLO detections + OCR blocks straight into a numbered mark\n * set. The seam `detect_elements`/grounding calls — pass whatever icon and text\n * boxes the scene already has.\n */\nexport function buildSceneSetOfMarks(\n args: {\n readonly detections?: readonly DetectedObjectLike[];\n readonly ocrBlocks?: readonly OcrBlockLike[];\n },\n options?: SetOfMarksOptions,\n): SomMark[] {\n return buildSetOfMarks(\n [\n ...somCandidatesFromDetections(args.detections ?? []),\n ...somCandidatesFromOcr(args.ocrBlocks ?? []),\n ],\n options,\n );\n}\n\n/**\n * Composite a numbered Set-of-Marks overlay onto a source PNG.\n *\n * Returns PNG bytes the same size as the input. `sharp` is loaded lazily so the\n * pure core (`buildSetOfMarks`) carries no native dependency for consumers that\n * only need coordinates.\n */\nexport async function renderSetOfMarksOverlay(\n pngBytes: Uint8Array,\n marks: readonly SomMark[],\n options: SomOverlayOptions = {},\n): Promise<Buffer> {\n const { default: sharp } = await import(\"sharp\");\n const base = sharp(Buffer.from(pngBytes));\n const meta = await base.metadata();\n const width = meta.width ?? 0;\n const height = meta.height ?? 0;\n if (width <= 0 || height <= 0) {\n throw new Error(\n `[vision/som] cannot overlay marks: source image has no dimensions`,\n );\n }\n const svg = buildSetOfMarksSvg(marks, width, height, options);\n return base\n .composite([{ input: Buffer.from(svg), top: 0, left: 0 }])\n .png()\n .toBuffer();\n}\n",
|
|
19
|
+
"import type { Plugin } from \"@elizaos/core\";\nimport { logger, promoteSubactionsToActions } from \"@elizaos/core\";\nimport { visionAction } from \"./action\";\nimport { wireComputerUseOcrBridge } from \"./computeruse-ocr-bridge\";\nimport { LinuxTesseractOcrService } from \"./ocr-service-linux-tesseract\";\nimport { PaddleOcrService } from \"./ocr-service-paddleocr\";\nimport { WindowsMediaOcrService } from \"./ocr-service-windows\";\nimport {\n getOcrWithCoordsService,\n RapidOcrCoordAdapter,\n registerOcrWithCoordsService,\n} from \"./ocr-with-coords\";\nimport { visionProvider } from \"./provider\";\nimport { visionRoutes } from \"./routes\";\nimport { ScreenCaptureBridgeService } from \"./screen-capture-bridge\";\nimport { VisionService } from \"./service\";\nimport { wireComputerUseSetOfMarksBridge } from \"./set-of-marks-provider\";\n\ntype LocalInferenceServicesModule = {\n registerVisionContextAugmenter?: (augmenter: unknown) => void;\n};\n\nconst dynamicImport = (specifier: string) => import(specifier);\n\nexport const visionPlugin: Plugin = {\n name: \"vision\",\n description:\n \"Provides visual perception through camera integration and scene analysis\",\n services: [VisionService, ScreenCaptureBridgeService],\n providers: [visionProvider],\n routes: visionRoutes,\n actions: [...promoteSubactionsToActions(visionAction)],\n // Self-declared auto-enable: activate when features.vision is enabled OR\n // when media.vision.provider is configured.\n autoEnable: {\n shouldEnable: (_env, config) => {\n const f = (config?.features as Record<string, unknown> | undefined)\n ?.vision;\n const featureOn =\n f === true ||\n (typeof f === \"object\" &&\n f !== null &&\n (f as { enabled?: unknown }).enabled !== false);\n if (featureOn) return true;\n const media = config?.media as Record<string, unknown> | undefined;\n const visionMedia = media?.vision as\n | { enabled?: unknown; provider?: unknown }\n | undefined;\n return Boolean(\n visionMedia &&\n visionMedia.enabled !== false &&\n typeof visionMedia.provider === \"string\" &&\n visionMedia.provider.length > 0,\n );\n },\n },\n init: async (_config, _runtime) => {\n // Wire full-screen OCR-with-coords so plugin-computeruse's scene-builder\n // and GET_SCREEN can consume it. plugin-vision owns the OCR engines; it\n // registers a coord-OCR service locally and bridges it into computeruse's\n // CoordOcrProvider seam via a best-effort dynamic import (no hard dep — the\n // bridge is skipped cleanly when computeruse is not installed).\n if (!getOcrWithCoordsService()) {\n // Prefer the native OS OCR engine where available (zero LLM tokens,\n // NPU-accelerated): Windows.Media.Ocr on Windows; the classic tesseract\n // CLI on Linux when installed; otherwise the docTR / Apple-Vision chain.\n // Native providers can override via registerOcrWithCoordsService later.\n if (PaddleOcrService.isAvailable()) {\n // Opt-in alternate engine (#9581): ELIZA_VISION_OCR_BACKEND=paddleocr.\n // Cross-platform; only selected when explicitly requested so it never\n // displaces a verified default provider.\n registerOcrWithCoordsService(new PaddleOcrService());\n } else if (WindowsMediaOcrService.isAvailable()) {\n registerOcrWithCoordsService(new WindowsMediaOcrService());\n } else if (LinuxTesseractOcrService.isAvailable()) {\n registerOcrWithCoordsService(new LinuxTesseractOcrService());\n } else {\n registerOcrWithCoordsService(new RapidOcrCoordAdapter());\n }\n }\n // Vision-context fusion (#9105): register an augmenter that runs OCR +\n // object/face detection over describe-image inputs and folds the results\n // into the Gemma-4 VL prompt. plugin-local-inference owns the registry; we\n // wire into it via a best-effort dynamic import (no hard dep — skipped\n // cleanly when local-inference is not installed), same as the OCR bridge.\n try {\n const li = (await dynamicImport(\n \"@elizaos/plugin-local-inference/services\",\n )) as LocalInferenceServicesModule;\n if (typeof li.registerVisionContextAugmenter === \"function\") {\n const { createDefaultVisionAugmenter } = await import(\n \"./vision-context-augmenter.js\"\n );\n li.registerVisionContextAugmenter(createDefaultVisionAugmenter());\n logger.info(\n \"[vision] registered vision-context augmenter (OCR+object+face fusion) into IMAGE_DESCRIPTION\",\n );\n }\n } catch (err) {\n logger.debug(\n `[vision] local-inference vision-augment seam not available; describe runs unaugmented (${\n err instanceof Error ? err.message : String(err)\n })`,\n );\n }\n\n try {\n const mod = (await import(\n \"@elizaos/plugin-computeruse/mobile/ocr-provider\"\n )) as {\n registerCoordOcrProvider?: (provider: unknown) => void;\n registerSetOfMarksProvider?: (provider: unknown) => void;\n };\n if (typeof mod.registerCoordOcrProvider === \"function\") {\n wireComputerUseOcrBridge(\n mod.registerCoordOcrProvider as (provider: unknown) => void,\n );\n logger.info(\n \"[vision] registered coord-OCR bridge into plugin-computeruse scene seam\",\n );\n }\n // Set-of-Marks grounding (#9170 M9): fuse GGUF YOLO icons + OCR text into\n // numbered marks + overlay for computeruse's detect_elements.\n if (typeof mod.registerSetOfMarksProvider === \"function\") {\n wireComputerUseSetOfMarksBridge(\n mod.registerSetOfMarksProvider as (provider: unknown) => void,\n );\n logger.info(\n \"[vision] registered Set-of-Marks bridge into plugin-computeruse detect_elements seam\",\n );\n }\n } catch (err) {\n logger.debug(\n `[vision] plugin-computeruse OCR seam not available; running standalone (${\n err instanceof Error ? err.message : String(err)\n })`,\n );\n }\n },\n async dispose(runtime) {\n const svc = runtime.getService<VisionService>(VisionService.serviceType);\n await svc?.stop();\n },\n};\n\nexport default visionPlugin;\n",
|
|
20
|
+
"import {\n type Action,\n type ActionExample,\n type ActionResult,\n ContentType,\n createUniqueUuid,\n type HandlerCallback,\n type IAgentRuntime,\n isMobilePlatform,\n logger,\n type Media,\n type Memory,\n type State,\n} from \"@elizaos/core\";\nimport { buildGetScreen, summarizeGetScreen } from \"./get-screen\";\nimport { assertValidVisionImageBuffer } from \"./image-input\";\nimport {\n SCREEN_CAPTURE_BRIDGE_SERVICE_TYPE,\n type ScreenCaptureBridgeService,\n} from \"./screen-capture-bridge\";\nimport type { VisionService } from \"./service\";\nimport { VisionMode } from \"./types\";\n\nconst VISION_ACTION_TIMEOUT_MS = 10_000;\nconst MAX_VISION_TEXT_LENGTH = 4000;\nconst MAX_VISION_ENTITIES = 25;\n\nconst VISION_OPS = [\n \"describe\",\n \"capture\",\n \"get_screen\",\n \"set_mode\",\n \"enable_camera\",\n \"disable_camera\",\n \"enable_screen\",\n \"disable_screen\",\n \"name_entity\",\n \"identify_person\",\n \"track_entity\",\n] as const;\n\ntype VisionOp = (typeof VISION_OPS)[number];\n\nconst ALL_VISION_CONTEXTS = [\n \"media\",\n \"screen_time\",\n \"automation\",\n \"memory\",\n \"settings\",\n] as const;\n\nconst GET_SCREEN_KEYWORDS = [\n \"get_screen\",\n \"get screen\",\n \"read the screen\",\n \"read screen\",\n \"screen text\",\n \"text on screen\",\n \"what's on my screen\",\n \"whats on my screen\",\n \"what is on my screen\",\n \"screen contents\",\n \"ocr\",\n \"extract text\",\n];\n\nconst DESCRIBE_KEYWORDS = [\n \"describe\",\n \"scene\",\n \"see\",\n \"look\",\n \"camera\",\n \"screen\",\n \"object\",\n \"person\",\n \"escena\",\n \"ver\",\n \"camara\",\n \"décrire\",\n \"scène\",\n \"voir\",\n \"beschreiben\",\n \"szene\",\n \"sehen\",\n \"descrivi\",\n \"scena\",\n \"vedi\",\n \"説明\",\n \"見える\",\n \"场景\",\n \"描述\",\n \"看见\",\n \"장면\",\n \"설명\",\n \"보여\",\n];\n\nconst CAPTURE_KEYWORDS = [\n \"capture\",\n \"image\",\n \"photo\",\n \"picture\",\n \"snapshot\",\n \"screenshot\",\n \"camera\",\n \"captura\",\n \"foto\",\n \"imagen\",\n \"capturer\",\n \"photo\",\n \"bild\",\n \"foto\",\n \"capturare\",\n \"写真\",\n \"画像\",\n \"スクリーンショット\",\n \"拍照\",\n \"截图\",\n \"이미지\",\n \"사진\",\n \"스크린샷\",\n];\n\nconst SET_MODE_KEYWORDS = [\n \"vision\",\n \"mode\",\n \"camera\",\n \"screen\",\n \"both\",\n \"disable\",\n \"enable\",\n \"off\",\n \"visión\",\n \"camara\",\n \"pantalla\",\n \"écran\",\n \"kamera\",\n \"bildschirm\",\n \"schermo\",\n \"ビジョン\",\n \"カメラ\",\n \"画面\",\n \"视觉\",\n \"相机\",\n \"屏幕\",\n \"비전\",\n \"카메라\",\n \"화면\",\n];\n\nconst NAME_ENTITY_KEYWORDS = [\n \"name\",\n \"named\",\n \"call\",\n \"person\",\n \"entity\",\n \"remember\",\n \"object\",\n \"nombre\",\n \"llama\",\n \"persona\",\n \"nom\",\n \"appelle\",\n \"personne\",\n \"name\",\n \"nenne\",\n \"person\",\n \"nome\",\n \"chiama\",\n \"persona\",\n \"名前\",\n \"呼ぶ\",\n \"人\",\n \"命名\",\n \"叫\",\n \"人\",\n \"이름\",\n \"불러\",\n \"사람\",\n];\n\nconst IDENTIFY_PERSON_KEYWORDS = [\n \"identify\",\n \"recognize\",\n \"who is\",\n \"person\",\n \"face\",\n \"seen before\",\n \"identificar\",\n \"reconoces\",\n \"persona\",\n \"visage\",\n \"reconnais\",\n \"personne\",\n \"erkennen\",\n \"gesicht\",\n \"person\",\n \"riconosci\",\n \"persona\",\n \"識別\",\n \"誰\",\n \"顔\",\n \"识别\",\n \"是谁\",\n \"人\",\n \"식별\",\n \"누구\",\n \"얼굴\",\n];\n\nconst TRACK_ENTITY_KEYWORDS = [\n \"track\",\n \"follow\",\n \"watch\",\n \"keep an eye\",\n \"entity\",\n \"person\",\n \"object\",\n \"rastrear\",\n \"seguir\",\n \"vigilar\",\n \"persona\",\n \"suivre\",\n \"surveiller\",\n \"personne\",\n \"verfolgen\",\n \"beobachten\",\n \"person\",\n \"traccia\",\n \"segui\",\n \"persona\",\n \"追跡\",\n \"見張\",\n \"人\",\n \"跟踪\",\n \"关注\",\n \"人\",\n \"추적\",\n \"지켜봐\",\n \"사람\",\n];\n\nfunction withVisionTimeout<T>(promise: Promise<T>, label: string): Promise<T> {\n return Promise.race([\n promise,\n new Promise<never>((_, reject) =>\n setTimeout(\n () => reject(new Error(`${label} timed out`)),\n VISION_ACTION_TIMEOUT_MS,\n ),\n ),\n ]);\n}\n\nasync function saveExecutionRecord(\n runtime: IAgentRuntime,\n messageContext: Memory,\n thought: string,\n text: string,\n actions?: string[],\n attachments?: Media[],\n): Promise<void> {\n const memory: Memory = {\n id: createUniqueUuid(runtime, `vision-record-${Date.now()}`),\n content: {\n text,\n thought,\n actions: actions || [\"VISION_ANALYSIS\"],\n attachments,\n },\n entityId: createUniqueUuid(runtime, runtime.agentId),\n agentId: runtime.agentId,\n roomId: messageContext.roomId,\n worldId: messageContext.worldId,\n createdAt: Date.now(),\n };\n await runtime.createMemory(memory, \"messages\");\n}\n\nfunction readActionParams(\n options?: Record<string, unknown>,\n): Record<string, unknown> {\n const direct =\n options && typeof options === \"object\"\n ? (options as Record<string, unknown>)\n : {};\n const parameters =\n direct.parameters && typeof direct.parameters === \"object\"\n ? (direct.parameters as Record<string, unknown>)\n : {};\n return { ...direct, ...parameters };\n}\n\nfunction selectedContextMatches(\n state: State | undefined,\n contexts: readonly string[],\n): boolean {\n const selected = new Set<string>();\n const collect = (value: unknown) => {\n if (!Array.isArray(value)) return;\n for (const item of value) {\n if (typeof item === \"string\") selected.add(item);\n }\n };\n collect(\n (state?.values as Record<string, unknown> | undefined)?.selectedContexts,\n );\n collect(\n (state?.data as Record<string, unknown> | undefined)?.selectedContexts,\n );\n const contextObject = (state?.data as Record<string, unknown> | undefined)\n ?.contextObject as\n | {\n trajectoryPrefix?: { selectedContexts?: unknown };\n metadata?: { selectedContexts?: unknown };\n }\n | undefined;\n collect(contextObject?.trajectoryPrefix?.selectedContexts);\n collect(contextObject?.metadata?.selectedContexts);\n return contexts.some((context) => selected.has(context));\n}\n\nfunction visionServiceIsActive(runtime: IAgentRuntime): boolean {\n const visionService = runtime.getService<VisionService>(\"VISION\");\n return Boolean(visionService?.isActive());\n}\n\nfunction normalizeOp(value: unknown): VisionOp | null {\n if (typeof value !== \"string\") return null;\n const normalized = value\n .trim()\n .toLowerCase()\n .replace(/[\\s-]+/g, \"_\");\n if (!normalized) return null;\n const aliases: Record<string, VisionOp> = {\n describe_scene: \"describe\",\n scene: \"describe\",\n capture_image: \"capture\",\n image: \"capture\",\n photo: \"capture\",\n snapshot: \"capture\",\n screenshot: \"capture\",\n set_vision_mode: \"set_mode\",\n mode: \"set_mode\",\n vision_mode: \"set_mode\",\n camera_on: \"enable_camera\",\n turn_on_camera: \"enable_camera\",\n start_camera: \"enable_camera\",\n camera_off: \"disable_camera\",\n turn_off_camera: \"disable_camera\",\n stop_camera: \"disable_camera\",\n screen_on: \"enable_screen\",\n turn_on_screen: \"enable_screen\",\n start_screen: \"enable_screen\",\n screen_off: \"disable_screen\",\n turn_off_screen: \"disable_screen\",\n stop_screen: \"disable_screen\",\n name: \"name_entity\",\n identify: \"identify_person\",\n recognize: \"identify_person\",\n track: \"track_entity\",\n follow: \"track_entity\",\n };\n if (aliases[normalized]) return aliases[normalized];\n return (VISION_OPS as readonly string[]).includes(normalized)\n ? (normalized as VisionOp)\n : null;\n}\n\nfunction inferOpFromMessage(text: string): VisionOp | null {\n const lower = text.toLowerCase();\n if (\n NAME_ENTITY_KEYWORDS.some((k) => lower.includes(k.toLowerCase())) &&\n /\\b(call|name|named)\\b/.test(lower)\n ) {\n return \"name_entity\";\n }\n if (\n IDENTIFY_PERSON_KEYWORDS.some((k) => lower.includes(k.toLowerCase())) &&\n /\\b(who|identify|recognize)\\b/.test(lower)\n ) {\n return \"identify_person\";\n }\n if (\n TRACK_ENTITY_KEYWORDS.some((k) => lower.includes(k.toLowerCase())) &&\n /\\b(track|follow|watch|keep an eye)\\b/.test(lower)\n ) {\n return \"track_entity\";\n }\n if (\n SET_MODE_KEYWORDS.some((k) => lower.includes(k.toLowerCase())) &&\n /\\b(mode|enable|disable|turn off|turn on)\\b/.test(lower)\n ) {\n return \"set_mode\";\n }\n if (GET_SCREEN_KEYWORDS.some((k) => lower.includes(k.toLowerCase()))) {\n return \"get_screen\";\n }\n if (CAPTURE_KEYWORDS.some((k) => lower.includes(k.toLowerCase()))) {\n return \"capture\";\n }\n if (DESCRIBE_KEYWORDS.some((k) => lower.includes(k.toLowerCase()))) {\n return \"describe\";\n }\n return null;\n}\n\n/** Structural view of plugin-computeruse's screenshot capability (no hard dep). */\ninterface ComputerUseLike {\n executeCommand?: (\n command: string,\n params?: Record<string, unknown>,\n ) => Promise<{ success?: boolean; screenshot?: string; displayId?: number }>;\n}\n\n/**\n * Acquire a fresh screen frame for GET_SCREEN. Prefers plugin-computeruse's\n * verified OS screenshot (which also drives the CUA loop); falls back to the\n * vision service's own screen capture. Returns null when neither is available.\n *\n * On mobile the agent has no desktop capture sources; the renderer-pulled\n * ScreenCaptureBridgeService is the ONLY source (the renderer polls, captures\n * via the Capacitor ScreenCapture MediaProjection plugin, and POSTs the frame\n * back). Return its result directly — do not fall through to desktop sources.\n */\nasync function acquireScreenFrame(runtime: IAgentRuntime): Promise<{\n pngBytes: Uint8Array;\n displayId: number;\n capturedAt: number;\n} | null> {\n if (isMobilePlatform()) {\n const bridge = runtime.getService<ScreenCaptureBridgeService>(\n SCREEN_CAPTURE_BRIDGE_SERVICE_TYPE,\n );\n return bridge ? await bridge.requestFrame() : null;\n }\n const cu = runtime.getService(\"computeruse\") as ComputerUseLike | null;\n if (cu?.executeCommand) {\n try {\n const r = await cu.executeCommand(\"screenshot\");\n if (\n r?.success !== false &&\n typeof r?.screenshot === \"string\" &&\n r.screenshot\n ) {\n return {\n pngBytes: new Uint8Array(Buffer.from(r.screenshot, \"base64\")),\n displayId: typeof r.displayId === \"number\" ? r.displayId : 0,\n capturedAt: Date.now(),\n };\n }\n } catch (err) {\n logger.debug(\n `[vision] computeruse screenshot unavailable for get_screen (${\n err instanceof Error ? err.message : String(err)\n })`,\n );\n }\n }\n const visionService = runtime.getService<VisionService>(\"VISION\");\n const cap = await visionService?.getScreenCapture();\n if (cap?.data && cap.data.byteLength > 0) {\n return {\n pngBytes: new Uint8Array(cap.data),\n displayId: 0,\n capturedAt: cap.timestamp ?? Date.now(),\n };\n }\n return null;\n}\n\nasync function runGetScreen(\n runtime: IAgentRuntime,\n message: Memory,\n options: Record<string, unknown>,\n callback?: HandlerCallback,\n): Promise<ActionResult> {\n const includeImage = options.includeImage === true;\n const includeOcr = options.includeOcr !== false;\n const displayId =\n typeof options.displayId === \"number\" ? options.displayId : undefined;\n\n const frame = await acquireScreenFrame(runtime);\n if (!frame) {\n const thought = \"No screen capture source is available.\";\n const text =\n \"I couldn't read the screen — neither the desktop capture (plugin-computeruse) nor screen-vision mode is available right now.\";\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) await callback({ thought, text, actions: [\"VISION\"] });\n return {\n success: false,\n text: \"No screen capture source available for get_screen\",\n values: { success: false, visionAvailable: false },\n data: {\n actionName: \"VISION\",\n op: \"get_screen\",\n error: \"no_capture_source\",\n },\n };\n }\n\n const result = await buildGetScreen({\n pngBytes: frame.pngBytes,\n displayId: displayId ?? frame.displayId,\n includeImage,\n includeOcr,\n capturedAt: frame.capturedAt,\n });\n const text = summarizeGetScreen(result);\n await saveExecutionRecord(runtime, message, text, text, [\"VISION\"]);\n if (callback) await callback({ thought: text, text, actions: [\"VISION\"] });\n return {\n success: true,\n text,\n values: {\n success: true,\n visionAvailable: true,\n ocrAvailable: result.ocrAvailable,\n elementCount: result.elementCount,\n width: result.width,\n height: result.height,\n },\n data: { actionName: \"VISION\", ...result },\n };\n}\n\nasync function runDescribe(\n runtime: IAgentRuntime,\n message: Memory,\n options: Record<string, unknown>,\n callback?: HandlerCallback,\n): Promise<ActionResult> {\n const visionService = runtime.getService<VisionService>(\"VISION\");\n\n if (!visionService?.isActive()) {\n const thought =\n \"Vision service is not available or no camera is connected.\";\n const text = \"I cannot see anything right now. No camera is available.\";\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text: \"Vision service unavailable - cannot analyze scene\",\n values: {\n success: false,\n visionAvailable: false,\n error: \"Vision service not available\",\n },\n data: {\n actionName: \"VISION\",\n op: \"describe\",\n error: \"Vision service not available or no camera connected\",\n },\n };\n }\n\n try {\n const scene = await withVisionTimeout(\n visionService.getSceneDescription(),\n \"vision scene description\",\n );\n const cameraInfo = visionService.getCameraInfo();\n\n if (!scene) {\n const thought = \"Camera is connected but no scene has been analyzed yet.\";\n const text = `Camera \"${cameraInfo?.name}\" is connected, but I haven't analyzed any scenes yet. Please wait a moment.`;\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text: \"Camera connected but no scene analyzed yet\",\n values: {\n success: false,\n visionAvailable: true,\n sceneAnalyzed: false,\n cameraName: cameraInfo?.name || undefined,\n },\n data: {\n actionName: \"VISION\",\n op: \"describe\",\n cameraInfo: cameraInfo\n ? {\n id: cameraInfo.id,\n name: cameraInfo.name,\n connected: cameraInfo.connected,\n }\n : undefined,\n sceneStatus: \"not_analyzed\",\n },\n };\n }\n\n const peopleCount = scene.people.length;\n const objectCount = scene.objects.length;\n const people = scene.people.slice(0, MAX_VISION_ENTITIES);\n const objects = scene.objects.slice(0, MAX_VISION_ENTITIES);\n const timestamp = new Date(scene.timestamp).toLocaleString();\n const detailLevel =\n options.detailLevel === \"summary\" ? \"summary\" : \"detailed\";\n\n let description = `Looking through ${cameraInfo?.name || \"the camera\"}, `;\n description += scene.description;\n\n if (detailLevel === \"detailed\" && peopleCount > 0) {\n description += `\\n\\nI can see ${peopleCount} ${peopleCount === 1 ? \"person\" : \"people\"}`;\n const facingData = people.reduce(\n (acc, person) => {\n if (person.facing && person.facing !== \"unknown\") {\n acc[person.facing] = (acc[person.facing] || 0) + 1;\n }\n return acc;\n },\n {} as Record<string, number>,\n );\n\n if (Object.keys(facingData).length > 0) {\n const facingDescriptions = Object.entries(facingData).map(\n ([direction, count]) => `${count} facing ${direction}`,\n );\n description += ` (${facingDescriptions.join(\", \")})`;\n }\n description += \".\";\n }\n\n if (detailLevel === \"detailed\" && objectCount > 0) {\n const objectTypes = objects.reduce(\n (acc, obj) => {\n acc[obj.type] = (acc[obj.type] || 0) + 1;\n return acc;\n },\n {} as Record<string, number>,\n );\n\n const objectDescriptions = Object.entries(objectTypes).map(\n ([type, count]) => `${count} ${type}${count > 1 ? \"s\" : \"\"}`,\n );\n description += `\\n\\nObjects detected: ${objectDescriptions.join(\", \")}.`;\n }\n\n if (\n detailLevel === \"detailed\" &&\n scene.sceneChanged &&\n scene.changePercentage\n ) {\n description += `\\n\\n(Scene changed by ${scene.changePercentage.toFixed(1)}% since last analysis)`;\n }\n\n const thought = `Analyzed the visual scene at ${timestamp}.`;\n const text = description.slice(0, MAX_VISION_TEXT_LENGTH);\n\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n\n return {\n success: true,\n text,\n values: {\n success: true,\n visionAvailable: true,\n sceneAnalyzed: true,\n peopleCount,\n objectCount,\n cameraName: cameraInfo?.name || undefined,\n sceneChanged: scene.sceneChanged,\n changePercentage: scene.changePercentage,\n detailLevel,\n },\n data: {\n actionName: \"VISION\",\n op: \"describe\",\n sceneTimestamp: scene.timestamp,\n sceneDescription: scene.description.slice(0, MAX_VISION_TEXT_LENGTH),\n sceneChanged: scene.sceneChanged,\n changePercentage: scene.changePercentage,\n audioTranscription: scene.audioTranscription || undefined,\n objectCount: objects.length,\n peopleCount: people.length,\n cameraInfo: cameraInfo\n ? {\n id: cameraInfo.id,\n name: cameraInfo.name,\n connected: cameraInfo.connected,\n }\n : undefined,\n timestamp,\n description: text,\n },\n };\n } catch (error: unknown) {\n logger.error(\n \"[VISION/describe] Error analyzing scene:\",\n error instanceof Error ? error.message : String(error),\n );\n const thought =\n \"An error occurred while trying to analyze the visual scene.\";\n const text = `Error analyzing scene: ${error instanceof Error ? error.message : String(error)}`;\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n\n const errorMessage = error instanceof Error ? error.message : String(error);\n return {\n success: false,\n text: \"Error analyzing scene\",\n values: {\n success: false,\n visionAvailable: true,\n error: true,\n errorMessage,\n },\n data: {\n actionName: \"VISION\",\n op: \"describe\",\n error: errorMessage,\n errorType: \"analysis_error\",\n },\n };\n }\n}\n\nasync function runCapture(\n runtime: IAgentRuntime,\n message: Memory,\n callback?: HandlerCallback,\n): Promise<ActionResult> {\n const visionService = runtime.getService<VisionService>(\"VISION\");\n\n if (!visionService?.isActive()) {\n const thought =\n \"Vision service is not available or no camera is connected.\";\n const text = \"I cannot capture an image right now. No camera is available.\";\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text: \"Vision service unavailable - cannot capture image\",\n values: {\n success: false,\n visionAvailable: false,\n error: \"Vision service not available\",\n },\n data: {\n actionName: \"VISION\",\n op: \"capture\",\n error: \"Vision service not available or no camera connected\",\n },\n };\n }\n\n try {\n const imageBuffer = await Promise.race([\n visionService.captureImage(),\n new Promise<never>((_, reject) =>\n setTimeout(\n () => reject(new Error(\"vision capture timed out\")),\n VISION_ACTION_TIMEOUT_MS,\n ),\n ),\n ]);\n const cameraInfo = visionService.getCameraInfo();\n\n if (!imageBuffer) {\n const thought = \"Failed to capture image from camera.\";\n const text =\n \"I could not capture an image from the camera. Please try again.\";\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text: \"Failed to capture image from camera\",\n values: {\n success: false,\n visionAvailable: true,\n captureSuccess: false,\n },\n data: {\n actionName: \"VISION\",\n op: \"capture\",\n error: \"Camera capture failed\",\n cameraInfo: cameraInfo\n ? {\n id: cameraInfo.id,\n name: cameraInfo.name,\n connected: cameraInfo.connected,\n }\n : undefined,\n },\n };\n }\n\n const imageInfo = await assertValidVisionImageBuffer(imageBuffer);\n const attachmentId = createUniqueUuid(runtime, `capture-${Date.now()}`);\n const timestamp = new Date().toISOString();\n\n const imageAttachment: Media = {\n id: attachmentId,\n title: `Camera Capture - ${timestamp}`,\n contentType: ContentType.IMAGE,\n source: `camera:${cameraInfo?.name || \"unknown\"}`,\n url: `data:${imageInfo.contentType};base64,${imageBuffer.toString(\"base64\")}`,\n };\n\n const thought = `Captured an image from camera \"${cameraInfo?.name}\".`;\n const text = `I've captured an image from the camera at ${timestamp}.`;\n\n await saveExecutionRecord(\n runtime,\n message,\n thought,\n text,\n [\"VISION\"],\n [imageAttachment],\n );\n\n if (callback) {\n await callback({\n thought,\n text,\n actions: [\"VISION\"],\n attachments: [imageAttachment],\n });\n }\n\n return {\n success: true,\n text: `I've captured an image from the camera at ${timestamp}.`,\n values: {\n success: true,\n visionAvailable: true,\n captureSuccess: true,\n cameraName: cameraInfo?.name || undefined,\n timestamp,\n },\n data: {\n actionName: \"VISION\",\n op: \"capture\",\n imageAttachment: {\n id: imageAttachment.id,\n title: imageAttachment.title,\n contentType: imageAttachment.contentType,\n source: imageAttachment.source,\n url: imageAttachment.url,\n },\n cameraInfo: cameraInfo\n ? {\n id: cameraInfo.id,\n name: cameraInfo.name,\n connected: cameraInfo.connected,\n }\n : undefined,\n timestamp,\n },\n };\n } catch (error) {\n logger.error({ error }, \"[VISION/capture] Error capturing image:\");\n const thought = \"An error occurred while trying to capture an image.\";\n const errorMessage = error instanceof Error ? error.message : String(error);\n const text = `Error capturing image: ${errorMessage}`;\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n\n return {\n success: false,\n text: \"Error capturing image\",\n values: {\n success: false,\n visionAvailable: true,\n error: true,\n errorMessage,\n },\n data: {\n actionName: \"VISION\",\n op: \"capture\",\n error: errorMessage,\n errorType: \"capture_error\",\n },\n };\n }\n}\n\nasync function runToggleSubMode(\n runtime: IAgentRuntime,\n _message: Memory,\n op: \"enable_camera\" | \"disable_camera\" | \"enable_screen\" | \"disable_screen\",\n options: Record<string, unknown>,\n callback?: HandlerCallback,\n): Promise<ActionResult> {\n const visionService = runtime.getService<VisionService>(\"VISION\");\n if (!visionService) {\n const text = \"Vision service is not available.\";\n if (callback) await callback({ text, actions: [\"VISION\"] });\n return { success: false, text, data: { actionName: \"VISION\", op } };\n }\n try {\n const before = visionService.getVisionMode();\n if (op === \"enable_camera\") {\n await visionService.enableCamera();\n } else if (op === \"disable_camera\") {\n await visionService.disableCamera();\n } else if (op === \"enable_screen\") {\n const displayIds = Array.isArray(options.displayIds)\n ? (options.displayIds as unknown[])\n .map((v) => (typeof v === \"number\" ? v : Number(v)))\n .filter((v) => Number.isFinite(v))\n : undefined;\n await visionService.enableScreen(displayIds);\n } else {\n await visionService.disableScreen();\n }\n const after = visionService.getVisionMode();\n const text = `Vision mode: ${before} -> ${after} (${op})`;\n if (callback) await callback({ text, actions: [\"VISION\"] });\n return {\n success: true,\n text,\n values: { visionMode: after, previousMode: before, op },\n data: {\n actionName: \"VISION\",\n op,\n visionMode: after,\n previousMode: before,\n },\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n logger.error(`[VISION/${op}] error:`, errorMessage);\n if (callback) {\n await callback({\n text: `Failed to ${op}: ${errorMessage}`,\n actions: [\"VISION\"],\n });\n }\n return {\n success: false,\n text: `Failed to ${op}`,\n error: errorMessage,\n data: { actionName: \"VISION\", op, error: errorMessage },\n };\n }\n}\n\nasync function runSetMode(\n runtime: IAgentRuntime,\n message: Memory,\n options: Record<string, unknown>,\n callback?: HandlerCallback,\n): Promise<ActionResult> {\n const visionService = runtime.getService<VisionService>(\"VISION\");\n\n if (!visionService) {\n const thought = \"Vision service is not available.\";\n const text =\n \"I cannot change vision mode because the vision service is not available.\";\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text,\n data: { actionName: \"VISION\", op: \"set_mode\" },\n };\n }\n\n try {\n const explicitMode =\n typeof options.mode === \"string\" ? options.mode.toLowerCase() : \"\";\n const messageText =\n explicitMode || message.content.text?.toLowerCase() || \"\";\n let newMode: VisionMode | null = null;\n\n if (messageText.includes(\"off\") || messageText.includes(\"disable\")) {\n newMode = VisionMode.OFF;\n } else if (messageText.includes(\"both\")) {\n newMode = VisionMode.BOTH;\n } else if (messageText.includes(\"screen\")) {\n newMode = VisionMode.SCREEN;\n } else if (messageText.includes(\"camera\")) {\n newMode = VisionMode.CAMERA;\n }\n\n if (!newMode) {\n const thought =\n \"Could not determine the desired vision mode from the message.\";\n const text =\n \"Please specify the vision mode: OFF, CAMERA, SCREEN, or BOTH.\";\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text,\n data: { actionName: \"VISION\", op: \"set_mode\" },\n };\n }\n\n const currentMode = visionService.getVisionMode();\n await Promise.race([\n visionService.setVisionMode(newMode),\n new Promise<never>((_, reject) =>\n setTimeout(\n () => reject(new Error(\"vision mode change timed out\")),\n VISION_ACTION_TIMEOUT_MS,\n ),\n ),\n ]);\n\n const thought = `Changed vision mode from ${currentMode} to ${newMode}.`;\n let text = \"\";\n\n switch (newMode) {\n case VisionMode.OFF:\n text =\n \"Vision has been disabled. I will no longer process visual input.\";\n break;\n case VisionMode.CAMERA:\n text =\n \"Vision mode set to CAMERA only. I will process input from the camera.\";\n break;\n case VisionMode.SCREEN:\n text =\n \"Vision mode set to SCREEN only. I will analyze what's on your screen.\";\n break;\n case VisionMode.BOTH:\n text =\n \"Vision mode set to BOTH. I will process input from both camera and screen.\";\n break;\n }\n\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: true,\n text,\n values: { visionMode: newMode },\n data: { actionName: \"VISION\", op: \"set_mode\", visionMode: newMode },\n };\n } catch (error) {\n logger.error({ error }, \"[VISION/set_mode] Error changing vision mode:\");\n const errorMessage = error instanceof Error ? error.message : String(error);\n const thought = \"An error occurred while trying to change the vision mode.\";\n const text = `Error changing vision mode: ${errorMessage}`;\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text,\n error: errorMessage,\n data: { actionName: \"VISION\", op: \"set_mode\" },\n };\n }\n}\n\nasync function runNameEntity(\n runtime: IAgentRuntime,\n message: Memory,\n options: Record<string, unknown>,\n callback?: HandlerCallback,\n): Promise<ActionResult> {\n try {\n const visionService = runtime.getService<VisionService>(\"VISION\");\n\n if (!visionService) {\n const thought = \"Vision service is not available.\";\n const text =\n \"I cannot name entities because the vision service is not available.\";\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text,\n data: { actionName: \"VISION\", op: \"name_entity\" },\n };\n }\n\n const scene = await withVisionTimeout(\n visionService.getSceneDescription(),\n \"vision scene description\",\n );\n\n if (!scene || scene.people.length === 0) {\n const thought = \"No people visible to name.\";\n const text = \"I don't see any people in the current scene to name.\";\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text,\n data: { actionName: \"VISION\", op: \"name_entity\" },\n };\n }\n\n const messageText = message.content.text?.toLowerCase() || \"\";\n const explicitName =\n typeof options.name === \"string\" ? options.name.trim() : \"\";\n const nameMatch = explicitName\n ? [explicitName, explicitName]\n : messageText.match(/(?:named?|call(?:ed)?|is)\\s+(\\w+)/i);\n\n if (!nameMatch) {\n const thought = \"Could not extract name from message.\";\n const text =\n 'I couldn\\'t understand what name to assign. Please say something like \"The person is named Alice\".';\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text,\n data: { actionName: \"VISION\", op: \"name_entity\" },\n };\n }\n\n const name = nameMatch[1];\n const entityTracker = visionService.getEntityTracker();\n\n await entityTracker.updateEntities(\n scene.objects.slice(0, MAX_VISION_ENTITIES),\n scene.people.slice(0, MAX_VISION_ENTITIES),\n undefined,\n runtime,\n );\n const activeEntities = entityTracker.getActiveEntities();\n const people = activeEntities.filter((e) => e.entityType === \"person\");\n\n if (people.length === 0) {\n const thought = \"No tracked people found.\";\n const text =\n \"I can see someone but haven't established tracking yet. Please try again in a moment.\";\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text,\n data: { actionName: \"VISION\", op: \"name_entity\" },\n };\n }\n\n let targetPerson = people[0];\n if (people.length > 1) {\n targetPerson = people.reduce((prev, curr) => {\n const prevArea = prev.lastPosition.width * prev.lastPosition.height;\n const currArea = curr.lastPosition.width * curr.lastPosition.height;\n return currArea > prevArea ? curr : prev;\n });\n }\n\n const success = entityTracker.assignNameToEntity(targetPerson.id, name);\n\n if (success) {\n const thought = `Named entity \"${name}\" and associated with person in scene.`;\n const text = `I've identified the person as ${name}. I'll remember them for future interactions.`;\n\n await saveExecutionRecord(\n runtime,\n message,\n thought,\n text,\n [\"VISION\"],\n undefined,\n );\n\n if (callback) {\n await callback({\n thought,\n text,\n actions: [\"VISION\"],\n data: { entityId: targetPerson.id, name },\n });\n }\n\n logger.info(\n `[VISION/name_entity] Assigned name \"${name}\" to entity ${targetPerson.id}`,\n );\n return {\n success: true,\n text,\n values: { entityId: targetPerson.id, name },\n data: {\n actionName: \"VISION\",\n op: \"name_entity\",\n entityId: targetPerson.id,\n name,\n },\n };\n } else {\n const thought = \"Failed to assign name to entity.\";\n const text = \"There was an error assigning the name. Please try again.\";\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text,\n data: { actionName: \"VISION\", op: \"name_entity\" },\n };\n }\n } catch (error) {\n logger.error({ error }, \"[VISION/name_entity] Error:\");\n const thought = \"Failed to name entity.\";\n const text = `Sorry, I couldn't name the entity: ${error instanceof Error ? error.message : \"Unknown error\"}`;\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text,\n error: error instanceof Error ? error.message : String(error),\n data: { actionName: \"VISION\", op: \"name_entity\" },\n };\n }\n}\n\nasync function runIdentifyPerson(\n runtime: IAgentRuntime,\n message: Memory,\n callback?: HandlerCallback,\n): Promise<ActionResult> {\n try {\n const visionService = runtime.getService<VisionService>(\"VISION\");\n\n if (!visionService) {\n const thought = \"Vision service is not available.\";\n const text =\n \"I cannot identify people because the vision service is not available.\";\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text,\n data: { actionName: \"VISION\", op: \"identify_person\" },\n };\n }\n\n const scene = await withVisionTimeout(\n visionService.getSceneDescription(),\n \"vision scene description\",\n );\n\n if (!scene || scene.people.length === 0) {\n const thought = \"No people visible to identify.\";\n const text = \"I don't see any people in the current scene.\";\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text,\n data: { actionName: \"VISION\", op: \"identify_person\" },\n };\n }\n\n const entityTracker = visionService.getEntityTracker();\n\n await entityTracker.updateEntities(\n scene.objects.slice(0, MAX_VISION_ENTITIES),\n scene.people.slice(0, MAX_VISION_ENTITIES),\n undefined,\n runtime,\n );\n const activeEntities = entityTracker.getActiveEntities();\n const people = activeEntities.filter((e) => e.entityType === \"person\");\n\n if (people.length === 0) {\n const thought = \"No tracked people found.\";\n const text = \"I can see someone but I'm still processing their identity.\";\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text,\n data: { actionName: \"VISION\", op: \"identify_person\" },\n };\n }\n\n let recognizedCount = 0;\n let unknownCount = 0;\n const identifications: string[] = [];\n\n for (const person of people) {\n const name = person.attributes.name;\n const duration = Date.now() - person.firstSeen;\n const durationStr =\n duration < 60000\n ? `${Math.round(duration / 1000)} seconds`\n : `${Math.round(duration / 60000)} minutes`;\n\n if (name) {\n recognizedCount++;\n const personInfo = `I can see ${name}. They've been here for ${durationStr}.`;\n identifications.push(personInfo);\n\n if (person.appearances.length > 5) {\n identifications.push(\"I've been tracking them consistently.\");\n }\n } else {\n unknownCount++;\n const personInfo = `I see an unidentified person who has been here for ${durationStr}.`;\n identifications.push(personInfo);\n\n if (person.attributes.faceId) {\n identifications.push(\n \"I've captured their face profile but they haven't been named yet.\",\n );\n }\n }\n }\n\n const recentlyLeft = entityTracker.getRecentlyLeft();\n if (recentlyLeft.length > 0) {\n identifications.push(\"\\nRecently departed:\");\n for (const { entity, leftAt } of recentlyLeft) {\n if (entity.entityType === \"person\" && entity.attributes.name) {\n const timeAgo = Date.now() - leftAt;\n const timeStr =\n timeAgo < 60000\n ? `${Math.round(timeAgo / 1000)} seconds ago`\n : `${Math.round(timeAgo / 60000)} minutes ago`;\n identifications.push(`${entity.attributes.name} left ${timeStr}.`);\n }\n }\n }\n\n const thought = `Identified ${recognizedCount} known people and ${unknownCount} unknown people.`;\n const text = identifications.join(\" \");\n\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n\n if (callback) {\n await callback({\n thought,\n text,\n actions: [\"VISION\"],\n data: {\n identifications: people.slice(0, MAX_VISION_ENTITIES).map((p) => ({\n id: p.id,\n entityType: p.entityType,\n name: p.attributes.name || undefined,\n })),\n },\n });\n }\n return {\n success: true,\n text,\n values: { recognizedCount, unknownCount },\n data: {\n actionName: \"VISION\",\n op: \"identify_person\",\n recognizedCount,\n unknownCount,\n },\n };\n } catch (error) {\n logger.error({ error }, \"[VISION/identify_person] Error:\");\n const thought = \"Failed to identify people.\";\n const text = `Sorry, I couldn't identify people: ${error instanceof Error ? error.message : \"Unknown error\"}`;\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text,\n error: error instanceof Error ? error.message : String(error),\n data: { actionName: \"VISION\", op: \"identify_person\" },\n };\n }\n}\n\nasync function runTrackEntity(\n runtime: IAgentRuntime,\n message: Memory,\n callback?: HandlerCallback,\n): Promise<ActionResult> {\n try {\n const visionService = runtime.getService<VisionService>(\"VISION\");\n\n if (!visionService) {\n const thought = \"Vision service is not available.\";\n const text =\n \"I cannot track entities because the vision service is not available.\";\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text,\n data: { actionName: \"VISION\", op: \"track_entity\" },\n };\n }\n\n const scene = await withVisionTimeout(\n visionService.getSceneDescription(),\n \"vision scene description\",\n );\n\n if (!scene) {\n const thought = \"No scene available for tracking.\";\n const text =\n \"I need a moment to process the visual scene before I can track entities.\";\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text,\n data: { actionName: \"VISION\", op: \"track_entity\" },\n };\n }\n\n const entityTracker = visionService.getEntityTracker();\n await entityTracker.updateEntities(\n scene.objects.slice(0, MAX_VISION_ENTITIES),\n scene.people.slice(0, MAX_VISION_ENTITIES),\n undefined,\n runtime,\n );\n const stats = entityTracker.getStatistics();\n\n const thought = `Tracking ${stats.activeEntities} entities in the scene.`;\n const summary = [\n `I'm now tracking ${stats.activeEntities} entities in the scene`,\n `(${stats.people} people, ${stats.objects} objects).`,\n \"The visual tracking system will maintain persistent IDs for all entities\",\n \"and notify you of significant changes.\",\n ];\n const responseText = summary.join(\" \");\n\n await saveExecutionRecord(runtime, message, thought, responseText, [\n \"VISION\",\n ]);\n\n if (callback) {\n await callback({\n thought,\n text: responseText,\n actions: [\"VISION\"],\n data: { entities: stats.activeEntities },\n });\n }\n\n logger.info(\n `[VISION/track_entity] Tracking ${stats.activeEntities} entities`,\n );\n return {\n success: true,\n text: responseText,\n values: {\n activeEntities: stats.activeEntities,\n people: stats.people,\n objects: stats.objects,\n },\n data: {\n actionName: \"VISION\",\n op: \"track_entity\",\n activeEntities: stats.activeEntities,\n people: stats.people,\n objects: stats.objects,\n },\n };\n } catch (error) {\n logger.error({ error }, \"[VISION/track_entity] Error:\");\n const thought = \"Failed to track entities.\";\n const text = `Sorry, I couldn't track entities: ${error instanceof Error ? error.message : \"Unknown error\"}`;\n await saveExecutionRecord(runtime, message, thought, text, [\"VISION\"]);\n if (callback) {\n await callback({ thought, text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text,\n error: error instanceof Error ? error.message : String(error),\n data: { actionName: \"VISION\", op: \"track_entity\" },\n };\n }\n}\n\nexport const visionAction: Action = {\n name: \"VISION\",\n contexts: [...ALL_VISION_CONTEXTS],\n contextGate: { anyOf: [...ALL_VISION_CONTEXTS] },\n roleGate: { minRole: \"USER\" },\n similes: [\n \"DESCRIBE_SCENE\",\n \"CAPTURE_IMAGE\",\n \"SET_VISION_MODE\",\n \"NAME_ENTITY\",\n \"IDENTIFY_PERSON\",\n \"TRACK_ENTITY\",\n \"ANALYZE_SCENE\",\n \"WHAT_DO_YOU_SEE\",\n \"VISION_CHECK\",\n \"LOOK_AROUND\",\n \"TAKE_PHOTO\",\n \"SCREENSHOT\",\n \"CAPTURE_FRAME\",\n \"TAKE_PICTURE\",\n \"GET_SCREEN\",\n \"READ_SCREEN\",\n \"SCREEN_TEXT\",\n \"OCR_SCREEN\",\n ],\n description:\n \"Camera and screen vision: describe the current scene, capture an image, GET_SCREEN (token-frugal structured readout — OCR text + grounded UI elements with coordinates, no image unless includeImage=true), switch vision mode (off/camera/screen/both), name a visible entity, identify a person, or start tracking an entity. The action is inferred from the message text when not explicitly provided.\",\n descriptionCompressed:\n \"Vision: describe / capture / get_screen (OCR+elements, no image) / set_mode / name_entity / identify_person / track_entity.\",\n parameters: [\n {\n name: \"action\",\n description:\n \"Operation to perform: describe, capture, set_mode, name_entity, identify_person, or track_entity. Inferred from message text when omitted.\",\n required: false,\n schema: { type: \"string\", enum: [...VISION_OPS] },\n },\n {\n name: \"subaction\",\n description: \"Legacy alias for action.\",\n required: false,\n schema: { type: \"string\", enum: [...VISION_OPS] },\n },\n {\n name: \"detailLevel\",\n description:\n \"For action=describe: 'summary' to omit object/person breakdowns, 'detailed' for the full breakdown.\",\n required: false,\n schema: {\n type: \"string\",\n enum: [\"summary\", \"detailed\"],\n default: \"detailed\",\n },\n },\n {\n name: \"includeImage\",\n description:\n \"For action=get_screen: when true, attach the base64 screenshot too (costs image tokens). Default false — return only OCR text + grounded elements.\",\n required: false,\n schema: { type: \"boolean\", default: false },\n },\n {\n name: \"mode\",\n description:\n \"For action=set_mode: vision mode to set: off, camera, screen, or both.\",\n required: false,\n schema: { type: \"string\", enum: [\"off\", \"camera\", \"screen\", \"both\"] },\n },\n {\n name: \"name\",\n description:\n \"For action=name_entity: the name to assign to the most relevant visible person or object.\",\n required: false,\n schema: { type: \"string\" },\n },\n {\n name: \"targetHint\",\n description:\n \"For action=name_entity or action=identify_person: optional phrase describing which visible entity to focus on.\",\n required: false,\n schema: { type: \"string\" },\n },\n {\n name: \"description\",\n description:\n \"For action=track_entity: optional description of the visible entity to prioritize for tracking.\",\n required: false,\n schema: { type: \"string\" },\n },\n {\n name: \"includeUnknown\",\n description:\n \"For action=identify_person: whether to mention unidentified people in the response.\",\n required: false,\n schema: { type: \"boolean\", default: true },\n },\n ],\n validate: async (\n runtime: IAgentRuntime,\n _message: Memory,\n state?: State,\n options?: Record<string, unknown>,\n ): Promise<boolean> => {\n if (!visionServiceIsActive(runtime)) {\n // set_mode does not require active vision; allow if service is registered.\n const visionService = runtime.getService<VisionService>(\"VISION\");\n if (!visionService) return false;\n }\n const params = readActionParams(options);\n return (\n selectedContextMatches(state, ALL_VISION_CONTEXTS) ||\n typeof params.action === \"string\" ||\n typeof params.op === \"string\" ||\n typeof params.subaction === \"string\"\n );\n },\n handler: async (\n runtime: IAgentRuntime,\n message: Memory,\n _state?: State,\n _options?: Record<string, unknown>,\n callback?: HandlerCallback,\n _responses?: Memory[],\n ): Promise<ActionResult> => {\n const params = readActionParams(_options);\n const explicitOp = normalizeOp(\n params.action ?? params.subaction ?? params.op,\n );\n const inferredOp =\n explicitOp ?? inferOpFromMessage(message.content?.text ?? \"\");\n\n if (!inferredOp) {\n const text = `VISION could not determine the operation. Specify one of: ${VISION_OPS.join(\", \")}.`;\n if (callback) {\n await callback({ text, actions: [\"VISION\"] });\n }\n return {\n success: false,\n text,\n values: { error: \"MISSING\" },\n data: {\n actionName: \"VISION\",\n availableOps: VISION_OPS,\n },\n };\n }\n\n switch (inferredOp) {\n case \"describe\":\n return runDescribe(runtime, message, params, callback);\n case \"capture\":\n return runCapture(runtime, message, callback);\n case \"get_screen\":\n return runGetScreen(runtime, message, params, callback);\n case \"set_mode\":\n return runSetMode(runtime, message, params, callback);\n case \"enable_camera\":\n case \"disable_camera\":\n case \"enable_screen\":\n case \"disable_screen\":\n return runToggleSubMode(runtime, message, inferredOp, params, callback);\n case \"name_entity\":\n return runNameEntity(runtime, message, params, callback);\n case \"identify_person\":\n return runIdentifyPerson(runtime, message, callback);\n case \"track_entity\":\n return runTrackEntity(runtime, message, callback);\n }\n },\n examples: [\n [\n { name: \"{{user}}\", content: { text: \"what do you see?\" } },\n {\n name: \"{{agent}}\",\n content: {\n actions: [\"VISION\"],\n thought: \"The user wants to know what I can see through my camera.\",\n text: \"I see a room with a desk and computer setup. There are 2 people, one is sitting and one is standing.\",\n },\n },\n ],\n [\n { name: \"{{user}}\", content: { text: \"take a photo\" } },\n {\n name: \"{{agent}}\",\n content: {\n actions: [\"VISION\"],\n thought: \"The user wants me to capture an image from the camera.\",\n text: \"I've captured an image from the camera.\",\n },\n },\n ],\n [\n { name: \"{{user}}\", content: { text: \"set vision mode to screen\" } },\n {\n name: \"{{agent}}\",\n content: {\n actions: [\"VISION\"],\n thought: \"The user wants to switch to screen vision mode.\",\n text: \"Vision mode set to SCREEN only. I will analyze what's on your screen.\",\n },\n },\n ],\n [\n {\n name: \"{{user}}\",\n content: { text: \"the person wearing the blue shirt is named Alice\" },\n },\n {\n name: \"{{agent}}\",\n content: {\n actions: [\"VISION\"],\n text: \"I've identified the person in the blue shirt as Alice. I'll remember them for future interactions.\",\n },\n },\n ],\n [\n {\n name: \"{{user}}\",\n content: { text: \"who is the person in front of you?\" },\n },\n {\n name: \"{{agent}}\",\n content: {\n actions: [\"VISION\"],\n text: \"That's Alice. I last saw her about 5 minutes ago.\",\n },\n },\n ],\n [\n {\n name: \"{{user}}\",\n content: { text: \"track the person wearing the red shirt\" },\n },\n {\n name: \"{{agent}}\",\n content: {\n actions: [\"VISION\"],\n text: \"I'm now tracking the person in the red shirt.\",\n },\n },\n ],\n ] as ActionExample[][],\n};\n",
|
|
21
|
+
"/**\n * GET_SCREEN core (issue #9105 / M2) — token-frugal structured screen readout.\n *\n * Returns OCR text + grounded elements (id/text/bbox/semantic position) from a\n * captured frame using the registered coord-OCR service (native Windows OCR /\n * docTR / Apple Vision — zero LLM tokens). The raw image is OMITTED by default\n * (`includeImage:false`) so a CUA loop can read the screen each tick without\n * spending image tokens; it is only base64-attached when explicitly requested.\n *\n * Pure + injectable (the OCR service can be passed in) so it is unit-testable\n * without a real capture or a registered provider.\n */\n\nimport {\n getOcrWithCoordsService,\n type OcrWithCoordsService,\n readPngDimensions,\n} from \"./ocr-with-coords.js\";\n\nexport interface GetScreenElement {\n /**\n * Monotonic 1-based Set-of-Marks number (reading order). A model can pick\n * `[3]` instead of regressing raw coordinates.\n */\n index: number;\n /** Stable per-result id. */\n id: string;\n text: string;\n /** Display-absolute [x, y, width, height]. */\n bbox: [number, number, number, number];\n /** Click target — the integer center of `bbox`, the point `index` resolves to. */\n center: { x: number; y: number };\n semantic_position: string;\n displayId: number;\n}\n\nexport interface GetScreenResult {\n op: \"get_screen\";\n displayId: number;\n width: number;\n height: number;\n /** When the source frame was captured (ms epoch). */\n lastChangeTime: number;\n /** True when a coord-OCR provider was available and ran. */\n ocrAvailable: boolean;\n ocrText: string;\n elements: GetScreenElement[];\n elementCount: number;\n /** Base64 PNG — only present when `includeImage` was requested. */\n image?: string;\n}\n\nexport interface BuildGetScreenOptions {\n pngBytes: Uint8Array;\n displayId?: number;\n includeImage?: boolean;\n includeOcr?: boolean;\n capturedAt?: number;\n /** Override for tests; defaults to the registered coord-OCR service. */\n ocrService?: OcrWithCoordsService | null;\n}\n\nexport async function buildGetScreen(\n opts: BuildGetScreenOptions,\n): Promise<GetScreenResult> {\n const displayId = opts.displayId ?? 0;\n const includeOcr = opts.includeOcr ?? true;\n const includeImage = opts.includeImage ?? false;\n const capturedAt = opts.capturedAt ?? 0;\n\n const dims = (await readPngDimensions(opts.pngBytes)) ?? {\n width: 0,\n height: 0,\n };\n\n const service =\n opts.ocrService !== undefined ? opts.ocrService : getOcrWithCoordsService();\n\n let elements: GetScreenElement[] = [];\n let ocrText = \"\";\n let ocrAvailable = false;\n\n if (includeOcr && service && opts.pngBytes.byteLength > 0) {\n ocrAvailable = true;\n const result = await service.describe({\n displayId: String(displayId),\n sourceX: 0,\n sourceY: 0,\n pngBytes: opts.pngBytes,\n });\n elements = result.blocks.map((block, i) => ({\n index: i + 1,\n id: `el-${i + 1}`,\n text: block.text,\n bbox: [block.bbox.x, block.bbox.y, block.bbox.width, block.bbox.height],\n center: {\n x: Math.round(block.bbox.x + block.bbox.width / 2),\n y: Math.round(block.bbox.y + block.bbox.height / 2),\n },\n semantic_position: block.semantic_position,\n displayId,\n }));\n ocrText = elements.map((e) => e.text).join(\"\\n\");\n }\n\n const out: GetScreenResult = {\n op: \"get_screen\",\n displayId,\n width: dims.width,\n height: dims.height,\n lastChangeTime: capturedAt,\n ocrAvailable,\n ocrText,\n elements,\n elementCount: elements.length,\n };\n if (includeImage && opts.pngBytes.byteLength > 0) {\n out.image = Buffer.from(opts.pngBytes).toString(\"base64\");\n }\n return out;\n}\n\n/** Human-readable one-line summary for the agent reply. */\nexport function summarizeGetScreen(r: GetScreenResult): string {\n if (!r.ocrAvailable) {\n return `Screen captured (${r.width}x${r.height}). No OCR provider is registered, so no text was extracted.`;\n }\n if (r.elementCount === 0) {\n return `Screen captured (${r.width}x${r.height}); no text was detected on it.`;\n }\n const preview = r.elements\n .slice(0, 8)\n .filter((e) => e.text)\n .map((e) => `[${e.index}] ${e.text}`)\n .join(\" | \");\n return `Screen captured (${r.width}x${r.height}). ${r.elementCount} text element(s) detected: ${preview}${r.elementCount > 8 ? \" …\" : \"\"}`;\n}\n",
|
|
22
|
+
"// Android agent-triggered screen-capture bridge (renderer-pulled).\n//\n// On Android the agent runs in a musl bun process with no Capacitor and no\n// agent->renderer push channel (the local-IPC base never opens a WebSocket).\n// So screen capture is renderer-PULLED: the agent enqueues a capture request\n// here; the renderer interval-polls `GET /api/vision/capture-requests`, takes a\n// frame via the Capacitor ScreenCapture plugin (MediaProjection), and POSTs the\n// PNG back to `POST /api/vision/screen-frame`, which calls `submitFrame` to\n// resolve the matching pending promise. The JNI loopback already forwards any\n// `/api/...` path, so no Java/Kotlin change is needed.\n\nimport { type IAgentRuntime, logger, Service } from \"@elizaos/core\";\n\n/** Service type used to resolve the bridge off the runtime. */\nexport const SCREEN_CAPTURE_BRIDGE_SERVICE_TYPE =\n \"vision-screen-capture-bridge\";\n\n/**\n * How long a `requestFrame` promise waits for the renderer to deliver a frame\n * before resolving `null`. The first capture has to wait on the Android\n * MediaProjection consent dialog, so this is generous.\n */\nconst REQUEST_FRAME_TIMEOUT_MS = 30_000;\n\n/** A single enqueued capture request, drained by the GET poll. */\nexport interface ScreenCaptureRequest {\n requestId: string;\n createdAt: number;\n displayId?: number;\n}\n\n/** Result of a completed capture, returned to `requestFrame` callers. */\nexport interface ScreenCaptureFrame {\n pngBytes: Uint8Array;\n displayId: number;\n capturedAt: number;\n}\n\ninterface PendingCapture {\n resolve: (frame: ScreenCaptureFrame | null) => void;\n displayId: number;\n timer: ReturnType<typeof setTimeout>;\n}\n\n/**\n * Renderer-pulled screen-capture bridge service.\n *\n * The agent calls `requestFrame()`; the renderer drains the queue via\n * `takeRequests()` and delivers frames via `submitFrame()`.\n */\nexport class ScreenCaptureBridgeService extends Service {\n static override serviceType: string = SCREEN_CAPTURE_BRIDGE_SERVICE_TYPE;\n override capabilityDescription =\n \"Renderer-pulled bridge for agent-triggered Android screen capture.\";\n\n private readonly queue: ScreenCaptureRequest[] = [];\n private readonly pending = new Map<string, PendingCapture>();\n private readonly timeoutMs: number;\n\n constructor(\n runtime?: IAgentRuntime,\n timeoutMs: number = REQUEST_FRAME_TIMEOUT_MS,\n ) {\n super(runtime);\n this.timeoutMs = timeoutMs;\n }\n\n static async start(\n runtime: IAgentRuntime,\n ): Promise<ScreenCaptureBridgeService> {\n return new ScreenCaptureBridgeService(runtime);\n }\n\n /**\n * Enqueue a capture request and wait for the renderer to deliver a frame.\n * Resolves `null` if no frame arrives within the timeout (never hangs).\n */\n requestFrame(displayId?: number): Promise<ScreenCaptureFrame | null> {\n const requestId = crypto.randomUUID();\n const request: ScreenCaptureRequest = {\n requestId,\n createdAt: Date.now(),\n };\n if (typeof displayId === \"number\") request.displayId = displayId;\n this.queue.push(request);\n\n return new Promise<ScreenCaptureFrame | null>((resolve) => {\n const timer = setTimeout(() => {\n this.pending.delete(requestId);\n logger.debug(\n `[ScreenCaptureBridgeService] capture request ${requestId} timed out after ${this.timeoutMs}ms`,\n );\n resolve(null);\n }, this.timeoutMs);\n // Do not keep the event loop alive solely for a pending capture.\n if (typeof timer.unref === \"function\") timer.unref();\n this.pending.set(requestId, {\n resolve,\n displayId: typeof displayId === \"number\" ? displayId : 0,\n timer,\n });\n });\n }\n\n /** Drain and return all queued requests (for the GET poll). */\n takeRequests(): ScreenCaptureRequest[] {\n return this.queue.splice(0, this.queue.length);\n }\n\n /**\n * Deliver a captured frame for a queued request. Returns false if the\n * requestId is unknown or already expired/resolved.\n */\n submitFrame(\n requestId: string,\n base64: string,\n _format: string,\n _width: number,\n _height: number,\n ): boolean {\n const pendingCapture = this.pending.get(requestId);\n if (!pendingCapture) return false;\n this.pending.delete(requestId);\n clearTimeout(pendingCapture.timer);\n const pngBytes = new Uint8Array(Buffer.from(base64, \"base64\"));\n pendingCapture.resolve({\n pngBytes,\n displayId: pendingCapture.displayId,\n capturedAt: Date.now(),\n });\n return true;\n }\n\n /**\n * Resolve a queued request as a skip/failure so the agent's pending promise\n * settles promptly (as `null`) instead of waiting the full timeout. The\n * renderer calls this when a capture throws or is unavailable. Returns false\n * for unknown/expired requestIds.\n */\n failFrame(requestId: string, reason: string): boolean {\n const pendingCapture = this.pending.get(requestId);\n if (!pendingCapture) return false;\n this.pending.delete(requestId);\n clearTimeout(pendingCapture.timer);\n logger.debug(\n `[ScreenCaptureBridgeService] capture request ${requestId} failed: ${reason}`,\n );\n pendingCapture.resolve(null);\n return true;\n }\n\n async stop(): Promise<void> {\n this.queue.length = 0;\n for (const [requestId, pendingCapture] of this.pending) {\n clearTimeout(pendingCapture.timer);\n pendingCapture.resolve(null);\n this.pending.delete(requestId);\n }\n }\n}\n",
|
|
23
|
+
"import type { DescribePauseReason } from \"./describe-backpressure\";\n\nexport const VisionServiceType = {\n VISION: \"VISION\" as const,\n};\n\ndeclare module \"@elizaos/core\" {\n interface ServiceTypeRegistry {\n VISION: \"VISION\";\n }\n}\n\nexport interface CameraInfo {\n id: string;\n name: string;\n connected: boolean;\n}\n\nexport interface SceneDescription {\n /** Freshest processed frame timestamp for object/person/change signals. */\n timestamp: number;\n /** Timestamp of the VLM prose in `description`; may be older than frame data. */\n descriptionTimestamp?: number;\n description: string;\n objects: DetectedObject[];\n people: PersonInfo[];\n sceneChanged: boolean;\n changePercentage: number;\n /** True when the VLM prose was reused after a describe skip. */\n descriptionStale?: boolean;\n /** True when the VLM describe step is currently paused by backpressure. */\n describePaused?: boolean;\n describePauseReason?: Exclude<DescribePauseReason, null>;\n audioTranscription?: string;\n}\n\nexport interface DetectedObject {\n id: string;\n type: string;\n confidence: number;\n boundingBox: BoundingBox;\n}\n\nexport interface PersonInfo {\n id: string;\n pose: \"sitting\" | \"standing\" | \"lying\" | \"unknown\";\n facing: \"camera\" | \"away\" | \"left\" | \"right\" | \"unknown\";\n confidence: number;\n boundingBox: BoundingBox;\n keypoints?: Array<{\n part: string;\n position: { x: number; y: number };\n score: number;\n }>;\n}\n\nexport interface BoundingBox {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport interface VisionFrame {\n timestamp: number;\n width: number;\n height: number;\n data: Buffer;\n format: \"rgb\" | \"rgba\" | \"jpeg\" | \"png\";\n}\n\nexport enum VisionMode {\n OFF = \"OFF\",\n CAMERA = \"CAMERA\",\n SCREEN = \"SCREEN\",\n BOTH = \"BOTH\",\n}\n\n// Screen capture types\nexport interface ScreenCapture {\n timestamp: number;\n width: number;\n height: number;\n data: Buffer;\n tiles: ScreenTile[];\n}\n\nexport interface ScreenTile {\n id: string;\n row: number;\n col: number;\n /** Tile origin X within the source capture (display-local pixels). */\n x: number;\n /** Tile origin Y within the source capture (display-local pixels). */\n y: number;\n width: number;\n height: number;\n data?: Buffer;\n analysis?: TileAnalysis;\n /**\n * Source display id, when the tile came from a per-display capture pass.\n * Stringified so opaque platform ids (CGDirectDisplayID, sway output names)\n * round-trip without lossy coercion.\n */\n displayId?: string;\n /**\n * Absolute pixel X of the tile origin in the source display's native space.\n * Same value as `x` when `displayId` refers to a single-display capture; it\n * becomes load-bearing once the capture pipeline composes per-display\n * screenshots into a multi-monitor stream.\n */\n sourceX?: number;\n /** Absolute pixel Y of the tile origin in the source display's native space. */\n sourceY?: number;\n}\n\nexport interface TileAnalysis {\n timestamp: number;\n ocr?: OCRResult;\n objects?: DetectedObject[];\n text?: string;\n summary?: string;\n}\n\nexport interface OCRResult {\n text: string;\n blocks: Array<{\n text: string;\n bbox: BoundingBox;\n confidence: number;\n words?: Array<{\n text: string;\n bbox: BoundingBox;\n confidence: number;\n }>;\n }>;\n fullText: string;\n}\n\nexport interface EnhancedSceneDescription extends SceneDescription {\n screenCapture?: ScreenCapture;\n screenAnalysis?: {\n fullScreenOCR?: string;\n activeTile?: TileAnalysis;\n gridSummary?: string;\n focusedApp?: string;\n uiElements?: Array<{\n type: string;\n text: string;\n position: BoundingBox;\n }>;\n };\n}\n\nexport interface VisionConfig {\n cameraName?: string;\n pixelChangeThreshold?: number;\n updateInterval?: number;\n enablePoseDetection?: boolean;\n enableObjectDetection?: boolean;\n tfUpdateInterval?: number;\n vlmUpdateInterval?: number;\n tfChangeThreshold?: number;\n vlmChangeThreshold?: number;\n visionMode?: VisionMode;\n screenCaptureInterval?: number;\n tileSize?: number;\n tileProcessingOrder?: \"sequential\" | \"priority\" | \"random\";\n ocrEnabled?: boolean;\n screenRegion?: {\n x: number;\n y: number;\n width: number;\n height: number;\n };\n displayIndex?: number;\n captureAllDisplays?: boolean;\n targetScreenFPS?: number;\n textRegions?: Array<{\n x: number;\n y: number;\n width: number;\n height: number;\n }>;\n}\n\nexport interface TrackedEntity {\n id: string;\n entityType: \"person\" | \"object\" | \"pet\";\n firstSeen: number;\n lastSeen: number;\n lastPosition: BoundingBox;\n appearances: EntityAppearance[];\n attributes: EntityAttributes;\n worldId?: string;\n roomId?: string;\n}\n\ninterface EntityAppearance {\n timestamp: number;\n boundingBox: BoundingBox;\n confidence: number;\n embedding?: number[]; // Face embedding for person recognition\n keypoints?: Array<{\n part: string;\n position: { x: number; y: number };\n score: number;\n }>;\n}\n\nexport interface EntityAttributes {\n [key: string]:\n | string\n | number\n | boolean\n | null\n | undefined\n | string[]\n | number[];\n name?: string;\n faceEmbedding?: number[];\n faceId?: string;\n clothing?: string[];\n hairColor?: string;\n accessories?: string[];\n\n // For objects\n objectType?: string;\n color?: string;\n size?: \"small\" | \"medium\" | \"large\";\n description?: string;\n tags?: string[];\n}\n\nexport interface FaceLibrary {\n faces: Map<string, FaceProfile>;\n embeddings: Map<string, number[][]>; // Multiple embeddings per profile\n}\n\nexport interface FaceProfile {\n id: string;\n name?: string;\n embeddings: number[][]; // Multiple embeddings for better recognition\n firstSeen: number;\n lastSeen: number;\n seenCount: number;\n attributes?: {\n age?: string;\n gender?: string;\n emotion?: string;\n };\n}\n\nexport interface WorldState {\n worldId: string;\n entities: Map<string, TrackedEntity>;\n lastUpdate: number;\n activeEntities: string[];\n recentlyLeft: Array<{\n entityId: string;\n leftAt: number;\n lastPosition: BoundingBox;\n }>;\n}\n",
|
|
24
|
+
"/**\n * Bridge plugin-vision's hierarchical OCR into plugin-computeruse's\n * `CoordOcrProvider` registry seam.\n *\n * plugin-vision owns the OCR implementations; plugin-computeruse's\n * scene-builder + GET_SCREEN want coordinate-aware OCR but must NOT take a\n * hard dependency on plugin-vision (that would create a cycle and force the\n * vision OCR stack onto every computeruse consumer). So plugin-vision\n * registers a bridge into computeruse's seam at boot via a best-effort dynamic\n * import (see `index.ts`).\n *\n * The two interfaces are structurally identical — vision's\n * `OcrWithCoordsService.describe(OcrWithCoordsInput) -> OcrWithCoordsResult`\n * and computeruse's `CoordOcrProvider.describe(CoordOcrInput) -> CoordOcrResult`\n * share field shapes (displayId/sourceX/sourceY/pngBytes in; blocks with\n * bbox+words+semantic_position out) — so the bridge is a thin pass-through.\n * The types live in different packages, so we describe computeruse's side\n * structurally here rather than importing it (keeps the no-hard-dep rule).\n *\n * Pure + injectable so the wiring is unit-testable without a real\n * plugin-computeruse present.\n */\n\nimport {\n getOcrWithCoordsService,\n type OcrWithCoordsResult,\n type OcrWithCoordsService,\n} from \"./ocr-with-coords.js\";\n\n/** Structural shape of `@elizaos/plugin-computeruse`'s `CoordOcrInput`. */\nexport interface CoordOcrInputLike {\n readonly displayId: string;\n readonly sourceX: number;\n readonly sourceY: number;\n readonly pngBytes: Uint8Array;\n}\n\n/** Structural shape of `@elizaos/plugin-computeruse`'s `CoordOcrProvider`. */\nexport interface CoordOcrProviderLike {\n readonly name: string;\n describe(input: CoordOcrInputLike): Promise<OcrWithCoordsResult>;\n}\n\nexport type RegisterCoordOcrProvider = (\n provider: CoordOcrProviderLike | null,\n) => void;\n\nexport const VISION_COORD_OCR_BRIDGE_NAME = \"vision-coord-ocr-bridge\";\n\n/**\n * Build a `CoordOcrProvider`-shaped bridge that delegates to whatever vision\n * `OcrWithCoordsService` is currently registered. Resolving the service lazily\n * (per call) means a later `registerOcrWithCoordsService()` (e.g. swapping in a\n * native Windows.Media.Ocr / Apple Vision provider) is picked up automatically.\n */\nexport function buildVisionCoordOcrBridge(\n resolve: () => OcrWithCoordsService | null = getOcrWithCoordsService,\n): CoordOcrProviderLike {\n return {\n name: VISION_COORD_OCR_BRIDGE_NAME,\n async describe(input: CoordOcrInputLike): Promise<OcrWithCoordsResult> {\n const service = resolve();\n if (!service) return { blocks: [] };\n // Field shapes match across the two interfaces — pass through directly.\n return service.describe({\n displayId: input.displayId,\n sourceX: input.sourceX,\n sourceY: input.sourceY,\n pngBytes: input.pngBytes,\n });\n },\n };\n}\n\n/**\n * Register the vision OCR bridge into computeruse's CoordOcrProvider seam.\n * Idempotent (the seam is last-call-wins). Returns true once registered.\n */\nexport function wireComputerUseOcrBridge(\n register: RegisterCoordOcrProvider,\n resolve?: () => OcrWithCoordsService | null,\n): boolean {\n register(buildVisionCoordOcrBridge(resolve));\n return true;\n}\n",
|
|
25
|
+
"/**\n * Native Linux OCR-with-coords via the classic `tesseract` CLI (issue #9105 /\n * M4).\n *\n * Zero LLM tokens, no in-repo model download, no ONNX — `tesseract` is a\n * standalone C++ engine packaged by every Linux distro (`apt install\n * tesseract-ocr`). We shell to it with `tsv` output, which emits one row per\n * recognized element with a `level` column (1=page, 2=block, 3=para, 4=line,\n * 5=word) plus per-element `left/top/width/height` boxes and a per-word `conf`.\n * Output maps onto `OcrWithCoordsResult`, so this plugs straight into the\n * `OcrWithCoordsService` registry seam and (via the M1 bridge) into\n * plugin-computeruse's `CoordOcrProvider`.\n *\n * We read the word rows (`level == 5`), group them by their parent\n * `(block, paragraph, line)` triple into one `OcrWithCoordsBlock` per text\n * line (block bbox = union of its word rects), compute the semantic position\n * against the source-tile thirds, and shift every bbox into display-absolute\n * coordinates via `sourceX/sourceY` — the same shape as the Windows provider.\n *\n * Availability is feature-detected on the `tesseract` binary and cached for the\n * process lifetime. When the binary is absent the provider reports unavailable\n * and `describe()` returns empty blocks; it never throws so the boot chain\n * falls through to the docTR ggml backend cleanly.\n */\n\nimport { execFile, execFileSync } from \"node:child_process\";\nimport { existsSync, mkdtempSync, readdirSync, writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { logger } from \"@elizaos/core\";\nimport {\n computeSemanticPosition,\n type OcrWithCoordsBlock,\n type OcrWithCoordsInput,\n type OcrWithCoordsResult,\n type OcrWithCoordsService,\n type OcrWithCoordsWord,\n} from \"./ocr-with-coords.js\";\nimport type { BoundingBox } from \"./types.js\";\n\n/** A single `level == 5` (word) row parsed from the tesseract TSV. */\ninterface TesseractWordRow {\n readonly blockNum: number;\n readonly parNum: number;\n readonly lineNum: number;\n readonly left: number;\n readonly top: number;\n readonly width: number;\n readonly height: number;\n /** Tesseract confidence in [0, 100]; `-1` for non-word rows (filtered out). */\n readonly conf: number;\n readonly text: string;\n}\n\n/** tesseract TSV column order (fixed across 3.x/4.x/5.x). */\nconst COL = {\n level: 0,\n blockNum: 2,\n parNum: 3,\n lineNum: 4,\n left: 6,\n top: 7,\n width: 8,\n height: 9,\n conf: 10,\n text: 11,\n} as const;\n\nconst WORD_LEVEL = 5;\n\n/**\n * Parse the raw tesseract TSV into word rows. Pure — exported for tests so the\n * column mapping has a single source of truth and CI never needs a real\n * tesseract binary. Skips the header row, non-word levels, blank text, and any\n * row with too few columns.\n */\nexport function parseTesseractTsv(tsv: string): TesseractWordRow[] {\n const rows: TesseractWordRow[] = [];\n const lines = tsv.split(/\\r?\\n/);\n for (const raw of lines) {\n if (!raw) continue;\n const cols = raw.split(\"\\t\");\n // Header row begins with the literal \"level\"; data rows are numeric.\n if (cols.length <= COL.text || cols[COL.level] === \"level\") continue;\n const level = Number.parseInt(cols[COL.level], 10);\n if (level !== WORD_LEVEL) continue;\n // The text column may itself contain tabs in pathological cases; rejoin\n // everything from COL.text onward so a tab inside a token is preserved.\n const text = cols.slice(COL.text).join(\"\\t\");\n if (text.trim().length === 0) continue;\n rows.push({\n blockNum: Number.parseInt(cols[COL.blockNum], 10),\n parNum: Number.parseInt(cols[COL.parNum], 10),\n lineNum: Number.parseInt(cols[COL.lineNum], 10),\n left: Number.parseInt(cols[COL.left], 10),\n top: Number.parseInt(cols[COL.top], 10),\n width: Number.parseInt(cols[COL.width], 10),\n height: Number.parseInt(cols[COL.height], 10),\n conf: Number.parseFloat(cols[COL.conf]),\n text,\n });\n }\n return rows;\n}\n\n/**\n * Map grouped word rows (one text line) to an `OcrWithCoordsBlock` in\n * display-absolute coordinates. The block bbox is the union of its word rects.\n */\nfunction lineToBlock(\n words: readonly TesseractWordRow[],\n tileWidth: number,\n tileHeight: number,\n sourceX: number,\n sourceY: number,\n): OcrWithCoordsBlock {\n const mappedWords: OcrWithCoordsWord[] = words.map((w) => {\n const tileBox: BoundingBox = {\n x: w.left,\n y: w.top,\n width: w.width,\n height: w.height,\n };\n return {\n text: w.text,\n bbox: {\n x: w.left + sourceX,\n y: w.top + sourceY,\n width: w.width,\n height: w.height,\n },\n semantic_position: computeSemanticPosition({\n bbox: tileBox,\n tileWidth,\n tileHeight,\n }),\n };\n });\n\n // Union of word rects (tile-relative) → block bbox.\n let minX = Number.POSITIVE_INFINITY;\n let minY = Number.POSITIVE_INFINITY;\n let maxX = Number.NEGATIVE_INFINITY;\n let maxY = Number.NEGATIVE_INFINITY;\n for (const w of words) {\n minX = Math.min(minX, w.left);\n minY = Math.min(minY, w.top);\n maxX = Math.max(maxX, w.left + w.width);\n maxY = Math.max(maxY, w.top + w.height);\n }\n if (!Number.isFinite(minX)) {\n minX = 0;\n minY = 0;\n maxX = 0;\n maxY = 0;\n }\n const tileBlockBox: BoundingBox = {\n x: minX,\n y: minY,\n width: maxX - minX,\n height: maxY - minY,\n };\n return {\n text: words.map((w) => w.text).join(\" \"),\n bbox: {\n x: minX + sourceX,\n y: minY + sourceY,\n width: maxX - minX,\n height: maxY - minY,\n },\n words: mappedWords,\n semantic_position: computeSemanticPosition({\n bbox: tileBlockBox,\n tileWidth,\n tileHeight,\n }),\n };\n}\n\n/**\n * Pure mapper: raw tesseract TSV → `OcrWithCoordsResult`. Exported for\n * cross-platform unit tests that inject a fixed TSV string (no real binary).\n * Word rows are grouped by their `(block, paragraph, line)` triple — one\n * `OcrWithCoordsBlock` per recognized text line — in first-seen order.\n */\nexport function mapTesseractTsvToResult(\n tsv: string,\n tileWidth: number,\n tileHeight: number,\n sourceX: number,\n sourceY: number,\n): OcrWithCoordsResult {\n const safeWidth = tileWidth > 0 ? tileWidth : 1;\n const safeHeight = tileHeight > 0 ? tileHeight : 1;\n const words = parseTesseractTsv(tsv);\n\n const order: string[] = [];\n const groups = new Map<string, TesseractWordRow[]>();\n for (const w of words) {\n const key = `${w.blockNum}/${w.parNum}/${w.lineNum}`;\n let group = groups.get(key);\n if (!group) {\n group = [];\n groups.set(key, group);\n order.push(key);\n }\n group.push(w);\n }\n\n const blocks = order.map((key) =>\n lineToBlock(\n groups.get(key) as TesseractWordRow[],\n safeWidth,\n safeHeight,\n sourceX,\n sourceY,\n ),\n );\n return { blocks };\n}\n\n/** Resolved tesseract invocation: the binary path + the env it must run under. */\nexport interface TesseractResolution {\n bin: string;\n /** Extra env merged onto `process.env` for child runs (LD_LIBRARY_PATH,\n * TESSDATA_PREFIX) — non-empty only when a bundled tesseract is used. */\n env: Record<string, string>;\n}\n\n/**\n * Resolve a tesseract to run, so the OCR path \"just ships and works\" without a\n * system `apt install tesseract-ocr` (#9105). Order:\n *\n * 1. `ELIZA_TESSERACT_BIN` — an explicit binary path (CI / power users).\n * 2. A vendored bundle the app ships, found at\n * `${ELIZA_VISION_VENDOR_DIR}/tesseract/{bin/tesseract, lib/*.so*,\n * tessdata/<lang>.traineddata}`. The desktop build stages a portable\n * tesseract there (binary + libtesseract/libleptonica + eng.traineddata);\n * we then run it with that `lib/` on `LD_LIBRARY_PATH` and that `tessdata/`\n * as `TESSDATA_PREFIX`, so no host install is needed.\n * 3. `tesseract` on `PATH` (a system install, the legacy path).\n *\n * Pure-ish + exported for tests (it only reads env + the filesystem); cached for\n * the process lifetime.\n */\nexport function resolveTesseract(): TesseractResolution {\n const binOverride = process.env.ELIZA_TESSERACT_BIN;\n if (binOverride && binOverride.length > 0) {\n return { bin: binOverride, env: {} };\n }\n const vendor = process.env.ELIZA_VISION_VENDOR_DIR;\n if (vendor && vendor.length > 0) {\n const root = join(vendor, \"tesseract\");\n const cand = join(root, \"bin\", \"tesseract\");\n const tessdata = join(root, \"tessdata\");\n // Only select the vendor tier when the bundle is actually usable: a binary\n // AND a language model. A half-staged dir (binary present, tessdata missing)\n // would otherwise be chosen and then fail at OCR time; fall through to PATH\n // so the system tesseract still works.\n if (existsSync(cand) && hasTraineddata(tessdata)) {\n const lib = join(root, \"lib\");\n const prior = process.env.LD_LIBRARY_PATH;\n return {\n bin: cand,\n env: {\n LD_LIBRARY_PATH: prior ? `${lib}:${prior}` : lib,\n TESSDATA_PREFIX: tessdata,\n },\n };\n }\n }\n return { bin: \"tesseract\", env: {} };\n}\n\n/** A vendored tessdata dir is only usable if it carries at least one language\n * model (`<lang>.traineddata`); otherwise selecting the bundle fails at OCR time. */\nfunction hasTraineddata(tessdataDir: string): boolean {\n if (!existsSync(tessdataDir)) return false;\n return readdirSync(tessdataDir).some((f) => f.endsWith(\".traineddata\"));\n}\n\nlet availabilityCache: boolean | null = null;\nlet resolutionCache: TesseractResolution | null = null;\n\nfunction resolved(): TesseractResolution {\n if (!resolutionCache) resolutionCache = resolveTesseract();\n return resolutionCache;\n}\n\n/**\n * Feature-detect the resolved tesseract by running `--version` under its env.\n * Cached for the process lifetime. Synchronous so it slots into the boot-time\n * availability probe; the probe is cheap (one short-lived child process) and\n * only runs once.\n */\nfunction detectTesseract(): boolean {\n if (availabilityCache !== null) return availabilityCache;\n if (process.platform !== \"linux\") {\n availabilityCache = false;\n return false;\n }\n const { bin, env } = resolved();\n try {\n execFileSync(bin, [\"--version\"], {\n timeout: 5000,\n stdio: [\"ignore\", \"ignore\", \"ignore\"],\n env: { ...process.env, ...env },\n });\n availabilityCache = true;\n } catch {\n availabilityCache = false;\n }\n return availabilityCache;\n}\n\n/** Test-only: reset the cached availability + resolution probes between cases. */\nexport function _resetTesseractAvailabilityForTests(): void {\n availabilityCache = null;\n resolutionCache = null;\n}\n\nfunction runTesseract(imagePath: string): Promise<string> {\n const { bin, env } = resolved();\n return new Promise((resolve, reject) => {\n execFile(\n bin,\n [imagePath, \"stdout\", \"--psm\", \"11\", \"tsv\"],\n {\n timeout: 15000,\n maxBuffer: 16 * 1024 * 1024,\n env: { ...process.env, ...env },\n },\n (err, stdout, stderr) => {\n if (err) {\n reject(new Error(`tesseract failed: ${stderr || err.message}`));\n return;\n }\n resolve(stdout);\n },\n );\n });\n}\n\n/**\n * Read width/height from the PNG IHDR chunk so the semantic-position thirds are\n * computed against the real tile dimensions (the TSV carries word boxes but no\n * page size header we can trust across versions). PNG signature is 8 bytes;\n * IHDR width/height are big-endian uint32 at offsets 16 and 20.\n */\nfunction readPngDimensions(pngBytes: Uint8Array): {\n width: number;\n height: number;\n} {\n if (pngBytes.byteLength < 24) return { width: 0, height: 0 };\n const view = new DataView(\n pngBytes.buffer,\n pngBytes.byteOffset,\n pngBytes.byteLength,\n );\n return {\n width: view.getUint32(16, false),\n height: view.getUint32(20, false),\n };\n}\n\nexport class LinuxTesseractOcrService implements OcrWithCoordsService {\n readonly name = \"linux-tesseract\";\n\n static isAvailable(): boolean {\n return detectTesseract();\n }\n\n async describe(input: OcrWithCoordsInput): Promise<OcrWithCoordsResult> {\n if (input.pngBytes.byteLength === 0) return { blocks: [] };\n if (!LinuxTesseractOcrService.isAvailable()) return { blocks: [] };\n\n const dir = mkdtempSync(join(tmpdir(), \"eliza-tesseract-\"));\n const imgPath = join(dir, \"frame.png\");\n writeFileSync(imgPath, Buffer.from(input.pngBytes));\n try {\n const tsv = await runTesseract(imgPath);\n const { width, height } = readPngDimensions(input.pngBytes);\n return mapTesseractTsvToResult(\n tsv,\n width,\n height,\n input.sourceX,\n input.sourceY,\n );\n } catch (err) {\n logger.warn(\n `[LinuxTesseractOcr] OCR failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n return { blocks: [] };\n }\n }\n}\n",
|
|
26
|
+
"/**\n * PaddleOCR / Paddle-Lite OCR-with-coords backend (issue #9581).\n *\n * The alternate coord-OCR provider beyond the shipped Tesseract + RapidOCR\n * adapters. PaddleOCR is a standalone, cross-platform OCR engine (pip install\n * paddleocr) with strong multilingual detection. We drive it through a small\n * self-contained Python wrapper so the JS side parses a stable JSON shape we\n * control — not PaddleOCR's version-sensitive raw `ocr.ocr()` return — and so\n * the wrapper absorbs the numpy/tuple conversion and the 2.x detection layout\n * (`[page][det] = [box4pts, (text, conf)]`).\n *\n * The wrapper emits one object per recognized text line:\n * `[{ \"box\": [[x,y],[x,y],[x,y],[x,y]], \"text\": \"...\", \"conf\": 0.0..1.0 }, …]`\n * PaddleOCR returns line-level (not word-level) detections, so each entry maps\n * to one `OcrWithCoordsBlock` whose single word is the line; the block bbox is\n * the axis-aligned hull of the (possibly rotated) detection quad, shifted into\n * display-absolute coordinates via `sourceX/sourceY` — the same output shape as\n * the Tesseract and Windows providers, so it plugs straight into the\n * `OcrWithCoordsService` registry seam (and via the bridge into\n * plugin-computeruse's `CoordOcrProvider`).\n *\n * Opt-in: this provider is only selected when `ELIZA_VISION_OCR_BACKEND` is\n * `paddleocr`, so it never displaces a verified default provider. When PaddleOCR\n * (or python3) is absent it reports unavailable and `describe()` returns empty\n * blocks; it never throws, so the boot chain falls through cleanly.\n *\n * NOTE (#9581): the JSON parser below is unit-tested without the engine (CI\n * needs no PaddleOCR install). End-to-end behaviour against a real PaddleOCR\n * install still needs on-target verification before this becomes a default.\n */\n\nimport { execFile, execFileSync } from \"node:child_process\";\nimport { mkdtempSync, writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { logger } from \"@elizaos/core\";\nimport {\n computeSemanticPosition,\n type OcrWithCoordsBlock,\n type OcrWithCoordsInput,\n type OcrWithCoordsResult,\n type OcrWithCoordsService,\n} from \"./ocr-with-coords.js\";\nimport type { BoundingBox } from \"./types.js\";\n\n/** One detection from the wrapper's stable JSON: a quad + line text + score. */\ninterface PaddleOcrDetection {\n readonly box: ReadonlyArray<readonly [number, number]>;\n readonly text: string;\n readonly conf: number;\n}\n\n/**\n * Self-contained Python driver. Reads the image path from argv, runs PaddleOCR,\n * and prints the stable JSON shape. Degrades to `[]` (never a non-zero exit)\n * when the package can't be imported or a detection is malformed, so the JS\n * `available()` probe and `describe()` both see a clean empty result.\n */\nconst PADDLE_PY = `\nimport sys, json\ntry:\n from paddleocr import PaddleOCR\nexcept Exception:\n print(\"[]\"); sys.exit(0)\ntry:\n ocr = PaddleOCR(use_angle_cls=True, lang=\"en\", show_log=False)\n res = ocr.ocr(sys.argv[1], cls=True)\nexcept Exception:\n print(\"[]\"); sys.exit(0)\nout = []\nfor page in (res or []):\n for det in (page or []):\n try:\n box, rec = det\n text, conf = rec\n out.append({\n \"box\": [[float(p[0]), float(p[1])] for p in box],\n \"text\": str(text),\n \"conf\": float(conf),\n })\n except Exception:\n continue\nprint(json.dumps(out))\n`;\n\n/** Axis-aligned bounding box (hull) of a detection quad (tile-relative). */\nfunction bboxFromQuad(\n points: ReadonlyArray<readonly [number, number]>,\n): BoundingBox {\n let minX = Number.POSITIVE_INFINITY;\n let minY = Number.POSITIVE_INFINITY;\n let maxX = Number.NEGATIVE_INFINITY;\n let maxY = Number.NEGATIVE_INFINITY;\n for (const p of points) {\n const x = p[0];\n const y = p[1];\n if (!Number.isFinite(x) || !Number.isFinite(y)) continue;\n minX = Math.min(minX, x);\n minY = Math.min(minY, y);\n maxX = Math.max(maxX, x);\n maxY = Math.max(maxY, y);\n }\n if (!Number.isFinite(minX)) return { x: 0, y: 0, width: 0, height: 0 };\n return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };\n}\n\n/**\n * Parse the wrapper's stable JSON into typed detections. Pure — exported for\n * tests so the contract with `PADDLE_PY` has a single source of truth and CI\n * never needs a real PaddleOCR install. Drops entries without a 4-point box,\n * blank text, or a non-finite score.\n */\nexport function parsePaddleOcrJson(raw: string): PaddleOcrDetection[] {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return [];\n }\n if (!Array.isArray(parsed)) return [];\n const dets: PaddleOcrDetection[] = [];\n for (const entry of parsed) {\n if (!entry || typeof entry !== \"object\") continue;\n const e = entry as Record<string, unknown>;\n const box = e.box;\n const text = e.text;\n const conf = e.conf;\n if (\n !Array.isArray(box) ||\n box.length < 3 ||\n typeof text !== \"string\" ||\n text.trim().length === 0 ||\n typeof conf !== \"number\" ||\n !Number.isFinite(conf)\n ) {\n continue;\n }\n const points: Array<readonly [number, number]> = [];\n for (const p of box) {\n if (\n Array.isArray(p) &&\n typeof p[0] === \"number\" &&\n typeof p[1] === \"number\"\n ) {\n points.push([p[0], p[1]]);\n }\n }\n if (points.length < 3) continue;\n dets.push({ box: points, text, conf });\n }\n return dets;\n}\n\n/**\n * Pure mapper: wrapper JSON → `OcrWithCoordsResult`. Exported for unit tests\n * that inject a fixed JSON string (no real engine). One block per detected line\n * (PaddleOCR is line-level), in first-seen order; the single word is the line.\n */\nexport function mapPaddleOcrJsonToResult(\n raw: string,\n tileWidth: number,\n tileHeight: number,\n sourceX: number,\n sourceY: number,\n): OcrWithCoordsResult {\n const safeWidth = tileWidth > 0 ? tileWidth : 1;\n const safeHeight = tileHeight > 0 ? tileHeight : 1;\n const blocks: OcrWithCoordsBlock[] = parsePaddleOcrJson(raw).map((det) => {\n const tileBox = bboxFromQuad(det.box);\n const displayBox: BoundingBox = {\n x: tileBox.x + sourceX,\n y: tileBox.y + sourceY,\n width: tileBox.width,\n height: tileBox.height,\n };\n const semantic = computeSemanticPosition({\n bbox: tileBox,\n tileWidth: safeWidth,\n tileHeight: safeHeight,\n });\n return {\n text: det.text,\n bbox: displayBox,\n words: [\n { text: det.text, bbox: displayBox, semantic_position: semantic },\n ],\n semantic_position: semantic,\n };\n });\n return { blocks };\n}\n\n/**\n * Read width/height from the PNG IHDR chunk (big-endian uint32 at offsets 16/20)\n * so the semantic-position thirds use the real tile dimensions. Mirrors the\n * Tesseract provider's reader.\n */\nfunction readPngDimensions(pngBytes: Uint8Array): {\n width: number;\n height: number;\n} {\n if (pngBytes.byteLength < 24) return { width: 0, height: 0 };\n const view = new DataView(\n pngBytes.buffer,\n pngBytes.byteOffset,\n pngBytes.byteLength,\n );\n return {\n width: view.getUint32(16, false),\n height: view.getUint32(20, false),\n };\n}\n\nlet availabilityCache: boolean | null = null;\n\n/**\n * Feature-detect PaddleOCR: python3 present AND `import paddleocr` succeeds.\n * Opt-in — only probed when `ELIZA_VISION_OCR_BACKEND === \"paddleocr\"`. Cached\n * for the process lifetime; the probe is one short-lived python process.\n */\nfunction detectPaddleOcr(): boolean {\n if (availabilityCache !== null) return availabilityCache;\n if (process.env.ELIZA_VISION_OCR_BACKEND !== \"paddleocr\") {\n availabilityCache = false;\n return false;\n }\n try {\n execFileSync(\"python3\", [\"-c\", \"import paddleocr\"], {\n timeout: 20000,\n stdio: [\"ignore\", \"ignore\", \"ignore\"],\n });\n availabilityCache = true;\n } catch {\n availabilityCache = false;\n }\n return availabilityCache;\n}\n\n/** Test-only: reset the cached availability probe between cases. */\nexport function _resetPaddleOcrAvailabilityForTests(): void {\n availabilityCache = null;\n}\n\nfunction runPaddleOcr(imagePath: string): Promise<string> {\n return new Promise((resolve, reject) => {\n execFile(\n \"python3\",\n [\"-c\", PADDLE_PY, imagePath],\n { timeout: 30000, maxBuffer: 32 * 1024 * 1024 },\n (err, stdout, stderr) => {\n if (err) {\n reject(new Error(`paddleocr failed: ${stderr || err.message}`));\n return;\n }\n resolve(stdout);\n },\n );\n });\n}\n\nexport class PaddleOcrService implements OcrWithCoordsService {\n readonly name = \"paddleocr\";\n\n static isAvailable(): boolean {\n return detectPaddleOcr();\n }\n\n async describe(input: OcrWithCoordsInput): Promise<OcrWithCoordsResult> {\n if (input.pngBytes.byteLength === 0) return { blocks: [] };\n if (!PaddleOcrService.isAvailable()) return { blocks: [] };\n\n const dir = mkdtempSync(join(tmpdir(), \"eliza-paddleocr-\"));\n const imgPath = join(dir, \"frame.png\");\n writeFileSync(imgPath, Buffer.from(input.pngBytes));\n try {\n const json = await runPaddleOcr(imgPath);\n const { width, height } = readPngDimensions(input.pngBytes);\n return mapPaddleOcrJsonToResult(\n json,\n width,\n height,\n input.sourceX,\n input.sourceY,\n );\n } catch (err) {\n logger.warn(\n `[PaddleOcr] OCR failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n return { blocks: [] };\n }\n }\n}\n",
|
|
27
|
+
"/**\n * Native Windows OCR-with-coords via the built-in WinRT `Windows.Media.Ocr`\n * engine (issue #9105 / M4a).\n *\n * Zero LLM tokens, no model download, NPU-accelerated where available. The\n * WinRT projection is only reachable from Windows PowerShell 5.1 (`powershell`),\n * not PowerShell 7 (`pwsh`), so we shell to `powershell` with an embedded\n * script. Output is `OcrWithCoordsResult`, so this plugs straight into the\n * `OcrWithCoordsService` registry seam and (via the M1 bridge) into\n * plugin-computeruse's `CoordOcrProvider`.\n *\n * The engine returns text LINES, each with WORDS that carry bounding rects.\n * We map each line to one `OcrWithCoordsBlock` (block bbox = union of its word\n * rects), compute the semantic position against the source tile thirds, and\n * shift every bbox into display-absolute coordinates via `sourceX/sourceY`.\n */\n\nimport { execFile } from \"node:child_process\";\nimport { mkdtempSync, rmSync, writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { logger } from \"@elizaos/core\";\nimport { ocrHostAvailable, runOcrHost } from \"./ocr-host-windows.js\";\nimport {\n computeSemanticPosition,\n type OcrWithCoordsBlock,\n type OcrWithCoordsInput,\n type OcrWithCoordsResult,\n type OcrWithCoordsService,\n type OcrWithCoordsWord,\n} from \"./ocr-with-coords.js\";\nimport type { BoundingBox } from \"./types.js\";\n\n/** Shape emitted by the embedded PowerShell script (parsed from stdout JSON). */\ninterface WinOcrRaw {\n width: number;\n height: number;\n lines: Array<{\n text: string;\n words: Array<{\n text: string;\n x: number;\n y: number;\n width: number;\n height: number;\n }>;\n }>;\n}\n\n/**\n * Windows PowerShell 5.1 script: render the input PNG into a SoftwareBitmap and\n * run `Windows.Media.Ocr`, emitting compact JSON. `$ImagePath` is passed via\n * `-ImagePath`. Kept as a string so the build doesn't have to copy an asset.\n */\nconst WIN_OCR_PS1 =\n String.raw`param([Parameter(Mandatory=$true)][string]$ImagePath)\n$ErrorActionPreference = 'Stop'\nAdd-Type -AssemblyName System.Runtime.WindowsRuntime\n$asTaskGeneric = ([System.WindowsRuntimeSystemExtensions].GetMethods() | Where-Object {\n $_.Name -eq 'AsTask' -and $_.GetParameters().Count -eq 1 -and\n $_.GetParameters()[0].ParameterType.Name -eq 'IAsyncOperation` +\n \"`\" +\n `1'\n})[0]\nfunction Await($op, $resultType) {\n $m = $asTaskGeneric.MakeGenericMethod($resultType)\n $t = $m.Invoke($null, @($op))\n $t.Wait(-1) | Out-Null\n $t.Result\n}\n[Windows.Media.Ocr.OcrEngine, Windows.Media.Ocr, ContentType = WindowsRuntime] | Out-Null\n[Windows.Graphics.Imaging.BitmapDecoder, Windows.Graphics.Imaging, ContentType = WindowsRuntime] | Out-Null\n[Windows.Storage.StorageFile, Windows.Storage, ContentType = WindowsRuntime] | Out-Null\n$file = Await ([Windows.Storage.StorageFile]::GetFileFromPathAsync($ImagePath)) ([Windows.Storage.StorageFile])\n$stream = Await ($file.OpenAsync([Windows.Storage.FileAccessMode]::Read)) ([Windows.Storage.Streams.IRandomAccessStream])\n$decoder = Await ([Windows.Graphics.Imaging.BitmapDecoder]::CreateAsync($stream)) ([Windows.Graphics.Imaging.BitmapDecoder])\n$bitmap = Await ($decoder.GetSoftwareBitmapAsync()) ([Windows.Graphics.Imaging.SoftwareBitmap])\n$engine = [Windows.Media.Ocr.OcrEngine]::TryCreateFromUserProfileLanguages()\nif ($null -eq $engine) { Write-Output '{\"width\":0,\"height\":0,\"lines\":[]}'; exit 0 }\n$result = Await ($engine.RecognizeAsync($bitmap)) ([Windows.Media.Ocr.OcrResult])\n$lines = @()\nforeach ($line in $result.Lines) {\n $words = @()\n foreach ($w in $line.Words) {\n $r = $w.BoundingRect\n $words += [pscustomobject]@{ text = $w.Text; x = [int]$r.X; y = [int]$r.Y; width = [int]$r.Width; height = [int]$r.Height }\n }\n $lines += [pscustomobject]@{ text = $line.Text; words = $words }\n}\n[pscustomobject]@{ width = [int]$bitmap.PixelWidth; height = [int]$bitmap.PixelHeight; lines = $lines } | ConvertTo-Json -Depth 6 -Compress`;\n\nlet cachedScriptPath: string | null = null;\n\nfunction ensureScriptOnDisk(): string {\n if (cachedScriptPath) return cachedScriptPath;\n const dir = mkdtempSync(join(tmpdir(), \"eliza-winocr-\"));\n const p = join(dir, \"windows-ocr.ps1\");\n writeFileSync(p, WIN_OCR_PS1, \"utf8\");\n cachedScriptPath = p;\n return p;\n}\n\nfunction runPowerShell(scriptPath: string, imagePath: string): Promise<string> {\n return new Promise((resolve, reject) => {\n execFile(\n \"powershell\",\n [\n \"-NoProfile\",\n \"-NonInteractive\",\n \"-ExecutionPolicy\",\n \"Bypass\",\n \"-File\",\n scriptPath,\n \"-ImagePath\",\n imagePath,\n ],\n { timeout: 15000, maxBuffer: 16 * 1024 * 1024, windowsHide: true },\n (err, stdout, stderr) => {\n if (err) {\n reject(\n new Error(\n `windows-ocr powershell failed: ${stderr || err.message}`,\n ),\n );\n return;\n }\n resolve(stdout);\n },\n );\n });\n}\n\n/**\n * Map a raw Windows OCR line to an `OcrWithCoordsBlock` in display-absolute\n * coordinates. The block bbox is the union of its word rects.\n */\nfunction lineToBlock(\n line: WinOcrRaw[\"lines\"][number],\n tileWidth: number,\n tileHeight: number,\n sourceX: number,\n sourceY: number,\n): OcrWithCoordsBlock {\n const words: OcrWithCoordsWord[] = line.words.map((w) => {\n const tileBox: BoundingBox = {\n x: w.x,\n y: w.y,\n width: w.width,\n height: w.height,\n };\n return {\n text: w.text,\n bbox: {\n x: w.x + sourceX,\n y: w.y + sourceY,\n width: w.width,\n height: w.height,\n },\n semantic_position: computeSemanticPosition({\n bbox: tileBox,\n tileWidth,\n tileHeight,\n }),\n };\n });\n\n // Union of word rects (tile-relative) → block bbox.\n let minX = Number.POSITIVE_INFINITY;\n let minY = Number.POSITIVE_INFINITY;\n let maxX = Number.NEGATIVE_INFINITY;\n let maxY = Number.NEGATIVE_INFINITY;\n for (const w of line.words) {\n minX = Math.min(minX, w.x);\n minY = Math.min(minY, w.y);\n maxX = Math.max(maxX, w.x + w.width);\n maxY = Math.max(maxY, w.y + w.height);\n }\n if (!Number.isFinite(minX)) {\n minX = 0;\n minY = 0;\n maxX = 0;\n maxY = 0;\n }\n const tileBlockBox: BoundingBox = {\n x: minX,\n y: minY,\n width: maxX - minX,\n height: maxY - minY,\n };\n return {\n text: line.text,\n bbox: {\n x: minX + sourceX,\n y: minY + sourceY,\n width: maxX - minX,\n height: maxY - minY,\n },\n words,\n semantic_position: computeSemanticPosition({\n bbox: tileBlockBox,\n tileWidth,\n tileHeight,\n }),\n };\n}\n\n/** Pure mapper (exported for cross-platform unit tests). */\nexport function mapWinOcrToResult(\n raw: WinOcrRaw,\n sourceX: number,\n sourceY: number,\n): OcrWithCoordsResult {\n const tileWidth = raw.width > 0 ? raw.width : 1;\n const tileHeight = raw.height > 0 ? raw.height : 1;\n const blocks = (raw.lines ?? [])\n .filter((l) => (l.words?.length ?? 0) > 0)\n .map((l) => lineToBlock(l, tileWidth, tileHeight, sourceX, sourceY));\n return { blocks };\n}\n\nexport class WindowsMediaOcrService implements OcrWithCoordsService {\n readonly name = \"windows-media-ocr\";\n\n static isAvailable(): boolean {\n return process.platform === \"win32\";\n }\n\n async describe(input: OcrWithCoordsInput): Promise<OcrWithCoordsResult> {\n if (input.pngBytes.byteLength === 0) return { blocks: [] };\n if (process.platform !== \"win32\") return { blocks: [] };\n\n const dir = mkdtempSync(join(tmpdir(), \"eliza-winocr-img-\"));\n const imgPath = join(dir, \"frame.png\");\n writeFileSync(imgPath, Buffer.from(input.pngBytes));\n try {\n // Prefer the warm OCR host (no per-call cold `powershell.exe` spawn nor\n // WinRT type-load); fall back to the one-shot `-File` spawn on any failure.\n let stdout: string;\n if (ocrHostAvailable()) {\n try {\n stdout = await runOcrHost(imgPath);\n } catch {\n stdout = await runPowerShell(ensureScriptOnDisk(), imgPath);\n }\n } else {\n stdout = await runPowerShell(ensureScriptOnDisk(), imgPath);\n }\n const raw = JSON.parse(\n stdout.trim() || '{\"width\":0,\"height\":0,\"lines\":[]}',\n ) as WinOcrRaw;\n return mapWinOcrToResult(raw, input.sourceX, input.sourceY);\n } catch (err) {\n logger.warn(\n `[WindowsMediaOcr] OCR failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n return { blocks: [] };\n } finally {\n // Clean up the per-call temp image. The warm host disposes its file\n // handle each iteration and the one-shot process has exited, so the file\n // is unlocked — important now that frequent OCR through the host would\n // otherwise accumulate temp dirs.\n try {\n rmSync(dir, { recursive: true, force: true });\n } catch {\n /* best effort */\n }\n }\n }\n}\n",
|
|
28
|
+
"/**\n * Persistent WinRT OCR host (Windows-only) — kills the per-OCR cold-spawn tax.\n *\n * `WindowsMediaOcrService.describe()` previously ran `powershell -File\n * windows-ocr.ps1` for EVERY recognized region. On Defender-heavy hosts a cold\n * `powershell.exe` spawn is ~10-16s (#9581), and OCR fires on every dirty region\n * every turn — and the scene pipeline OCRs regions in parallel, so a turn would\n * spawn N cold processes at once and thrash the AV scanner.\n *\n * This keeps ONE long-lived `powershell.exe` that loads the (expensive) WinRT\n * projection + `OcrEngine` ONCE in its parent scope, then loops: read an image\n * path on stdin, recognize, emit one compact JSON line on stdout. So each call\n * pays neither the process spawn NOR the WinRT type-load — only the recognize\n * (~0.3-1s). Requests are serialized over the one pipe (fine — each is fast).\n *\n * It is a pure latency optimization: `describe()` falls back to the original\n * one-shot `-File` spawn whenever the host is unavailable / disabled / errors,\n * so output is unchanged. No-op off Windows. Disable with `ELIZA_VISION_OCR_HOST=0`.\n *\n * Protocol: JS writes `<absolute-image-path>\\n`; the host writes exactly one\n * line of compact JSON (`{width,height,lines}` — same shape as the one-shot\n * script). base64 isn't needed: temp image paths never contain newlines, and\n * `ConvertTo-Json -Compress` output is always a single physical line.\n */\n\nimport { type ChildProcessWithoutNullStreams, spawn } from \"node:child_process\";\nimport { unlinkSync, writeFileSync } from \"node:fs\";\nimport { platform, tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\n\nconst STARTUP_TIMEOUT_MS = 25_000;\nconst REQUEST_TIMEOUT_MS = 15_000;\nconst MAX_START_FAILURES = 2;\n\nlet host: ChildProcessWithoutNullStreams | null = null;\nlet starting: Promise<void> | null = null;\nlet startFailures = 0;\nlet loopScriptPath: string | null = null;\nlet stdoutBuf = \"\";\nlet stderrRing = \"\";\nlet pending: {\n resolve: (line: string) => void;\n reject: (err: Error) => void;\n timer: ReturnType<typeof setTimeout>;\n} | null = null;\nlet chain: Promise<unknown> = Promise.resolve();\n\n// One-time preamble loads the WinRT projection + OcrEngine in the parent scope;\n// the loop reuses them per request. Mirrors the recognition logic of the\n// one-shot `WIN_OCR_PS1` exactly so output is identical — only the spawn + the\n// type-load are amortized. Streams/bitmaps are disposed each iteration (a\n// long-lived session must not leak handles or keep temp PNGs locked).\nconst OCR_SERVER_PS1 =\n String.raw`$ErrorActionPreference = 'Stop'\n[Console]::OutputEncoding = [System.Text.Encoding]::UTF8\nAdd-Type -AssemblyName System.Runtime.WindowsRuntime\n$asTaskGeneric = ([System.WindowsRuntimeSystemExtensions].GetMethods() | Where-Object {\n $_.Name -eq 'AsTask' -and $_.GetParameters().Count -eq 1 -and\n $_.GetParameters()[0].ParameterType.Name -eq 'IAsyncOperation` +\n \"`\" +\n String.raw`1'\n})[0]\nfunction Await($op, $resultType) {\n $m = $asTaskGeneric.MakeGenericMethod($resultType)\n $t = $m.Invoke($null, @($op))\n $t.Wait(-1) | Out-Null\n $t.Result\n}\n[Windows.Media.Ocr.OcrEngine, Windows.Media.Ocr, ContentType = WindowsRuntime] | Out-Null\n[Windows.Graphics.Imaging.BitmapDecoder, Windows.Graphics.Imaging, ContentType = WindowsRuntime] | Out-Null\n[Windows.Storage.StorageFile, Windows.Storage, ContentType = WindowsRuntime] | Out-Null\n$engine = [Windows.Media.Ocr.OcrEngine]::TryCreateFromUserProfileLanguages()\nwhile ($true) {\n $ImagePath = [Console]::In.ReadLine()\n if ($null -eq $ImagePath) { break }\n if ($ImagePath.Length -eq 0) { continue }\n $stream = $null\n $bitmap = $null\n try {\n if ($null -eq $engine) { [Console]::Out.WriteLine('{\"width\":0,\"height\":0,\"lines\":[]}'); [Console]::Out.Flush(); continue }\n $file = Await ([Windows.Storage.StorageFile]::GetFileFromPathAsync($ImagePath)) ([Windows.Storage.StorageFile])\n $stream = Await ($file.OpenAsync([Windows.Storage.FileAccessMode]::Read)) ([Windows.Storage.Streams.IRandomAccessStream])\n $decoder = Await ([Windows.Graphics.Imaging.BitmapDecoder]::CreateAsync($stream)) ([Windows.Graphics.Imaging.BitmapDecoder])\n $bitmap = Await ($decoder.GetSoftwareBitmapAsync()) ([Windows.Graphics.Imaging.SoftwareBitmap])\n $result = Await ($engine.RecognizeAsync($bitmap)) ([Windows.Media.Ocr.OcrResult])\n $lines = @()\n foreach ($line in $result.Lines) {\n $words = @()\n foreach ($w in $line.Words) {\n $r = $w.BoundingRect\n $words += [pscustomobject]@{ text = $w.Text; x = [int]$r.X; y = [int]$r.Y; width = [int]$r.Width; height = [int]$r.Height }\n }\n $lines += [pscustomobject]@{ text = $line.Text; words = $words }\n }\n $out = [pscustomobject]@{ width = [int]$bitmap.PixelWidth; height = [int]$bitmap.PixelHeight; lines = $lines } | ConvertTo-Json -Depth 6 -Compress\n [Console]::Out.WriteLine($out)\n } catch {\n [Console]::Out.WriteLine('{\"width\":0,\"height\":0,\"lines\":[],\"error\":\"ocr-host\"}')\n } finally {\n # Always release the file handle + bitmap, even on a mid-iteration throw —\n # otherwise the handle leaks and keeps the temp PNG locked so the caller's\n # rmSync cannot delete it (this is a long-lived session).\n if ($null -ne $bitmap) { try { $bitmap.Dispose() } catch {} }\n if ($null -ne $stream) { try { $stream.Dispose() } catch {} }\n }\n [Console]::Out.Flush()\n}`;\n\nexport function ocrHostAvailable(): boolean {\n if (platform() !== \"win32\") return false;\n if (process.env.ELIZA_VISION_OCR_HOST === \"0\") return false;\n if (startFailures >= MAX_START_FAILURES) return false;\n return true;\n}\n\nfunction onStdout(chunk: Buffer): void {\n stdoutBuf += chunk.toString(\"utf8\");\n if (!pending) return;\n const nl = stdoutBuf.indexOf(\"\\n\");\n if (nl === -1) return;\n const line = stdoutBuf.slice(0, nl).replace(/\\r$/, \"\");\n stdoutBuf = stdoutBuf.slice(nl + 1);\n const p = pending;\n pending = null;\n clearTimeout(p.timer);\n p.resolve(line);\n}\n\nfunction onExit(): void {\n host = null;\n starting = null;\n stdoutBuf = \"\";\n if (pending) {\n const p = pending;\n pending = null;\n clearTimeout(p.timer);\n p.reject(new Error(\"ocr-host exited unexpectedly\"));\n }\n}\n\nexport function shutdownOcrHost(): void {\n if (host) {\n try {\n host.stdin.end();\n } catch {\n /* best effort */\n }\n try {\n host.kill();\n } catch {\n /* best effort */\n }\n }\n if (loopScriptPath) {\n try {\n unlinkSync(loopScriptPath);\n } catch {\n /* best effort */\n }\n loopScriptPath = null;\n }\n onExit();\n}\n\nasync function ensureHost(): Promise<void> {\n if (host) return;\n if (starting) return starting;\n starting = (async () => {\n const scriptPath = join(tmpdir(), `eliza-ocr-host-${process.pid}.ps1`);\n writeFileSync(scriptPath, OCR_SERVER_PS1, \"utf8\");\n loopScriptPath = scriptPath;\n const child = spawn(\n \"powershell\",\n [\n \"-NoProfile\",\n \"-NoLogo\",\n \"-NonInteractive\",\n \"-ExecutionPolicy\",\n \"Bypass\",\n \"-File\",\n scriptPath,\n ],\n { stdio: [\"pipe\", \"pipe\", \"pipe\"], windowsHide: true },\n );\n child.stdout.on(\"data\", onStdout);\n child.stderr.on(\"data\", (c: Buffer) => {\n stderrRing = (stderrRing + c.toString(\"utf8\")).slice(-2048);\n });\n // Swallow stdin pipe errors (EPIPE when the host dies between requests) so\n // Node doesn't throw an uncaught exception and crash the process; the dead\n // pipe surfaces via onExit → a normal rejection the caller falls back from.\n child.stdin.on(\"error\", () => {});\n // Bind exit/error to THIS child so a previously-killed host's late 'exit'\n // can't tear down a freshly respawned host or reject its pending request.\n const onChildGone = () => {\n if (host !== child) return;\n onExit();\n };\n child.once(\"exit\", onChildGone);\n child.once(\"error\", onChildGone);\n host = child;\n // Probe: a blank line is ignored by the loop, so prove readiness by sending\n // a path we expect to fail recognition — the loop always answers one JSON\n // line (the error branch), which confirms the preamble loaded and the loop\n // is reading.\n await sendRaw(\n join(tmpdir(), `eliza-ocr-probe-nonexistent-${process.pid}.png`),\n STARTUP_TIMEOUT_MS,\n );\n })();\n try {\n await starting;\n startFailures = 0;\n } catch (err) {\n startFailures += 1;\n shutdownOcrHost();\n throw err;\n } finally {\n starting = null;\n }\n}\n\nfunction sendRaw(imagePath: string, timeoutMs: number): Promise<string> {\n return new Promise<string>((resolve, reject) => {\n if (!host) {\n reject(new Error(\"ocr-host not running\"));\n return;\n }\n const timer = setTimeout(() => {\n pending = null;\n shutdownOcrHost();\n reject(\n new Error(\n `ocr-host timeout after ${timeoutMs}ms${stderrRing ? ` (stderr: ${stderrRing.trim().slice(-200)})` : \"\"}`,\n ),\n );\n }, timeoutMs);\n pending = { resolve, reject, timer };\n try {\n host.stdin.write(`${imagePath}\\n`);\n } catch (err) {\n clearTimeout(timer);\n pending = null;\n shutdownOcrHost();\n reject(err instanceof Error ? err : new Error(String(err)));\n }\n });\n}\n\n/**\n * Recognize the image at `imagePath` via the warm host, returning the raw JSON\n * line (same shape the one-shot script emits). Serialized against other calls.\n * Rejects (so the caller can fall back to a one-shot spawn) on host-start\n * failure, timeout, or unexpected exit.\n */\nexport function runOcrHost(imagePath: string): Promise<string> {\n const task = async (): Promise<string> => {\n await ensureHost();\n return sendRaw(imagePath, REQUEST_TIMEOUT_MS);\n };\n const run = chain.then(task, task);\n chain = run.catch(() => {});\n return run;\n}\n\nprocess.once(\"exit\", () => {\n if (host) {\n try {\n host.kill();\n } catch {\n /* best effort */\n }\n }\n});\n",
|
|
29
|
+
"import {\n type IAgentRuntime,\n logger,\n type Memory,\n type Provider,\n type State,\n} from \"@elizaos/core\";\nimport type { VisionService } from \"./service\";\nimport type {\n BoundingBox,\n EnhancedSceneDescription,\n EntityAttributes,\n} from \"./types\";\n\nconst MAX_VISION_OBJECTS_IN_STATE = 50;\nconst MAX_VISION_PEOPLE_IN_STATE = 25;\nconst MAX_TRACKED_ENTITIES_IN_STATE = 25;\n\nexport const visionProvider: Provider = {\n name: \"VISION_PERCEPTION\",\n description:\n \"Provides current visual perception data including scene description, detected objects, people, and entity tracking. This provider is always active and provides real-time visual awareness.\",\n position: 99,\n contexts: [\"media\", \"browser\"],\n contextGate: { anyOf: [\"media\", \"browser\"] },\n cacheStable: false,\n cacheScope: \"turn\",\n dynamic: false,\n get: async (runtime: IAgentRuntime, message: Memory, _state: State) => {\n const visionService = runtime.getService<VisionService>(\"VISION\");\n\n if (!visionService) {\n logger.warn(\"[visionProvider] VisionService not found.\");\n return {\n values: {\n visionAvailable: false,\n sceneDescription: \"Vision service is not available.\",\n cameraStatus: \"No camera connected\",\n },\n text: JSON.stringify(\n {\n visual_perception: {\n visionAvailable: false,\n sceneDescription: \"Vision service is not available.\",\n cameraStatus: \"No camera connected\",\n },\n },\n null,\n 2,\n ),\n data: { hasVision: false },\n };\n }\n\n try {\n const sceneDescription =\n (await visionService.getEnhancedSceneDescription()) ||\n (await visionService.getSceneDescription());\n const cameraInfo = visionService.getCameraInfo();\n const isActive = visionService.isActive();\n const visionMode = visionService.getVisionMode();\n const screenCapture = await visionService.getScreenCapture();\n const _worldId = message.worldId || \"default-world\";\n const entityTracker = visionService.getEntityTracker();\n\n let entityData: {\n activeEntities: Array<{\n id: string;\n type: \"person\" | \"object\" | \"pet\";\n name: string | undefined;\n firstSeen: number;\n duration: number;\n position: BoundingBox;\n attributes: EntityAttributes;\n }>;\n recentlyLeft: Array<{\n id: string;\n name: string | undefined;\n leftAt: number;\n timeAgo: number;\n }>;\n statistics: {\n totalEntities: number;\n activeEntities: number;\n recentlyLeft: number;\n people: number;\n objects: number;\n };\n } | null = null;\n\n if (sceneDescription && entityTracker) {\n await entityTracker.updateEntities(\n sceneDescription.objects,\n sceneDescription.people,\n undefined,\n runtime,\n );\n\n const activeEntities = entityTracker.getActiveEntities();\n const recentlyLeft = entityTracker.getRecentlyLeft();\n const stats = entityTracker.getStatistics();\n\n entityData = {\n activeEntities: activeEntities\n .slice(0, MAX_TRACKED_ENTITIES_IN_STATE)\n .map((e) => ({\n id: e.id,\n type: e.entityType,\n name: e.attributes.name,\n firstSeen: e.firstSeen,\n duration: Date.now() - e.firstSeen,\n position: e.lastPosition,\n attributes: e.attributes,\n })),\n recentlyLeft: recentlyLeft\n .slice(0, MAX_TRACKED_ENTITIES_IN_STATE)\n .map(({ entity, leftAt }) => ({\n id: entity.id,\n name: entity.attributes.name,\n leftAt,\n timeAgo: Date.now() - leftAt,\n })),\n statistics: stats,\n };\n }\n\n let perceptionText = \"\";\n let values = {};\n let data = {};\n\n if (!isActive) {\n perceptionText = `Vision mode: ${visionMode}\\n`;\n if (visionMode === \"OFF\") {\n perceptionText += \"Vision is disabled.\";\n } else {\n perceptionText += \"Vision service is initializing...\";\n }\n\n values = {\n visionAvailable: false,\n visionMode,\n sceneDescription: \"Vision not active\",\n cameraStatus: cameraInfo\n ? `Camera \"${cameraInfo.name}\" detected but not active`\n : \"No camera\",\n };\n } else {\n perceptionText = `Vision mode: ${visionMode}\\n\\n`;\n\n if (\n (visionMode === \"CAMERA\" || visionMode === \"BOTH\") &&\n sceneDescription\n ) {\n const descriptionTimestamp =\n sceneDescription.descriptionTimestamp ?? sceneDescription.timestamp;\n const ageInSeconds = (Date.now() - descriptionTimestamp) / 1000;\n const secondsAgo = Math.round(ageInSeconds);\n\n perceptionText += `Camera view (${secondsAgo}s ago):\\n${sceneDescription.description}`;\n\n if (\n sceneDescription.descriptionStale ||\n sceneDescription.describePaused\n ) {\n const reason = sceneDescription.describePauseReason\n ? ` (${sceneDescription.describePauseReason})`\n : \"\";\n perceptionText += `\\n\\nVLM description is stale because describe is paused${reason}; object, person, OCR, and change signals may be newer than the prose above.`;\n }\n\n if (sceneDescription.people.length > 0) {\n perceptionText += `\\n\\nPeople detected: ${sceneDescription.people.length}`;\n const poses = sceneDescription.people\n .map((p) => p.pose)\n .filter((p) => p !== \"unknown\");\n const facings = sceneDescription.people\n .map((p) => p.facing)\n .filter((f) => f !== \"unknown\");\n\n if (poses.length > 0) {\n const poseCounts = poses.reduce(\n (acc, pose) => {\n acc[pose] = (acc[pose] || 0) + 1;\n return acc;\n },\n {} as Record<string, number>,\n );\n perceptionText += `\\n Poses: ${Object.entries(poseCounts)\n .map(([pose, count]) => `${count} ${pose}`)\n .join(\", \")}`;\n }\n\n if (facings.length > 0) {\n const facingCounts = facings.reduce(\n (acc, facing) => {\n acc[facing] = (acc[facing] || 0) + 1;\n return acc;\n },\n {} as Record<string, number>,\n );\n perceptionText += `\\n Facing: ${Object.entries(facingCounts)\n .map(([facing, count]) => `${count} facing ${facing}`)\n .join(\", \")}`;\n }\n }\n\n if (sceneDescription.objects.length > 0) {\n const objectTypes = sceneDescription.objects\n .slice(0, MAX_VISION_OBJECTS_IN_STATE)\n .map((o) => o.type);\n const uniqueObjects = [...new Set(objectTypes)];\n perceptionText += `\\n\\nObjects detected: ${uniqueObjects.join(\", \")}`;\n }\n\n if (sceneDescription.sceneChanged) {\n perceptionText += `\\n\\nScene change: ${sceneDescription.changePercentage.toFixed(1)}% of pixels changed`;\n }\n\n if (entityData) {\n if (entityData.activeEntities.length > 0) {\n perceptionText += \"\\n\\nCurrently tracking:\";\n for (const entity of entityData.activeEntities) {\n const name = entity.name || `Unknown ${entity.type}`;\n const duration =\n entity.duration < 60000\n ? `${Math.round(entity.duration / 1000)}s`\n : `${Math.round(entity.duration / 60000)}m`;\n perceptionText += `\\n- ${name} (present for ${duration})`;\n }\n }\n\n if (entityData.recentlyLeft.length > 0) {\n perceptionText += \"\\n\\nRecently left:\";\n for (const departed of entityData.recentlyLeft) {\n const name = departed.name || \"Unknown person\";\n const timeStr =\n departed.timeAgo < 60000\n ? `${Math.round(departed.timeAgo / 1000)}s ago`\n : `${Math.round(departed.timeAgo / 60000)}m ago`;\n perceptionText += `\\n- ${name} left ${timeStr}`;\n }\n }\n }\n }\n\n if (\n (visionMode === \"SCREEN\" || visionMode === \"BOTH\") &&\n screenCapture\n ) {\n const screenAge = (Date.now() - screenCapture.timestamp) / 1000;\n const screenSecondsAgo = Math.round(screenAge);\n\n if (visionMode === \"BOTH\") {\n perceptionText += \"\\n\\n---\\n\\n\";\n }\n\n perceptionText += `Screen capture (${screenSecondsAgo}s ago):\\n`;\n perceptionText += `Resolution: ${screenCapture.width}x${screenCapture.height}\\n`;\n\n const enhanced = sceneDescription as EnhancedSceneDescription;\n if (enhanced?.screenAnalysis) {\n const tileAnalysis = enhanced.screenAnalysis.activeTile;\n if (tileAnalysis) {\n if (tileAnalysis.summary) {\n perceptionText += `\\nActive area: ${tileAnalysis.summary}`;\n }\n\n if (tileAnalysis.text) {\n perceptionText += `\\n\\nVisible text:\\n\"${tileAnalysis.text.substring(0, 200)}${tileAnalysis.text.length > 200 ? \"...\" : \"\"}\"`;\n }\n\n if (tileAnalysis.objects && tileAnalysis.objects.length > 0) {\n const uiElements = tileAnalysis.objects.map(\n (o) => (o as { type?: string }).type || \"unknown\",\n );\n const uniqueElements = [...new Set(uiElements)];\n perceptionText += `\\n\\nUI elements: ${uniqueElements.join(\", \")}`;\n }\n }\n\n if (enhanced.screenAnalysis.focusedApp) {\n perceptionText += `\\n\\nActive application: ${enhanced.screenAnalysis.focusedApp}`;\n }\n }\n }\n\n values = {\n visionAvailable: true,\n visionMode,\n sceneDescription: sceneDescription?.description || \"Processing...\",\n cameraStatus: cameraInfo\n ? `Connected to ${cameraInfo.name}`\n : \"No camera\",\n cameraId: cameraInfo?.id,\n peopleCount: sceneDescription?.people.length || 0,\n objectCount: sceneDescription?.objects.length || 0,\n sceneAge: sceneDescription\n ? Math.round(\n (Date.now() -\n (sceneDescription.descriptionTimestamp ??\n sceneDescription.timestamp)) /\n 1000,\n )\n : null,\n descriptionStale: sceneDescription?.descriptionStale || false,\n describePaused: sceneDescription?.describePaused || false,\n describePauseReason: sceneDescription?.describePauseReason || null,\n lastChange: sceneDescription?.sceneChanged\n ? sceneDescription.changePercentage\n : 0,\n hasScreenCapture: !!screenCapture,\n screenResolution: screenCapture\n ? `${screenCapture.width}x${screenCapture.height}`\n : null,\n activeEntities: entityData?.activeEntities || [],\n recentlyLeft: entityData?.recentlyLeft || [],\n entityStatistics: entityData?.statistics || null,\n };\n\n data = {\n objects:\n sceneDescription?.objects.slice(0, MAX_VISION_OBJECTS_IN_STATE) ||\n [],\n people:\n sceneDescription?.people.slice(0, MAX_VISION_PEOPLE_IN_STATE) || [],\n screenCapture: screenCapture || null,\n enhancedData:\n (sceneDescription as EnhancedSceneDescription)?.screenAnalysis ||\n null,\n trackedEntities: entityData?.activeEntities || [],\n worldState: entityData || null,\n };\n }\n\n return {\n values,\n text: JSON.stringify(\n {\n visual_perception: {\n summary: perceptionText,\n ...values,\n },\n },\n null,\n 2,\n ),\n data,\n };\n } catch (error) {\n return {\n values: {\n visionAvailable: false,\n error: error instanceof Error ? error.message : String(error),\n },\n text: JSON.stringify(\n {\n visual_perception: {\n visionAvailable: false,\n error: error instanceof Error ? error.message : String(error),\n },\n },\n null,\n 2,\n ),\n data: {\n hasVision: false,\n error: error instanceof Error ? error.message : String(error),\n },\n };\n }\n },\n};\n",
|
|
30
|
+
"// Renderer-pull routes for the Android screen-capture bridge.\n//\n// The renderer interval-polls the GET route to drain queued capture requests,\n// captures each via the Capacitor ScreenCapture plugin, then POSTs the PNG\n// back to the POST route. Both mount at their exact paths (`rawPath: true`)\n// because the Android JNI loopback forwards by literal `/api/...` path.\n\nimport type { Route } from \"@elizaos/core\";\nimport {\n SCREEN_CAPTURE_BRIDGE_SERVICE_TYPE,\n type ScreenCaptureBridgeService,\n} from \"./screen-capture-bridge\";\n\ninterface ScreenFrameBody {\n requestId: string;\n base64: string;\n format: string;\n width: number;\n height: number;\n}\n\nfunction isScreenFrameBody(value: unknown): value is ScreenFrameBody {\n if (typeof value !== \"object\" || value === null) return false;\n const body = value as Record<string, unknown>;\n return (\n typeof body.requestId === \"string\" &&\n typeof body.base64 === \"string\" &&\n typeof body.format === \"string\" &&\n typeof body.width === \"number\" &&\n typeof body.height === \"number\"\n );\n}\n\nfunction jsonResult(\n status: number,\n body: unknown,\n): { status: number; headers: Record<string, string>; body: string } {\n return {\n status,\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n };\n}\n\n/** GET — drain the queue of pending capture requests for the renderer poller. */\nexport const captureRequestsRoute: Route = {\n type: \"GET\",\n path: \"/api/vision/capture-requests\",\n rawPath: true,\n routeHandler: async (ctx) => {\n const bridge = ctx.runtime.getService<ScreenCaptureBridgeService>(\n SCREEN_CAPTURE_BRIDGE_SERVICE_TYPE,\n );\n if (!bridge) return jsonResult(200, { requests: [] });\n return jsonResult(200, { requests: bridge.takeRequests() });\n },\n};\n\n/** POST — accept a captured frame (or a skip) for a queued request. */\nexport const screenFrameRoute: Route = {\n type: \"POST\",\n path: \"/api/vision/screen-frame\",\n rawPath: true,\n routeHandler: async (ctx) => {\n const bridge = ctx.runtime.getService<ScreenCaptureBridgeService>(\n SCREEN_CAPTURE_BRIDGE_SERVICE_TYPE,\n );\n if (!bridge)\n return jsonResult(404, { ok: false, error: \"bridge_unavailable\" });\n\n const body = ctx.body;\n // Renderer signalled a capture failure/skip so the pending request settles\n // immediately rather than waiting out the bridge timeout.\n if (\n typeof body === \"object\" &&\n body !== null &&\n typeof (body as Record<string, unknown>).requestId === \"string\" &&\n (body as Record<string, unknown>).error !== undefined\n ) {\n const requestId = (body as Record<string, unknown>).requestId as string;\n const reason = String((body as Record<string, unknown>).error);\n const failed = bridge.failFrame(requestId, reason);\n return failed\n ? jsonResult(200, { ok: true })\n : jsonResult(404, { ok: false, error: \"unknown_request\" });\n }\n\n if (!isScreenFrameBody(body)) {\n return jsonResult(400, { ok: false, error: \"invalid_body\" });\n }\n\n const ok = bridge.submitFrame(\n body.requestId,\n body.base64,\n body.format,\n body.width,\n body.height,\n );\n return ok\n ? jsonResult(200, { ok: true })\n : jsonResult(404, { ok: false, error: \"unknown_request\" });\n },\n};\n\nexport const visionRoutes: Route[] = [captureRequestsRoute, screenFrameRoute];\n",
|
|
31
|
+
"// Vision service for camera integration and scene analysis\n\nimport { exec } from \"node:child_process\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { promisify } from \"node:util\";\nimport {\n type IAgentRuntime,\n logger,\n ModelType,\n Service,\n type ServiceTypeName,\n withStandaloneTrajectory,\n} from \"@elizaos/core\";\nimport { AudioCaptureService, type AudioConfig } from \"./audio-capture\";\nimport {\n StreamingAudioCaptureService,\n type StreamingAudioConfig,\n} from \"./audio-capture-stream\";\nimport {\n DescribeBackpressureController,\n type DescribePauseReason,\n} from \"./describe-backpressure\";\nimport { DirtyTileDescriber } from \"./dirty-tile-describer\";\nimport {\n createTileDescribeFn,\n type FrameHash,\n type TileDescribeFn,\n tilePngToImageUrl,\n} from \"./dirty-tile-scene\";\nimport { EntityTracker } from \"./entity-tracker\";\nimport type { FaceRecognition } from \"./face-recognition-ggml\";\nimport { getSharp } from \"./image/sharp-compat\";\nimport {\n assertValidVisionImageBuffer,\n parseVisionDataImageUrl,\n} from \"./image-input\";\nimport { resolveArbiterFromRuntime } from \"./lifecycle\";\nimport { OCRService } from \"./ocr-service\";\nimport { ScreenCaptureService } from \"./screen-capture\";\nimport { getTestImage } from \"./test-input\";\nimport {\n type BoundingBox,\n type CameraInfo,\n type DetectedObject,\n type EnhancedSceneDescription,\n type PersonInfo,\n type SceneDescription,\n type ScreenCapture,\n type ScreenTile,\n type TileAnalysis,\n type VisionConfig,\n type VisionFrame,\n VisionMode,\n VisionServiceType,\n} from \"./types\";\nimport { VisionWorkerManager } from \"./vision-worker-manager\";\nimport type { YOLODetector } from \"./yolo-detector\";\n\nconst execAsync = promisify(exec);\n\n// Service type registered by plugin-computeruse's VisionContextProvider. We\n// duck-type the consumer interface here rather than taking a hard package\n// dependency on @elizaos/plugin-computeruse — the provider is optional and\n// lives in a peer plugin. The structural contract must stay in sync with the\n// `VisionContext` exported from plugin-computeruse.\nconst VISION_CONTEXT_SERVICE_TYPE = \"vision-context\";\nconst SCENE_CONTEXT_OPEN_APPS_LIMIT = 20;\nconst SCENE_CONTEXT_RECENT_ACTIONS_LIMIT = 10;\nconst SCENE_DESCRIPTION_OCR_LINE_LIMIT = 40;\nconst SCENE_DESCRIPTION_OCR_TEXT_LIMIT = 2000;\nconst SCENE_DESCRIPTION_OBJECT_LIMIT = 20;\nconst SCENE_DESCRIPTION_FACE_LIMIT = 10;\n\nexport interface VisionContextSnapshot {\n openApps: string[];\n focusedWindow: {\n app: string;\n title: string;\n bbox: [number, number, number, number] | null;\n } | null;\n recentActions: Array<{ action: string; ts: number }>;\n currentTaskGoal: string | null;\n}\n\ninterface VisionContextProviderLike {\n getContext(): Promise<VisionContextSnapshot>;\n}\n\nconst SCENE_DESCRIPTION_INSTRUCTIONS = [\n \"Describe visible people, objects, UI, text, and notable scene changes.\",\n \"Keep the answer concise and factual.\",\n];\n\n/**\n * A face that the ggml face-recognition pipeline matched to a known profile,\n * shaped for the VLM prompt. `label` is the profile's display name when set,\n * otherwise the opaque profile id. `bbox` is the detected face region.\n */\nexport interface RecognizedFace {\n label: string;\n bbox: BoundingBox;\n}\n\n/** Prompt-shaped detected object: label + confidence + region. */\ninterface DetectedObjectForPrompt {\n type: string;\n confidence: number;\n bbox: BoundingBox;\n}\n\nfunction isVisionContextProvider(\n candidate: unknown,\n): candidate is VisionContextProviderLike {\n return (\n typeof candidate === \"object\" &&\n candidate !== null &&\n typeof (candidate as { getContext?: unknown }).getContext === \"function\"\n );\n}\n\nfunction trimVisionContextForPrompt(\n context: VisionContextSnapshot,\n): VisionContextSnapshot {\n return {\n openApps: context.openApps.slice(0, SCENE_CONTEXT_OPEN_APPS_LIMIT),\n focusedWindow: context.focusedWindow,\n recentActions: context.recentActions.slice(\n -SCENE_CONTEXT_RECENT_ACTIONS_LIMIT,\n ),\n currentTaskGoal: context.currentTaskGoal,\n };\n}\n\nexport function buildSceneDescriptionPrompt(\n context: VisionContextSnapshot | null,\n ocrText?: string | null,\n detectedObjects?: DetectedObject[] | null,\n recognizedFaces?: RecognizedFace[] | null,\n): string {\n const payload: Record<string, unknown> = {\n task: \"describe_visual_scene\",\n instructions: SCENE_DESCRIPTION_INSTRUCTIONS,\n };\n if (context) payload.context = trimVisionContextForPrompt(context);\n const detectedText = normalizeOcrTextForPrompt(ocrText);\n if (detectedText) payload.detectedText = detectedText;\n const objects = normalizeDetectedObjectsForPrompt(detectedObjects);\n if (objects.length > 0) payload.detectedObjects = objects;\n const faces = normalizeRecognizedFacesForPrompt(recognizedFaces);\n if (faces.length > 0) payload.recognizedFaces = faces;\n return JSON.stringify(payload, null, 2);\n}\n\nfunction normalizeDetectedObjectsForPrompt(\n objects?: DetectedObject[] | null,\n): DetectedObjectForPrompt[] {\n if (!objects || objects.length === 0) return [];\n return [...objects]\n .sort((a, b) => b.confidence - a.confidence)\n .slice(0, SCENE_DESCRIPTION_OBJECT_LIMIT)\n .map((obj) => ({\n type: obj.type,\n confidence: obj.confidence,\n bbox: obj.boundingBox,\n }));\n}\n\nfunction normalizeRecognizedFacesForPrompt(\n faces?: RecognizedFace[] | null,\n): RecognizedFace[] {\n if (!faces || faces.length === 0) return [];\n const seen = new Set<string>();\n const result: RecognizedFace[] = [];\n for (const face of faces) {\n const label = face.label.trim();\n if (label.length === 0) continue;\n if (seen.has(label)) continue;\n seen.add(label);\n result.push({ label, bbox: face.bbox });\n if (result.length >= SCENE_DESCRIPTION_FACE_LIMIT) break;\n }\n return result;\n}\n\nfunction normalizeOcrTextForPrompt(text?: string | null): string | null {\n if (!text) return null;\n const seen = new Set<string>();\n const lines: string[] = [];\n\n for (const rawLine of text.split(/\\r?\\n/)) {\n const line = rawLine.replace(/\\s+/g, \" \").trim();\n if (line.length === 0) continue;\n const dedupeKey = line.toLowerCase();\n if (seen.has(dedupeKey)) continue;\n seen.add(dedupeKey);\n lines.push(line);\n if (lines.length >= SCENE_DESCRIPTION_OCR_LINE_LIMIT) break;\n }\n\n const normalized = lines\n .join(\"\\n\")\n .slice(0, SCENE_DESCRIPTION_OCR_TEXT_LIMIT)\n .trim();\n return normalized.length > 0 ? normalized : null;\n}\n\ninterface CameraDevice {\n id: string;\n name: string;\n capture: () => Promise<Buffer>;\n}\n\nexport class VisionService extends Service {\n static override serviceType: ServiceTypeName = VisionServiceType.VISION;\n override capabilityDescription =\n \"Provides visual perception through camera integration and scene analysis.\";\n\n private visionConfig: VisionConfig;\n private camera: CameraDevice | null = null;\n private lastFrame: VisionFrame | null = null;\n private lastSceneDescription: SceneDescription | null = null;\n private frameProcessingInterval: NodeJS.Timeout | null = null;\n private screenProcessingInterval: NodeJS.Timeout | null = null;\n private isProcessing = false;\n private isProcessingScreen = false;\n private objectDetector: YOLODetector | null = null;\n private hasObjectDetection = false;\n // Lazily constructed: the face backend is dynamically imported on first use\n // so plugin-vision's module graph never pulls native code at module-eval\n // (required for the Android bun-musl agent).\n private faceRecognition: FaceRecognition | null = null;\n private entityTracker: EntityTracker;\n private audioCapture: AudioCaptureService | null = null;\n private streamingAudioCapture: StreamingAudioCaptureService | null = null;\n\n // Screen vision components\n private screenCapture: ScreenCaptureService;\n private ocrService: OCRService;\n private lastScreenCapture: ScreenCapture | null = null;\n private lastEnhancedScene: EnhancedSceneDescription | null = null;\n\n // Worker manager for high-FPS processing\n private workerManager: VisionWorkerManager | null = null;\n\n // Add tracking for last update times\n private lastTfUpdateTime = 0;\n private lastVlmUpdateTime = 0;\n private lastTfDescription = \"\";\n\n // Memory-pressure pause owner for the continuous VLM describe step\n // (#9105 M8 / #9581). Gates only the expensive IMAGE_DESCRIPTION call;\n // OCR/YOLO/dHash keep running while describing is paused. Fed by both the\n // WS1 memory arbiter (when present) and a local RSS cap (always).\n private readonly describeBackpressure: DescribeBackpressureController;\n private arbiterUnsubscribe: (() => void) | null = null;\n\n // Change-gated per-tile describe (#9105). Built lazily on first VLM tick:\n // null until we know whether a perceptual hash is available. When present it\n // re-describes only the screen tiles that changed since the previous frame;\n // when absent the VLM path stays exactly as before (full-frame describe).\n private dirtyTileDescriber: DirtyTileDescriber | null = null;\n private dirtyTileDescriberInit = false;\n // Per-frame prompt context for the per-tile describe. Set immediately before\n // each `dirtyTileDescriber.describe(...)` and read by the bound describeTile\n // closure (screen/camera processing is serialized, so there is no overlap).\n private dirtyTileDescribeContext: {\n detectedObjects: DetectedObject[];\n recognizedFaces: RecognizedFace[];\n } = { detectedObjects: [], recognizedFaces: [] };\n\n // Default configuration\n private readonly DEFAULT_CONFIG: VisionConfig = {\n pixelChangeThreshold: 50, // 50% change required for VLM update\n updateInterval: 100, // Process frames every 100ms\n enablePoseDetection: false,\n enableObjectDetection: false,\n tfUpdateInterval: 1000, // TensorFlow update every 1 second\n vlmUpdateInterval: 10000, // VLM update every 10 seconds\n tfChangeThreshold: 10, // 10% change triggers TF update\n vlmChangeThreshold: 50, // 50% change triggers VLM update\n visionMode: VisionMode.CAMERA, // Default to camera only\n screenCaptureInterval: 2000, // Screen capture every 2 seconds\n tileSize: 256,\n tileProcessingOrder: \"priority\",\n ocrEnabled: true,\n };\n\n constructor(runtime?: IAgentRuntime) {\n super(runtime);\n\n // Load configuration from runtime settings\n this.visionConfig = this.parseConfig(this.runtime);\n\n // Face recognition is constructed lazily (see getFaceRecognition).\n\n // Initialize entity tracker\n const worldIdValue = this.runtime.getSetting(\"WORLD_ID\");\n const worldId =\n typeof worldIdValue === \"string\" ? worldIdValue : \"default-world\";\n this.entityTracker = new EntityTracker(worldId);\n\n // Initialize screen capture\n this.screenCapture = new ScreenCaptureService(this.visionConfig);\n\n // Initialize OCR service\n this.ocrService = new OCRService();\n\n // Memory-pressure pause owner for the continuous describe loop. The cap\n // mirrors the documented MAX_MEMORY_USAGE_MB setting (default 2000 MB);\n // `0`/invalid disables the local RSS guard so only arbiter pressure pauses.\n const memoryCapMb = Number(\n this.runtime.getSetting(\"MAX_MEMORY_USAGE_MB\") ??\n this.runtime.getSetting(\"VISION_MAX_MEMORY_USAGE_MB\") ??\n 2000,\n );\n this.describeBackpressure = new DescribeBackpressureController({\n memoryCapBytes:\n Number.isFinite(memoryCapMb) && memoryCapMb > 0\n ? memoryCapMb * 1024 * 1024\n : 0,\n });\n\n logger.info(\n \"[VisionService] Constructed with config:\",\n JSON.stringify(this.visionConfig),\n );\n }\n\n private parseConfig(runtime: IAgentRuntime): VisionConfig {\n const getSettingString = (key: string): string | undefined => {\n const value = runtime.getSetting(key);\n return value === true || value === false\n ? String(value)\n : typeof value === \"string\"\n ? value\n : typeof value === \"number\"\n ? String(value)\n : undefined;\n };\n const getBooleanSetting = (\n primaryKey: string,\n secondaryKey: string,\n defaultValue: boolean,\n ): boolean => {\n const raw =\n getSettingString(primaryKey) ?? getSettingString(secondaryKey);\n if (raw === undefined) return defaultValue;\n return raw.trim().toLowerCase() === \"true\";\n };\n\n return {\n ...this.DEFAULT_CONFIG,\n cameraName:\n getSettingString(\"CAMERA_NAME\") ||\n getSettingString(\"VISION_CAMERA_NAME\"),\n pixelChangeThreshold:\n Number(\n runtime.getSetting(\"PIXEL_CHANGE_THRESHOLD\") ||\n runtime.getSetting(\"VISION_PIXEL_CHANGE_THRESHOLD\"),\n ) || this.DEFAULT_CONFIG.pixelChangeThreshold,\n enableObjectDetection:\n runtime.getSetting(\"ENABLE_OBJECT_DETECTION\") === \"true\" ||\n runtime.getSetting(\"VISION_ENABLE_OBJECT_DETECTION\") === \"true\",\n enablePoseDetection:\n runtime.getSetting(\"ENABLE_POSE_DETECTION\") === \"true\" ||\n runtime.getSetting(\"VISION_ENABLE_POSE_DETECTION\") === \"true\",\n tfUpdateInterval:\n Number(\n runtime.getSetting(\"TF_UPDATE_INTERVAL\") ||\n runtime.getSetting(\"VISION_TF_UPDATE_INTERVAL\"),\n ) || this.DEFAULT_CONFIG.tfUpdateInterval,\n vlmUpdateInterval:\n Number(\n runtime.getSetting(\"VLM_UPDATE_INTERVAL\") ||\n runtime.getSetting(\"VISION_VLM_UPDATE_INTERVAL\"),\n ) || this.DEFAULT_CONFIG.vlmUpdateInterval,\n tfChangeThreshold:\n Number(\n runtime.getSetting(\"TF_CHANGE_THRESHOLD\") ||\n runtime.getSetting(\"VISION_TF_CHANGE_THRESHOLD\"),\n ) || this.DEFAULT_CONFIG.tfChangeThreshold,\n vlmChangeThreshold:\n Number(\n runtime.getSetting(\"VLM_CHANGE_THRESHOLD\") ||\n runtime.getSetting(\"VISION_VLM_CHANGE_THRESHOLD\"),\n ) || this.DEFAULT_CONFIG.vlmChangeThreshold,\n visionMode:\n (getSettingString(\"VISION_MODE\") as VisionMode) ||\n this.DEFAULT_CONFIG.visionMode,\n screenCaptureInterval:\n Number(\n runtime.getSetting(\"SCREEN_CAPTURE_INTERVAL\") ||\n runtime.getSetting(\"VISION_SCREEN_CAPTURE_INTERVAL\"),\n ) || this.DEFAULT_CONFIG.screenCaptureInterval,\n ocrEnabled: getBooleanSetting(\n \"OCR_ENABLED\",\n \"VISION_OCR_ENABLED\",\n this.DEFAULT_CONFIG.ocrEnabled ?? true,\n ),\n };\n }\n\n static async start(runtime: IAgentRuntime): Promise<VisionService> {\n const service = new VisionService(runtime);\n await service.initialize();\n return service;\n }\n\n private async checkCameraTools(): Promise<{\n available: boolean;\n tool: string;\n }> {\n const platform = process.platform;\n\n try {\n if (platform === \"darwin\") {\n // Check if imagesnap is installed\n await execAsync(\"which imagesnap\");\n return { available: true, tool: \"imagesnap\" };\n } else if (platform === \"linux\") {\n // Check if fswebcam is installed\n await execAsync(\"which fswebcam\");\n return { available: true, tool: \"fswebcam\" };\n } else if (platform === \"win32\") {\n // Check if ffmpeg is available\n await execAsync(\"where ffmpeg\");\n return { available: true, tool: \"ffmpeg\" };\n }\n return { available: false, tool: \"none\" };\n } catch (_error) {\n // Tool not found\n return { available: false, tool: \"none\" };\n }\n }\n\n private async initialize(): Promise<void> {\n try {\n // Initialize the ggml YOLOv8 object detector when object detection is\n // enabled. There is no pose backend yet — pose detection falls through\n // to the heuristic path (detectPeopleFromMotion).\n if (this.visionConfig.enableObjectDetection) {\n try {\n const { YOLODetector } = await import(\"./yolo-detector\");\n this.objectDetector = new YOLODetector();\n await this.objectDetector.initialize();\n this.hasObjectDetection = true;\n logger.info(\n \"[VisionService] ggml YOLOv8 object detector initialized\",\n );\n } catch (yoloError) {\n // Native lib / GGUF not built yet — leave object detection off so\n // the motion/heuristic + VLM fallback still runs. Never fake it.\n this.objectDetector = null;\n this.hasObjectDetection = false;\n logger.warn(\n \"[VisionService] ggml YOLOv8 detector unavailable, object detection disabled (using motion/heuristic + VLM fallback):\",\n yoloError instanceof Error ? yoloError.message : String(yoloError),\n );\n }\n }\n\n if (this.visionConfig.enablePoseDetection) {\n logger.warn(\n \"[VisionService] ggml pose detection is not yet available; falling back to heuristic person detection\",\n );\n }\n\n // Initialize screen vision if enabled\n if (\n this.visionConfig.visionMode === VisionMode.SCREEN ||\n this.visionConfig.visionMode === VisionMode.BOTH\n ) {\n await this.initializeScreenVision();\n }\n\n // Initialize camera if enabled\n if (\n this.visionConfig.visionMode === VisionMode.CAMERA ||\n this.visionConfig.visionMode === VisionMode.BOTH\n ) {\n await this.initializeCameraVision();\n }\n\n // Initialize audio capture if enabled\n await this.initializeAudioCapture();\n\n // Start processing based on mode\n this.startProcessing();\n } catch (error) {\n logger.error({ error }, \"[VisionService] Failed to initialize:\");\n }\n }\n\n private async initializeScreenVision(): Promise<void> {\n try {\n logger.info(\"[VisionService] Initializing screen vision...\");\n\n // Check if we should use worker threads for high-FPS processing\n const useWorkers =\n this.visionConfig.targetScreenFPS &&\n this.visionConfig.targetScreenFPS > 10;\n\n if (useWorkers) {\n // Initialize worker manager for high-FPS processing\n logger.info(\n \"[VisionService] Initializing worker threads for high-FPS processing...\",\n );\n this.workerManager = new VisionWorkerManager(this.visionConfig);\n await this.workerManager.initialize();\n logger.info(\"[VisionService] Worker threads initialized\");\n } else {\n // Initialize OCR if enabled\n if (this.visionConfig.ocrEnabled) {\n await this.ocrService.initialize();\n }\n }\n\n // Get screen info\n const screenInfo = await this.screenCapture.getScreenInfo();\n if (screenInfo) {\n logger.info(\n `[VisionService] Screen resolution: ${screenInfo.width}x${screenInfo.height}`,\n );\n }\n\n logger.info(\"[VisionService] Screen vision initialized\");\n } catch (error) {\n logger.error(\n { error },\n \"[VisionService] Failed to initialize screen vision:\",\n );\n }\n }\n\n private async initializeCameraVision(): Promise<void> {\n // Check if camera tools are available\n const toolCheck = await this.checkCameraTools();\n if (!toolCheck.available) {\n const platform = process.platform;\n const toolName =\n platform === \"darwin\"\n ? \"imagesnap\"\n : platform === \"linux\"\n ? \"fswebcam\"\n : \"ffmpeg\";\n logger.warn(\n `[VisionService] Camera capture tool '${toolName}' not found. Install it to enable camera functionality.`,\n );\n logger.warn(\"[VisionService] For macOS: brew install imagesnap\");\n logger.warn(\"[VisionService] For Linux: sudo apt-get install fswebcam\");\n logger.warn(\n \"[VisionService] For Windows: Install ffmpeg and add to PATH\",\n );\n return;\n }\n\n // Find and connect to camera\n const camera = await this.findCamera();\n if (camera) {\n this.camera = camera;\n logger.info(`[VisionService] Connected to camera: ${camera.name}`);\n } else {\n logger.warn(\"[VisionService] No suitable camera found\");\n }\n }\n\n private async initializeAudioCapture(): Promise<void> {\n const getSettingString = (key: string): string | undefined => {\n const value = this.runtime.getSetting(key);\n return value === true || value === false\n ? String(value)\n : typeof value === \"string\"\n ? value\n : typeof value === \"number\"\n ? String(value)\n : undefined;\n };\n const enableMicrophone = getSettingString(\"ENABLE_MICROPHONE\") === \"true\";\n const useStreamingAudio =\n getSettingString(\"USE_STREAMING_AUDIO\") === \"true\";\n\n if (!enableMicrophone) {\n logger.info(\"[VisionService] Microphone capture disabled\");\n return;\n }\n\n try {\n if (useStreamingAudio) {\n // Use new streaming audio with VAD\n const getSettingNumber = (\n key: string,\n defaultValue: number,\n ): number => {\n const value = this.runtime.getSetting(key);\n if (typeof value === \"number\") return value;\n if (typeof value === \"string\") {\n const parsed = Number(value);\n return Number.isNaN(parsed) ? defaultValue : parsed;\n }\n return defaultValue;\n };\n const streamingConfig: StreamingAudioConfig = {\n enabled: true,\n sampleRate: 16000,\n channels: 1,\n vadThreshold: getSettingNumber(\"VAD_THRESHOLD\", 0.01),\n silenceTimeout: getSettingNumber(\"SILENCE_TIMEOUT\", 1500),\n responseDelay: getSettingNumber(\"RESPONSE_DELAY\", 3000),\n };\n\n this.streamingAudioCapture = new StreamingAudioCaptureService(\n this.runtime,\n streamingConfig,\n );\n\n // Set up event listeners\n this.streamingAudioCapture.on(\"speechStart\", () => {\n logger.info(\"[VisionService] User started speaking\");\n });\n\n this.streamingAudioCapture.on(\"speechEnd\", () => {\n logger.info(\"[VisionService] User stopped speaking\");\n });\n\n this.streamingAudioCapture.on(\n \"transcription\",\n (data: { text: string; isFinal: boolean }) => {\n logger.info(\n `[VisionService] Transcription (${data.isFinal ? \"final\" : \"partial\"}): ${data.text}`,\n );\n },\n );\n\n this.streamingAudioCapture.on(\n \"utteranceComplete\",\n async (text: string) => {\n logger.info(\"[VisionService] Processing complete utterance:\", text);\n // Store the transcription in memory for context\n await this.storeAudioTranscription(text);\n },\n );\n\n await this.streamingAudioCapture.initialize();\n logger.info(\n \"[VisionService] Streaming audio capture initialized with VAD\",\n );\n } else {\n // Use original batch audio capture\n const getSettingNumber = (\n key: string,\n defaultValue: number,\n ): number => {\n const value = this.runtime.getSetting(key);\n if (typeof value === \"number\") return value;\n if (typeof value === \"string\") {\n const parsed = Number(value);\n return Number.isNaN(parsed) ? defaultValue : parsed;\n }\n return defaultValue;\n };\n const audioConfig: AudioConfig = {\n enabled: true,\n transcriptionInterval: getSettingNumber(\n \"TRANSCRIPTION_INTERVAL\",\n 30000,\n ),\n };\n\n this.audioCapture = new AudioCaptureService(this.runtime, audioConfig);\n await this.audioCapture.initialize();\n logger.info(\"[VisionService] Batch audio capture initialized\");\n }\n } catch (error) {\n logger.error(\n { error },\n \"[VisionService] Failed to initialize audio capture:\",\n );\n // Continue without audio\n }\n }\n\n private async storeAudioTranscription(text: string): Promise<void> {\n try {\n // Store transcription in the current scene description\n if (this.lastSceneDescription) {\n this.lastSceneDescription.audioTranscription = text;\n }\n\n // You could also create a memory here if needed\n logger.debug(\n \"[VisionService] Stored audio transcription in scene context\",\n );\n } catch (error) {\n logger.error(\n { error },\n \"[VisionService] Failed to store audio transcription:\",\n );\n }\n }\n\n private startProcessing(): void {\n // Wire the continuous describe loop to the memory arbiter (if WS1 is\n // loaded) so device memory pressure pauses the expensive VLM describe.\n this.attachMemoryArbiter();\n\n // Start camera processing if enabled\n if (\n (this.visionConfig.visionMode === VisionMode.CAMERA ||\n this.visionConfig.visionMode === VisionMode.BOTH) &&\n this.camera\n ) {\n this.startFrameProcessing();\n }\n\n // Start screen processing if enabled\n if (\n this.visionConfig.visionMode === VisionMode.SCREEN ||\n this.visionConfig.visionMode === VisionMode.BOTH\n ) {\n this.startScreenProcessing();\n }\n }\n\n /**\n * Subscribe the describe-backpressure controller to WS1 memory-pressure\n * events. Resolves the arbiter dynamically (no hard dependency on\n * `@elizaos/plugin-local-inference`); when none is registered the controller\n * still pauses on the local RSS cap. Idempotent — a prior subscription is\n * released first so a restart doesn't double-subscribe.\n */\n private attachMemoryArbiter(): void {\n if (this.arbiterUnsubscribe) {\n this.arbiterUnsubscribe();\n this.arbiterUnsubscribe = null;\n }\n const arbiter = resolveArbiterFromRuntime(this.runtime);\n if (!arbiter) return;\n // `onPressure` fires with a non-empty holder list when pressure is high\n // enough to shed load, and (on the WS1 bridge) an empty list on any\n // non-nominal tier. Either way that means \"pause describing\"; the next\n // tick with no pressure event keeps describing. The bridge only emits on\n // pressure, so we treat any callback as \"critical\" and rely on the WS1\n // side clearing — for finer levels a direct IModelArbiter can be extended\n // later. Empty/any callback ⇒ pause.\n this.arbiterUnsubscribe = arbiter.onPressure(() => {\n this.describeBackpressure.setPressure(\"critical\");\n });\n logger.debug(\"[VisionService] Memory arbiter attached to describe loop\");\n }\n\n /**\n * Clear the arbiter-driven pause. Called by the WS1 bridge consumer when\n * pressure returns to nominal; also exposed so an embedder can resume the\n * describe loop explicitly.\n */\n public resumeDescribeLoop(): void {\n this.describeBackpressure.setPressure(\"nominal\");\n }\n\n /** Current describe-backpressure stats (telemetry / tests). */\n public getBackpressureStats() {\n return this.describeBackpressure.stats();\n }\n\n private startFrameProcessing(): void {\n if (this.frameProcessingInterval) {\n return;\n }\n\n this.frameProcessingInterval = setInterval(async () => {\n if (!this.isProcessing && this.camera) {\n this.isProcessing = true;\n try {\n await this.captureAndProcessFrame();\n } catch (error) {\n logger.error({ error }, \"[VisionService] Frame processing error:\");\n }\n this.isProcessing = false;\n }\n }, this.visionConfig.updateInterval || 100);\n\n logger.debug(\"[VisionService] Started frame processing loop\");\n }\n\n private async captureAndProcessFrame(): Promise<void> {\n if (!this.camera) {\n return;\n }\n\n try {\n // Capture frame from camera\n const frameData = await this.camera.capture();\n\n // Skip if no data\n if (!frameData || frameData.length === 0) {\n logger.debug(\"[VisionService] Camera returned empty frame, skipping\");\n return;\n }\n\n // Convert to standardized format\n const frame = await this.processFrameData(frameData);\n\n // Validate frame before processing\n if (!frame || frame.width === 0 || frame.height === 0) {\n logger.warn(\"[VisionService] Invalid frame dimensions, skipping\");\n return;\n }\n\n // Check if scene has changed significantly\n const changePercentage = this.lastFrame\n ? await this.calculatePixelChange(this.lastFrame, frame)\n : 100;\n\n // Update scene description if change is significant or enough time has passed\n // Always call updateSceneDescription - it will decide what to update based on thresholds\n await this.updateSceneDescription(frame, changePercentage);\n\n this.lastFrame = frame;\n } catch (error) {\n logger.error({ error }, \"[VisionService] Error capturing frame:\");\n }\n }\n\n private async processFrameData(data: Buffer): Promise<VisionFrame> {\n await assertValidVisionImageBuffer(data);\n\n // Use sharp to ensure consistent format\n const sharp = await getSharp();\n const image = sharp(data);\n const metadata = await image.metadata();\n\n // Validate metadata\n if (\n !metadata.width ||\n !metadata.height ||\n metadata.width === 0 ||\n metadata.height === 0\n ) {\n throw new Error(\n `Invalid image dimensions: ${metadata.width}x${metadata.height}`,\n );\n }\n\n const rgbaBuffer = await image.ensureAlpha().raw().toBuffer();\n\n return {\n timestamp: Date.now(),\n width: metadata.width,\n height: metadata.height,\n data: rgbaBuffer,\n format: \"rgba\",\n };\n }\n\n private async calculatePixelChange(\n frame1: VisionFrame,\n frame2: VisionFrame,\n ): Promise<number> {\n if (frame1.width !== frame2.width || frame1.height !== frame2.height) {\n return 100; // Different dimensions = complete change\n }\n\n const pixels1 = frame1.data;\n const pixels2 = frame2.data;\n let changedPixels = 0;\n const totalPixels = frame1.width * frame1.height;\n const threshold = 30; // RGB difference threshold\n\n for (let i = 0; i < pixels1.length; i += 4) {\n const r1 = pixels1[i];\n const g1 = pixels1[i + 1];\n const b1 = pixels1[i + 2];\n const r2 = pixels2[i];\n const g2 = pixels2[i + 1];\n const b2 = pixels2[i + 2];\n\n const diff = Math.abs(r1 - r2) + Math.abs(g1 - g2) + Math.abs(b1 - b2);\n if (diff > threshold) {\n changedPixels++;\n }\n }\n\n return (changedPixels / totalPixels) * 100;\n }\n\n private async updateSceneDescription(\n frame: VisionFrame,\n changePercentage: number,\n ): Promise<void> {\n try {\n const currentTime = Date.now();\n const previousSceneDescription = this.lastSceneDescription;\n\n // Test-input override: when ELIZA_VISION_TEST_INPUT=image, replace the\n // captured frame with the fixture PNG so the rest of the pipeline runs\n // unmodified. Returns null when no override is active.\n const testImage = getTestImage();\n\n // Convert frame to base64 for VLM\n const sharp = await getSharp();\n const jpegBuffer = testImage\n ? await sharp(testImage).jpeg().toBuffer()\n : await sharp(frame.data, {\n raw: {\n width: frame.width,\n height: frame.height,\n channels: 4,\n },\n })\n .jpeg()\n .toBuffer();\n\n const base64Image = jpegBuffer.toString(\"base64\");\n const imageUrl = `data:image/jpeg;base64,${base64Image}`;\n\n // Determine if we should update VLM description\n const timeSinceVlmUpdate = currentTime - this.lastVlmUpdateTime;\n const vlmUpdateInterval = this.visionConfig.vlmUpdateInterval ?? 10000;\n const vlmChangeThreshold = this.visionConfig.vlmChangeThreshold ?? 50;\n const shouldUpdateVlm =\n timeSinceVlmUpdate >= vlmUpdateInterval || // Time threshold\n changePercentage >= vlmChangeThreshold; // Change threshold\n\n let description =\n previousSceneDescription?.description ?? this.lastTfDescription;\n let descriptionTimestamp =\n previousSceneDescription?.descriptionTimestamp ??\n previousSceneDescription?.timestamp ??\n frame.timestamp;\n let descriptionStale = false;\n let describePaused = false;\n let describePauseReason: Exclude<DescribePauseReason, null> | undefined;\n\n // Determine if we should update TensorFlow detections\n const timeSinceTfUpdate = currentTime - this.lastTfUpdateTime;\n const tfUpdateInterval = this.visionConfig.tfUpdateInterval ?? 1000;\n const tfChangeThreshold = this.visionConfig.tfChangeThreshold ?? 10;\n const shouldUpdateTf =\n timeSinceTfUpdate >= tfUpdateInterval || // Time threshold\n changePercentage >= tfChangeThreshold; // Change threshold\n\n let detectedObjects: DetectedObject[] = [];\n let people: PersonInfo[] = [];\n\n if (\n shouldUpdateTf &&\n (this.visionConfig.enableObjectDetection ||\n this.visionConfig.enablePoseDetection)\n ) {\n this.lastTfUpdateTime = currentTime;\n logger.debug(\n `[VisionService] TF updating: ${timeSinceTfUpdate}ms since last update, ${changePercentage.toFixed(1)}% change`,\n );\n\n // Object detection via the ggml YOLOv8 detector. The detector\n // consumes an encoded image buffer (it reads metadata via sharp), so\n // we reuse the JPEG already produced above for the VLM path.\n if (this.visionConfig.enableObjectDetection && this.objectDetector) {\n try {\n detectedObjects = await this.objectDetector.detect(jpegBuffer);\n logger.debug(\n `[VisionService] YOLOv8 detected ${detectedObjects.length} objects`,\n );\n } catch (detectError) {\n logger.warn(\n \"[VisionService] YOLOv8 object detection failed, falling back to motion-based:\",\n detectError instanceof Error\n ? detectError.message\n : String(detectError),\n );\n detectedObjects = await this.detectMotionObjects(frame);\n }\n }\n\n // No ggml pose backend yet — when pose detection is requested, fall\n // through to the heuristic person detector (motion-derived candidates\n // → coarse pose/facing). Keeps the PersonInfo shape intact.\n if (this.visionConfig.enablePoseDetection && people.length === 0) {\n const motionObjects = await this.detectMotionObjects(frame);\n people = await this.detectPeopleFromMotion(frame, motionObjects);\n }\n\n // If no people detected via pose but objects detected, check for person objects\n if (people.length === 0 && detectedObjects.length > 0) {\n const personObjects = detectedObjects.filter(\n (obj) => obj.type === \"person\",\n );\n people = personObjects.map((obj) => ({\n id: `person-${obj.id}`,\n pose: \"unknown\" as const,\n facing: \"unknown\" as const,\n confidence: obj.confidence,\n boundingBox: obj.boundingBox,\n }));\n }\n } else if (!shouldUpdateTf && this.lastSceneDescription) {\n // Reuse last detection results if not updating\n detectedObjects = this.lastSceneDescription.objects;\n people = this.lastSceneDescription.people;\n } else {\n // Fall back to motion-based detection\n detectedObjects = await this.detectMotionObjects(frame);\n people = await this.detectPeopleFromMotion(frame, detectedObjects);\n }\n\n // Face recognition and entity tracking\n const faceProfiles = new Map<string, string>();\n const recognizedFaces: RecognizedFace[] = [];\n const getSettingString = (key: string): string | undefined => {\n const value = this.runtime.getSetting(key);\n return value === true || value === false\n ? String(value)\n : typeof value === \"string\"\n ? value\n : typeof value === \"number\"\n ? String(value)\n : undefined;\n };\n const enableFaceRecognition =\n getSettingString(\"ENABLE_FACE_RECOGNITION\") === \"true\";\n\n if (\n enableFaceRecognition &&\n people.length > 0 &&\n frame.width > 0 &&\n frame.height > 0 &&\n frame.data.length > 0\n ) {\n try {\n // Detect faces in the frame\n const faceRecognition = await this.getFaceRecognition();\n const faces = await faceRecognition.detectFaces(\n frame.data,\n frame.width,\n frame.height,\n );\n\n // Match faces to people based on bounding box overlap\n for (const face of faces) {\n const faceBox = face.detection.box;\n\n // Find the person this face belongs to\n for (const person of people) {\n const overlap = this.calculateBoxOverlap(person.boundingBox, {\n x: Math.round(faceBox.x),\n y: Math.round(faceBox.y),\n width: Math.round(faceBox.width),\n height: Math.round(faceBox.height),\n });\n\n if (overlap > 0.5) {\n // 50% overlap threshold\n // Recognize or register the face\n const match = await faceRecognition.recognizeFace(\n face.descriptor,\n );\n let profileId: string;\n\n if (match) {\n profileId = match.profileId;\n logger.debug(\n `[VisionService] Recognized face: ${profileId} (distance: ${match.distance})`,\n );\n } else {\n // Register new face. The native ggml backend produces no\n // expression / age-gender estimates, so no attributes.\n profileId = await faceRecognition.addOrUpdateFace(\n face.descriptor,\n );\n logger.info(\n `[VisionService] New face registered: ${profileId}`,\n );\n }\n\n faceProfiles.set(person.id, profileId);\n const profile = faceRecognition.getFaceProfile(profileId);\n recognizedFaces.push({\n label: profile?.name ?? profileId,\n bbox: {\n x: Math.round(faceBox.x),\n y: Math.round(faceBox.y),\n width: Math.round(faceBox.width),\n height: Math.round(faceBox.height),\n },\n });\n break;\n }\n }\n }\n } catch (faceError) {\n logger.error(\n { error: faceError },\n \"[VisionService] Face recognition error:\",\n );\n }\n }\n\n // VLM scene description runs after detection so the success path can\n // feed the model the freshly-computed YOLO objects + recognized faces\n // as additional context alongside the image. The describe step is the\n // dominant token + RAM cost, so it is gated by the memory-pressure\n // backpressure owner: under device pressure or over the RSS cap we skip\n // the VLM call (keeping the cheap OCR/YOLO/dHash work) and reuse the last\n // description until pressure clears (#9105 M8 / #9581).\n const describeGate = shouldUpdateVlm\n ? this.describeBackpressure.evaluate()\n : null;\n if (describeGate?.transitionedTo === \"paused\") {\n logger.info(\n `[VisionService] VLM describe paused (${describeGate.reason}); reusing last scene description`,\n );\n } else if (describeGate?.transitionedTo === \"active\") {\n logger.info(\"[VisionService] VLM describe resumed\");\n }\n if (describeGate?.warnPaused) {\n const stats = this.describeBackpressure.stats();\n logger.warn(\n {\n reason: describeGate.reason,\n pausedForMs: describeGate.pausedForMs,\n describesSkipped: stats.describesSkipped,\n memoryGrowthBytes: stats.memoryGrowthBytes,\n },\n \"[VisionService] VLM describe still paused; reusing stale scene description\",\n );\n }\n if (shouldUpdateVlm && describeGate?.describe) {\n // Prefer the change-gated per-tile describe on incremental updates: once\n // a prior scene description exists we only re-describe the tiles that\n // changed since the last frame (the rest reuse cached tile text), which\n // avoids paying for a full-frame VLM pass every tick. The first frame,\n // the test-image override, and any unavailable/empty result fall back to\n // the full-frame describe below.\n const incremental =\n !testImage && this.lastSceneDescription\n ? await this.describeSceneWithDirtyTiles(\n await sharp(frame.data, {\n raw: {\n width: frame.width,\n height: frame.height,\n channels: 4,\n },\n })\n .png()\n .toBuffer(),\n frame.width,\n frame.height,\n detectedObjects,\n recognizedFaces,\n )\n : null;\n description =\n incremental ??\n (await this.describeSceneWithVLM(\n imageUrl,\n detectedObjects,\n recognizedFaces,\n ));\n this.lastVlmUpdateTime = currentTime;\n this.lastTfDescription = description;\n descriptionTimestamp = frame.timestamp;\n logger.debug(\n `[VisionService] VLM updated: ${timeSinceVlmUpdate}ms since last update, ${changePercentage.toFixed(1)}% change${\n incremental ? \" (per-tile)\" : \" (full-frame)\"\n }`,\n );\n } else if (shouldUpdateVlm && describeGate && !describeGate.describe) {\n describePaused = true;\n describePauseReason = describeGate.reason ?? undefined;\n if (previousSceneDescription?.description) {\n description = previousSceneDescription.description;\n descriptionTimestamp =\n previousSceneDescription.descriptionTimestamp ??\n previousSceneDescription.timestamp;\n descriptionStale = true;\n }\n }\n\n // Update entity tracker\n const _trackedEntities = await this.entityTracker.updateEntities(\n detectedObjects,\n people,\n faceProfiles,\n this.runtime,\n );\n\n // Create scene description\n this.lastSceneDescription = {\n timestamp: frame.timestamp,\n descriptionTimestamp,\n description,\n objects: detectedObjects,\n people,\n sceneChanged: shouldUpdateVlm || shouldUpdateTf,\n changePercentage,\n descriptionStale,\n describePaused,\n ...(describePauseReason ? { describePauseReason } : {}),\n };\n\n // Enhanced logging\n if (shouldUpdateVlm || shouldUpdateTf) {\n logger.info(\"[VisionService] Scene Analysis Complete:\");\n logger.info(` VLM Description: ${description.substring(0, 100)}...`);\n logger.info(` Change: ${changePercentage.toFixed(1)}%`);\n logger.info(\n ` Updates: ${shouldUpdateVlm ? \"VLM\" : \"\"}${shouldUpdateVlm && shouldUpdateTf ? \" + \" : \"\"}${shouldUpdateTf ? \"TF\" : \"\"}`,\n );\n logger.info(\n ` Detection Mode: ${this.hasObjectDetection ? \"ggml YOLOv8\" : \"Motion-based\"}`,\n );\n\n if (detectedObjects.length > 0) {\n logger.info(` Objects: ${detectedObjects.length} detected`);\n\n // Group objects by type for summary\n const objectSummary = detectedObjects.reduce(\n (acc, obj) => {\n acc[obj.type] = (acc[obj.type] || 0) + 1;\n return acc;\n },\n {} as Record<string, number>,\n );\n\n for (const [type, count] of Object.entries(objectSummary)) {\n logger.info(` - ${count} ${type}(s)`);\n }\n }\n\n if (people.length > 0) {\n logger.info(` People: ${people.length} detected`);\n for (const person of people) {\n logger.info(\n ` - Person: ${person.pose} pose, facing ${person.facing}, confidence: ${person.confidence.toFixed(2)}`,\n );\n }\n }\n }\n } catch (error) {\n logger.error(\n { error },\n \"[VisionService] Failed to update scene description:\",\n );\n }\n }\n\n /**\n * Normalize the various shapes that `useModel(IMAGE_DESCRIPTION, …)` may\n * return into a non-empty string. Returns `null` when the result is the\n * \"I'm unable to analyze images\" sentinel or empty.\n */\n private extractDescriptionFromUseModel(result: unknown): string | null {\n if (!result) return null;\n let description = \"\";\n if (typeof result === \"string\") description = result;\n else if (\n typeof result === \"object\" &&\n result !== null &&\n \"description\" in result\n ) {\n const d = (result as { description?: unknown }).description;\n if (typeof d === \"string\") description = d;\n }\n if (!description) return null;\n if (\n description.includes(\"I'm unable to analyze images\") ||\n description.includes(\"I can't analyze images\")\n ) {\n return null;\n }\n return description;\n }\n\n /**\n * Pull the latest desktop scene context from plugin-computeruse's\n * VisionContextProvider when registered. Returns `null` when no provider is\n * available (or when the lookup fails) so the VLM still receives a valid\n * prompt — the context block is purely additive.\n */\n private async collectVisionContext(): Promise<VisionContextSnapshot | null> {\n const candidate = this.runtime.getService(VISION_CONTEXT_SERVICE_TYPE);\n if (!isVisionContextProvider(candidate)) return null;\n try {\n return await candidate.getContext();\n } catch (error) {\n logger.warn(\n { error },\n \"[VisionService] vision-context provider getContext() failed:\",\n );\n return null;\n }\n }\n\n private collectCurrentOcrTextForPrompt(): string | null {\n const screenAnalysis = this.lastEnhancedScene?.screenAnalysis;\n const candidates = [\n screenAnalysis?.fullScreenOCR,\n screenAnalysis?.activeTile?.ocr?.fullText,\n screenAnalysis?.activeTile?.text,\n ];\n const text = candidates\n .filter((candidate): candidate is string => Boolean(candidate?.trim()))\n .join(\"\\n\");\n return text.length > 0 ? text : null;\n }\n\n /**\n * Resolve the change-gated per-tile describer, building it once. Returns\n * `null` (and degrades to full-frame describe) when no perceptual hash is\n * available — i.e. plugin-computeruse's `frameDhash` cannot be imported.\n *\n * The dHash is resolved via a best-effort dynamic import so plugin-vision\n * never eagerly pulls computeruse's module graph at boot (same idiom as the\n * coord-OCR bridge wiring in `index.ts`).\n */\n private async ensureDirtyTileDescriber(): Promise<DirtyTileDescriber | null> {\n if (this.dirtyTileDescriberInit) {\n return this.dirtyTileDescriber;\n }\n this.dirtyTileDescriberInit = true;\n const hashTile = await this.resolveFrameHash();\n if (!hashTile) {\n logger.debug(\n \"[VisionService] per-tile dHash unavailable; using full-frame VLM describe\",\n );\n return null;\n }\n const describeTile = this.buildTileDescribeFn();\n this.dirtyTileDescriber = new DirtyTileDescriber({\n hashTile,\n describeTile,\n });\n logger.info(\n \"[VisionService] change-gated per-tile describe enabled (#9105)\",\n );\n return this.dirtyTileDescriber;\n }\n\n private async resolveFrameHash(): Promise<FrameHash | null> {\n // Indirect the specifier through a const so the bundler does not eagerly\n // resolve the optional peer at build time (same idiom as the OCR-bridge\n // dynamic import in index.ts) — plugin-computeruse is an optional peer.\n const computerUseSpecifier = \"@elizaos/plugin-computeruse\";\n try {\n const mod = (await import(/* @vite-ignore */ computerUseSpecifier)) as {\n frameDhash?: FrameHash;\n };\n return typeof mod.frameDhash === \"function\" ? mod.frameDhash : null;\n } catch (err) {\n logger.debug(\n `[VisionService] plugin-computeruse dHash not available (${\n err instanceof Error ? err.message : String(err)\n })`,\n );\n return null;\n }\n }\n\n /**\n * Build the per-tile describe call bound to this service's runtime. Reads the\n * current frame's prompt context (`dirtyTileDescribeContext`) so each tile is\n * described with the same context the full-frame path would use.\n */\n private buildTileDescribeFn(): TileDescribeFn {\n return createTileDescribeFn({\n buildTileImageUrl: tilePngToImageUrl,\n buildTilePrompt: async () => {\n const sceneContext = await this.collectVisionContext();\n return buildSceneDescriptionPrompt(\n sceneContext,\n this.collectCurrentOcrTextForPrompt(),\n this.dirtyTileDescribeContext.detectedObjects,\n this.dirtyTileDescribeContext.recognizedFaces,\n );\n },\n invokeModel: (imageUrl, prompt) =>\n this.runtime.useModel(ModelType.IMAGE_DESCRIPTION, {\n imageUrl,\n prompt,\n }),\n extractDescription: (result) =>\n this.extractDescriptionFromUseModel(result),\n });\n }\n\n /**\n * Per-tile incremental scene describe. Re-describes only the tiles whose\n * perceptual hash changed since the previous frame; unchanged tiles reuse\n * their cached description. Returns `null` when the per-tile path is\n * unavailable or yields no usable text, so the caller falls back to the\n * full-frame describe.\n */\n private async describeSceneWithDirtyTiles(\n pngBytes: Buffer,\n width: number,\n height: number,\n detectedObjects: DetectedObject[],\n recognizedFaces: RecognizedFace[],\n ): Promise<string | null> {\n const describer = await this.ensureDirtyTileDescriber();\n if (!describer) return null;\n this.dirtyTileDescribeContext = { detectedObjects, recognizedFaces };\n const out = await describer.describe({\n displayId: 0,\n width,\n height,\n pngBytes,\n });\n const stats = describer.getStats();\n logger.debug(\n `[VisionService] dirty-tile describe: ${out.tiles.length} tiles, ${stats.tilesSkipped} reused, ~${stats.approxTokensSaved} tokens saved`,\n );\n const scene = out.vlmScene.trim();\n return scene.length > 0 ? scene : null;\n }\n\n private async describeSceneWithVLM(\n imageUrl: string,\n detectedObjects: DetectedObject[] = [],\n recognizedFaces: RecognizedFace[] = [],\n ): Promise<string> {\n return withStandaloneTrajectory(\n this.runtime,\n {\n source: \"plugin-vision:scene-description\",\n metadata: { modelType: ModelType.IMAGE_DESCRIPTION },\n },\n () =>\n this.describeSceneWithVLMInTrajectory(\n imageUrl,\n detectedObjects,\n recognizedFaces,\n ),\n );\n }\n\n private async describeSceneWithVLMInTrajectory(\n imageUrl: string,\n detectedObjects: DetectedObject[],\n recognizedFaces: RecognizedFace[],\n ): Promise<string> {\n try {\n try {\n parseVisionDataImageUrl(imageUrl);\n } catch (inputError) {\n logger.warn(\n \"[VisionService] rejected unsafe VLM image input:\",\n inputError instanceof Error ? inputError.message : String(inputError),\n );\n return \"Unable to describe scene\";\n }\n\n // Route every VLM call through the runtime IMAGE_DESCRIPTION handler.\n // When eliza-1 local Gemma vision is registered it owns this slot;\n // otherwise the runtime rotates to whichever cloud/remote provider\n // has registered IMAGE_DESCRIPTION. plugin-vision no longer ships its\n // own VLM.\n const sceneContext = await this.collectVisionContext();\n const prompt = buildSceneDescriptionPrompt(\n sceneContext,\n this.collectCurrentOcrTextForPrompt(),\n detectedObjects,\n recognizedFaces,\n );\n try {\n const result = await this.runtime.useModel(\n ModelType.IMAGE_DESCRIPTION,\n { imageUrl, prompt },\n );\n const description = this.extractDescriptionFromUseModel(result);\n if (description) {\n return description;\n }\n } catch (modelError) {\n logger.warn(\n { error: modelError },\n \"[VisionService] IMAGE_DESCRIPTION call failed:\",\n );\n }\n\n // No usable VLM result — synthesize a description from the latest\n // detector (YOLO / pose) outputs so callers always get something.\n if (this.lastSceneDescription) {\n const { objects, people } = this.lastSceneDescription;\n let description = \"Scene contains\";\n\n if (people.length > 0) {\n description += ` ${people.length} person${people.length > 1 ? \"s\" : \"\"}`;\n const poses = people\n .map((p) => p.pose)\n .filter((p) => p !== \"unknown\");\n if (poses.length > 0) {\n description += ` (${poses.join(\", \")})`;\n }\n }\n\n if (objects.length > 0 && people.length > 0) {\n description += \" and\";\n }\n\n if (objects.length > 0) {\n const objectTypes = [...new Set(objects.map((o) => o.type))];\n description += ` ${objectTypes.join(\", \")}`;\n }\n\n if (people.length === 0 && objects.length === 0) {\n description = \"Scene appears to be empty or static\";\n }\n\n return description;\n }\n\n // Final fallback\n return \"Visual scene captured\";\n } catch (error) {\n logger.error({ error }, \"[VisionService] VLM description failed:\");\n return \"Unable to describe scene\";\n }\n }\n\n private async detectMotionObjects(\n frame: VisionFrame,\n ): Promise<DetectedObject[]> {\n if (!this.lastFrame) {\n return [];\n }\n\n const objects: DetectedObject[] = [];\n const blockSize = 64; // Larger blocks for less noise\n const motionThreshold = 50; // Higher threshold for more significant changes\n\n // Divide frame into blocks and detect motion regions\n for (let y = 0; y < frame.height - blockSize; y += blockSize / 2) {\n // Overlap blocks\n for (let x = 0; x < frame.width - blockSize; x += blockSize / 2) {\n let blockMotion = 0;\n let pixelCount = 0;\n\n // Check motion in this block\n for (let by = 0; by < blockSize; by += 2) {\n // Sample every other pixel for speed\n for (let bx = 0; bx < blockSize; bx += 2) {\n const px = x + bx;\n const py = y + by;\n const idx = (py * frame.width + px) * 4;\n\n if (idx < frame.data.length && idx < this.lastFrame.data.length) {\n const r1 = frame.data[idx];\n const g1 = frame.data[idx + 1];\n const b1 = frame.data[idx + 2];\n const r2 = this.lastFrame.data[idx];\n const g2 = this.lastFrame.data[idx + 1];\n const b2 = this.lastFrame.data[idx + 2];\n\n const diff =\n Math.abs(r1 - r2) + Math.abs(g1 - g2) + Math.abs(b1 - b2);\n if (diff > motionThreshold) {\n blockMotion++;\n }\n pixelCount++;\n }\n }\n }\n\n // If significant motion in block, consider it an object\n const motionPercentage = (blockMotion / pixelCount) * 100;\n if (motionPercentage > 30) {\n // 30% of sampled pixels show motion\n objects.push({\n id: `motion-${x}-${y}-${frame.timestamp}`,\n type: \"motion-object\",\n confidence: Math.min(motionPercentage / 100, 1),\n boundingBox: {\n x,\n y,\n width: blockSize,\n height: blockSize,\n },\n });\n }\n }\n }\n\n // Merge adjacent motion blocks into larger objects\n const merged = this.mergeAdjacentObjects(objects);\n\n // Filter out very small objects (likely noise)\n const filtered = merged.filter((obj) => {\n const area = obj.boundingBox.width * obj.boundingBox.height;\n return area > 2000; // Minimum area threshold\n });\n\n return filtered;\n }\n\n private mergeAdjacentObjects(objects: DetectedObject[]): DetectedObject[] {\n if (objects.length === 0) {\n return [];\n }\n\n const merged: DetectedObject[] = [];\n const used = new Set<number>();\n const mergeDistance = 80; // Distance to consider objects adjacent\n\n for (let i = 0; i < objects.length; i++) {\n if (used.has(i)) {\n continue;\n }\n\n const current = objects[i];\n const cluster: DetectedObject[] = [current];\n used.add(i);\n\n // Find all adjacent objects\n let foundNew = true;\n while (foundNew) {\n foundNew = false;\n for (let j = 0; j < objects.length; j++) {\n if (used.has(j)) {\n continue;\n }\n\n const other = objects[j];\n\n // Check if adjacent to any object in cluster\n for (const clusterObj of cluster) {\n const isAdjacent =\n Math.abs(clusterObj.boundingBox.x - other.boundingBox.x) <=\n mergeDistance &&\n Math.abs(clusterObj.boundingBox.y - other.boundingBox.y) <=\n mergeDistance;\n\n if (isAdjacent) {\n cluster.push(other);\n used.add(j);\n foundNew = true;\n break;\n }\n }\n }\n }\n\n // Merge cluster into single object\n if (cluster.length > 0) {\n const minX = Math.min(...cluster.map((o) => o.boundingBox.x));\n const minY = Math.min(...cluster.map((o) => o.boundingBox.y));\n const maxX = Math.max(\n ...cluster.map((o) => o.boundingBox.x + o.boundingBox.width),\n );\n const maxY = Math.max(\n ...cluster.map((o) => o.boundingBox.y + o.boundingBox.height),\n );\n const avgConfidence =\n cluster.reduce((sum, o) => sum + o.confidence, 0) / cluster.length;\n\n merged.push({\n id: `merged-${minX}-${minY}-${Date.now()}`,\n type: this.classifyObjectBySize(maxX - minX, maxY - minY),\n confidence: avgConfidence,\n boundingBox: {\n x: minX,\n y: minY,\n width: maxX - minX,\n height: maxY - minY,\n },\n });\n }\n }\n\n return merged;\n }\n\n private classifyObjectBySize(width: number, height: number): string {\n const area = width * height;\n const aspectRatio = width / height;\n\n // Improved classification heuristics\n if (area > 30000 && aspectRatio > 0.4 && aspectRatio < 0.8) {\n return \"person-candidate\";\n } else if (area > 20000) {\n return \"large-object\";\n } else if (area > 8000) {\n return \"medium-object\";\n } else {\n return \"small-object\";\n }\n }\n\n private async detectPeopleFromMotion(\n frame: VisionFrame,\n objects: DetectedObject[],\n ): Promise<PersonInfo[]> {\n const people: PersonInfo[] = [];\n const personCandidates = objects.filter(\n (o) => o.type === \"person-candidate\",\n );\n\n for (let i = 0; i < personCandidates.length; i++) {\n const candidate = personCandidates[i];\n const box = candidate.boundingBox;\n\n // Simple heuristic: if height > width * 1.5, likely standing\n // if width > height, likely sitting/lying\n const aspectRatio = box.width / box.height;\n let pose: \"standing\" | \"sitting\" | \"lying\" | \"unknown\" = \"unknown\";\n\n if (aspectRatio < 0.6) {\n pose = \"standing\";\n } else if (aspectRatio > 1.2) {\n pose = \"lying\";\n } else {\n pose = \"sitting\";\n }\n\n // Estimate facing based on motion direction (simplified)\n let facing: \"camera\" | \"away\" | \"left\" | \"right\" | \"unknown\" = \"unknown\";\n if (this.lastFrame) {\n // Without a pose backend this service only records a coarse default.\n facing = \"camera\"; // Default assumption\n }\n\n people.push({\n id: `person-${i}-${frame.timestamp}`,\n confidence: candidate.confidence,\n pose,\n facing,\n boundingBox: box,\n });\n }\n\n return people;\n }\n\n private startScreenProcessing(): void {\n if (this.screenProcessingInterval) {\n return;\n }\n\n this.screenProcessingInterval = setInterval(async () => {\n if (!this.isProcessingScreen) {\n this.isProcessingScreen = true;\n try {\n await this.captureAndProcessScreen();\n } catch (error) {\n logger.error({ error }, \"[VisionService] Screen processing error:\");\n }\n this.isProcessingScreen = false;\n }\n }, this.visionConfig.screenCaptureInterval || 2000);\n\n logger.debug(\"[VisionService] Started screen processing loop\");\n }\n\n private async captureAndProcessScreen(): Promise<void> {\n try {\n // Capture screen\n const capture = await this.screenCapture.captureScreen();\n this.lastScreenCapture = capture;\n\n // Process active tile\n const activeTile = this.screenCapture.getActiveTile();\n if (activeTile?.data) {\n const tileAnalysis = await this.analyzeTile(activeTile);\n activeTile.analysis = tileAnalysis;\n }\n\n // Update enhanced scene description\n await this.updateEnhancedSceneDescription();\n } catch (error) {\n logger.error({ error }, \"[VisionService] Error capturing screen:\");\n }\n }\n\n private async analyzeTile(tile: ScreenTile): Promise<TileAnalysis> {\n const analysis: TileAnalysis = {\n timestamp: Date.now(),\n };\n\n try {\n // Run OCR if enabled — coordinates feed back to the agent for grounding.\n if (this.visionConfig.ocrEnabled && tile.data) {\n analysis.ocr = await this.ocrService.extractFromTile(tile);\n analysis.text = analysis.ocr.fullText;\n }\n } catch (error) {\n logger.error({ error }, \"[VisionService] Error analyzing tile:\");\n }\n\n return analysis;\n }\n\n private async updateEnhancedSceneDescription(): Promise<void> {\n if (!this.lastScreenCapture) {\n return;\n }\n\n const enhancedScene: EnhancedSceneDescription = {\n ...(this.lastSceneDescription || {\n timestamp: Date.now(),\n description: \"\",\n objects: [],\n people: [],\n sceneChanged: false,\n changePercentage: 0,\n }),\n screenCapture: this.lastScreenCapture,\n screenAnalysis: {\n fullScreenOCR: \"\",\n activeTile: this.screenCapture.getActiveTile()?.analysis,\n gridSummary: \"\",\n focusedApp: \"\",\n uiElements: [],\n },\n };\n\n // Aggregate OCR from all processed tiles\n const processedTiles = this.lastScreenCapture.tiles.filter(\n (t) => t.analysis?.ocr,\n );\n if (processedTiles.length > 0 && enhancedScene.screenAnalysis) {\n enhancedScene.screenAnalysis.fullScreenOCR = processedTiles\n .map((t) => t.analysis?.ocr?.fullText)\n .join(\"\\n\");\n }\n\n // Generate grid summary\n if (\n this.lastScreenCapture.tiles.length > 0 &&\n enhancedScene.screenAnalysis\n ) {\n const tilesWithContent = this.lastScreenCapture.tiles.filter(\n (t) => t.analysis,\n );\n enhancedScene.screenAnalysis.gridSummary = `Screen divided into ${this.lastScreenCapture.tiles.length} tiles, ${tilesWithContent.length} analyzed`;\n }\n\n this.lastEnhancedScene = enhancedScene;\n }\n\n // Public API methods\n\n public async getCurrentFrame(): Promise<VisionFrame | null> {\n return this.lastFrame;\n }\n\n public async getSceneDescription(): Promise<SceneDescription | null> {\n return this.lastSceneDescription;\n }\n\n public async getEnhancedSceneDescription(): Promise<EnhancedSceneDescription | null> {\n // If worker manager is available, use its high-FPS data\n if (this.workerManager) {\n return this.workerManager.getLatestEnhancedScene();\n }\n\n // Otherwise fall back to standard processing\n return this.lastEnhancedScene || this.lastSceneDescription;\n }\n\n public async getScreenCapture(): Promise<ScreenCapture | null> {\n return this.lastScreenCapture;\n }\n\n public getVisionMode(): VisionMode {\n return this.visionConfig.visionMode || VisionMode.CAMERA;\n }\n\n /**\n * Enable the camera input. If screen is already active, switches to BOTH;\n * otherwise to CAMERA.\n */\n public async enableCamera(): Promise<void> {\n const current = this.getVisionMode();\n const next =\n current === VisionMode.SCREEN || current === VisionMode.BOTH\n ? VisionMode.BOTH\n : VisionMode.CAMERA;\n await this.setVisionMode(next);\n }\n\n /**\n * Disable the camera input. Keeps screen capture if active; otherwise OFF.\n */\n public async disableCamera(): Promise<void> {\n const current = this.getVisionMode();\n const next =\n current === VisionMode.BOTH || current === VisionMode.SCREEN\n ? VisionMode.SCREEN\n : VisionMode.OFF;\n await this.setVisionMode(next);\n }\n\n /**\n * Enable screen capture. If displayIds are passed, the first id wins as\n * the `displayIndex` (multi-display capture is still single-display\n * upstream).\n */\n public async enableScreen(displayIds?: number[]): Promise<void> {\n if (displayIds && displayIds.length > 0) {\n this.visionConfig.displayIndex = displayIds[0];\n this.visionConfig.captureAllDisplays = displayIds.length > 1;\n }\n const current = this.getVisionMode();\n const next =\n current === VisionMode.CAMERA || current === VisionMode.BOTH\n ? VisionMode.BOTH\n : VisionMode.SCREEN;\n await this.setVisionMode(next);\n }\n\n /**\n * Disable screen capture. Keeps camera if active; otherwise OFF.\n */\n public async disableScreen(): Promise<void> {\n const current = this.getVisionMode();\n const next =\n current === VisionMode.BOTH || current === VisionMode.CAMERA\n ? VisionMode.CAMERA\n : VisionMode.OFF;\n await this.setVisionMode(next);\n }\n\n public async setVisionMode(mode: VisionMode): Promise<void> {\n logger.info(\n `[VisionService] Changing vision mode from ${this.visionConfig.visionMode} to ${mode}`,\n );\n\n // Stop current processing\n this.stopProcessing();\n\n // Update configuration\n this.visionConfig.visionMode = mode;\n\n // Reinitialize based on new mode\n if (mode === VisionMode.OFF) {\n logger.info(\"[VisionService] Vision disabled\");\n return;\n }\n\n // Initialize components for new mode\n if (\n (mode === VisionMode.CAMERA || mode === VisionMode.BOTH) &&\n !this.camera\n ) {\n await this.initializeCameraVision();\n }\n\n if (\n (mode === VisionMode.SCREEN || mode === VisionMode.BOTH) &&\n !this.ocrService.isInitialized()\n ) {\n await this.initializeScreenVision();\n }\n\n // Start processing for new mode\n this.startProcessing();\n }\n\n private stopProcessing(): void {\n if (this.frameProcessingInterval) {\n clearInterval(this.frameProcessingInterval);\n this.frameProcessingInterval = null;\n }\n\n if (this.screenProcessingInterval) {\n clearInterval(this.screenProcessingInterval);\n this.screenProcessingInterval = null;\n }\n\n if (this.arbiterUnsubscribe) {\n this.arbiterUnsubscribe();\n this.arbiterUnsubscribe = null;\n }\n }\n\n public getCameraInfo(): CameraInfo | null {\n if (!this.camera) {\n return null;\n }\n\n return {\n id: this.camera.id,\n name: this.camera.name,\n connected: true,\n };\n }\n\n public isActive(): boolean {\n return this.camera !== null && this.frameProcessingInterval !== null;\n }\n\n // Helper methods for face recognition\n private calculateBoxOverlap(box1: BoundingBox, box2: BoundingBox): number {\n const x1 = Math.max(box1.x, box2.x);\n const y1 = Math.max(box1.y, box2.y);\n const x2 = Math.min(box1.x + box1.width, box2.x + box2.width);\n const y2 = Math.min(box1.y + box1.height, box2.y + box2.height);\n\n if (x2 < x1 || y2 < y1) {\n return 0;\n }\n\n const intersection = (x2 - x1) * (y2 - y1);\n const area1 = box1.width * box1.height;\n const area2 = box2.width * box2.height;\n const union = area1 + area2 - intersection;\n\n return intersection / union;\n }\n\n // Public methods for entity tracking\n public getEntityTracker(): EntityTracker {\n return this.entityTracker;\n }\n\n public async getFaceRecognition(): Promise<FaceRecognition> {\n if (!this.faceRecognition) {\n const { FaceRecognition } = await import(\"./face-recognition-ggml\");\n this.faceRecognition = new FaceRecognition();\n }\n return this.faceRecognition;\n }\n\n async stop(): Promise<void> {\n logger.info(\"[VisionService] Stopping vision service...\");\n\n this.stopProcessing();\n\n if (this.audioCapture) {\n await this.audioCapture.stop();\n this.audioCapture = null;\n }\n\n if (this.streamingAudioCapture) {\n await this.streamingAudioCapture.stop();\n this.streamingAudioCapture = null;\n }\n\n if (this.objectDetector) {\n await this.objectDetector.dispose();\n this.objectDetector = null;\n this.hasObjectDetection = false;\n }\n\n if (this.workerManager) {\n await this.workerManager.stop();\n this.workerManager = null;\n }\n\n this.camera = null;\n this.lastFrame = null;\n this.lastSceneDescription = null;\n this.lastScreenCapture = null;\n this.lastEnhancedScene = null;\n this.dirtyTileDescriber = null;\n this.dirtyTileDescriberInit = false;\n this.isProcessing = false;\n this.isProcessingScreen = false;\n\n // Dispose of models\n await this.ocrService.dispose();\n\n logger.info(\"[VisionService] Stopped.\");\n }\n\n private async findCamera(): Promise<CameraDevice | null> {\n try {\n // Get list of available cameras\n const cameras = await this.listCameras();\n\n if (cameras.length === 0) {\n logger.warn(\"[VisionService] No cameras detected\");\n return null;\n }\n\n // If camera name is specified, try to find it\n if (this.visionConfig.cameraName) {\n const searchName = this.visionConfig.cameraName.toLowerCase();\n const matchedCamera = cameras.find((cam) =>\n cam.name.toLowerCase().includes(searchName),\n );\n\n if (matchedCamera) {\n return this.createCameraDevice(matchedCamera);\n }\n\n logger.warn(\n `[VisionService] Camera \"${this.visionConfig.cameraName}\" not found, using default`,\n );\n }\n\n // Use first available camera\n return this.createCameraDevice(cameras[0]);\n } catch (error) {\n logger.error({ error }, \"[VisionService] Error finding camera:\");\n return null;\n }\n }\n\n private async listCameras(): Promise<CameraInfo[]> {\n const platform = process.platform;\n\n try {\n if (platform === \"darwin\") {\n // macOS: Use system_profiler\n const { stdout } = await execAsync(\n \"system_profiler SPCameraDataType -json\",\n );\n const data = JSON.parse(stdout);\n const cameras: CameraInfo[] = [];\n\n if (data.SPCameraDataType && Array.isArray(data.SPCameraDataType)) {\n for (const camera of data.SPCameraDataType) {\n cameras.push({\n id: camera.unique_id || camera._name,\n name: camera._name,\n connected: true,\n });\n }\n }\n\n return cameras;\n } else if (platform === \"linux\") {\n // Linux: Use v4l2\n const { stdout } = await execAsync(\"v4l2-ctl --list-devices\");\n const cameras: CameraInfo[] = [];\n const lines = stdout.split(\"\\n\");\n\n let currentName = \"\";\n for (const line of lines) {\n if (line && !line.startsWith(\"\\t\")) {\n currentName = line.replace(\":\", \"\").trim();\n } else if (line.trim().startsWith(\"/dev/video\")) {\n const devicePath = line.trim();\n const id = devicePath.replace(\"/dev/video\", \"\");\n cameras.push({\n id,\n name: currentName,\n connected: true,\n });\n }\n }\n\n return cameras;\n } else if (platform === \"win32\") {\n // Windows: Use PowerShell\n const { stdout } = await execAsync(\n 'powershell -Command \"Get-PnpDevice -Class Camera | Select-Object FriendlyName, InstanceId | ConvertTo-Json\"',\n );\n const devices = JSON.parse(stdout);\n const cameras: CameraInfo[] = [];\n\n if (Array.isArray(devices)) {\n for (const device of devices) {\n cameras.push({\n id: device.InstanceId,\n name: device.FriendlyName,\n connected: true,\n });\n }\n }\n\n return cameras;\n }\n\n return [];\n } catch (error) {\n logger.error({ error }, \"[VisionService] Error listing cameras:\");\n return [];\n }\n }\n\n private createCameraDevice(info: CameraInfo): CameraDevice {\n const platform = process.platform;\n\n return {\n id: info.id,\n name: info.name,\n capture: async () => {\n const tempFile = path.join(\n process.cwd(),\n `temp_capture_${Date.now()}.jpg`,\n );\n\n try {\n if (platform === \"darwin\") {\n // macOS: Use imagesnap\n try {\n await execAsync(`imagesnap -d \"${info.name}\" \"${tempFile}\"`);\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n if (errorMessage.includes(\"command not found\")) {\n throw new Error(\n \"imagesnap not installed. Run: brew install imagesnap\",\n );\n }\n throw error;\n }\n } else if (platform === \"linux\") {\n // Linux: Use fswebcam\n try {\n await execAsync(\n `fswebcam -d /dev/video${info.id} -r 1280x720 --jpeg 85 \"${tempFile}\"`,\n );\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n if (errorMessage.includes(\"command not found\")) {\n throw new Error(\n \"fswebcam not installed. Run: sudo apt-get install fswebcam\",\n );\n }\n throw error;\n }\n } else if (platform === \"win32\") {\n // Windows: Use DirectShow via ffmpeg\n try {\n await execAsync(\n `ffmpeg -f dshow -i video=\"${info.name}\" -frames:v 1 -q:v 2 \"${tempFile}\" -y`,\n );\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n if (\n errorMessage.includes(\"not recognized\") ||\n errorMessage.includes(\"not found\")\n ) {\n throw new Error(\n \"ffmpeg not installed. Download from ffmpeg.org and add to PATH\",\n );\n }\n throw error;\n }\n } else {\n throw new Error(`Unsupported platform: ${platform}`);\n }\n\n // Read the captured image\n const imageBuffer = await fs.readFile(tempFile);\n\n // Clean up temp file\n await fs.unlink(tempFile).catch(() => {});\n\n return imageBuffer;\n } catch (error) {\n // Clean up temp file on error\n await fs.unlink(tempFile).catch(() => {});\n throw error;\n }\n },\n };\n }\n\n public async captureImage(): Promise<Buffer | null> {\n if (!this.camera) {\n logger.warn(\"[VisionService] No camera available for capture\");\n return null;\n }\n\n try {\n return await this.camera.capture();\n } catch (error) {\n logger.error({ error }, \"[VisionService] Failed to capture image:\");\n return null;\n }\n }\n}\n",
|
|
32
|
+
"import { exec } from \"node:child_process\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { promisify } from \"node:util\";\nimport {\n type IAgentRuntime,\n logger,\n ModelType,\n withStandaloneTrajectory,\n} from \"@elizaos/core\";\n\nconst execAsync = promisify(exec);\n\nexport interface AudioConfig {\n enabled: boolean;\n transcriptionInterval: number; // milliseconds\n device?: string;\n sampleRate?: number;\n channels?: number;\n}\n\nexport class AudioCaptureService {\n private runtime: IAgentRuntime;\n private config: AudioConfig;\n private isRecording = false;\n private recordingInterval: NodeJS.Timeout | null = null;\n\n constructor(runtime: IAgentRuntime, config: AudioConfig) {\n this.runtime = runtime;\n this.config = {\n sampleRate: 16000,\n channels: 1,\n ...config,\n };\n }\n\n async initialize(): Promise<void> {\n if (!this.config.enabled) {\n logger.info(\"[AudioCapture] Audio capture disabled\");\n return;\n }\n\n try {\n logger.info(\"[AudioCapture] Initializing audio capture...\");\n\n // Check for audio recording tools\n const tool = await this.checkAudioTools();\n if (!tool.available) {\n throw new Error(`Audio recording tool not available. ${tool.message}`);\n }\n\n logger.info(`[AudioCapture] Using ${tool.tool} for audio capture`);\n logger.info(\n `[AudioCapture] Transcription interval: ${this.config.transcriptionInterval}ms`,\n );\n\n // Start recording loop if interval is set\n if (this.config.transcriptionInterval > 0) {\n this.startTranscriptionLoop();\n }\n\n logger.info(\"[AudioCapture] Audio capture initialized\");\n } catch (error) {\n logger.error({ error }, \"[AudioCapture] Failed to initialize:\");\n throw error;\n }\n }\n\n private async checkAudioTools(): Promise<{\n available: boolean;\n tool: string;\n message?: string;\n }> {\n const platform = process.platform;\n\n try {\n if (platform === \"darwin\") {\n // macOS: Use sox\n await execAsync(\"which sox\");\n return { available: true, tool: \"sox\" };\n } else if (platform === \"linux\") {\n // Linux: Use arecord (ALSA)\n await execAsync(\"which arecord\");\n return { available: true, tool: \"arecord\" };\n } else if (platform === \"win32\") {\n // Windows: Use ffmpeg\n await execAsync(\"where ffmpeg\");\n return { available: true, tool: \"ffmpeg\" };\n }\n return {\n available: false,\n tool: \"none\",\n message: \"Unsupported platform\",\n };\n } catch (_error) {\n // Tool not found\n const toolName =\n platform === \"darwin\"\n ? \"sox\"\n : platform === \"linux\"\n ? \"arecord\"\n : \"ffmpeg\";\n const installCmd =\n platform === \"darwin\"\n ? \"brew install sox\"\n : platform === \"linux\"\n ? \"sudo apt-get install alsa-utils\"\n : \"Download ffmpeg from ffmpeg.org\";\n return {\n available: false,\n tool: toolName,\n message: `Install with: ${installCmd}`,\n };\n }\n }\n\n private startTranscriptionLoop(): void {\n if (this.recordingInterval) {\n return;\n }\n\n // Start continuous recording with periodic transcription\n this.recordingInterval = setInterval(async () => {\n if (!this.isRecording) {\n await this.recordAndTranscribe();\n }\n }, this.config.transcriptionInterval);\n\n logger.info(\"[AudioCapture] Started transcription loop\");\n }\n\n async recordAndTranscribe(): Promise<string | null> {\n if (this.isRecording) {\n logger.warn(\"[AudioCapture] Already recording\");\n return null;\n }\n\n this.isRecording = true;\n const audioFile = path.join(process.cwd(), `audio_${Date.now()}.wav`);\n\n try {\n logger.debug(\"[AudioCapture] Starting audio recording...\");\n\n // Record audio for the specified duration\n await this.recordAudio(\n audioFile,\n this.config.transcriptionInterval / 1000,\n );\n\n logger.debug(\"[AudioCapture] Recording complete, transcribing...\");\n\n // Transcribe using runtime model\n const audioBuffer = await fs.readFile(audioFile);\n const transcription = await withStandaloneTrajectory(\n this.runtime,\n {\n source: \"plugin-vision:audio-transcription\",\n metadata: {\n modelType: ModelType.TRANSCRIPTION,\n audioBytes: audioBuffer.byteLength,\n },\n },\n () => this.runtime.useModel(ModelType.TRANSCRIPTION, audioBuffer),\n );\n\n // Clean up audio file\n await fs.unlink(audioFile).catch(() => {});\n\n if (\n transcription &&\n typeof transcription === \"string\" &&\n transcription.trim()\n ) {\n logger.info(`[AudioCapture] Transcribed: \"${transcription}\"`);\n\n // Create a memory of what was heard\n await this.createAudioMemory(transcription);\n\n return transcription;\n }\n\n return null;\n } catch (error) {\n logger.error({ error }, \"[AudioCapture] Recording/transcription failed:\");\n await fs.unlink(audioFile).catch(() => {});\n return null;\n } finally {\n this.isRecording = false;\n }\n }\n\n private async recordAudio(\n outputPath: string,\n duration: number,\n ): Promise<void> {\n const platform = process.platform;\n\n try {\n if (platform === \"darwin\") {\n // macOS: Use sox\n const _device = this.config.device || \"default\";\n await execAsync(\n `sox -d -r ${this.config.sampleRate} -c ${this.config.channels} -b 16 \"${outputPath}\" trim 0 ${duration}`,\n );\n } else if (platform === \"linux\") {\n // Linux: Use arecord\n const device = this.config.device || \"default\";\n await execAsync(\n `arecord -D ${device} -f S16_LE -r ${this.config.sampleRate} -c ${this.config.channels} -d ${duration} \"${outputPath}\"`,\n );\n } else if (platform === \"win32\") {\n // Windows: Use ffmpeg with DirectShow\n const device = this.config.device || \"Microphone\";\n await execAsync(\n `ffmpeg -f dshow -i audio=\"${device}\" -t ${duration} -acodec pcm_s16le -ar ${this.config.sampleRate} -ac ${this.config.channels} \"${outputPath}\" -y`,\n );\n } else {\n throw new Error(`Unsupported platform: ${platform}`);\n }\n } catch (error: unknown) {\n logger.error(\n \"[AudioCapture] Audio recording failed:\",\n error instanceof Error ? error.message : String(error),\n );\n throw error;\n }\n }\n\n private async createAudioMemory(transcription: string): Promise<void> {\n try {\n const _memory = {\n content: {\n text: `[Audio Transcription] ${transcription}`,\n type: \"audio_transcription\",\n source: \"microphone\",\n timestamp: Date.now(),\n },\n metadata: {\n isAudioTranscription: true,\n duration: this.config.transcriptionInterval,\n },\n };\n\n // Store in agent's context\n // createMemory requires runtime-specific database adapter implementation\n logger.info(\"[AudioCapture] Audio transcription stored in context\");\n } catch (error) {\n logger.error({ error }, \"[AudioCapture] Failed to create audio memory:\");\n }\n }\n\n async listAudioDevices(): Promise<string[]> {\n const platform = process.platform;\n const devices: string[] = [];\n\n try {\n if (platform === \"darwin\") {\n // macOS: List audio devices using system_profiler\n const { stdout } = await execAsync(\n \"system_profiler SPAudioDataType -json\",\n );\n const data = JSON.parse(stdout);\n\n if (data.SPAudioDataType) {\n for (const device of data.SPAudioDataType) {\n if (device._name?.includes(\"Input\")) {\n devices.push(device._name);\n }\n }\n }\n } else if (platform === \"linux\") {\n // Linux: List ALSA devices\n const { stdout } = await execAsync(\"arecord -l\");\n const lines = stdout.split(\"\\n\");\n\n for (const line of lines) {\n if (line.includes(\"card\")) {\n const match = line.match(/card (\\d+):.*\\[(.*?)\\]/);\n if (match) {\n devices.push(`hw:${match[1]}`);\n }\n }\n }\n } else if (platform === \"win32\") {\n // Windows: List audio devices using ffmpeg\n try {\n const { stdout } = await execAsync(\n \"ffmpeg -list_devices true -f dshow -i dummy 2>&1\",\n );\n const lines = stdout.split(/\\r?\\n/u);\n let isAudioSection = false;\n\n for (const line of lines) {\n if (line.includes(\"DirectShow audio devices\")) {\n isAudioSection = true;\n } else if (isAudioSection && line.includes('\"')) {\n const match = line.match(/\"([^\"]+)\"/);\n if (match) {\n devices.push(match[1]);\n }\n }\n }\n } catch (_error) {\n // ffmpeg returns non-zero exit code when listing devices\n // but we can still parse the output\n }\n }\n } catch (error) {\n logger.error({ error }, \"[AudioCapture] Failed to list audio devices:\");\n }\n\n return devices;\n }\n\n isActive(): boolean {\n return this.config.enabled && this.recordingInterval !== null;\n }\n\n async stop(): Promise<void> {\n logger.info(\"[AudioCapture] Stopping audio capture...\");\n\n if (this.recordingInterval) {\n clearInterval(this.recordingInterval);\n this.recordingInterval = null;\n }\n\n // Wait for any ongoing recording to complete\n while (this.isRecording) {\n await new Promise((resolve) => setTimeout(resolve, 100));\n }\n\n logger.info(\"[AudioCapture] Audio capture stopped\");\n }\n}\n",
|
|
33
|
+
"import { type ChildProcess, spawn } from \"node:child_process\";\nimport { EventEmitter } from \"node:events\";\nimport {\n type IAgentRuntime,\n logger,\n ModelType,\n withStandaloneTrajectory,\n} from \"@elizaos/core\";\n\nexport interface StreamingAudioConfig {\n enabled: boolean;\n device?: string;\n sampleRate?: number;\n channels?: number;\n vadThreshold?: number; // 0-1, energy threshold for speech detection\n silenceTimeout?: number; // ms to wait before considering speech ended\n responseDelay?: number; // ms to wait before processing (for interruption detection)\n chunkSize?: number; // bytes per chunk for streaming\n}\n\ninterface AudioChunk {\n data: Buffer;\n timestamp: number;\n energy: number;\n}\n\nexport class StreamingAudioCaptureService extends EventEmitter {\n private runtime: IAgentRuntime;\n private config: StreamingAudioConfig;\n private captureProcess: ChildProcess | null = null;\n private isCapturing = false;\n private audioBuffer: AudioChunk[] = [];\n private isSpeaking = false;\n private silenceTimer: NodeJS.Timeout | null = null;\n private transcriptionInProgress = false;\n private currentTranscription = \"\";\n private responseTimer: NodeJS.Timeout | null = null;\n\n constructor(runtime: IAgentRuntime, config: StreamingAudioConfig) {\n super();\n this.runtime = runtime;\n this.config = {\n sampleRate: 16000,\n channels: 1,\n vadThreshold: 0.01,\n silenceTimeout: 1500, // 1.5 seconds of silence to end speech\n responseDelay: 3000, // 3 seconds before response (allows for interruption)\n chunkSize: 4096,\n ...config,\n };\n }\n\n async initialize(): Promise<void> {\n if (!this.config.enabled) {\n logger.info(\"[StreamingAudio] Audio capture disabled\");\n return;\n }\n\n try {\n logger.info(\"[StreamingAudio] Initializing streaming audio capture...\");\n\n // Start continuous audio capture\n await this.startContinuousCapture();\n\n logger.info(\"[StreamingAudio] Streaming audio capture initialized\");\n } catch (error) {\n logger.error({ error }, \"[StreamingAudio] Failed to initialize:\");\n throw error;\n }\n }\n\n private async startContinuousCapture(): Promise<void> {\n const platform = process.platform;\n let command: string;\n let args: string[];\n const sampleRate = String(this.config.sampleRate ?? 16000);\n const channels = String(this.config.channels ?? 1);\n\n if (platform === \"darwin\") {\n // macOS: Use sox for continuous capture\n command = \"sox\";\n args = [\n \"-d\", // default input device\n \"-r\",\n sampleRate,\n \"-c\",\n channels,\n \"-b\",\n \"16\",\n \"-e\",\n \"signed\",\n \"-t\",\n \"raw\",\n \"-\", // output to stdout\n ];\n } else if (platform === \"linux\") {\n // Linux: Use arecord\n command = \"arecord\";\n args = [\n \"-D\",\n this.config.device || \"default\",\n \"-f\",\n \"S16_LE\",\n \"-r\",\n sampleRate,\n \"-c\",\n channels,\n \"-t\",\n \"raw\",\n \"-\", // output to stdout\n ];\n } else if (platform === \"win32\") {\n // Windows: Use ffmpeg\n command = \"ffmpeg\";\n args = [\n \"-f\",\n \"dshow\",\n \"-i\",\n `audio=\"${this.config.device || \"Microphone\"}\"`,\n \"-acodec\",\n \"pcm_s16le\",\n \"-ar\",\n sampleRate,\n \"-ac\",\n channels,\n \"-f\",\n \"s16le\",\n \"pipe:1\", // output to stdout\n ];\n } else {\n throw new Error(`Unsupported platform: ${platform}`);\n }\n\n this.captureProcess = spawn(command, args);\n this.isCapturing = true;\n\n // Handle audio data stream\n this.captureProcess.stdout?.on(\"data\", (chunk: Buffer) => {\n this.processAudioChunk(chunk);\n });\n\n this.captureProcess.stderr?.on(\"data\", (data) => {\n logger.debug(\"[StreamingAudio] Capture stderr:\", data.toString());\n });\n\n this.captureProcess.on(\"error\", (error) => {\n logger.error(\n \"[StreamingAudio] Capture process error:\",\n error instanceof Error ? error.message : String(error),\n );\n this.isCapturing = false;\n });\n\n this.captureProcess.on(\"exit\", (code) => {\n logger.info(\n \"[StreamingAudio] Capture process exited with code:\",\n String(code ?? 0),\n );\n this.isCapturing = false;\n });\n }\n\n private processAudioChunk(chunk: Buffer): void {\n // Calculate audio energy for VAD\n const energy = this.calculateEnergy(chunk);\n const timestamp = Date.now();\n\n // Store chunk\n const audioChunk: AudioChunk = { data: chunk, timestamp, energy };\n\n // Voice Activity Detection\n if (energy > (this.config.vadThreshold ?? 0.01)) {\n if (!this.isSpeaking) {\n // Speech started\n this.isSpeaking = true;\n logger.debug(\"[StreamingAudio] Speech detected, starting recording\");\n this.emit(\"speechStart\");\n\n // Clear any pending response\n if (this.responseTimer) {\n clearTimeout(this.responseTimer);\n this.responseTimer = null;\n logger.debug(\n \"[StreamingAudio] Cancelled pending response due to new speech\",\n );\n }\n }\n\n // Add to buffer\n this.audioBuffer.push(audioChunk);\n\n // Reset silence timer\n if (this.silenceTimer) {\n clearTimeout(this.silenceTimer);\n }\n\n // Start streaming transcription if not already running\n if (!this.transcriptionInProgress) {\n this.startStreamingTranscription();\n }\n } else if (this.isSpeaking) {\n // Currently in speech but detected silence\n this.audioBuffer.push(audioChunk);\n\n // Set timer for end of speech\n if (!this.silenceTimer) {\n this.silenceTimer = setTimeout(() => {\n this.endSpeech();\n }, this.config.silenceTimeout ?? 1500);\n }\n }\n\n // Clean up old chunks (keep last 30 seconds)\n const cutoffTime = timestamp - 30000;\n this.audioBuffer = this.audioBuffer.filter((c) => c.timestamp > cutoffTime);\n }\n\n private calculateEnergy(chunk: Buffer): number {\n // Calculate RMS energy of audio chunk\n let sum = 0;\n const samples = chunk.length / 2; // 16-bit samples\n\n for (let i = 0; i < chunk.length; i += 2) {\n const sample = chunk.readInt16LE(i);\n sum += sample * sample;\n }\n\n const rms = Math.sqrt(sum / samples);\n return rms / 32768; // Normalize to 0-1\n }\n\n private async startStreamingTranscription(): Promise<void> {\n if (this.transcriptionInProgress) {\n return;\n }\n\n this.transcriptionInProgress = true;\n logger.debug(\"[StreamingAudio] Starting streaming transcription\");\n\n try {\n // Get audio data from buffer\n const audioData = this.getRecentAudioData();\n\n if (audioData.length === 0) {\n this.transcriptionInProgress = false;\n return;\n }\n\n // Use streaming transcription if available, otherwise batch\n const result = await this.transcribeAudio(audioData);\n\n if (result?.trim()) {\n this.currentTranscription = result;\n logger.info(`[StreamingAudio] Partial transcription: \"${result}\"`);\n this.emit(\"transcription\", { text: result, isFinal: false });\n }\n } catch (error) {\n logger.error({ error }, \"[StreamingAudio] Transcription error:\");\n }\n\n this.transcriptionInProgress = false;\n\n // Continue transcription if still speaking\n if (this.isSpeaking) {\n setTimeout(() => this.startStreamingTranscription(), 500);\n }\n }\n\n private endSpeech(): void {\n if (!this.isSpeaking) {\n return;\n }\n\n this.isSpeaking = false;\n this.silenceTimer = null;\n logger.debug(\"[StreamingAudio] Speech ended\");\n this.emit(\"speechEnd\");\n\n // Get final transcription\n this.processFinalTranscription();\n }\n\n private async processFinalTranscription(): Promise<void> {\n const audioData = this.getRecentAudioData();\n\n if (audioData.length === 0) {\n return;\n }\n\n try {\n // Get final transcription\n const finalText = await this.transcribeAudio(audioData);\n\n if (finalText?.trim()) {\n this.currentTranscription = finalText;\n logger.info(`[StreamingAudio] Final transcription: \"${finalText}\"`);\n this.emit(\"transcription\", { text: finalText, isFinal: true });\n\n // Set timer for response generation\n this.responseTimer = setTimeout(() => {\n this.generateResponse(finalText);\n }, this.config.responseDelay ?? 3000);\n }\n } catch (error) {\n logger.error({ error }, \"[StreamingAudio] Final transcription error:\");\n } finally {\n // Clear audio buffer\n this.audioBuffer = [];\n this.currentTranscription = \"\";\n }\n }\n\n private getRecentAudioData(): Buffer {\n if (this.audioBuffer.length === 0) {\n return Buffer.alloc(0);\n }\n\n // Get audio from start of speech to now\n const startTime = this.audioBuffer[0].timestamp;\n const relevantChunks = this.audioBuffer.filter(\n (c) => c.timestamp >= startTime,\n );\n\n // Combine chunks\n const totalLength = relevantChunks.reduce(\n (sum, c) => sum + c.data.length,\n 0,\n );\n const combined = Buffer.alloc(totalLength);\n let offset = 0;\n\n for (const chunk of relevantChunks) {\n chunk.data.copy(combined, offset);\n offset += chunk.data.length;\n }\n\n return combined;\n }\n\n private async transcribeAudio(audioData: Buffer): Promise<string | null> {\n try {\n // Convert raw audio to WAV format\n const wavBuffer = this.rawToWav(audioData);\n\n // Use runtime transcription model\n const result = await withStandaloneTrajectory(\n this.runtime,\n {\n source: \"plugin-vision:streaming-audio-transcription\",\n metadata: {\n modelType: ModelType.TRANSCRIPTION,\n audioBytes: wavBuffer.byteLength,\n },\n },\n () => this.runtime.useModel(ModelType.TRANSCRIPTION, wavBuffer),\n );\n\n return result as string;\n } catch (error) {\n logger.error({ error }, \"[StreamingAudio] Transcription failed:\");\n return null;\n }\n }\n\n private rawToWav(rawData: Buffer): Buffer {\n // Create WAV header\n const sampleRate = this.config.sampleRate ?? 16000;\n const channels = this.config.channels ?? 1;\n const bitsPerSample = 16;\n const byteRate = sampleRate * channels * (bitsPerSample / 8);\n const blockAlign = channels * (bitsPerSample / 8);\n const dataSize = rawData.length;\n const fileSize = 36 + dataSize;\n\n const header = Buffer.alloc(44);\n\n // RIFF chunk\n header.write(\"RIFF\", 0);\n header.writeUInt32LE(fileSize, 4);\n header.write(\"WAVE\", 8);\n\n // fmt chunk\n header.write(\"fmt \", 12);\n header.writeUInt32LE(16, 16); // fmt chunk size\n header.writeUInt16LE(1, 20); // PCM format\n header.writeUInt16LE(channels, 22);\n header.writeUInt32LE(sampleRate, 24);\n header.writeUInt32LE(byteRate, 28);\n header.writeUInt16LE(blockAlign, 32);\n header.writeUInt16LE(bitsPerSample, 34);\n\n // data chunk\n header.write(\"data\", 36);\n header.writeUInt32LE(dataSize, 40);\n\n return Buffer.concat([header, rawData]);\n }\n\n private async generateResponse(transcription: string): Promise<void> {\n this.responseTimer = null;\n\n try {\n // Create audio memory\n await this.createAudioMemory(transcription);\n\n // Emit event for response generation\n this.emit(\"utteranceComplete\", transcription);\n } catch (error) {\n logger.error({ error }, \"[StreamingAudio] Response generation error:\");\n }\n }\n\n private async createAudioMemory(transcription: string): Promise<void> {\n try {\n const _memory = {\n content: {\n text: `[Audio] ${transcription}`,\n type: \"audio_transcription\",\n source: \"microphone_streaming\",\n timestamp: Date.now(),\n },\n metadata: {\n isAudioTranscription: true,\n streaming: true,\n },\n };\n\n logger.info(\"[StreamingAudio] Audio transcription stored in context\");\n } catch (error) {\n logger.error(\n { error },\n \"[StreamingAudio] Failed to create audio memory:\",\n );\n }\n }\n\n async stop(): Promise<void> {\n logger.info(\"[StreamingAudio] Stopping audio capture...\");\n\n if (this.captureProcess) {\n this.captureProcess.kill();\n this.captureProcess = null;\n }\n\n if (this.silenceTimer) {\n clearTimeout(this.silenceTimer);\n this.silenceTimer = null;\n }\n\n if (this.responseTimer) {\n clearTimeout(this.responseTimer);\n this.responseTimer = null;\n }\n\n this.isCapturing = false;\n this.isSpeaking = false;\n this.audioBuffer = [];\n\n logger.info(\"[StreamingAudio] Audio capture stopped\");\n }\n\n isActive(): boolean {\n return this.isCapturing;\n }\n\n getCurrentTranscription(): string {\n return this.currentTranscription;\n }\n\n isSpeechActive(): boolean {\n return this.isSpeaking;\n }\n}\n",
|
|
34
|
+
"// DescribeBackpressureController — the owner of the \"run the expensive VLM\n// describe this tick?\" decision for VisionService's continuous loops\n// (#9105 milestone 8 / #9581). The DirtyTileDescriber / full-frame\n// `IMAGE_DESCRIPTION` call is the dominant token + RAM cost of the loop; the\n// cheap OCR/YOLO/dHash steps keep running while describing is paused. Two\n// independent pause signals:\n//\n// 1. **Arbiter memory-pressure** — the external WS1 signal cascaded from\n// `@elizaos/plugin-local-inference`'s MemoryArbiter (`memory_pressure`\n// events). The WS1 bridge only delivers *pressure* events, never the\n// recovery (`nominal`) edge, so a pressure signal pauses describing for a\n// cooldown window and auto-resumes after that window of silence. A direct\n// arbiter that does report `nominal` clears the pause immediately.\n// 2. **Local RSS GROWTH over a captured baseline** — a self-contained\n// low-RAM guard (`MAX_MEMORY_USAGE_MB`) so the loop throttles even when no\n// arbiter is registered (standalone / on-device), the common case for a\n// local agent on a memory-constrained machine. The cap measures\n// *vision-attributable growth* over the RSS baseline captured on the first\n// describe tick — NOT absolute process RSS. A local agent mmaps multi-GB\n// GGUF text + vision models, so its steady-state RSS routinely exceeds any\n// reasonable MB cap; comparing absolute RSS to the cap would pause\n// describing forever. Measuring growth over the loop's starting footprint\n// means a large-but-steady baseline never trips the guard, while a genuine\n// runaway still does. This signal is always-on and self-recovering:\n// describing resumes the moment RSS drops back within `baseline + cap`.\n//\n// While paused the describe step is skipped (backpressure) and the skip is\n// counted so the token telemetry can prove the saving. Pause/resume edges are\n// returned as transitions so the caller emits a single structured log line per\n// edge instead of once per tick.\n//\n// The controller is intentionally pure (no logger, no timers; injectable RSS\n// sampler + clock) so it is unit-testable in isolation — VisionService owns the\n// wiring and the logging.\n\nexport type MemoryPressureLevel = \"nominal\" | \"low\" | \"critical\";\n\nexport type DescribePauseReason = \"arbiter-pressure\" | \"memory-cap\" | null;\n\nexport interface DescribeBackpressureStats {\n /** True while the describe step is currently being skipped. */\n paused: boolean;\n /** Last arbiter pressure level applied via `setPressure`. */\n pressureLevel: MemoryPressureLevel;\n /** Describe ticks skipped because of backpressure since construction. */\n describesSkipped: number;\n /** Count of paused<->active edges (telemetry / test signal). */\n pauseTransitions: number;\n /** RSS captured on the first describe tick, used as the local cap baseline. */\n memoryBaselineBytes: number | null;\n /** Latest sampled RSS growth over the captured baseline. */\n memoryGrowthBytes: number | null;\n}\n\nexport interface DescribeBackpressureDecision {\n /** Run the expensive describe this tick? */\n describe: boolean;\n /** `\"paused\"`/`\"active\"` when this call flipped the state, else `null`. */\n transitionedTo: \"paused\" | \"active\" | null;\n /** Why we are paused (only meaningful when `describe === false`). */\n reason: DescribePauseReason;\n /** How long the current continuous pause has lasted, in ms. */\n pausedForMs: number;\n /** True when the caller should emit a throttled long-pause warning. */\n warnPaused: boolean;\n}\n\nexport interface DescribeBackpressureConfig {\n /**\n * RSS growth cap in bytes. The first describe tick captures the process RSS\n * baseline; while sampled RSS exceeds `baseline + memoryCapBytes`, the\n * describe step pauses. `0` or negative disables the local check — only the\n * arbiter signal can pause describing.\n */\n memoryCapBytes?: number;\n /**\n * RSS sampler; defaults to `process.memoryUsage().rss`. Injected by tests so\n * the cap can be exercised deterministically without allocating memory.\n */\n sampleRssBytes?: () => number;\n /**\n * How long a single arbiter pressure signal keeps the loop paused, in ms.\n * Because the WS1 bridge delivers pressure but not recovery, the pause\n * auto-clears after this window of silence. Default 15_000.\n */\n arbiterPauseCooldownMs?: number;\n /** Continuous pause duration before a warning is requested. Default 60s. */\n pauseWarningThresholdMs?: number;\n /** Minimum interval between repeated long-pause warnings. Default 60s. */\n pauseWarningIntervalMs?: number;\n /** Clock, injectable for tests. Defaults to `Date.now`. */\n now?: () => number;\n}\n\nconst DEFAULT_ARBITER_PAUSE_COOLDOWN_MS = 15_000;\nconst DEFAULT_PAUSE_WARNING_THRESHOLD_MS = 60_000;\nconst DEFAULT_PAUSE_WARNING_INTERVAL_MS = 60_000;\n\nexport class DescribeBackpressureController {\n private readonly memoryCapBytes: number;\n private readonly sampleRssBytes: () => number;\n private readonly arbiterPauseCooldownMs: number;\n private readonly pauseWarningThresholdMs: number;\n private readonly pauseWarningIntervalMs: number;\n private readonly now: () => number;\n private pressureLevel: MemoryPressureLevel = \"nominal\";\n private pauseUntilMs = 0;\n private paused = false;\n private describesSkipped = 0;\n private pauseTransitions = 0;\n private memoryBaselineBytes: number | null = null;\n private latestMemoryGrowthBytes: number | null = null;\n private pauseStartedAtMs: number | null = null;\n private lastPauseWarningAtMs = 0;\n\n constructor(config: DescribeBackpressureConfig = {}) {\n this.memoryCapBytes =\n typeof config.memoryCapBytes === \"number\" && config.memoryCapBytes > 0\n ? config.memoryCapBytes\n : 0;\n this.sampleRssBytes =\n config.sampleRssBytes ?? (() => process.memoryUsage().rss);\n this.arbiterPauseCooldownMs =\n typeof config.arbiterPauseCooldownMs === \"number\" &&\n config.arbiterPauseCooldownMs > 0\n ? config.arbiterPauseCooldownMs\n : DEFAULT_ARBITER_PAUSE_COOLDOWN_MS;\n this.pauseWarningThresholdMs =\n typeof config.pauseWarningThresholdMs === \"number\" &&\n config.pauseWarningThresholdMs > 0\n ? config.pauseWarningThresholdMs\n : DEFAULT_PAUSE_WARNING_THRESHOLD_MS;\n this.pauseWarningIntervalMs =\n typeof config.pauseWarningIntervalMs === \"number\" &&\n config.pauseWarningIntervalMs > 0\n ? config.pauseWarningIntervalMs\n : DEFAULT_PAUSE_WARNING_INTERVAL_MS;\n this.now = config.now ?? (() => Date.now());\n }\n\n /**\n * Apply an arbiter memory-pressure level. A non-nominal level opens (or\n * extends) the cooldown pause window; `nominal` clears it immediately (only\n * arbiters that actually report recovery do this — the WS1 bridge relies on\n * the cooldown instead).\n */\n setPressure(level: MemoryPressureLevel): void {\n this.pressureLevel = level;\n if (level === \"nominal\") {\n this.pauseUntilMs = 0;\n } else {\n this.pauseUntilMs = this.now() + this.arbiterPauseCooldownMs;\n }\n }\n\n /**\n * Decide whether the expensive describe step may run this tick. Call ONLY\n * when a describe would otherwise happen (the change/time gate already\n * passed), so the skip counter reflects real avoided work. Has side effects:\n * updates the skip counter and the pause/resume transition state. The\n * arbiter signal takes precedence over the local cap when both are active so\n * the reported `reason` is the more authoritative one.\n */\n evaluate(): DescribeBackpressureDecision {\n const now = this.now();\n const arbiterPaused = now < this.pauseUntilMs;\n const sampledRssBytes =\n this.memoryCapBytes > 0 ? this.sampleRssBytes() : null;\n if (sampledRssBytes !== null && this.memoryBaselineBytes === null) {\n this.memoryBaselineBytes = sampledRssBytes;\n }\n this.latestMemoryGrowthBytes =\n sampledRssBytes !== null && this.memoryBaselineBytes !== null\n ? Math.max(0, sampledRssBytes - this.memoryBaselineBytes)\n : null;\n const overCap =\n this.memoryCapBytes > 0 &&\n sampledRssBytes !== null &&\n this.memoryBaselineBytes !== null &&\n sampledRssBytes > this.memoryBaselineBytes + this.memoryCapBytes;\n const paused = arbiterPaused || overCap;\n\n let transitionedTo: \"paused\" | \"active\" | null = null;\n if (paused !== this.paused) {\n transitionedTo = paused ? \"paused\" : \"active\";\n this.paused = paused;\n this.pauseTransitions += 1;\n this.pauseStartedAtMs = paused ? now : null;\n this.lastPauseWarningAtMs = 0;\n }\n let pausedForMs = 0;\n let warnPaused = false;\n if (paused) {\n this.describesSkipped += 1;\n if (this.pauseStartedAtMs !== null) {\n pausedForMs = Math.max(0, now - this.pauseStartedAtMs);\n if (\n pausedForMs >= this.pauseWarningThresholdMs &&\n (this.lastPauseWarningAtMs === 0 ||\n now - this.lastPauseWarningAtMs >= this.pauseWarningIntervalMs)\n ) {\n warnPaused = true;\n this.lastPauseWarningAtMs = now;\n }\n }\n }\n\n const reason: DescribePauseReason = !paused\n ? null\n : arbiterPaused\n ? \"arbiter-pressure\"\n : \"memory-cap\";\n\n return {\n describe: !paused,\n transitionedTo,\n reason,\n pausedForMs,\n warnPaused,\n };\n }\n\n stats(): DescribeBackpressureStats {\n return {\n paused: this.paused,\n pressureLevel: this.pressureLevel,\n describesSkipped: this.describesSkipped,\n pauseTransitions: this.pauseTransitions,\n memoryBaselineBytes: this.memoryBaselineBytes,\n memoryGrowthBytes: this.latestMemoryGrowthBytes,\n };\n }\n}\n",
|
|
35
|
+
"/**\n * Overlap-aware screen tiler for the eliza-1 local Gemma vision pipeline.\n *\n * Why this exists:\n * Native ultra-wide or DPI-dense captures (e.g. 5120x2160 or a Retina 6K\n * panel) get resized down by the model preprocessor, which destroys small UI\n * text and makes OCR-class detail unreadable in a single pass. We instead\n * split the capture into a grid of local-VLM-sized tiles with a configurable\n * pixel overlap so words/glyphs that straddle a seam still appear intact in\n * at least one tile.\n *\n * Coordinates:\n * Every emitted tile carries `sourceX/sourceY` in the source display's\n * native pixel space. Combined with `displayId`, the agent can reconstruct\n * absolute on-screen coordinates for any pixel inside a tile (see\n * `reconstructAbsoluteCoords`). This is what lets the planner click the\n * thing the model just read.\n */\nimport { getSharp } from \"./image/sharp-compat\";\n\n/**\n * One output tile from `tileScreenshot`.\n *\n * - `sourceX/sourceY` are absolute pixel coords in the *source display's*\n * native space (i.e. the same space `displayId` is reported in by\n * `plugin-computeruse/src/platform/displays.ts`).\n * - `tileW/tileH` are the actual rendered dimensions of `pngBytes` and may\n * equal `sourceW/sourceH` (no resize) — the tiler does not downscale; it\n * only crops. Resizing is the model preprocessor's job.\n */\nexport interface ScreenTile {\n /** Stable id of the form `tile-<row>-<col>`. */\n id: string;\n /** Display this tile was sourced from. Stringified to keep types narrow. */\n displayId: string;\n /** Top-left X of the tile in the source display's pixel space. */\n sourceX: number;\n /** Top-left Y of the tile in the source display's pixel space. */\n sourceY: number;\n /** Width of the cropped region in source pixels. */\n sourceW: number;\n /** Height of the cropped region in source pixels. */\n sourceH: number;\n /** Pixel width of `pngBytes`. Equal to `sourceW` (no resize). */\n tileW: number;\n /** Pixel height of `pngBytes`. Equal to `sourceH` (no resize). */\n tileH: number;\n /** PNG-encoded crop. */\n pngBytes: Buffer;\n}\n\nexport interface TileScreenshotInput {\n displayId: string;\n width: number;\n height: number;\n pngBytes: Buffer;\n}\n\nexport interface TileScreenshotOptions {\n /** Maximum tile edge in pixels. Tiles never exceed this in either dim. */\n maxEdge: number;\n /**\n * Fraction of `tileSize` that adjacent tiles overlap. 0.12 (default) is\n * large enough to keep multi-glyph tokens intact across seams, small enough\n * to keep tile count near minimum.\n */\n overlapFraction: number;\n}\n\n/** Default local-VLM tile budget for Gemma vision. */\nexport const DEFAULT_MAX_EDGE = 1280;\n/** Default seam overlap (12%). */\nexport const DEFAULT_OVERLAP_FRACTION = 0.12;\n\n/**\n * Tile a captured screenshot into local-VLM-sized PNG patches with\n * pixel-overlap between neighbours.\n *\n * Single-tile fast path: when both dims fit within `maxEdge`, the input is\n * returned as a single `ScreenTile` whose pngBytes is the unmodified input.\n *\n * Grid path: chooses the smallest grid (cols, rows) such that no individual\n * tile exceeds `maxEdge`, then computes a per-axis stride that yields\n * `overlapFraction * tileSize` of overlap between adjacent tiles. The last\n * column/row is anchored to the source's right/bottom edge so we never\n * extend past the screen.\n */\nexport async function tileScreenshot(\n input: TileScreenshotInput,\n opts: TileScreenshotOptions = {\n maxEdge: DEFAULT_MAX_EDGE,\n overlapFraction: DEFAULT_OVERLAP_FRACTION,\n },\n): Promise<ScreenTile[]> {\n const { displayId, width, height, pngBytes } = input;\n validateInput(width, height, pngBytes);\n const { maxEdge, overlapFraction } = opts;\n validateOptions(maxEdge, overlapFraction);\n\n if (width <= maxEdge && height <= maxEdge) {\n return [\n {\n id: \"tile-0-0\",\n displayId,\n sourceX: 0,\n sourceY: 0,\n sourceW: width,\n sourceH: height,\n tileW: width,\n tileH: height,\n pngBytes,\n },\n ];\n }\n\n const cols = Math.max(1, Math.ceil(width / maxEdge));\n const rows = Math.max(1, Math.ceil(height / maxEdge));\n const tileWidth = Math.min(\n maxEdge,\n Math.ceil(width / cols + maxEdge * overlapFraction),\n );\n const tileHeight = Math.min(\n maxEdge,\n Math.ceil(height / rows + maxEdge * overlapFraction),\n );\n // Stride between top-left corners of adjacent tiles. With a single tile per\n // axis, stride is the full width/height — no overlap math needed.\n const strideX =\n cols > 1 ? Math.floor((width - tileWidth) / (cols - 1)) : tileWidth;\n const strideY =\n rows > 1 ? Math.floor((height - tileHeight) / (rows - 1)) : tileHeight;\n\n const sharp = await getSharp();\n const image = sharp(pngBytes);\n const tiles: ScreenTile[] = [];\n for (let row = 0; row < rows; row += 1) {\n for (let col = 0; col < cols; col += 1) {\n // Anchor the last col/row to the source's far edge so we never crop\n // outside [0, width)/[0, height). All other tiles slide by stride.\n const sourceX = col === cols - 1 ? width - tileWidth : col * strideX;\n const sourceY = row === rows - 1 ? height - tileHeight : row * strideY;\n const sx = Math.max(0, sourceX);\n const sy = Math.max(0, sourceY);\n const sw = Math.min(tileWidth, width - sx);\n const sh = Math.min(tileHeight, height - sy);\n const cropped = await image\n .clone()\n .extract({ left: sx, top: sy, width: sw, height: sh })\n .png()\n .toBuffer();\n tiles.push({\n id: `tile-${row}-${col}`,\n displayId,\n sourceX: sx,\n sourceY: sy,\n sourceW: sw,\n sourceH: sh,\n tileW: sw,\n tileH: sh,\n pngBytes: cropped,\n });\n }\n }\n return tiles;\n}\n\n/**\n * Map a (localX, localY) inside a tile back to the source display's\n * absolute pixel coordinates. Use this to translate \"model said click at\n * (x, y) inside tile-0-1\" into a coordinate the input driver can act on.\n */\nexport function reconstructAbsoluteCoords(\n tile: ScreenTile,\n localX: number,\n localY: number,\n): { displayId: string; absoluteX: number; absoluteY: number } {\n if (!Number.isFinite(localX) || !Number.isFinite(localY)) {\n throw new Error(\n `[ScreenTiler] reconstructAbsoluteCoords requires finite local coords, got (${localX}, ${localY})`,\n );\n }\n if (localX < 0 || localX > tile.tileW || localY < 0 || localY > tile.tileH) {\n throw new Error(\n `[ScreenTiler] local coords (${localX}, ${localY}) out of tile bounds (${tile.tileW}x${tile.tileH})`,\n );\n }\n return {\n displayId: tile.displayId,\n absoluteX: tile.sourceX + localX,\n absoluteY: tile.sourceY + localY,\n };\n}\n\nfunction validateInput(width: number, height: number, pngBytes: Buffer): void {\n if (!Number.isInteger(width) || width <= 0) {\n throw new Error(\n `[ScreenTiler] width must be a positive integer, got ${width}`,\n );\n }\n if (!Number.isInteger(height) || height <= 0) {\n throw new Error(\n `[ScreenTiler] height must be a positive integer, got ${height}`,\n );\n }\n if (!Buffer.isBuffer(pngBytes) || pngBytes.length === 0) {\n throw new Error(\"[ScreenTiler] pngBytes must be a non-empty Buffer\");\n }\n}\n\nfunction validateOptions(maxEdge: number, overlapFraction: number): void {\n if (!Number.isInteger(maxEdge) || maxEdge < 64) {\n throw new Error(\n `[ScreenTiler] maxEdge must be an integer >= 64, got ${maxEdge}`,\n );\n }\n if (\n !Number.isFinite(overlapFraction) ||\n overlapFraction < 0 ||\n overlapFraction >= 1\n ) {\n throw new Error(\n `[ScreenTiler] overlapFraction must be in [0, 1), got ${overlapFraction}`,\n );\n }\n}\n",
|
|
36
|
+
"/**\n * DirtyTileDescriber — change-gated, per-tile screen description (#9105 M3).\n *\n * The dominant token cost in a CUA loop is re-describing a whole screen to a\n * VLM every step even when almost nothing moved. The Brain already skips the\n * describe entirely when the *whole frame* dHash is unchanged\n * (`plugin-computeruse` `Brain` frame-dHash cache). This describer is the\n * finer-grained tier: it splits a frame into tiles (via `screen-tiler.ts`),\n * computes a per-tile perceptual hash, and only (re)describes tiles whose hash\n * changed since the last frame — every unchanged tile reuses its cached\n * description. So a single text field flipping characters re-describes one tile,\n * not the entire screen.\n *\n * The describer is pure + injectable: the tile hash (`hashTile`) and the\n * per-tile describe call (`describeTile`) are supplied by the caller. The real\n * boot wiring injects `plugin-computeruse`'s `frameDhash` (the existing\n * `scene/dhash.ts`) and a `runtime.useModel(IMAGE_DESCRIPTION)`-backed describe;\n * tests inject deterministic fakes with no model and no native dHash. The\n * counters (`describeCallsSaved`, `approxTokensSaved`) make the saving\n * measurable so a test can assert it.\n */\n\nimport type { ScreenTile } from \"./screen-tiler.js\";\nimport { tileScreenshot } from \"./screen-tiler.js\";\n\n/** Approx image tokens charged for one tile describe — used only for the saved-tokens estimate. */\nexport const APPROX_TOKENS_PER_TILE = 256;\n\n/** A described tile: its source rectangle plus the VLM/OCR text for it. */\nexport interface DescribedTile {\n /** Tiler id, e.g. `tile-1-0`. */\n id: string;\n displayId: string;\n /** Top-left of the tile in source display pixel space. */\n sourceX: number;\n sourceY: number;\n sourceW: number;\n sourceH: number;\n /** The description text for this tile. */\n description: string;\n /** True when this tile's description was reused from cache (no describe call). */\n cached: boolean;\n}\n\nexport interface DirtyTileDescription {\n /** One entry per tile, in tiler order. */\n tiles: DescribedTile[];\n /** Composed full-frame description (non-empty tile texts, source-order). */\n vlmScene: string;\n /** Per-tile elements suitable for `Scene.vlm_elements`. */\n elements: DirtyTileElement[];\n}\n\n/** A described tile projected into the `Scene.vlm_elements` shape. */\nexport interface DirtyTileElement {\n id: string;\n kind: string;\n desc: string;\n /** Display-local `[x, y, w, h]` of the tile. */\n bbox: [number, number, number, number];\n displayId: number;\n}\n\n/** Token-accounting snapshot for a describer. */\nexport interface DirtyTileStats {\n /** Tiles actually sent to the describe call. */\n tilesDescribed: number;\n /** Tiles served from the per-tile cache (no describe call). */\n tilesSkipped: number;\n /** Describe calls avoided by the cache (== tilesSkipped). */\n describeCallsSaved: number;\n /** Approx image tokens avoided (tilesSkipped × APPROX_TOKENS_PER_TILE). */\n approxTokensSaved: number;\n}\n\nexport interface DirtyTileDescriberDeps {\n /**\n * Perceptual hash of a tile PNG. Identical pixels MUST hash equal. The boot\n * wiring passes `plugin-computeruse`'s `frameDhash`; `null` means \"could not\n * hash\" and forces a (re)describe for that tile.\n */\n hashTile: (png: Buffer) => bigint | null;\n /** Describe one tile's pixels. Only called for changed/new tiles. */\n describeTile: (tile: ScreenTile) => Promise<string>;\n /** Tiling options forwarded to `tileScreenshot`. */\n maxEdge?: number;\n overlapFraction?: number;\n /** Tokens charged per describe, for the saved-tokens estimate. */\n approxTokensPerTile?: number;\n}\n\nexport class DirtyTileDescriber {\n /** tileId → { hash, description } from the previous frame. */\n private readonly cache = new Map<\n string,\n { hash: bigint | null; description: string }\n >();\n private stats: DirtyTileStats = {\n tilesDescribed: 0,\n tilesSkipped: 0,\n describeCallsSaved: 0,\n approxTokensSaved: 0,\n };\n\n constructor(private readonly deps: DirtyTileDescriberDeps) {}\n\n getStats(): DirtyTileStats {\n return { ...this.stats };\n }\n\n /**\n * Describe a frame, re-describing only tiles whose hash changed since the\n * previous call. Unchanged tiles reuse their cached description.\n */\n async describe(input: {\n displayId: number;\n width: number;\n height: number;\n pngBytes: Buffer;\n }): Promise<DirtyTileDescription> {\n const tiles = await tileScreenshot(\n {\n displayId: String(input.displayId),\n width: input.width,\n height: input.height,\n pngBytes: input.pngBytes,\n },\n {\n maxEdge: this.deps.maxEdge ?? 1280,\n overlapFraction: this.deps.overlapFraction ?? 0.12,\n },\n );\n const tokensPerTile =\n this.deps.approxTokensPerTile ?? APPROX_TOKENS_PER_TILE;\n const seen = new Set<string>();\n const described: DescribedTile[] = [];\n\n for (const tile of tiles) {\n seen.add(tile.id);\n const hash = this.deps.hashTile(tile.pngBytes);\n const prior = this.cache.get(tile.id);\n // A tile is reusable only when we have a prior description AND both the\n // prior and current hashes are real and equal. A null hash (undecodable)\n // always forces a fresh describe.\n const reusable =\n prior !== undefined &&\n prior.hash !== null &&\n hash !== null &&\n prior.hash === hash;\n if (reusable) {\n this.stats.tilesSkipped += 1;\n this.stats.describeCallsSaved += 1;\n this.stats.approxTokensSaved += tokensPerTile;\n described.push(this.toDescribed(tile, prior.description, true));\n continue;\n }\n const description = await this.deps.describeTile(tile);\n this.stats.tilesDescribed += 1;\n this.cache.set(tile.id, { hash, description });\n described.push(this.toDescribed(tile, description, false));\n }\n\n // Drop cache entries for tiles that no longer exist (e.g. resolution change\n // collapsed the grid) so the cache stays bounded by the live tile count.\n for (const id of this.cache.keys()) {\n if (!seen.has(id)) this.cache.delete(id);\n }\n\n return {\n tiles: described,\n vlmScene: composeVlmScene(described),\n elements: described\n .filter((t) => t.description.trim().length > 0)\n .map((t) => ({\n id: t.id,\n kind: \"tile\",\n desc: t.description,\n bbox: [t.sourceX, t.sourceY, t.sourceW, t.sourceH] as [\n number,\n number,\n number,\n number,\n ],\n displayId: input.displayId,\n })),\n };\n }\n\n private toDescribed(\n tile: ScreenTile,\n description: string,\n cached: boolean,\n ): DescribedTile {\n return {\n id: tile.id,\n displayId: tile.displayId,\n sourceX: tile.sourceX,\n sourceY: tile.sourceY,\n sourceW: tile.sourceW,\n sourceH: tile.sourceH,\n description,\n cached,\n };\n }\n}\n\nfunction composeVlmScene(tiles: DescribedTile[]): string {\n return tiles\n .map((t) => t.description.trim())\n .filter((d) => d.length > 0)\n .join(\"\\n\");\n}\n",
|
|
37
|
+
"/**\n * Wiring seam for the change-gated per-tile scene describe (#9105 efficiency).\n *\n * `DirtyTileDescriber` (dirty-tile-describer.ts) is pure + injectable: it owns\n * the per-tile hash cache and the \"only re-describe changed tiles\" loop, but it\n * does not know how to hash a tile or how to ask the VLM to describe one. This\n * module supplies those two collaborators from the live runtime so\n * `VisionService` can build a describer that re-describes only the screen\n * regions that actually changed since the previous frame instead of paying for\n * a whole-frame VLM pass every scene tick.\n *\n * Two collaborators:\n * - `hashTile`: a perceptual hash. We reuse plugin-computeruse's `frameDhash`\n * (the same dHash the Brain frame-cache uses), resolved via a best-effort\n * dynamic import so plugin-vision never eagerly pulls computeruse's module\n * graph at boot — exactly the idiom the OCR bridge already uses. When\n * computeruse is absent the resolve returns `null` and the caller degrades\n * to the existing full-frame describe.\n * - `describeTile`: one `runtime.useModel(IMAGE_DESCRIPTION, …)` call per\n * changed tile, built from a caller-supplied prompt + result normalizer so\n * the per-tile path reuses the same prompt plumbing as the full-frame path.\n */\n\nimport type { ScreenTile } from \"./screen-tiler.js\";\n\n/** PNG perceptual hash. Identical pixels MUST hash equal; `null` = undecodable. */\nexport type FrameHash = (png: Buffer) => bigint | null;\n\n/** Per-tile describe call. Returns the model's description text for one tile. */\nexport type TileDescribeFn = (tile: ScreenTile) => Promise<string>;\n\nexport interface TileDescribeDeps {\n /**\n * Build the per-tile image URL the VLM is asked to describe. The tile carries\n * PNG bytes (`tile.pngBytes`), so this is a `data:image/png;base64,…` URL.\n */\n buildTileImageUrl: (tile: ScreenTile) => string;\n /**\n * Build the per-tile prompt. Receives the tile so callers can include bounds.\n * Async because the scene context is pulled from a peer provider per call.\n */\n buildTilePrompt: (tile: ScreenTile) => Promise<string>;\n /** Invoke the IMAGE_DESCRIPTION model and return its raw result. */\n invokeModel: (imageUrl: string, prompt: string) => Promise<unknown>;\n /**\n * Normalize a model result into a description string, or `null` when the\n * result is unusable (sentinel / empty). A `null` result yields an empty tile\n * description, which the describer treats as \"nothing to compose for this\n * tile\" while still caching the (empty) result against the tile hash.\n */\n extractDescription: (result: unknown) => string | null;\n}\n\n/**\n * Build a `describeTile` function bound to the runtime's IMAGE_DESCRIPTION\n * model. The describer calls this only for tiles whose hash changed.\n */\nexport function createTileDescribeFn(deps: TileDescribeDeps): TileDescribeFn {\n return async (tile: ScreenTile): Promise<string> => {\n const imageUrl = deps.buildTileImageUrl(tile);\n const prompt = await deps.buildTilePrompt(tile);\n const result = await deps.invokeModel(imageUrl, prompt);\n return deps.extractDescription(result) ?? \"\";\n };\n}\n\n/** Encode a tile's PNG bytes into a base64 data URL for the VLM. */\nexport function tilePngToImageUrl(tile: ScreenTile): string {\n return `data:image/png;base64,${tile.pngBytes.toString(\"base64\")}`;\n}\n",
|
|
38
|
+
"import { createUniqueUuid, type IAgentRuntime, logger } from \"@elizaos/core\";\nimport type {\n BoundingBox,\n DetectedObject,\n PersonInfo,\n TrackedEntity,\n WorldState,\n} from \"./types\";\n\nexport class EntityTracker {\n private worldState: WorldState;\n private readonly POSITION_THRESHOLD = 100; // pixels\n private readonly MISSING_THRESHOLD = 5000; // 5 seconds\n private readonly CLEANUP_THRESHOLD = 60000; // 1 minute\n\n constructor(worldId: string) {\n this.worldState = {\n worldId,\n entities: new Map(),\n lastUpdate: Date.now(),\n activeEntities: [],\n recentlyLeft: [],\n };\n }\n\n async updateEntities(\n detectedObjects: DetectedObject[],\n people: PersonInfo[],\n faceProfiles?: Map<string, string>, // Maps person ID to face profile ID\n runtime?: IAgentRuntime,\n ): Promise<TrackedEntity[]> {\n const currentTime = Date.now();\n const frameEntities: TrackedEntity[] = [];\n const seenEntityIds = new Set<string>();\n\n // Process detected people\n for (const person of people) {\n const entity = await this.trackPerson(\n person,\n faceProfiles?.get(person.id),\n currentTime,\n );\n frameEntities.push(entity);\n seenEntityIds.add(entity.id);\n }\n\n // Process detected objects\n for (const obj of detectedObjects) {\n if (obj.type !== \"person\" && obj.type !== \"person-candidate\") {\n const entity = await this.trackObject(obj, currentTime);\n frameEntities.push(entity);\n seenEntityIds.add(entity.id);\n }\n }\n\n // Update world state\n this.updateWorldState(seenEntityIds, currentTime);\n\n // Store entities in runtime if available\n if (runtime) {\n await this.syncWithRuntime(runtime, frameEntities);\n }\n\n return frameEntities;\n }\n\n private async trackPerson(\n person: PersonInfo,\n faceProfileId: string | undefined,\n timestamp: number,\n ): Promise<TrackedEntity> {\n // Try to match with existing entities\n const matchedEntity = this.findMatchingEntity(\n person.boundingBox,\n \"person\",\n faceProfileId,\n );\n\n if (matchedEntity) {\n // Update existing entity\n matchedEntity.lastSeen = timestamp;\n matchedEntity.lastPosition = person.boundingBox;\n matchedEntity.appearances.push({\n timestamp,\n boundingBox: person.boundingBox,\n confidence: person.confidence,\n });\n\n // Update attributes\n if (faceProfileId && !matchedEntity.attributes.faceId) {\n matchedEntity.attributes.faceId = faceProfileId;\n }\n\n // Keep only last 100 appearances\n if (matchedEntity.appearances.length > 100) {\n matchedEntity.appearances = matchedEntity.appearances.slice(-100);\n }\n\n return matchedEntity;\n } else {\n // Create new entity\n const entityId = `person-${timestamp}-${Math.random().toString(36).substr(2, 9)}`;\n const newEntity: TrackedEntity = {\n id: entityId,\n entityType: \"person\",\n firstSeen: timestamp,\n lastSeen: timestamp,\n lastPosition: person.boundingBox,\n appearances: [\n {\n timestamp,\n boundingBox: person.boundingBox,\n confidence: person.confidence,\n },\n ],\n attributes: {\n faceId: faceProfileId,\n },\n worldId: this.worldState.worldId,\n };\n\n this.worldState.entities.set(entityId, newEntity);\n logger.info(`[EntityTracker] New person entity created: ${entityId}`);\n\n return newEntity;\n }\n }\n\n private async trackObject(\n obj: DetectedObject,\n timestamp: number,\n ): Promise<TrackedEntity> {\n // Try to match with existing entities\n const matchedEntity = this.findMatchingEntity(obj.boundingBox, \"object\");\n\n if (matchedEntity) {\n // Update existing entity\n matchedEntity.lastSeen = timestamp;\n matchedEntity.lastPosition = obj.boundingBox;\n matchedEntity.appearances.push({\n timestamp,\n boundingBox: obj.boundingBox,\n confidence: obj.confidence,\n });\n\n // Keep only last 50 appearances for objects\n if (matchedEntity.appearances.length > 50) {\n matchedEntity.appearances = matchedEntity.appearances.slice(-50);\n }\n\n return matchedEntity;\n } else {\n // Create new entity\n const entityId = `object-${timestamp}-${Math.random().toString(36).substr(2, 9)}`;\n const newEntity: TrackedEntity = {\n id: entityId,\n entityType: \"object\",\n firstSeen: timestamp,\n lastSeen: timestamp,\n lastPosition: obj.boundingBox,\n appearances: [\n {\n timestamp,\n boundingBox: obj.boundingBox,\n confidence: obj.confidence,\n },\n ],\n attributes: {\n objectType: obj.type,\n },\n worldId: this.worldState.worldId,\n };\n\n this.worldState.entities.set(entityId, newEntity);\n logger.debug(\n `[EntityTracker] New object entity created: ${entityId} (${obj.type})`,\n );\n\n return newEntity;\n }\n }\n\n private findMatchingEntity(\n boundingBox: BoundingBox,\n entityType: \"person\" | \"object\",\n faceProfileId?: string,\n ): TrackedEntity | null {\n const currentTime = Date.now();\n let bestMatch: TrackedEntity | null = null;\n let minDistance = Infinity;\n\n for (const entity of this.worldState.entities.values()) {\n // Skip if wrong type\n if (entity.entityType !== entityType) {\n continue;\n }\n\n // Skip if entity has been missing too long\n if (currentTime - entity.lastSeen > this.MISSING_THRESHOLD) {\n continue;\n }\n\n // If we have face ID, prioritize face matching for people\n if (\n entityType === \"person\" &&\n faceProfileId &&\n entity.attributes.faceId\n ) {\n if (entity.attributes.faceId === faceProfileId) {\n return entity; // Direct face match\n }\n }\n\n // Calculate position distance\n const distance = this.calculateDistance(entity.lastPosition, boundingBox);\n\n if (distance < this.POSITION_THRESHOLD && distance < minDistance) {\n minDistance = distance;\n bestMatch = entity;\n }\n }\n\n return bestMatch;\n }\n\n private calculateDistance(box1: BoundingBox, box2: BoundingBox): number {\n const center1 = {\n x: box1.x + box1.width / 2,\n y: box1.y + box1.height / 2,\n };\n const center2 = {\n x: box2.x + box2.width / 2,\n y: box2.y + box2.height / 2,\n };\n\n return Math.sqrt(\n (center1.x - center2.x) ** 2 + (center1.y - center2.y) ** 2,\n );\n }\n\n private updateWorldState(\n seenEntityIds: Set<string>,\n timestamp: number,\n ): void {\n // Update active entities\n this.worldState.activeEntities = Array.from(seenEntityIds);\n this.worldState.lastUpdate = timestamp;\n\n // Check for entities that left\n for (const [entityId, entity] of this.worldState.entities) {\n if (\n !seenEntityIds.has(entityId) &&\n this.worldState.activeEntities.includes(entityId)\n ) {\n // Entity just left the scene\n this.worldState.recentlyLeft.push({\n entityId,\n leftAt: timestamp,\n lastPosition: entity.lastPosition,\n });\n\n logger.info(`[EntityTracker] Entity left scene: ${entityId}`);\n }\n }\n\n // Clean up old \"recently left\" entries\n this.worldState.recentlyLeft = this.worldState.recentlyLeft.filter(\n (entry) => timestamp - entry.leftAt < this.CLEANUP_THRESHOLD,\n );\n\n // Clean up very old entities\n for (const [entityId, entity] of this.worldState.entities) {\n if (timestamp - entity.lastSeen > this.CLEANUP_THRESHOLD * 10) {\n this.worldState.entities.delete(entityId);\n logger.debug(`[EntityTracker] Cleaned up old entity: ${entityId}`);\n }\n }\n }\n\n private async syncWithRuntime(\n runtime: IAgentRuntime,\n frameEntities: TrackedEntity[],\n ): Promise<void> {\n try {\n // Sync detected entities with the runtime's entity system\n for (const entity of frameEntities) {\n // Convert the human-readable tracker ID (e.g. \"person-123-abc\") to a\n // deterministic UUID that PostgreSQL accepts. The same local ID always\n // maps to the same UUID for a given agent, so updates stay consistent.\n const entityUuid = createUniqueUuid(runtime, entity.id);\n\n const elizaEntity = {\n id: entityUuid,\n names: [entity.attributes.name || entity.id],\n metadata: {\n type: entity.entityType,\n firstSeen: entity.firstSeen,\n lastSeen: entity.lastSeen,\n attributes: entity.attributes,\n worldId: this.worldState.worldId,\n },\n agentId: runtime.agentId,\n };\n\n try {\n const existing = await runtime.getEntityById(entityUuid);\n if (!existing) {\n await runtime.createEntity(elizaEntity);\n logger.debug(\n `[EntityTracker] Created entity ${entity.id} (${entityUuid}) in runtime`,\n );\n } else {\n await runtime.updateEntity({\n ...elizaEntity,\n id: entityUuid,\n });\n logger.debug(\n `[EntityTracker] Updated entity ${entity.id} (${entityUuid}) in runtime`,\n );\n }\n } catch (err) {\n logger.debug(\n `[EntityTracker] Could not sync entity ${entity.id}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n } catch (error) {\n logger.error({ error }, \"[EntityTracker] Failed to sync with runtime:\");\n }\n }\n\n // Public API\n getWorldState(): WorldState {\n return this.worldState;\n }\n\n getActiveEntities(): TrackedEntity[] {\n return this.worldState.activeEntities\n .map((id) => this.worldState.entities.get(id))\n .filter(Boolean) as TrackedEntity[];\n }\n\n getEntity(entityId: string): TrackedEntity | undefined {\n return this.worldState.entities.get(entityId);\n }\n\n getRecentlyLeft(): Array<{ entity: TrackedEntity; leftAt: number }> {\n return this.worldState.recentlyLeft\n .map((entry) => ({\n entity: this.worldState.entities.get(entry.entityId),\n leftAt: entry.leftAt,\n }))\n .filter((entry) => entry.entity) as Array<{\n entity: TrackedEntity;\n leftAt: number;\n }>;\n }\n\n // Name assignment\n assignNameToEntity(entityId: string, name: string): boolean {\n const entity = this.worldState.entities.get(entityId);\n if (entity) {\n entity.attributes.name = name;\n logger.info(\n `[EntityTracker] Assigned name \"${name}\" to entity ${entityId}`,\n );\n return true;\n }\n return false;\n }\n\n // Get statistics\n getStatistics(): {\n totalEntities: number;\n activeEntities: number;\n recentlyLeft: number;\n people: number;\n objects: number;\n } {\n const entities = Array.from(this.worldState.entities.values());\n return {\n totalEntities: entities.length,\n activeEntities: this.worldState.activeEntities.length,\n recentlyLeft: this.worldState.recentlyLeft.length,\n people: entities.filter((e) => e.entityType === \"person\").length,\n objects: entities.filter((e) => e.entityType === \"object\").length,\n };\n }\n}\n",
|
|
39
|
+
"// VisionServiceLifecycleManager\n//\n// Manages dynamic load/unload of vision sub-services (YOLO, RapidOCR,\n// MediaPipe face, MoveNet pose). Two ownership signals drive release:\n//\n// 1. **Idle watchdog** — if a sub-service hasn't been queried for\n// `idleUnloadMs` (default 60s), it's released.\n// 2. **Memory-pressure listener** — when an external arbiter signals\n// pressure, the coldest sub-services are released first.\n//\n// The arbiter is owned by WS1 (`@elizaos/plugin-local-inference`). Until that\n// service is registered on the runtime we operate in standalone mode: idle\n// watchdog still ticks, but no external pressure signal arrives.\n//\n// Acquisition is opt-in: a sub-service that registers an `acquire` callback\n// will be re-loaded on demand the next time it's used after a release.\n\nimport { logger } from \"@elizaos/core\";\n\n/**\n * Minimal contract a memory arbiter must implement so vision can plug into\n * WS1's load/unload pipeline. Mirrors the (forthcoming) interface in\n * `@elizaos/plugin-local-inference/src/services/memory-arbiter.ts` but is\n * declared here so plugin-vision compiles standalone.\n */\nexport interface IModelArbiter {\n /**\n * Reserve `bytes` of model memory for `holder`. Returning `false` means the\n * arbiter refused — the caller must skip the load.\n */\n acquire(holder: string, bytes: number): Promise<boolean> | boolean;\n\n /**\n * Release the prior reservation for `holder`.\n */\n release(holder: string): Promise<void> | void;\n\n /**\n * Subscribe to memory-pressure events. The arbiter calls the listener with\n * a non-empty list of holders when pressure is high enough that those\n * holders should release.\n */\n onPressure(listener: (holders: string[]) => void): () => void;\n}\n\nexport interface VisionSubServiceHandle {\n /** Stable holder id (e.g. \"vision:yolo\"). */\n id: string;\n /** Approximate VRAM/RAM cost in bytes. Used by the arbiter; ignored if 0. */\n memoryBytes: number;\n /** Optional hook invoked when the sub-service has been released. */\n unload(): Promise<void> | void;\n /** Optional hook invoked to re-load after a prior release. */\n acquire?(): Promise<void> | void;\n}\n\nexport interface VisionLifecycleConfig {\n /** Milliseconds of inactivity before a sub-service is released. */\n idleUnloadMs?: number;\n /** Tick interval for the idle watchdog. */\n watchdogIntervalMs?: number;\n}\n\ninterface RegisteredSub {\n handle: VisionSubServiceHandle;\n registeredAt: number;\n loaded: boolean;\n lastUsed: number;\n}\n\nconst DEFAULT_IDLE_UNLOAD_MS = 60_000;\nconst DEFAULT_WATCHDOG_INTERVAL_MS = 15_000;\n\nexport class VisionServiceLifecycleManager {\n private readonly subs = new Map<string, RegisteredSub>();\n private readonly idleUnloadMs: number;\n private readonly watchdogIntervalMs: number;\n private arbiter: IModelArbiter | null = null;\n private unsubscribePressure: (() => void) | null = null;\n private watchdogTimer: NodeJS.Timeout | null = null;\n private stopped = false;\n\n constructor(config: VisionLifecycleConfig = {}) {\n this.idleUnloadMs = config.idleUnloadMs ?? DEFAULT_IDLE_UNLOAD_MS;\n this.watchdogIntervalMs =\n config.watchdogIntervalMs ?? DEFAULT_WATCHDOG_INTERVAL_MS;\n }\n\n attachArbiter(arbiter: IModelArbiter | null): void {\n if (this.arbiter === arbiter) return;\n if (this.unsubscribePressure) {\n this.unsubscribePressure();\n this.unsubscribePressure = null;\n }\n this.arbiter = arbiter;\n if (!arbiter) return;\n this.unsubscribePressure = arbiter.onPressure((holders) => {\n this.handlePressure(holders).catch((error) => {\n logger.error({ error }, \"[VisionLifecycle] pressure handler failed:\");\n });\n });\n }\n\n register(handle: VisionSubServiceHandle): void {\n if (this.subs.has(handle.id)) return;\n this.subs.set(handle.id, {\n handle,\n registeredAt: Date.now(),\n loaded: true,\n lastUsed: Date.now(),\n });\n this.ensureWatchdog();\n }\n\n unregister(id: string): void {\n this.subs.delete(id);\n }\n\n /**\n * Mark a sub-service as in-use. If it was previously released, re-acquire\n * via the registered `acquire` callback (if any).\n *\n * Returns `true` if the sub-service is loaded after the call.\n */\n async touch(id: string): Promise<boolean> {\n const sub = this.subs.get(id);\n if (!sub) return false;\n sub.lastUsed = Date.now();\n if (sub.loaded) return true;\n if (!sub.handle.acquire) return false;\n if (this.arbiter) {\n const ok = await this.arbiter.acquire(\n sub.handle.id,\n sub.handle.memoryBytes,\n );\n if (!ok) {\n logger.warn(\n `[VisionLifecycle] arbiter refused acquisition of ${sub.handle.id}`,\n );\n return false;\n }\n }\n try {\n await sub.handle.acquire();\n sub.loaded = true;\n return true;\n } catch (error) {\n logger.error(\n { error },\n `[VisionLifecycle] re-acquire failed for ${sub.handle.id}:`,\n );\n if (this.arbiter) await this.arbiter.release(sub.handle.id);\n return false;\n }\n }\n\n /**\n * Force-release a single holder.\n */\n async release(id: string): Promise<void> {\n const sub = this.subs.get(id);\n if (!sub || !sub.loaded) return;\n try {\n await sub.handle.unload();\n } catch (error) {\n logger.error({ error }, `[VisionLifecycle] unload failed for ${id}:`);\n }\n sub.loaded = false;\n if (this.arbiter) await this.arbiter.release(id);\n }\n\n /**\n * Drop every registered sub-service (used during plugin stop()).\n */\n async stop(): Promise<void> {\n if (this.stopped) return;\n this.stopped = true;\n if (this.watchdogTimer) {\n clearInterval(this.watchdogTimer);\n this.watchdogTimer = null;\n }\n if (this.unsubscribePressure) {\n this.unsubscribePressure();\n this.unsubscribePressure = null;\n }\n const ids = Array.from(this.subs.keys());\n for (const id of ids) {\n await this.release(id);\n }\n this.subs.clear();\n }\n\n /** Test-only: return current snapshot. */\n snapshot(): Array<{ id: string; loaded: boolean; lastUsed: number }> {\n return Array.from(this.subs.values()).map((s) => ({\n id: s.handle.id,\n loaded: s.loaded,\n lastUsed: s.lastUsed,\n }));\n }\n\n private ensureWatchdog(): void {\n if (this.watchdogTimer || this.stopped) return;\n this.watchdogTimer = setInterval(() => {\n this.runWatchdog().catch((error) => {\n logger.error({ error }, \"[VisionLifecycle] watchdog failed:\");\n });\n }, this.watchdogIntervalMs);\n // Don't keep the event loop alive on the watchdog alone.\n this.watchdogTimer.unref?.();\n }\n\n private async runWatchdog(): Promise<void> {\n const cutoff = Date.now() - this.idleUnloadMs;\n for (const [id, sub] of this.subs) {\n if (!sub.loaded) continue;\n if (sub.lastUsed > cutoff) continue;\n logger.info(\n `[VisionLifecycle] idle release: ${id} (last used ${Date.now() - sub.lastUsed}ms ago)`,\n );\n await this.release(id);\n }\n }\n\n private async handlePressure(holders: string[]): Promise<void> {\n // Sort our visible holders by lastUsed asc (coldest first), then release\n // the ones the arbiter named (or all if names not listed).\n const named = new Set(holders);\n const candidates = Array.from(this.subs.values())\n .filter((s) => s.loaded && (named.size === 0 || named.has(s.handle.id)))\n .sort((a, b) => a.lastUsed - b.lastUsed);\n\n for (const sub of candidates) {\n logger.info(`[VisionLifecycle] pressure release: ${sub.handle.id}`);\n await this.release(sub.handle.id);\n }\n }\n}\n\n/**\n * Minimal projection of the WS1 `MemoryArbiter` shape (from\n * `@elizaos/plugin-local-inference`) that the bridge below needs. The WS1\n * arbiter exposes typed events through `onEvent`; vision only cares about\n * `memory_pressure` events, so we adapt them into the `IModelArbiter.onPressure`\n * contract here rather than coupling plugin-vision to the full event union.\n */\ninterface WS1ArbiterLike {\n onEvent(\n listener: (event: { type: string; level?: string }) => void,\n ): () => void;\n}\n\nfunction isWS1ArbiterLike(value: unknown): value is WS1ArbiterLike {\n return (\n !!value &&\n typeof value === \"object\" &&\n typeof (value as { onEvent?: unknown }).onEvent === \"function\"\n );\n}\n\n/**\n * Adapt the WS1 `MemoryArbiter` (which manages per-capability model handles\n * via `acquire(capability, modelKey)` and emits `memory_pressure` events on\n * `onEvent`) into the per-holder, byte-budget `IModelArbiter` contract that\n * `VisionServiceLifecycleManager` uses to track sub-services (YOLO, OCR,\n * face). The WS1 arbiter has no per-holder byte ledger, so the bridge\n * `acquire`/`release` are no-ops that always succeed — the WS1 side handles\n * eviction at capability granularity, and the vision lifecycle drives\n * sub-service release through the pressure callback. This is the seam that\n * lets a pressure tick on the WS1 arbiter cascade to YOLO + OCR release in\n * plugin-vision.\n */\nfunction adaptWS1ArbiterToIModelArbiter(ws1: WS1ArbiterLike): IModelArbiter {\n return {\n acquire(): boolean {\n return true;\n },\n release(): void {\n // WS1 manages per-capability lifecycles.\n },\n onPressure(cb: (holders: string[]) => void): () => void {\n return ws1.onEvent((event) => {\n if (event.type !== \"memory_pressure\") return;\n if (event.level === \"nominal\") return;\n // Empty holders list → \"release whatever is cold.\" The vision\n // lifecycle's `handlePressure` walks `subs` and picks coldest-first\n // when the named set is empty, which is the right cascade for both\n // `low` (drop one) and `critical` (drop all non-text) WS1 tiers.\n cb([]);\n });\n },\n };\n}\n\n/**\n * Try to resolve a model arbiter from the runtime, dynamically. This avoids\n * a hard dependency on `@elizaos/plugin-local-inference` (WS1) — vision still\n * works standalone when WS1 isn't installed.\n *\n * Two resolution paths:\n * 1. Direct: a service named `MEMORY_ARBITER` / `memory_arbiter` /\n * `memoryArbiter` that already implements the `IModelArbiter` shape.\n * Used by tests and standalone arbiter services.\n * 2. WS1 bridge: a `localInferenceLoader` / `localInference` service that\n * exposes `getMemoryArbiter()` returning the WS1 `MemoryArbiter`. We\n * adapt it to `IModelArbiter` via `adaptWS1ArbiterToIModelArbiter` so\n * memory-pressure events cascade into vision sub-service release.\n */\nexport function resolveArbiterFromRuntime(runtime: {\n getService?: (name: string) => unknown;\n}): IModelArbiter | null {\n const candidates = [\"MEMORY_ARBITER\", \"memory_arbiter\", \"memoryArbiter\"];\n for (const name of candidates) {\n const svc = runtime.getService?.(name) as\n | Partial<IModelArbiter>\n | null\n | undefined;\n if (\n svc &&\n typeof svc.acquire === \"function\" &&\n typeof svc.release === \"function\" &&\n typeof svc.onPressure === \"function\"\n ) {\n return svc as IModelArbiter;\n }\n }\n // WS1 bridge path: discover the arbiter via the local-inference loader\n // service. Two loader names are in use across this repo\n // (`localInferenceLoader` is the runtime-registered one;\n // `localInference` / `LOCAL_INFERENCE` are legacy aliases).\n const loaderNames = [\n \"localInferenceLoader\",\n \"localInference\",\n \"LOCAL_INFERENCE\",\n ];\n for (const name of loaderNames) {\n const loader = runtime.getService?.(name) as\n | { getMemoryArbiter?: () => unknown }\n | null\n | undefined;\n if (!loader || typeof loader.getMemoryArbiter !== \"function\") continue;\n const ws1 = loader.getMemoryArbiter();\n if (isWS1ArbiterLike(ws1)) {\n return adaptWS1ArbiterToIModelArbiter(ws1);\n }\n }\n return null;\n}\n",
|
|
40
|
+
"import { exec } from \"node:child_process\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { promisify } from \"node:util\";\nimport { logger } from \"@elizaos/core\";\nimport { getSharp } from \"./image/sharp-compat\";\nimport {\n DEFAULT_MAX_EDGE,\n DEFAULT_OVERLAP_FRACTION,\n type ScreenTile as TilerScreenTile,\n tileScreenshot,\n} from \"./screen-tiler\";\nimport type { ScreenCapture, ScreenTile, VisionConfig } from \"./types\";\n\nconst execAsync = promisify(exec);\n\n// `tileSize` in VisionConfig is the legacy fixed-grid edge. The new tiler\n// treats it as `maxEdge` — the largest dimension a single tile may have. The\n// tiler's defaults target local Gemma vision OCR detail; respect the config\n// override only when it stays in a practical local-VLM range.\nconst MIN_TILER_EDGE = 64;\nconst SINGLE_DISPLAY_ID = \"primary\";\n\n/**\n * Project a tiler ScreenTile onto the plugin-vision ScreenTile shape consumed\n * by `service.ts` and `ocr-service.ts`. We carry through `displayId`,\n * `sourceX`, and `sourceY` for absolute-coord reconstruction; `row`/`col` are\n * recovered from the tiler id (`tile-<row>-<col>`).\n */\nfunction toVisionTile(\n tile: TilerScreenTile,\n index: number,\n total: number,\n): ScreenTile {\n const { row, col } = parseTilerId(tile.id, index, total);\n return {\n id: tile.id,\n row,\n col,\n x: tile.sourceX,\n y: tile.sourceY,\n width: tile.tileW,\n height: tile.tileH,\n displayId: tile.displayId,\n sourceX: tile.sourceX,\n sourceY: tile.sourceY,\n };\n}\n\nconst TILER_ID_RE = /^tile-(\\d+)-(\\d+)$/;\n\nfunction parseTilerId(\n id: string,\n index: number,\n total: number,\n): { row: number; col: number } {\n const match = TILER_ID_RE.exec(id);\n if (match?.[1] && match[2]) {\n return {\n row: Number.parseInt(match[1], 10),\n col: Number.parseInt(match[2], 10),\n };\n }\n // Fall back to a single-row layout when the id format ever drifts.\n const cols = Math.max(1, total);\n return { row: Math.floor(index / cols), col: index % cols };\n}\n\nfunction computeCols(tiles: TilerScreenTile[]): number {\n let maxCol = 0;\n for (const tile of tiles) {\n const match = TILER_ID_RE.exec(tile.id);\n if (match?.[2]) {\n const col = Number.parseInt(match[2], 10);\n if (col > maxCol) maxCol = col;\n }\n }\n return maxCol + 1;\n}\n\nexport class ScreenCaptureService {\n private config: VisionConfig;\n private activeTileIndex = 0;\n private lastCapture: ScreenCapture | null = null;\n\n constructor(config: VisionConfig) {\n this.config = config;\n }\n\n async getScreenInfo(): Promise<{ width: number; height: number } | null> {\n const platform = process.platform;\n\n try {\n if (platform === \"darwin\") {\n // macOS: Use system_profiler\n const { stdout } = await execAsync(\n \"system_profiler SPDisplaysDataType -json\",\n );\n const data = JSON.parse(stdout);\n\n if (data.SPDisplaysDataType?.[0]) {\n const display = data.SPDisplaysDataType[0];\n const resolution = display._items?.[0]?.native_resolution;\n if (resolution) {\n const match = resolution.match(/(\\d+) x (\\d+)/);\n if (match) {\n return {\n width: parseInt(match[1], 10),\n height: parseInt(match[2], 10),\n };\n }\n }\n }\n } else if (platform === \"linux\") {\n // Linux: Use xrandr\n const { stdout } = await execAsync(\n 'xrandr | grep \" connected primary\"',\n );\n const match = stdout.match(/(\\d+)x(\\d+)/);\n if (match) {\n return {\n width: parseInt(match[1], 10),\n height: parseInt(match[2], 10),\n };\n }\n } else if (platform === \"win32\") {\n // Windows: Use wmic\n const { stdout } = await execAsync(\n \"wmic path Win32_VideoController get CurrentHorizontalResolution,CurrentVerticalResolution /value\",\n );\n const width = stdout.match(/CurrentHorizontalResolution=(\\d+)/)?.[1];\n const height = stdout.match(/CurrentVerticalResolution=(\\d+)/)?.[1];\n if (width && height) {\n return {\n width: parseInt(width, 10),\n height: parseInt(height, 10),\n };\n }\n }\n } catch (error) {\n logger.error({ error }, \"[ScreenCapture] Failed to get screen info:\");\n }\n\n // Default fallback\n return { width: 1920, height: 1080 };\n }\n\n async captureScreen(): Promise<ScreenCapture> {\n const tempFile = path.join(process.cwd(), `temp_screen_${Date.now()}.png`);\n\n try {\n // Capture the screen\n await this.captureScreenToFile(tempFile);\n\n // Load and decode the image. The tiler does its own crop/extract so we\n // only need the metadata + raw bytes here.\n const imageBuffer = await fs.readFile(tempFile);\n const sharp = await getSharp();\n const metadata = await sharp(imageBuffer).metadata();\n\n const width = metadata.width || 1920;\n const height = metadata.height || 1080;\n\n // Hand layout to the overlap-aware tiler. It sizes tiles to the local\n // Gemma vision budget and seams them with overlap so glyphs that\n // straddle a boundary still appear intact in at least one tile.\n const maxEdge = Math.max(\n MIN_TILER_EDGE,\n this.config.tileSize ?? DEFAULT_MAX_EDGE,\n );\n const tilerTiles = await tileScreenshot(\n {\n displayId: SINGLE_DISPLAY_ID,\n width,\n height,\n pngBytes: imageBuffer,\n },\n { maxEdge, overlapFraction: DEFAULT_OVERLAP_FRACTION },\n );\n const tiles = tilerTiles.map((tile, index) =>\n toVisionTile(tile, index, tilerTiles.length),\n );\n\n // Process active tile based on order\n const cols = computeCols(tilerTiles);\n if (this.config.tileProcessingOrder === \"priority\") {\n // Focus on center tiles first\n const centerRow = Math.floor(tiles.length / 2 / cols);\n const centerCol = Math.floor((tiles.length / 2) % cols);\n this.activeTileIndex = Math.min(\n tiles.length - 1,\n centerRow * cols + centerCol,\n );\n } else if (this.config.tileProcessingOrder === \"random\") {\n this.activeTileIndex = Math.floor(Math.random() * tiles.length);\n } else {\n // Sequential\n this.activeTileIndex = (this.activeTileIndex + 1) % tiles.length;\n }\n\n // Tiler already produced a PNG buffer for every tile — wire the chosen\n // one into the active slot for downstream OCR / VLM consumption.\n const activeTile = tiles[this.activeTileIndex];\n const activeTilerTile = tilerTiles[this.activeTileIndex];\n if (activeTile && activeTilerTile) {\n activeTile.data = activeTilerTile.pngBytes;\n }\n\n // Clean up temp file\n await fs.unlink(tempFile).catch(() => {});\n\n // Create screen capture object\n const capture: ScreenCapture = {\n timestamp: Date.now(),\n width,\n height,\n data: imageBuffer,\n tiles,\n };\n\n this.lastCapture = capture;\n return capture;\n } catch (error) {\n // Clean up temp file on error\n await fs.unlink(tempFile).catch(() => {});\n throw error;\n }\n }\n\n private async captureScreenToFile(outputPath: string): Promise<void> {\n const platform = process.platform;\n\n try {\n if (platform === \"darwin\") {\n // macOS: Use screencapture\n await execAsync(`screencapture -x \"${outputPath}\"`);\n } else if (platform === \"linux\") {\n // Linux: Use scrot or gnome-screenshot\n try {\n await execAsync(`scrot \"${outputPath}\"`);\n } catch (_error) {\n // Fallback to gnome-screenshot\n await execAsync(`gnome-screenshot -f \"${outputPath}\"`);\n }\n } else if (platform === \"win32\") {\n // Windows: Use PowerShell\n const script = `\n Add-Type -AssemblyName System.Windows.Forms;\n Add-Type -AssemblyName System.Drawing;\n $screen = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds;\n $bitmap = New-Object System.Drawing.Bitmap $screen.Width, $screen.Height;\n $graphics = [System.Drawing.Graphics]::FromImage($bitmap);\n $graphics.CopyFromScreen($screen.Location, [System.Drawing.Point]::Empty, $screen.Size);\n $bitmap.Save('${outputPath.replace(/\\\\/g, \"\\\\\\\\\")}');\n $graphics.Dispose();\n $bitmap.Dispose();\n `;\n await execAsync(`powershell -Command \"${script.replace(/\\n/g, \" \")}\"`);\n } else {\n throw new Error(`Unsupported platform: ${platform}`);\n }\n } catch (error) {\n logger.error({ error }, \"[ScreenCapture] Screen capture failed:\");\n\n // Provide helpful error messages\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n if (platform === \"linux\" && errorMessage.includes(\"command not found\")) {\n throw new Error(\n \"Screen capture tool not found. Install with: sudo apt-get install scrot\",\n );\n }\n throw error;\n }\n }\n\n getActiveTile(): ScreenTile | null {\n if (!this.lastCapture?.tiles[this.activeTileIndex]) {\n return null;\n }\n return this.lastCapture.tiles[this.activeTileIndex];\n }\n\n getAllTiles(): ScreenTile[] {\n return this.lastCapture?.tiles || [];\n }\n\n getProcessedTiles(): ScreenTile[] {\n return this.lastCapture?.tiles.filter((t) => t.analysis) || [];\n }\n}\n",
|
|
19
41
|
"/**\n * Test-input shim for plugin-vision.\n *\n * Lets tests inject a fixture image into the vision analysis pipeline\n * without monkey-patching platform capture code.\n *\n * Selection: read `ELIZA_VISION_TEST_INPUT`:\n * - \"image\" → return the fixture bytes (resolved via\n * `ELIZA_VISION_TEST_FIXTURE` env var, default the bundled\n * test/fixtures/sample-scene.png path).\n * - \"camera\" / \"screen\" / unset → return null, signaling that the caller\n * should use the existing platform capture path.\n *\n * Single-purpose helper: anything that wants test-injected pixels reads\n * `getTestImage()`. When it returns a Buffer, use those bytes. When it\n * returns null, fall through to live capture.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { logger } from \"@elizaos/core\";\n\nexport type TestInputMode = \"image\" | \"camera\" | \"screen\" | \"unset\";\n\nexport function getTestInputMode(): TestInputMode {\n const raw = (process.env.ELIZA_VISION_TEST_INPUT ?? \"\").trim().toLowerCase();\n if (raw === \"image\") return \"image\";\n if (raw === \"camera\") return \"camera\";\n if (raw === \"screen\") return \"screen\";\n return \"unset\";\n}\n\nconst FIXTURE_DEFAULT_REL = \"test/fixtures/sample-scene.png\";\n\nfunction resolveFixturePath(): string {\n const fromEnv = process.env.ELIZA_VISION_TEST_FIXTURE;\n if (fromEnv) return resolve(fromEnv);\n // Resolve relative to the package root (parent of `src` / `dist`).\n return resolve(process.cwd(), FIXTURE_DEFAULT_REL);\n}\n\nlet cached: Buffer | null = null;\nlet cachedKey: string | null = null;\n\n/**\n * If `ELIZA_VISION_TEST_INPUT=image`, return fixture bytes (PNG buffer);\n * otherwise return null. Result is cached per-fixture-path for the process.\n */\nexport function getTestImage(): Buffer | null {\n if (getTestInputMode() !== \"image\") return null;\n const path = resolveFixturePath();\n if (cachedKey === path && cached) return cached;\n if (!existsSync(path)) {\n logger.warn(\n `[plugin-vision] ELIZA_VISION_TEST_INPUT=image set but fixture not found at ${path}.`,\n );\n return null;\n }\n cached = readFileSync(path);\n cachedKey = path;\n return cached;\n}\n",
|
|
20
|
-
"// Vision models for object detection and pose estimation\n\nimport { logger } from \"@elizaos/core\";\nimport type { DetectedObject, PersonInfo } from \"./types\";\n\n// Lazy-loaded TensorFlow.js modules — the native addon may not be available\n// (e.g. when installed via bun or on platforms without prebuilt binaries).\n// We load them on first use so the rest of the plugin still works.\nlet tf: typeof import(\"@tensorflow/tfjs-node\") | null = null;\nlet cocoSsd: typeof import(\"@tensorflow-models/coco-ssd\") | null = null;\nlet poseDetection: typeof import(\"@tensorflow-models/pose-detection\") | null =\n null;\n\nasync function loadTfModules(): Promise<boolean> {\n if (tf) return true;\n try {\n tf = await import(\"@tensorflow/tfjs-node\");\n cocoSsd = await import(\"@tensorflow-models/coco-ssd\");\n poseDetection = await import(\"@tensorflow-models/pose-detection\");\n return true;\n } catch (err) {\n logger.warn(\n \"[VisionModels] TensorFlow.js native addon not available — \" +\n \"falling back to description-based detection. \" +\n \"Run `npm rebuild @tensorflow/tfjs-node --build-addon-from-source` to enable hardware-accelerated vision.\",\n );\n return false;\n }\n}\n\n// Define types that are missing from types.ts\nexport interface VisionModelConfig {\n enableObjectDetection?: boolean;\n enablePoseDetection?: boolean;\n florence2?: {\n baseUrl: string;\n apiKey?: string;\n };\n vlm?: {\n model: string;\n temperature: number;\n maxTokens: number;\n };\n}\n\nexport type Pose = \"sitting\" | \"standing\" | \"lying\" | \"walking\" | \"unknown\";\n\nexport interface PoseLandmark {\n name: string;\n x: number;\n y: number;\n score: number;\n}\n\nexport class VisionModels {\n private objectDetectionModel: Awaited<\n ReturnType<NonNullable<typeof cocoSsd>[\"load\"]>\n > | null = null;\n private poseDetector: Awaited<\n ReturnType<NonNullable<typeof poseDetection>[\"createDetector\"]>\n > | null = null;\n private initialized = false;\n private tfAvailable = false;\n\n async initialize(config: VisionModelConfig): Promise<void> {\n if (this.initialized) {\n return;\n }\n\n logger.info(\"[VisionModels] Initializing vision models...\");\n\n this.tfAvailable = await loadTfModules();\n\n if (!this.tfAvailable || !tf || !cocoSsd || !poseDetection) {\n // Mark as initialized so we use the fallback paths instead of retrying.\n this.initialized = true;\n logger.info(\n \"[VisionModels] Initialized without TensorFlow (fallback mode)\",\n );\n return;\n }\n\n try {\n // Initialize TensorFlow.js backend\n await tf.ready();\n logger.info(\"[VisionModels] TensorFlow.js backend ready\");\n\n // Load object detection model\n if (config.enableObjectDetection) {\n try {\n logger.info(\"[VisionModels] Loading COCO-SSD model...\");\n this.objectDetectionModel = await cocoSsd.load({\n base: \"mobilenet_v2\",\n });\n logger.info(\"[VisionModels] COCO-SSD model loaded\");\n } catch (error) {\n logger.error(\"[VisionModels] Failed to load COCO-SSD model:\", error);\n }\n }\n\n // Load pose detection model\n if (config.enablePoseDetection) {\n try {\n logger.info(\"[VisionModels] Loading PoseNet model...\");\n const detectorConfig = {\n architecture: \"MobileNetV1\" as const,\n outputStride: 16 as const,\n inputResolution: { width: 640, height: 480 },\n multiplier: 0.75 as const,\n };\n\n this.poseDetector = await poseDetection.createDetector(\n poseDetection.SupportedModels.PoseNet,\n detectorConfig,\n );\n logger.info(\"[VisionModels] PoseNet model loaded\");\n } catch (error) {\n logger.error(\"[VisionModels] Failed to load PoseNet model:\", error);\n }\n }\n\n this.initialized = true;\n logger.info(\"[VisionModels] Vision models initialized\");\n } catch (error) {\n logger.error(\"[VisionModels] Initialization failed:\", error);\n throw error;\n }\n }\n\n hasObjectDetection(): boolean {\n return this.objectDetectionModel !== null;\n }\n\n hasPoseDetection(): boolean {\n return this.poseDetector !== null;\n }\n\n async detectObjects(\n imageData: Buffer,\n _width: number,\n _height: number,\n description?: string,\n ): Promise<DetectedObject[]> {\n if (!this.objectDetectionModel || !tf) {\n logger.warn(\"[VisionModels] Object detection model not loaded\");\n return this.enhancedObjectDetection(description);\n }\n\n try {\n // Convert image data to tensor\n const imageTensor = tf.node.decodeImage(imageData, 3);\n\n // Ensure the tensor has the right shape [1, height, width, 3]\n const batched = imageTensor.expandDims(0);\n\n // Run detection - cocoSsd.detect expects specific input types\n // We squeeze the batch dimension back for detection\n const squeezed = batched.squeeze([0]) as ReturnType<\n typeof imageTensor.expandDims\n > extends infer T\n ? T\n : never;\n const predictions = await this.objectDetectionModel.detect(\n squeezed as Parameters<typeof this.objectDetectionModel.detect>[0],\n );\n squeezed.dispose();\n\n // Clean up tensors\n imageTensor.dispose();\n batched.dispose();\n\n // Convert predictions to our format\n const objects: DetectedObject[] = predictions.map((pred, idx) => ({\n id: `obj-${Date.now()}-${idx}`,\n type: pred.class,\n confidence: pred.score,\n boundingBox: {\n x: pred.bbox[0],\n y: pred.bbox[1],\n width: pred.bbox[2],\n height: pred.bbox[3],\n },\n }));\n\n logger.debug(`[VisionModels] Detected ${objects.length} objects`);\n return objects;\n } catch (error) {\n logger.error(\"[VisionModels] Object detection failed:\", error);\n return this.enhancedObjectDetection(description);\n }\n }\n\n private enhancedObjectDetection(description?: string): DetectedObject[] {\n // Enhanced object detection based on scene description\n if (!description) {\n return [];\n }\n\n const objects: DetectedObject[] = [];\n\n // Extract objects from description using patterns\n const objectPatterns = [\n {\n pattern:\n /(\\d+)?\\s*(person|people|man|men|woman|women|child|children)/gi,\n type: \"person\",\n },\n {\n pattern: /(\\d+)?\\s*(laptop|computer|monitor|screen|display)/gi,\n type: \"laptop\",\n },\n { pattern: /(\\d+)?\\s*(phone|smartphone|mobile)/gi, type: \"cell phone\" },\n { pattern: /(\\d+)?\\s*(book|notebook|journal)/gi, type: \"book\" },\n { pattern: /(\\d+)?\\s*(cup|mug|glass|bottle)/gi, type: \"cup\" },\n { pattern: /(\\d+)?\\s*(chair|seat|sofa|couch)/gi, type: \"chair\" },\n { pattern: /(\\d+)?\\s*(table|desk)/gi, type: \"dining table\" },\n { pattern: /(\\d+)?\\s*(car|vehicle|truck|bus)/gi, type: \"car\" },\n { pattern: /(\\d+)?\\s*(dog|cat|pet|animal)/gi, type: \"animal\" },\n { pattern: /(\\d+)?\\s*(plant|tree|flower)/gi, type: \"potted plant\" },\n ];\n\n for (const { pattern, type } of objectPatterns) {\n const matches = Array.from(description.matchAll(pattern));\n for (const match of matches) {\n const count = match[1] ? parseInt(match[1], 10) : 1;\n for (let i = 0; i < count; i++) {\n objects.push({\n id: `obj-${type}-${Date.now()}-${i}`,\n type,\n confidence: 0.85, // High confidence since it's from VLM\n boundingBox: this.generatePlausibleBoundingBox(type, i, count),\n });\n }\n }\n }\n\n return objects;\n }\n\n private generatePlausibleBoundingBox(\n type: string,\n index: number,\n total: number,\n ): {\n x: number;\n y: number;\n width: number;\n height: number;\n } {\n // Generate plausible bounding boxes based on object type and position\n const basePositions: Record<\n string,\n { width: number; height: number; y: number }\n > = {\n person: { width: 150, height: 300, y: 100 },\n laptop: { width: 200, height: 150, y: 250 },\n \"cell phone\": { width: 50, height: 100, y: 300 },\n book: { width: 100, height: 150, y: 280 },\n cup: { width: 60, height: 80, y: 300 },\n chair: { width: 180, height: 200, y: 200 },\n \"dining table\": { width: 400, height: 200, y: 250 },\n car: { width: 300, height: 200, y: 150 },\n animal: { width: 120, height: 100, y: 300 },\n \"potted plant\": { width: 100, height: 150, y: 200 },\n };\n\n const base = basePositions[type] || { width: 100, height: 100, y: 200 };\n const spacing = 640 / (total + 1); // Distribute across frame width\n\n return {\n x: spacing * (index + 1) - base.width / 2,\n y: base.y + (Math.random() - 0.5) * 50,\n width: base.width + (Math.random() - 0.5) * 40,\n height: base.height + (Math.random() - 0.5) * 40,\n };\n }\n\n async detectPoses(\n imageData: Buffer,\n width: number,\n height: number,\n description?: string,\n ): Promise<PersonInfo[]> {\n if (!this.poseDetector || !tf) {\n logger.warn(\"[VisionModels] Pose detection model not loaded\");\n return this.enhancedPoseDetection(description);\n }\n\n try {\n // Convert image data to tensor\n const imageTensor = tf.node.decodeImage(imageData, 3);\n\n // Run pose detection - estimatePoses expects ImageData-like object\n const poses = await this.poseDetector.estimatePoses({\n data: new Uint8ClampedArray(imageTensor.dataSync()),\n width,\n height,\n } as ImageData);\n\n // Clean up tensor\n imageTensor.dispose();\n\n // Convert poses to PersonInfo\n return this.convertPosesToPersonInfo(poses);\n } catch (error) {\n logger.error(\"[VisionModels] Pose detection failed:\", error);\n return this.enhancedPoseDetection(description);\n }\n }\n\n private enhancedPoseDetection(description?: string): PersonInfo[] {\n // Enhanced pose detection based on scene description\n if (!description) {\n return [];\n }\n\n const people: PersonInfo[] = [];\n const descLower = description.toLowerCase();\n\n // Extract people count and descriptions\n const peopleMatch = description.match(\n /(\\d+)?\\s*(person|people|man|men|woman|women|child|children)/gi,\n );\n if (!peopleMatch) {\n return [];\n }\n\n const count = peopleMatch[0].match(/\\d+/)?.[0]\n ? parseInt(peopleMatch[0].match(/\\d+/)?.[0], 10)\n : 1;\n\n // Analyze description for pose and facing information\n const poseKeywords = {\n standing: [\"standing\", \"stand\", \"upright\"],\n sitting: [\"sitting\", \"seated\", \"sit\", \"chair\"],\n walking: [\"walking\", \"walk\", \"moving\"],\n lying: [\"lying\", \"laying\", \"reclined\"],\n };\n\n const facingKeywords = {\n camera: [\n \"facing camera\",\n \"looking at camera\",\n \"facing forward\",\n \"front view\",\n ],\n away: [\"back to camera\", \"facing away\", \"back view\"],\n left: [\"facing left\", \"profile left\", \"left side\"],\n right: [\"facing right\", \"profile right\", \"right side\"],\n };\n\n let detectedPose = \"standing\";\n let detectedFacing = \"camera\";\n\n // Detect pose\n for (const [pose, keywords] of Object.entries(poseKeywords)) {\n if (keywords.some((kw) => descLower.includes(kw))) {\n detectedPose = pose;\n break;\n }\n }\n\n // Detect facing\n for (const [facing, keywords] of Object.entries(facingKeywords)) {\n if (keywords.some((kw) => descLower.includes(kw))) {\n detectedFacing = facing;\n break;\n }\n }\n\n // Create PersonInfo for each detected person\n for (let i = 0; i < count; i++) {\n const boundingBox = this.generatePlausibleBoundingBox(\"person\", i, count);\n\n people.push({\n id: `person-${Date.now()}-${i}`,\n boundingBox,\n pose: detectedPose as \"sitting\" | \"standing\" | \"lying\" | \"unknown\",\n facing: detectedFacing as \"camera\" | \"away\" | \"left\" | \"right\",\n confidence: 0.85,\n keypoints: this.generatePlausibleKeypoints(\n boundingBox,\n detectedPose as Pose,\n detectedFacing,\n ).map((kp) => ({\n part: kp.name,\n position: { x: kp.x, y: kp.y },\n score: kp.score,\n })),\n });\n }\n\n return people;\n }\n\n private generatePlausibleKeypoints(\n boundingBox: { x: number; y: number; width: number; height: number },\n pose: Pose,\n _facing: string,\n ): PoseLandmark[] {\n // Generate plausible keypoints based on pose and facing\n const { x, y, width, height } = boundingBox;\n const centerX = x + width / 2;\n\n const keypoints: PoseLandmark[] = [];\n\n // Basic keypoint positions relative to bounding box\n const positions = {\n nose: { x: centerX, y: y + height * 0.1 },\n leftEye: { x: centerX - width * 0.1, y: y + height * 0.08 },\n rightEye: { x: centerX + width * 0.1, y: y + height * 0.08 },\n leftEar: { x: centerX - width * 0.15, y: y + height * 0.1 },\n rightEar: { x: centerX + width * 0.15, y: y + height * 0.1 },\n leftShoulder: { x: centerX - width * 0.25, y: y + height * 0.25 },\n rightShoulder: { x: centerX + width * 0.25, y: y + height * 0.25 },\n leftElbow: { x: centerX - width * 0.3, y: y + height * 0.4 },\n rightElbow: { x: centerX + width * 0.3, y: y + height * 0.4 },\n leftWrist: { x: centerX - width * 0.25, y: y + height * 0.55 },\n rightWrist: { x: centerX + width * 0.25, y: y + height * 0.55 },\n leftHip: { x: centerX - width * 0.15, y: y + height * 0.5 },\n rightHip: { x: centerX + width * 0.15, y: y + height * 0.5 },\n leftKnee: { x: centerX - width * 0.15, y: y + height * 0.7 },\n rightKnee: { x: centerX + width * 0.15, y: y + height * 0.7 },\n leftAnkle: { x: centerX - width * 0.15, y: y + height * 0.9 },\n rightAnkle: { x: centerX + width * 0.15, y: y + height * 0.9 },\n };\n\n // Adjust positions based on pose\n if (pose === \"sitting\") {\n // Lower hips and knees for sitting pose\n positions.leftHip.y += height * 0.1;\n positions.rightHip.y += height * 0.1;\n positions.leftKnee.y -= height * 0.1;\n positions.rightKnee.y -= height * 0.1;\n }\n\n // Convert to PoseLandmark format\n Object.entries(positions).forEach(([name, pos]) => {\n keypoints.push({\n name: name as string,\n x: pos.x,\n y: pos.y,\n score: 0.85,\n });\n });\n\n return keypoints;\n }\n\n convertPosesToPersonInfo(\n poses: Array<{\n keypoints: Array<{ name?: string; x: number; y: number; score?: number }>;\n score?: number;\n }>,\n ): PersonInfo[] {\n return poses.map((pose, index) => {\n const keypoints = pose.keypoints;\n\n // Calculate bounding box from keypoints\n const xs = keypoints.map((kp) => kp.x);\n const ys = keypoints.map((kp) => kp.y);\n const minX = Math.min(...xs);\n const maxX = Math.max(...xs);\n const minY = Math.min(...ys);\n const maxY = Math.max(...ys);\n\n const boundingBox = {\n x: minX,\n y: minY,\n width: maxX - minX,\n height: maxY - minY,\n };\n\n // Determine pose from keypoints\n const detectedPose = this.determinePoseFromKeypoints(keypoints);\n\n // Determine facing direction\n const facing = this.determineFacingDirection(keypoints);\n\n // Convert keypoints to our format\n const convertedKeypoints = keypoints.map((kp) => ({\n part: kp.name || \"unknown\",\n position: { x: kp.x, y: kp.y },\n score: kp.score || 0,\n }));\n\n return {\n id: `person-${Date.now()}-${index}`,\n boundingBox,\n pose: detectedPose as \"sitting\" | \"standing\" | \"lying\" | \"unknown\",\n facing,\n confidence: pose.score || 0.5,\n keypoints: convertedKeypoints,\n };\n });\n }\n\n private determinePoseFromKeypoints(\n keypoints: Array<{ name?: string; x: number; y: number; score?: number }>,\n ): Pose {\n // Simple heuristic to determine pose\n const leftHip = keypoints.find((kp) => kp.name === \"left_hip\");\n const rightHip = keypoints.find((kp) => kp.name === \"right_hip\");\n const leftKnee = keypoints.find((kp) => kp.name === \"left_knee\");\n const rightKnee = keypoints.find((kp) => kp.name === \"right_knee\");\n const leftShoulder = keypoints.find((kp) => kp.name === \"left_shoulder\");\n const rightShoulder = keypoints.find((kp) => kp.name === \"right_shoulder\");\n\n if (!leftHip || !rightHip || !leftKnee || !rightKnee) {\n return \"unknown\";\n }\n\n const hipY = (leftHip.y + rightHip.y) / 2;\n const kneeY = (leftKnee.y + rightKnee.y) / 2;\n const shoulderY =\n leftShoulder && rightShoulder\n ? (leftShoulder.y + rightShoulder.y) / 2\n : hipY - 100;\n\n // Check if person is lying down (shoulders and hips at similar height)\n if (Math.abs(shoulderY - hipY) < 50) {\n return \"lying\";\n }\n\n // Check if person is sitting (knees close to hips)\n if (Math.abs(hipY - kneeY) < 100) {\n return \"sitting\";\n }\n\n // Otherwise assume standing\n return \"standing\";\n }\n\n private determineFacingDirection(\n keypoints: Array<{ name?: string; x: number; y: number; score?: number }>,\n ): \"camera\" | \"away\" | \"left\" | \"right\" {\n const leftShoulder = keypoints.find((kp) => kp.name === \"left_shoulder\");\n const rightShoulder = keypoints.find((kp) => kp.name === \"right_shoulder\");\n const nose = keypoints.find((kp) => kp.name === \"nose\");\n\n if (!leftShoulder || !rightShoulder || !nose) {\n return \"camera\"; // Default\n }\n\n const shoulderWidth = Math.abs(rightShoulder.x - leftShoulder.x);\n const shoulderMidpoint = (leftShoulder.x + rightShoulder.x) / 2;\n const noseOffset = nose.x - shoulderMidpoint;\n\n // If shoulders are narrow, person is likely in profile\n if (shoulderWidth < 50) {\n return noseOffset > 0 ? \"right\" : \"left\";\n }\n\n // If nose is significantly offset from shoulder midpoint, person is turning\n if (Math.abs(noseOffset) > shoulderWidth * 0.3) {\n return noseOffset > 0 ? \"right\" : \"left\";\n }\n\n // Check if both ears are visible (facing camera) or not (facing away)\n const leftEar = keypoints.find((kp) => kp.name === \"left_ear\");\n const rightEar = keypoints.find((kp) => kp.name === \"right_ear\");\n\n if (leftEar && rightEar && leftEar.score && rightEar.score) {\n if (leftEar.score > 0.5 && rightEar.score > 0.5) {\n return \"camera\";\n }\n }\n\n return \"camera\"; // Default\n }\n\n async dispose(): Promise<void> {\n if (this.objectDetectionModel) {\n // COCO-SSD doesn't have a dispose method, but we can clear the reference\n this.objectDetectionModel = null;\n }\n\n if (this.poseDetector) {\n this.poseDetector.dispose();\n this.poseDetector = null;\n }\n\n this.initialized = false;\n logger.info(\"[VisionModels] Models disposed\");\n }\n}\n",
|
|
21
|
-
"import * as path from \"node:path\";\nimport { TextDecoder } from \"node:util\";\nimport { Worker } from \"node:worker_threads\";\nimport { logger } from \"@elizaos/core\";\nimport type {\n EnhancedSceneDescription,\n Florence2Result,\n OCRResult,\n ScreenCapture,\n VisionConfig,\n} from \"./types\";\n\ninterface WorkerStats {\n fps: number;\n frameCount: number;\n lastUpdate: number;\n}\n\nexport class VisionWorkerManager {\n private config: VisionConfig;\n\n // Workers\n private screenCaptureWorker: Worker | null = null;\n private florence2Worker: Worker | null = null;\n private ocrWorker: Worker | null = null;\n\n // Shared buffers\n private screenBuffer: SharedArrayBuffer;\n private florence2ResultsBuffer: SharedArrayBuffer;\n private ocrResultsBuffer: SharedArrayBuffer;\n\n // Buffer views\n private screenAtomicState: Int32Array;\n private florence2ResultsView: DataView;\n private ocrResultsView: DataView;\n\n // Buffer sizes\n private readonly SCREEN_BUFFER_SIZE = 50 * 1024 * 1024; // 50MB for 4K screen\n private readonly FLORENCE2_RESULTS_SIZE = 10 * 1024 * 1024; // 10MB for results\n private readonly OCR_RESULTS_SIZE = 5 * 1024 * 1024; // 5MB for OCR text\n\n // Atomic indices\n private readonly FRAME_ID_INDEX = 0;\n private readonly WIDTH_INDEX = 2;\n private readonly HEIGHT_INDEX = 3;\n private readonly DISPLAY_INDEX = 4;\n private readonly TIMESTAMP_INDEX = 5;\n\n // Worker stats\n private workerStats = new Map<string, WorkerStats>();\n\n // Latest processed data cache\n private latestScreenCapture: ScreenCapture | null = null;\n private latestFlorence2Results = new Map<string, Florence2Result>();\n private latestOCRResult: OCRResult | null = null;\n private lastProcessedFrameId = -1;\n\n // Worker restart tracking\n private restartAttempts = new Map<string, number>();\n private readonly MAX_RESTART_ATTEMPTS = 3;\n\n constructor(config: VisionConfig) {\n this.config = config;\n\n // Initialize shared buffers\n this.screenBuffer = new SharedArrayBuffer(this.SCREEN_BUFFER_SIZE);\n this.florence2ResultsBuffer = new SharedArrayBuffer(\n this.FLORENCE2_RESULTS_SIZE,\n );\n this.ocrResultsBuffer = new SharedArrayBuffer(this.OCR_RESULTS_SIZE);\n\n // Create views\n this.screenAtomicState = new Int32Array(this.screenBuffer, 0, 6);\n this.florence2ResultsView = new DataView(this.florence2ResultsBuffer);\n this.ocrResultsView = new DataView(this.ocrResultsBuffer);\n }\n\n async initialize(): Promise<void> {\n logger.info(\"[VisionWorkerManager] Initializing worker threads...\");\n\n try {\n // Start screen capture worker\n await this.startScreenCaptureWorker();\n\n // Start Florence-2 worker if enabled\n if (this.config.florence2Enabled) {\n await this.startFlorence2Worker();\n }\n\n // Start OCR worker if enabled\n if (this.config.ocrEnabled) {\n await this.startOCRWorker();\n }\n\n logger.info(\"[VisionWorkerManager] All workers initialized\");\n } catch (error) {\n logger.error(\n \"[VisionWorkerManager] Failed to initialize workers:\",\n error,\n );\n throw error;\n }\n }\n\n private async startScreenCaptureWorker(): Promise<void> {\n const workerPath = path.join(\n __dirname,\n \"workers\",\n \"screen-capture-worker.js\",\n );\n\n this.screenCaptureWorker = new Worker(workerPath, {\n workerData: {\n config: {\n displayIndex: this.config.displayIndex,\n captureAllDisplays: this.config.captureAllDisplays,\n targetFPS: this.config.targetScreenFPS,\n sharedBufferSize: this.SCREEN_BUFFER_SIZE,\n },\n sharedBuffer: this.screenBuffer,\n },\n });\n\n this.screenCaptureWorker.on(\"message\", (msg) => {\n if (msg.type === \"fps\") {\n this.workerStats.set(\"screenCapture\", {\n fps: msg.fps,\n frameCount: msg.frameCount,\n lastUpdate: Date.now(),\n });\n } else if (msg.type === \"error\") {\n logger.error(\"[ScreenCaptureWorker] Error:\", msg.error);\n } else if (msg.type === \"log\") {\n // Handle worker log messages\n this.handleWorkerLog(\"ScreenCaptureWorker\", msg);\n }\n });\n\n this.screenCaptureWorker.on(\"error\", (error) => {\n logger.error(\n \"[ScreenCaptureWorker] Worker error:\",\n error instanceof Error ? error.message : String(error),\n );\n // Attempt to restart worker after error\n setTimeout(() => this.restartScreenCaptureWorker(), 1000);\n });\n\n this.screenCaptureWorker.on(\"exit\", (code) => {\n if (code !== 0) {\n logger.error(\n `[ScreenCaptureWorker] Worker stopped with exit code ${code}`,\n );\n // Attempt to restart worker after crash\n setTimeout(() => this.restartScreenCaptureWorker(), 1000);\n }\n });\n }\n\n private async startFlorence2Worker(): Promise<void> {\n const workerPath = path.join(__dirname, \"workers\", \"florence2-worker.js\");\n\n // Calculate priority tiles (center tiles)\n const priorityTiles: number[] = [];\n const tileSize = this.config.tileSize || 256;\n const estimatedCols = Math.ceil(1920 / tileSize); // Estimate based on common resolution\n const centerRow = Math.floor(estimatedCols / 2);\n const centerCol = Math.floor(estimatedCols / 2);\n\n // Add center and adjacent tiles as priority\n for (let r = centerRow - 1; r <= centerRow + 1; r++) {\n for (let c = centerCol - 1; c <= centerCol + 1; c++) {\n if (r >= 0 && c >= 0) {\n priorityTiles.push(r * estimatedCols + c);\n }\n }\n }\n\n this.florence2Worker = new Worker(workerPath, {\n workerData: {\n config: {\n tileSize: this.config.tileSize || 256,\n priorityTiles,\n },\n sharedBuffer: this.screenBuffer,\n resultsBuffer: this.florence2ResultsBuffer,\n },\n });\n\n this.florence2Worker.on(\"message\", (msg) => {\n if (msg.type === \"fps\") {\n this.workerStats.set(\"florence2\", {\n fps: msg.fps,\n frameCount: msg.frameCount,\n lastUpdate: Date.now(),\n });\n } else if (msg.type === \"tile_analyzed\") {\n // Update latest results cache\n this.updateFlorence2Cache(msg);\n } else if (msg.type === \"error\") {\n logger.error(\"[Florence2Worker] Error:\", msg.error);\n } else if (msg.type === \"log\") {\n // Handle worker log messages\n this.handleWorkerLog(\"Florence2Worker\", msg);\n }\n });\n\n this.florence2Worker.on(\"error\", (error) => {\n logger.error(\n \"[Florence2Worker] Worker error:\",\n error instanceof Error ? error.message : String(error),\n );\n // Attempt to restart worker after error\n setTimeout(() => this.restartFlorence2Worker(), 1000);\n });\n\n this.florence2Worker.on(\"exit\", (code) => {\n if (code !== 0) {\n logger.error(`[Florence2Worker] Worker stopped with exit code ${code}`);\n // Attempt to restart worker after crash\n setTimeout(() => this.restartFlorence2Worker(), 1000);\n }\n });\n }\n\n private async startOCRWorker(): Promise<void> {\n const workerPath = path.join(__dirname, \"workers\", \"ocr-worker.js\");\n\n this.ocrWorker = new Worker(workerPath, {\n workerData: {\n config: {\n processFullScreen: true,\n tileSize: this.config.tileSize || 256,\n textRegions: this.config.textRegions,\n },\n sharedBuffer: this.screenBuffer,\n resultsBuffer: this.ocrResultsBuffer,\n },\n });\n\n this.ocrWorker.on(\"message\", (msg) => {\n if (msg.type === \"fps\") {\n this.workerStats.set(\"ocr\", {\n fps: msg.fps,\n frameCount: msg.frameCount,\n lastUpdate: Date.now(),\n });\n } else if (msg.type === \"ocr_complete\") {\n // Update latest OCR cache\n this.updateOCRCache(msg);\n } else if (msg.type === \"error\") {\n logger.error(\"[OCRWorker] Error:\", msg.error);\n } else if (msg.type === \"log\") {\n // Handle worker log messages\n this.handleWorkerLog(\"OCRWorker\", msg);\n }\n });\n\n this.ocrWorker.on(\"error\", (error) => {\n logger.error(\n \"[OCRWorker] Worker error:\",\n error instanceof Error ? error.message : String(error),\n );\n // Attempt to restart worker after error\n setTimeout(() => this.restartOCRWorker(), 1000);\n });\n\n this.ocrWorker.on(\"exit\", (code) => {\n if (code !== 0) {\n logger.error(`[OCRWorker] Worker stopped with exit code ${code}`);\n // Attempt to restart worker after crash\n setTimeout(() => this.restartOCRWorker(), 1000);\n }\n });\n }\n\n private updateFlorence2Cache(msg: { tileId: string }): void {\n // Read result from shared buffer\n try {\n const tileId = msg.tileId;\n const result = this.readFlorence2Result(tileId);\n if (result) {\n this.latestFlorence2Results.set(tileId, result);\n }\n } catch (error) {\n logger.error(\n \"[VisionWorkerManager] Failed to update Florence2 cache:\",\n error,\n );\n }\n }\n\n private updateOCRCache(_msg: unknown): void {\n // Read OCR result from shared buffer\n try {\n const result = this.readOCRResult();\n if (result) {\n this.latestOCRResult = result;\n }\n } catch (error) {\n logger.error(\"[VisionWorkerManager] Failed to update OCR cache:\", error);\n }\n }\n\n private readFlorence2Result(tileId: string): Florence2Result | null {\n try {\n // Calculate tile index from ID\n const match = tileId.match(/tile-(\\d+)-(\\d+)/);\n if (!match) {\n return null;\n }\n\n const row = parseInt(match[1], 10);\n const col = parseInt(match[2], 10);\n const tileIndex = row * 10 + col; // Assuming max 10 columns\n\n const RESULTS_HEADER_SIZE = 16;\n const MAX_RESULT_SIZE = 4096;\n const offset = RESULTS_HEADER_SIZE + tileIndex * MAX_RESULT_SIZE;\n\n // Read length\n const length = this.florence2ResultsView.getUint32(offset, true);\n if (length === 0 || length > MAX_RESULT_SIZE - 4) {\n return null;\n }\n\n // Read JSON data\n const bytes = new Uint8Array(length);\n for (let i = 0; i < length; i++) {\n bytes[i] = this.florence2ResultsView.getUint8(offset + 4 + i);\n }\n\n const json = new TextDecoder().decode(bytes);\n return JSON.parse(json);\n } catch (error) {\n logger.error(\n \"[VisionWorkerManager] Failed to read Florence2 result:\",\n error,\n );\n return null;\n }\n }\n\n private readOCRResult(): OCRResult | null {\n try {\n const RESULTS_HEADER_SIZE = 16;\n const offset = RESULTS_HEADER_SIZE;\n\n // Read length\n const length = this.ocrResultsView.getUint32(offset, true);\n if (length === 0) {\n return null;\n }\n\n // Read frame ID and timestamp\n const _frameId = this.ocrResultsView.getUint32(offset + 4, true);\n const _timestamp = this.ocrResultsView.getFloat64(offset + 8, true);\n\n // Read JSON data\n const dataOffset = offset + 16;\n const bytes = new Uint8Array(Math.min(length, 65536));\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = this.ocrResultsView.getUint8(dataOffset + i);\n }\n\n const json = new TextDecoder().decode(bytes);\n return JSON.parse(json);\n } catch (error) {\n logger.error(\"[VisionWorkerManager] Failed to read OCR result:\", error);\n return null;\n }\n }\n\n // Public API - Non-blocking access to latest data\n\n getLatestScreenCapture(): ScreenCapture | null {\n // Read current frame metadata\n const frameId = Atomics.load(this.screenAtomicState, this.FRAME_ID_INDEX);\n\n if (frameId <= this.lastProcessedFrameId) {\n return this.latestScreenCapture;\n }\n\n try {\n const width = Atomics.load(this.screenAtomicState, this.WIDTH_INDEX);\n const height = Atomics.load(this.screenAtomicState, this.HEIGHT_INDEX);\n const _displayIndex = Atomics.load(\n this.screenAtomicState,\n this.DISPLAY_INDEX,\n );\n const timestamp = Atomics.load(\n this.screenAtomicState,\n this.TIMESTAMP_INDEX,\n );\n\n // Create screen capture object\n this.latestScreenCapture = {\n timestamp,\n width,\n height,\n data: Buffer.alloc(0), // We don't copy the full data for performance\n tiles: this.generateTiles(width, height),\n };\n\n this.lastProcessedFrameId = frameId;\n } catch (error) {\n logger.error(\n \"[VisionWorkerManager] Failed to read screen capture:\",\n error,\n );\n }\n\n return this.latestScreenCapture;\n }\n\n getLatestEnhancedScene(): EnhancedSceneDescription {\n const screenCapture = this.getLatestScreenCapture();\n\n // Combine all Florence-2 results\n const florence2Captions: string[] = [];\n const allObjects: Array<{\n label: string;\n confidence: number;\n bbox: { x: number; y: number; width: number; height: number };\n }> = [];\n const allTags = new Set<string>();\n\n this.latestFlorence2Results.forEach((result) => {\n if (result.caption) {\n florence2Captions.push(result.caption);\n }\n if (result.objects) {\n allObjects.push(...result.objects);\n }\n if (result.tags) {\n for (const tag of result.tags) {\n allTags.add(tag);\n }\n }\n });\n\n const _tiles = this.generateTiles(\n screenCapture?.width || 0,\n screenCapture?.height || 0,\n );\n\n // Map allObjects to DetectedObject format\n const mappedObjects = allObjects.map((obj, index) => ({\n id: `obj-${index}`,\n type: obj.label,\n confidence: obj.confidence,\n boundingBox: obj.bbox,\n }));\n\n return {\n timestamp: Date.now(),\n description: florence2Captions.join(\". \"),\n objects: mappedObjects,\n people: [], // Could be populated by TensorFlow worker\n sceneChanged: true,\n changePercentage: 100,\n screenCapture: this.latestScreenCapture || undefined,\n screenAnalysis: {\n fullScreenOCR: this.latestOCRResult?.fullText,\n activeTile: {\n timestamp: Date.now(),\n florence2: this.latestFlorence2Results.values().next().value,\n ocr: this.latestOCRResult || undefined,\n },\n gridSummary: `${screenCapture?.tiles.length || 0} tiles analyzed`,\n uiElements: allObjects.map((obj) => ({\n type: obj.label,\n text: \"\",\n position: obj.bbox,\n })),\n },\n };\n }\n\n private generateTiles(\n width: number,\n height: number,\n ): Array<{\n id: string;\n row: number;\n col: number;\n x: number;\n y: number;\n width: number;\n height: number;\n }> {\n const tileSize = this.config.tileSize || 256;\n const tiles: Array<{\n id: string;\n row: number;\n col: number;\n x: number;\n y: number;\n width: number;\n height: number;\n }> = [];\n\n for (let row = 0; row < Math.ceil(height / tileSize); row++) {\n for (let col = 0; col < Math.ceil(width / tileSize); col++) {\n const x = col * tileSize;\n const y = row * tileSize;\n tiles.push({\n id: `tile-${row}-${col}`,\n row,\n col,\n x,\n y,\n width: Math.min(tileSize, width - x),\n height: Math.min(tileSize, height - y),\n });\n }\n }\n\n return tiles;\n }\n\n getWorkerStats(): Map<string, WorkerStats> {\n return new Map(this.workerStats);\n }\n\n async setDisplayIndex(index: number): Promise<void> {\n if (this.screenCaptureWorker) {\n this.screenCaptureWorker.postMessage({\n type: \"set_display\",\n displayIndex: index,\n });\n }\n }\n\n async setTextRegions(\n regions: Array<{ x: number; y: number; width: number; height: number }>,\n ): Promise<void> {\n if (this.ocrWorker) {\n this.ocrWorker.postMessage({\n type: \"update_regions\",\n regions,\n });\n }\n }\n\n async stop(): Promise<void> {\n logger.info(\"[VisionWorkerManager] Stopping all workers...\");\n\n const stopPromises: Promise<void>[] = [];\n\n if (this.screenCaptureWorker) {\n stopPromises.push(\n new Promise((resolve) => {\n this.screenCaptureWorker?.once(\"exit\", () => resolve());\n this.screenCaptureWorker?.postMessage({ type: \"stop\" });\n }),\n );\n }\n\n if (this.florence2Worker) {\n stopPromises.push(\n new Promise((resolve) => {\n this.florence2Worker?.once(\"exit\", () => resolve());\n this.florence2Worker?.postMessage({ type: \"stop\" });\n }),\n );\n }\n\n if (this.ocrWorker) {\n stopPromises.push(\n new Promise((resolve) => {\n this.ocrWorker?.once(\"exit\", () => resolve());\n this.ocrWorker?.postMessage({ type: \"stop\" });\n }),\n );\n }\n\n await Promise.all(stopPromises);\n logger.info(\"[VisionWorkerManager] All workers stopped\");\n }\n\n private handleWorkerLog(\n workerName: string,\n msg: { level: string; message: string; args: unknown[] },\n ): void {\n const { level, message, args } = msg;\n const formattedMessage = `[${workerName}] ${message}`;\n const stringArgs = args.map((arg) => String(arg));\n\n switch (level) {\n case \"info\":\n logger.info(formattedMessage, ...stringArgs);\n break;\n case \"warn\":\n logger.warn(formattedMessage, ...stringArgs);\n break;\n case \"error\":\n logger.error(formattedMessage, ...stringArgs);\n break;\n case \"debug\":\n logger.debug(formattedMessage, ...stringArgs);\n break;\n }\n }\n\n private async restartScreenCaptureWorker(): Promise<void> {\n const attempts = this.restartAttempts.get(\"screenCapture\") || 0;\n\n if (attempts >= this.MAX_RESTART_ATTEMPTS) {\n logger.error(\n \"[VisionWorkerManager] Max restart attempts reached for screen capture worker\",\n );\n return;\n }\n\n this.restartAttempts.set(\"screenCapture\", attempts + 1);\n logger.info(\n `[VisionWorkerManager] Restarting screen capture worker (attempt ${attempts + 1})`,\n );\n\n try {\n // Clean up existing worker\n if (this.screenCaptureWorker) {\n this.screenCaptureWorker.removeAllListeners();\n this.screenCaptureWorker = null;\n }\n\n // Start new worker\n await this.startScreenCaptureWorker();\n\n // Reset restart counter on successful start\n this.restartAttempts.set(\"screenCapture\", 0);\n } catch (error) {\n logger.error(\n \"[VisionWorkerManager] Failed to restart screen capture worker:\",\n error,\n );\n }\n }\n\n private async restartFlorence2Worker(): Promise<void> {\n const attempts = this.restartAttempts.get(\"florence2\") || 0;\n\n if (attempts >= this.MAX_RESTART_ATTEMPTS) {\n logger.error(\n \"[VisionWorkerManager] Max restart attempts reached for Florence2 worker\",\n );\n return;\n }\n\n this.restartAttempts.set(\"florence2\", attempts + 1);\n logger.info(\n `[VisionWorkerManager] Restarting Florence2 worker (attempt ${attempts + 1})`,\n );\n\n try {\n // Clean up existing worker\n if (this.florence2Worker) {\n this.florence2Worker.removeAllListeners();\n this.florence2Worker = null;\n }\n\n // Start new worker\n await this.startFlorence2Worker();\n\n // Reset restart counter on successful start\n this.restartAttempts.set(\"florence2\", 0);\n } catch (error) {\n logger.error(\n \"[VisionWorkerManager] Failed to restart Florence2 worker:\",\n error,\n );\n }\n }\n\n private async restartOCRWorker(): Promise<void> {\n const attempts = this.restartAttempts.get(\"ocr\") || 0;\n\n if (attempts >= this.MAX_RESTART_ATTEMPTS) {\n logger.error(\n \"[VisionWorkerManager] Max restart attempts reached for OCR worker\",\n );\n return;\n }\n\n this.restartAttempts.set(\"ocr\", attempts + 1);\n logger.info(\n `[VisionWorkerManager] Restarting OCR worker (attempt ${attempts + 1})`,\n );\n\n try {\n // Clean up existing worker\n if (this.ocrWorker) {\n this.ocrWorker.removeAllListeners();\n this.ocrWorker = null;\n }\n\n // Start new worker\n await this.startOCRWorker();\n\n // Reset restart counter on successful start\n this.restartAttempts.set(\"ocr\", 0);\n } catch (error) {\n logger.error(\n \"[VisionWorkerManager] Failed to restart OCR worker:\",\n error,\n );\n }\n }\n}\n",
|
|
22
|
-
"import type { IAgentRuntime, Memory } from \"@elizaos/core\";\nimport { createUniqueUuid } from \"@elizaos/core\";\nimport { visionAction } from \"../../action\";\nimport type { VisionService } from \"../../service\";\nimport { VisionMode } from \"../../types\";\n\nexport class ScreenVisionE2ETestSuite {\n name = \"plugin-vision-screen-e2e\";\n description =\n \"E2E tests for screen vision functionality including Florence-2 and OCR\";\n\n tests = [\n {\n name: \"Should initialize screen vision components\",\n fn: async (runtime: IAgentRuntime) => {\n console.log(\"Testing screen vision initialization...\");\n\n const visionService = runtime.getService<VisionService>(\"VISION\");\n if (!visionService) {\n throw new Error(\"Vision service not available\");\n }\n\n // Set vision mode to SCREEN\n await visionService.setVisionMode(VisionMode.SCREEN);\n\n // Wait for initialization\n await new Promise((resolve) => setTimeout(resolve, 2000));\n\n const mode = visionService.getVisionMode();\n if (mode !== VisionMode.SCREEN) {\n throw new Error(`Expected vision mode SCREEN but got ${mode}`);\n }\n\n console.log(\"✓ Screen vision mode activated\");\n\n // Check if screen capture is available\n const screenInfo = await visionService.getScreenCapture();\n if (screenInfo) {\n console.log(\n `✓ Screen capture available: ${screenInfo.width}x${screenInfo.height}`,\n );\n } else {\n console.log(\n \"⚠️ Screen capture not yet available (may still be initializing)\",\n );\n }\n },\n },\n\n {\n name: \"Should capture and tile screen\",\n fn: async (runtime: IAgentRuntime) => {\n console.log(\"Testing screen capture and tiling...\");\n\n const visionService = runtime.getService<VisionService>(\"VISION\");\n if (!visionService) {\n throw new Error(\"Vision service not available\");\n }\n\n // Ensure screen mode is active\n await visionService.setVisionMode(VisionMode.SCREEN);\n\n // Wait for capture\n await new Promise((resolve) => setTimeout(resolve, 3000));\n\n const screenCapture = await visionService.getScreenCapture();\n if (!screenCapture) {\n console.warn(\n \"⚠️ No screen capture available - screen capture may not be supported in this environment\",\n );\n return;\n }\n\n console.log(\n `✓ Screen captured: ${screenCapture.width}x${screenCapture.height}`,\n );\n console.log(`✓ Divided into ${screenCapture.tiles.length} tiles`);\n\n // Check tile structure\n const firstTile = screenCapture.tiles[0];\n if (!firstTile) {\n throw new Error(\"No tiles created from screen capture\");\n }\n\n console.log(\n ` First tile: ${firstTile.id} at (${firstTile.x}, ${firstTile.y})`,\n );\n console.log(` Tile size: ${firstTile.width}x${firstTile.height}`);\n\n // Check if priority tiles have data\n const tilesWithData = screenCapture.tiles.filter(\n (t) => t.data !== undefined,\n );\n console.log(` Tiles with data: ${tilesWithData.length}`);\n\n if (tilesWithData.length === 0) {\n console.warn(\"⚠️ No tiles have been processed yet\");\n }\n },\n },\n\n {\n name: \"Should analyze screen content with Florence-2 and OCR\",\n fn: async (runtime: IAgentRuntime) => {\n console.log(\"Testing screen content analysis...\");\n\n const visionService = runtime.getService<VisionService>(\"VISION\");\n if (!visionService) {\n throw new Error(\"Vision service not available\");\n }\n\n // Ensure screen mode is active\n await visionService.setVisionMode(VisionMode.SCREEN);\n\n // Wait for analysis\n await new Promise((resolve) => setTimeout(resolve, 5000));\n\n const enhancedScene = await visionService.getEnhancedSceneDescription();\n if (!enhancedScene || !enhancedScene.screenAnalysis) {\n console.warn(\"⚠️ No enhanced scene analysis available yet\");\n return;\n }\n\n console.log(\"✓ Enhanced scene analysis available\");\n\n const screenAnalysis = enhancedScene.screenAnalysis;\n\n // Check active tile analysis\n if (screenAnalysis.activeTile) {\n console.log(\"✓ Active tile analyzed\");\n\n if (screenAnalysis.activeTile.florence2) {\n console.log(\n ` Florence-2 caption: ${screenAnalysis.activeTile.florence2.caption}`,\n );\n console.log(\n ` Objects detected: ${screenAnalysis.activeTile.florence2.objects?.length || 0}`,\n );\n console.log(\n ` Tags: ${screenAnalysis.activeTile.florence2.tags?.join(\", \") || \"none\"}`,\n );\n }\n\n if (screenAnalysis.activeTile.ocr) {\n console.log(\n ` OCR text blocks: ${screenAnalysis.activeTile.ocr.blocks.length}`,\n );\n console.log(\n ` OCR preview: \"${screenAnalysis.activeTile.ocr.fullText.substring(0, 50)}...\"`,\n );\n }\n }\n\n // Check full screen OCR\n if (screenAnalysis.fullScreenOCR) {\n console.log(\n `✓ Full screen OCR: ${screenAnalysis.fullScreenOCR.length} characters`,\n );\n }\n\n // Check UI elements\n if (screenAnalysis.uiElements && screenAnalysis.uiElements.length > 0) {\n console.log(\n `✓ UI elements detected: ${screenAnalysis.uiElements.length}`,\n );\n const elementTypes = screenAnalysis.uiElements.map((e) => e.type);\n const uniqueTypes = [...new Set(elementTypes)];\n console.log(` Types: ${uniqueTypes.join(\", \")}`);\n }\n },\n },\n\n {\n name: \"Should switch between vision modes\",\n fn: async (runtime: IAgentRuntime) => {\n console.log(\"Testing vision mode switching...\");\n\n const visionService = runtime.getService<VisionService>(\"VISION\");\n if (!visionService) {\n throw new Error(\"Vision service not available\");\n }\n\n // Test all modes\n const modes = [\n VisionMode.CAMERA,\n VisionMode.SCREEN,\n VisionMode.BOTH,\n VisionMode.OFF,\n ];\n\n for (const mode of modes) {\n console.log(` Switching to ${mode} mode...`);\n await visionService.setVisionMode(mode);\n\n // Wait for mode switch\n await new Promise((resolve) => setTimeout(resolve, 1000));\n\n const currentMode = visionService.getVisionMode();\n if (currentMode !== mode) {\n throw new Error(\n `Failed to switch to ${mode} mode, current mode is ${currentMode}`,\n );\n }\n\n console.log(` ✓ Successfully switched to ${mode} mode`);\n }\n\n // Test with action\n console.log(\" Testing VISION action with op=set_mode...\");\n\n const message: Memory = {\n id: createUniqueUuid(runtime, \"test-msg\"),\n entityId: runtime.agentId,\n content: { text: \"set vision mode to both\" },\n agentId: runtime.agentId,\n roomId: createUniqueUuid(runtime, \"test-room\"),\n createdAt: Date.now(),\n };\n\n let callbackCalled = false;\n await visionAction.handler(\n runtime,\n message,\n { values: {}, data: {}, text: \"\" },\n { parameters: { op: \"set_mode\" } },\n async (response) => {\n callbackCalled = true;\n console.log(` Action response: ${response.text}`);\n return [];\n },\n );\n\n if (!callbackCalled) {\n throw new Error(\"VISION set_mode op did not call callback\");\n }\n\n const finalMode = visionService.getVisionMode();\n if (finalMode !== VisionMode.BOTH) {\n throw new Error(\n `SET_VISION_MODE action failed, mode is ${finalMode}`,\n );\n }\n\n console.log(\"✓ Vision mode switching works correctly\");\n },\n },\n\n {\n name: \"Should provide combined vision data in BOTH mode\",\n fn: async (runtime: IAgentRuntime) => {\n console.log(\"Testing combined camera and screen vision...\");\n\n const visionService = runtime.getService<VisionService>(\"VISION\");\n if (!visionService) {\n throw new Error(\"Vision service not available\");\n }\n\n // Set to BOTH mode\n await visionService.setVisionMode(VisionMode.BOTH);\n\n // Wait for both systems to initialize\n await new Promise((resolve) => setTimeout(resolve, 5000));\n\n const enhancedScene = await visionService.getEnhancedSceneDescription();\n const hasCamera = visionService.getCameraInfo() !== null;\n const hasScreen = (await visionService.getScreenCapture()) !== null;\n\n console.log(` Camera available: ${hasCamera}`);\n console.log(` Screen capture available: ${hasScreen}`);\n\n if (!hasCamera && !hasScreen) {\n console.warn(\n \"⚠️ Neither camera nor screen capture available in this environment\",\n );\n return;\n }\n\n if (enhancedScene) {\n // Check for camera data\n if (hasCamera && enhancedScene.description) {\n console.log(\"✓ Camera data present in combined mode\");\n console.log(\n ` Scene: ${enhancedScene.description.substring(0, 50)}...`,\n );\n }\n\n // Check for screen data\n if (hasScreen && enhancedScene.screenAnalysis) {\n console.log(\"✓ Screen data present in combined mode\");\n console.log(` Grid: ${enhancedScene.screenAnalysis.gridSummary}`);\n }\n }\n\n // Check provider output\n const state = await runtime.composeState({\n id: createUniqueUuid(runtime, \"test-msg\"),\n entityId: runtime.agentId,\n content: { text: \"test\" },\n agentId: runtime.agentId,\n roomId: createUniqueUuid(runtime, \"test-room\"),\n createdAt: Date.now(),\n });\n\n if (state.text.includes(\"Vision mode: BOTH\")) {\n console.log(\"✓ Provider correctly reports BOTH mode\");\n }\n },\n },\n\n {\n name: \"Should handle screen capture errors gracefully\",\n fn: async (runtime: IAgentRuntime) => {\n console.log(\"Testing error handling...\");\n\n const visionService = runtime.getService<VisionService>(\"VISION\");\n if (!visionService) {\n throw new Error(\"Vision service not available\");\n }\n\n // Try to set invalid region (should handle gracefully)\n // Access private property for testing purposes\n type TestVisionConfig = {\n screenRegion?: {\n x: number;\n y: number;\n width: number;\n height: number;\n };\n };\n const originalConfig = Reflect.get(\n visionService,\n \"visionConfig\",\n ) as TestVisionConfig;\n const invalidConfig: TestVisionConfig = {\n ...originalConfig,\n screenRegion: {\n x: -100,\n y: -100,\n width: 50000,\n height: 50000,\n },\n };\n Reflect.set(visionService, \"visionConfig\", invalidConfig);\n\n await visionService.setVisionMode(VisionMode.SCREEN);\n await new Promise((resolve) => setTimeout(resolve, 2000));\n\n // Service should still be active despite invalid region\n const isActive = visionService.isActive();\n console.log(` Service active after invalid config: ${isActive}`);\n\n // Restore config\n Reflect.set(visionService, \"visionConfig\", originalConfig);\n\n console.log(\"✓ Error handling works correctly\");\n },\n },\n ];\n}\n\nexport default new ScreenVisionE2ETestSuite();\n",
|
|
23
|
-
"import type {\n Content,\n IAgentRuntime,\n Memory,\n ServiceTypeName,\n State,\n} from \"@elizaos/core\";\nimport { createUniqueUuid } from \"@elizaos/core\";\nimport { visionAction } from \"../../action\";\nimport type { VisionService } from \"../../service\";\n\nexport class VisionBasicE2ETestSuite {\n name = \"plugin-vision-basic-e2e\";\n description = \"Basic end-to-end tests for vision plugin functionality\";\n\n tests = [\n {\n name: \"Should initialize vision service\",\n fn: async (runtime: IAgentRuntime) => {\n console.log(\"Testing vision service initialization...\");\n\n const visionService = runtime.getService<VisionService>(\n \"VISION\" as ServiceTypeName,\n );\n if (!visionService) {\n throw new Error(\n \"Vision service not available - service must be registered\",\n );\n }\n\n // Check if service is active\n const isActive = visionService.isActive();\n\n // Get camera info\n const cameraInfo = visionService.getCameraInfo();\n\n if (!isActive || !cameraInfo) {\n // For CI/CD environments without cameras, check that service at least initializes\n console.warn(\n \"⚠️ No camera detected. Service initialized but not active.\",\n );\n console.log(\n \" This is acceptable in CI/CD environments without cameras.\",\n );\n } else {\n console.log(\"✓ Vision service initialized and active\");\n console.log(\n `✓ Connected to camera: ${cameraInfo.name} (ID: ${cameraInfo.id})`,\n );\n }\n },\n },\n\n {\n name: \"Should describe scene when requested\",\n fn: async (runtime: IAgentRuntime) => {\n console.log(\"Testing scene description action...\");\n\n const roomId = createUniqueUuid(runtime, \"test-room\");\n const message: Memory = {\n id: createUniqueUuid(runtime, \"test-msg-describe\"),\n entityId: runtime.agentId,\n content: { text: \"what do you see?\" },\n agentId: runtime.agentId,\n roomId,\n createdAt: Date.now(),\n };\n\n let callbackCalled = false;\n let callbackResponse: Content | null = null;\n\n const state: State = { values: {}, data: {}, text: \"\" };\n\n // Get vision service to check if active\n const visionService = runtime.getService<VisionService>(\n \"VISION\" as ServiceTypeName,\n );\n\n // Validate the action\n const isValid = await visionAction.validate(runtime, message, state);\n\n if (!visionService || !visionService.isActive()) {\n // If vision service is not active, validation should return false\n if (isValid) {\n throw new Error(\n \"Action validation should return false when vision service is not active\",\n );\n }\n console.log(\n \" Action validation correctly returned false (vision not active)\",\n );\n\n // But handler should still work and provide appropriate message\n await visionAction.handler(\n runtime,\n message,\n state,\n { parameters: { op: \"describe\" } },\n async (response) => {\n callbackCalled = true;\n callbackResponse = response;\n return [];\n },\n );\n\n if (!callbackCalled) {\n throw new Error(\"Callback was not called - action handler failed\");\n }\n\n if (!callbackResponse || !callbackResponse.text) {\n throw new Error(\"No response text returned from action\");\n }\n\n console.log(\n \"✓ Scene description action handled unavailability correctly\",\n );\n console.log(` Response: ${callbackResponse.text}`);\n\n // Verify it indicates camera not available\n if (\n !callbackResponse.text.includes(\"cannot see\") &&\n !callbackResponse.text.includes(\"no camera\")\n ) {\n throw new Error(\"Response does not indicate camera unavailability\");\n }\n } else {\n // Vision is active, normal test flow\n if (!isValid) {\n throw new Error(\n \"visionAction validation failed despite active vision\",\n );\n }\n console.log(\" Action validation: passed\");\n\n await visionAction.handler(\n runtime,\n message,\n state,\n { parameters: { op: \"describe\" } },\n async (response) => {\n callbackCalled = true;\n callbackResponse = response;\n return [];\n },\n );\n\n if (!callbackCalled) {\n throw new Error(\"Callback was not called - action handler failed\");\n }\n\n if (!callbackResponse || !callbackResponse.text) {\n throw new Error(\"No response text returned from action\");\n }\n\n console.log(\"✓ Scene description action executed\");\n console.log(` Response: ${callbackResponse.text}`);\n if (callbackResponse.thought) {\n console.log(` Thought: ${callbackResponse.thought}`);\n }\n }\n\n // Verify response contains expected action\n if (\n !callbackResponse.actions ||\n !callbackResponse.actions.includes(\"VISION\")\n ) {\n throw new Error(\"Response does not include VISION action\");\n }\n },\n },\n\n {\n name: \"Should capture image when requested\",\n fn: async (runtime: IAgentRuntime) => {\n console.log(\"Testing image capture action...\");\n\n const roomId = createUniqueUuid(runtime, \"test-room\");\n const message: Memory = {\n id: createUniqueUuid(runtime, \"test-msg-capture\"),\n entityId: runtime.agentId,\n content: { text: \"take a photo\" },\n agentId: runtime.agentId,\n roomId,\n createdAt: Date.now(),\n };\n\n let callbackCalled = false;\n let callbackResponse: Content | null = null;\n\n const state: State = { values: {}, data: {}, text: \"\" };\n\n // Get vision service to check if active\n const visionService = runtime.getService<VisionService>(\n \"VISION\" as ServiceTypeName,\n );\n\n // Validate the action\n const isValid = await visionAction.validate(runtime, message, state);\n\n if (!visionService || !visionService.isActive()) {\n // If vision service is not active, validation should return false\n if (isValid) {\n throw new Error(\n \"Action validation should return false when vision service is not active\",\n );\n }\n console.log(\n \" Action validation correctly returned false (vision not active)\",\n );\n\n // But handler should still work and provide appropriate message\n await visionAction.handler(\n runtime,\n message,\n state,\n { parameters: { op: \"capture\" } },\n async (response) => {\n callbackCalled = true;\n callbackResponse = response;\n return [];\n },\n );\n\n if (!callbackCalled) {\n throw new Error(\"Callback was not called - action handler failed\");\n }\n\n if (!callbackResponse || !callbackResponse.text) {\n throw new Error(\"No response text returned from action\");\n }\n\n console.log(\n \"✓ Image capture action handled unavailability correctly\",\n );\n console.log(` Response: ${callbackResponse.text}`);\n\n // Verify it indicates camera not available\n if (\n !callbackResponse.text.includes(\"cannot capture\") &&\n !callbackResponse.text.includes(\"no camera\")\n ) {\n throw new Error(\"Response does not indicate camera unavailability\");\n }\n } else {\n // Vision is active, normal test flow\n if (!isValid) {\n throw new Error(\n \"visionAction validation failed despite active vision\",\n );\n }\n console.log(\" Action validation: passed\");\n\n await visionAction.handler(\n runtime,\n message,\n state,\n { parameters: { op: \"capture\" } },\n async (response) => {\n callbackCalled = true;\n callbackResponse = response;\n return [];\n },\n );\n\n if (!callbackCalled) {\n throw new Error(\"Callback was not called - action handler failed\");\n }\n\n if (!callbackResponse || !callbackResponse.text) {\n throw new Error(\"No response text returned from action\");\n }\n\n console.log(\"✓ Image capture action executed\");\n console.log(` Response: ${callbackResponse.text}`);\n\n // If camera is active, we should have an attachment\n if (\n !callbackResponse.attachments ||\n callbackResponse.attachments.length === 0\n ) {\n throw new Error(\n \"No image attachment returned despite active camera\",\n );\n }\n\n const attachment = callbackResponse.attachments[0];\n if (!attachment.url || !attachment.url.startsWith(\"data:image/\")) {\n throw new Error(\"Invalid image attachment format\");\n }\n\n console.log(` ✓ Image attachment valid: ${attachment.title}`);\n }\n\n // Verify response contains expected action\n if (\n !callbackResponse.actions ||\n !callbackResponse.actions.includes(\"VISION\")\n ) {\n throw new Error(\"Response does not include VISION action\");\n }\n },\n },\n\n {\n name: \"Should provide vision context through provider\",\n fn: async (runtime: IAgentRuntime) => {\n console.log(\"Testing vision provider...\");\n\n // Compose state to trigger providers\n const message: Memory = {\n id: createUniqueUuid(runtime, \"test-msg-provider\"),\n entityId: runtime.agentId,\n content: { text: \"test provider\" },\n agentId: runtime.agentId,\n roomId: createUniqueUuid(runtime, \"test-room\"),\n createdAt: Date.now(),\n };\n\n const state = await runtime.composeState(message);\n\n // Vision provider should always add data\n if (state.values.visionAvailable === undefined) {\n throw new Error(\n \"Vision provider data missing - provider not registered or failed\",\n );\n }\n\n console.log(\"✓ Vision provider data found in state\");\n console.log(` Vision available: ${state.values.visionAvailable}`);\n console.log(` Camera status: ${state.values.cameraStatus}`);\n\n // Verify vision context in formatted text\n if (!state.text.includes(\"Visual Perception\")) {\n throw new Error(\"Vision context not included in state text\");\n }\n console.log(\"✓ Vision context included in state text\");\n\n // If vision is available, verify scene data\n if (state.values.visionAvailable && state.values.sceneDescription) {\n console.log(` Scene description: ${state.values.sceneDescription}`);\n }\n },\n },\n\n {\n name: \"Should handle scene changes efficiently\",\n fn: async (runtime: IAgentRuntime) => {\n console.log(\"Testing scene change detection...\");\n\n const visionService = runtime.getService<VisionService>(\n \"VISION\" as ServiceTypeName,\n );\n if (!visionService) {\n throw new Error(\"Vision service not available\");\n }\n\n if (!visionService.isActive()) {\n console.warn(\n \"⚠️ Vision service not active - skipping scene change test\",\n );\n console.log(\" This is acceptable in environments without cameras\");\n return;\n }\n\n // Get initial scene description\n const initialScene = await visionService.getSceneDescription();\n console.log(\n ` Initial scene: ${initialScene ? \"Available\" : \"Pending...\"}`,\n );\n\n // Wait for scene processing\n await new Promise((resolve) => setTimeout(resolve, 2000));\n\n // Get updated scene description\n const updatedScene = await visionService.getSceneDescription();\n\n if (!updatedScene) {\n throw new Error(\"No scene description available after 2 seconds\");\n }\n\n console.log(\"✓ Scene monitoring active\");\n console.log(\n ` Scene timestamp: ${new Date(updatedScene.timestamp).toISOString()}`,\n );\n console.log(\n ` Description: ${updatedScene.description.substring(0, 100)}...`,\n );\n\n if (updatedScene.changePercentage !== undefined) {\n console.log(\n ` Last change: ${updatedScene.changePercentage.toFixed(1)}%`,\n );\n }\n },\n },\n\n {\n name: \"Should detect objects and people in scene\",\n fn: async (runtime: IAgentRuntime) => {\n console.log(\"Testing object and person detection...\");\n\n const visionService = runtime.getService<VisionService>(\n \"VISION\" as ServiceTypeName,\n );\n if (!visionService) {\n throw new Error(\"Vision service not available\");\n }\n\n if (!visionService.isActive()) {\n console.warn(\n \"⚠️ Vision service not active - skipping detection test\",\n );\n console.log(\" This is acceptable in environments without cameras\");\n return;\n }\n\n // Wait for scene processing to accumulate frames\n console.log(\" Waiting for scene analysis...\");\n await new Promise((resolve) => setTimeout(resolve, 3000));\n\n // Get scene description\n const scene = await visionService.getSceneDescription();\n\n if (!scene) {\n throw new Error(\"No scene description available after 3 seconds\");\n }\n\n console.log(\"✓ Scene analysis complete\");\n console.log(` Description: ${scene.description.substring(0, 100)}...`);\n console.log(` Objects detected: ${scene.objects.length}`);\n console.log(` People detected: ${scene.people.length}`);\n\n // Verify object detection\n if (scene.objects.length > 0) {\n console.log(\" Detected objects:\");\n const objectTypes = scene.objects.reduce(\n (acc, obj) => {\n acc[obj.type] = (acc[obj.type] || 0) + 1;\n return acc;\n },\n {} as Record<string, number>,\n );\n\n for (const [type, count] of Object.entries(objectTypes)) {\n console.log(` - ${count} ${type}(s)`);\n }\n\n // Verify objects have required fields\n for (const obj of scene.objects) {\n if (\n !obj.id ||\n !obj.type ||\n obj.confidence === undefined ||\n !obj.boundingBox\n ) {\n throw new Error(\"Detected object missing required fields\");\n }\n }\n }\n\n // Verify person detection\n if (scene.people.length > 0) {\n console.log(\" Detected people:\");\n for (const person of scene.people) {\n console.log(\n ` - Person ${person.id}: ${person.pose} pose, facing ${person.facing}, confidence ${person.confidence.toFixed(2)}`,\n );\n\n // Verify person has required fields\n if (\n !person.id ||\n !person.pose ||\n !person.facing ||\n person.confidence === undefined ||\n !person.boundingBox\n ) {\n throw new Error(\"Detected person missing required fields\");\n }\n }\n }\n\n // If there's motion, we should detect something\n if (scene.changePercentage > 10) {\n console.log(` Scene change: ${scene.changePercentage.toFixed(1)}%`);\n if (scene.objects.length === 0 && scene.people.length === 0) {\n console.warn(\n \" ⚠️ Significant scene change but no objects/people detected\",\n );\n console.log(\n \" This might indicate the motion detection threshold needs adjustment\",\n );\n }\n }\n },\n },\n ];\n}\n\nexport default new VisionBasicE2ETestSuite();\n",
|
|
24
|
-
"import * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport type { IAgentRuntime } from \"@elizaos/core\";\nimport type { VisionService } from \"../../service\";\n\n/** A single vision capture entry (success or error) */\ninterface VisionCaptureEntry {\n index: number;\n timestamp: string;\n timestampMs?: number;\n elapsedMs?: number;\n scene?: {\n description: string;\n changePercentage: number;\n sceneChanged: boolean;\n objectCount: number;\n peopleCount: number;\n objects: { type: string }[];\n people: { pose: string }[];\n } | null;\n frame?: {\n width: number;\n height: number;\n format: string;\n timestamp: number;\n } | null;\n imageBase64?: string | null;\n error?: string;\n}\n\nexport class VisionCaptureLogTestSuite {\n name = \"plugin-vision-capture-log\";\n description =\n \"Captures 30 seconds of vision data and saves to logs for analysis\";\n\n tests = [\n {\n name: \"Should capture and log 30 seconds of vision data\",\n fn: async (runtime: IAgentRuntime) => {\n console.log(\"Starting 30-second vision capture test...\");\n\n const visionService = runtime.getService<VisionService>(\"VISION\");\n if (!visionService) {\n throw new Error(\"Vision service not available\");\n }\n\n if (!visionService.isActive()) {\n console.warn(\"⚠️ Vision service not active - no camera available\");\n console.log(\" Cannot capture vision data without a camera\");\n return;\n }\n\n // Create logs directory if it doesn't exist\n const logsDir = path.join(process.cwd(), \"logs\");\n const sessionDir = path.join(\n logsDir,\n `vision-capture-${new Date().toISOString().replace(/[:.]/g, \"-\")}`,\n );\n await fs.mkdir(sessionDir, { recursive: true });\n\n console.log(`✓ Created log directory: ${sessionDir}`);\n\n // Initialize capture data\n const captureData = {\n sessionId: `vision-capture-${Date.now()}`,\n startTime: new Date().toISOString(),\n endTime: \"\",\n runtime: {\n agentId: runtime.agentId,\n characterName: runtime.character.name,\n },\n camera: visionService.getCameraInfo(),\n captures: [] as VisionCaptureEntry[],\n statistics: {\n totalFrames: 0,\n totalSceneChanges: 0,\n totalObjectsDetected: 0,\n totalPeopleDetected: 0,\n averageChangePercentage: 0,\n objectTypeCounts: {} as Record<string, number>,\n poseCounts: {} as Record<string, number>,\n },\n };\n\n // Capture interval - every 500ms for 30 seconds = 60 captures\n const captureInterval = 500;\n const totalDuration = 30000;\n const expectedCaptures = totalDuration / captureInterval;\n\n console.log(\n `📸 Capturing vision data every ${captureInterval}ms for ${totalDuration / 1000} seconds...`,\n );\n console.log(` Expected captures: ${expectedCaptures}`);\n\n let captureCount = 0;\n let totalChangePercentage = 0;\n let lastLoggedProgress = 0;\n\n const startTime = Date.now();\n\n while (Date.now() - startTime < totalDuration) {\n const captureStartTime = Date.now();\n\n try {\n // Get current scene description\n const scene = await visionService.getSceneDescription();\n const frame = await visionService.getCurrentFrame();\n\n // Capture image as base64\n const imageBuffer = await visionService.captureImage();\n let imageBase64: string | null = null;\n if (imageBuffer) {\n imageBase64 = imageBuffer.toString(\"base64\");\n }\n\n const capture = {\n index: captureCount,\n timestamp: new Date().toISOString(),\n timestampMs: Date.now(),\n elapsedMs: Date.now() - startTime,\n scene: scene\n ? {\n description: scene.description,\n changePercentage: scene.changePercentage,\n sceneChanged: scene.sceneChanged,\n objectCount: scene.objects.length,\n peopleCount: scene.people.length,\n objects: scene.objects,\n people: scene.people,\n }\n : null,\n frame: frame\n ? {\n width: frame.width,\n height: frame.height,\n format: frame.format,\n timestamp: frame.timestamp,\n }\n : null,\n imageBase64: imageBase64 ?? null,\n };\n\n captureData.captures.push(capture);\n\n // Save full image separately\n if (imageBase64) {\n const imagePath = path.join(\n sessionDir,\n `capture-${String(captureCount).padStart(3, \"0\")}.jpg`,\n );\n await fs.writeFile(imagePath, Buffer.from(imageBase64, \"base64\"));\n }\n\n // Update statistics\n if (scene) {\n captureData.statistics.totalFrames++;\n if (scene.sceneChanged) {\n captureData.statistics.totalSceneChanges++;\n }\n if (scene.changePercentage) {\n totalChangePercentage += scene.changePercentage;\n }\n captureData.statistics.totalObjectsDetected +=\n scene.objects.length;\n captureData.statistics.totalPeopleDetected += scene.people.length;\n\n // Count object types\n for (const obj of scene.objects) {\n captureData.statistics.objectTypeCounts[obj.type] =\n (captureData.statistics.objectTypeCounts[obj.type] || 0) + 1;\n }\n\n // Count poses\n for (const person of scene.people) {\n captureData.statistics.poseCounts[person.pose] =\n (captureData.statistics.poseCounts[person.pose] || 0) + 1;\n }\n\n // Save detailed scene log\n const sceneLogPath = path.join(\n sessionDir,\n `scene-${String(captureCount).padStart(3, \"0\")}.json`,\n );\n await fs.writeFile(\n sceneLogPath,\n JSON.stringify(\n {\n capture: captureCount,\n timestamp: capture.timestamp,\n scene,\n frame: frame\n ? {\n width: frame.width,\n height: frame.height,\n format: frame.format,\n }\n : null,\n },\n null,\n 2,\n ),\n );\n }\n\n captureCount++;\n\n // Progress logging every 5 seconds\n const elapsedSeconds = Math.floor((Date.now() - startTime) / 1000);\n if (\n elapsedSeconds > lastLoggedProgress &&\n elapsedSeconds % 5 === 0\n ) {\n lastLoggedProgress = elapsedSeconds;\n const progress = (elapsedSeconds / 30) * 100;\n console.log(\n ` Progress: ${progress.toFixed(0)}% (${elapsedSeconds}/30s) - Captured ${captureCount} frames`,\n );\n\n if (scene) {\n console.log(\n ` Last scene: \"${scene.description.substring(0, 60)}...\"`,\n );\n if (scene.objects.length > 0 || scene.people.length > 0) {\n console.log(\n ` Detected: ${scene.objects.length} objects, ${scene.people.length} people`,\n );\n }\n }\n }\n } catch (error) {\n console.error(` Error in capture ${captureCount}:`, error);\n captureData.captures.push({\n index: captureCount,\n timestamp: new Date().toISOString(),\n error: error instanceof Error ? error.message : String(error),\n });\n captureCount++;\n }\n\n // Wait for next capture interval\n const captureEndTime = Date.now();\n const captureDuration = captureEndTime - captureStartTime;\n const waitTime = Math.max(0, captureInterval - captureDuration);\n\n if (waitTime > 0) {\n await new Promise((resolve) => setTimeout(resolve, waitTime));\n }\n }\n\n // Finalize statistics\n captureData.endTime = new Date().toISOString();\n captureData.statistics.averageChangePercentage =\n captureData.statistics.totalFrames > 0\n ? totalChangePercentage / captureData.statistics.totalFrames\n : 0;\n\n // Save main capture log\n const mainLogPath = path.join(\n sessionDir,\n \"vision-capture-summary.json\",\n );\n await fs.writeFile(mainLogPath, JSON.stringify(captureData, null, 2));\n\n // Generate markdown report\n const reportPath = path.join(sessionDir, \"vision-capture-report.md\");\n const report = `# Vision Capture Report\n\n## Session Information\n- **Session ID**: ${captureData.sessionId}\n- **Start Time**: ${captureData.startTime}\n- **End Time**: ${captureData.endTime}\n- **Duration**: 30 seconds\n- **Agent**: ${captureData.runtime.characterName} (${captureData.runtime.agentId})\n\n## Camera Information\n- **Name**: ${captureData.camera?.name || \"Unknown\"}\n- **ID**: ${captureData.camera?.id || \"Unknown\"}\n\n## Capture Statistics\n- **Total Frames Captured**: ${captureCount}\n- **Total Scene Changes**: ${captureData.statistics.totalSceneChanges}\n- **Average Change Percentage**: ${captureData.statistics.averageChangePercentage.toFixed(2)}%\n- **Total Objects Detected**: ${captureData.statistics.totalObjectsDetected}\n- **Total People Detected**: ${captureData.statistics.totalPeopleDetected}\n\n## Object Type Distribution\n${\n Object.entries(captureData.statistics.objectTypeCounts)\n .sort(([, a], [, b]) => b - a)\n .map(([type, count]) => `- **${type}**: ${count} detections`)\n .join(\"\\n\") || \"- No objects detected\"\n}\n\n## Pose Distribution\n${\n Object.entries(captureData.statistics.poseCounts)\n .map(([pose, count]) => `- **${pose}**: ${count} detections`)\n .join(\"\\n\") || \"- No people detected\"\n}\n\n## Sample Scene Descriptions\n${captureData.captures\n .filter((c) => c.scene?.description)\n .slice(0, 5)\n .map(\n (c, _i) => `### Capture ${c.index} (${c.elapsedMs ?? 0}ms)\n\"${c.scene?.description ?? \"\"}\"\n- Change: ${c.scene?.changePercentage?.toFixed(1) ?? \"0\"}%\n- Objects: ${c.scene?.objectCount ?? 0}\n- People: ${c.scene?.peopleCount ?? 0}`,\n )\n .join(\"\\n\\n\")}\n\n## Files Generated\n- \\`vision-capture-summary.json\\` - Complete capture data\n- \\`vision-capture-report.md\\` - This report\n- \\`capture-XXX.jpg\\` - Individual captured images\n- \\`scene-XXX.json\\` - Detailed scene data for each capture\n`;\n\n await fs.writeFile(reportPath, report);\n\n console.log(\"\\n✅ Vision capture test completed!\");\n console.log(\"📊 Capture Summary:\");\n console.log(` - Total frames: ${captureCount}`);\n console.log(\n ` - Scene changes: ${captureData.statistics.totalSceneChanges}`,\n );\n console.log(\n ` - Average change: ${captureData.statistics.averageChangePercentage.toFixed(2)}%`,\n );\n console.log(\n ` - Objects detected: ${captureData.statistics.totalObjectsDetected}`,\n );\n console.log(\n ` - People detected: ${captureData.statistics.totalPeopleDetected}`,\n );\n console.log(`\\n📁 Results saved to: ${sessionDir}`);\n console.log(\" - Summary: vision-capture-summary.json\");\n console.log(\" - Report: vision-capture-report.md\");\n console.log(\" - Images: capture-XXX.jpg\");\n console.log(\" - Scene data: scene-XXX.json\");\n\n console.log(\"✅ Vision capture log test PASSED\");\n },\n },\n ];\n}\n\nexport default new VisionCaptureLogTestSuite();\n",
|
|
25
|
-
"import type { Action, Content, IAgentRuntime, Provider } from \"@elizaos/core\";\nimport { logger } from \"@elizaos/core\";\nimport type { VisionService } from \"../../service\";\nimport { VisionMode, VisionServiceType } from \"../../types\";\n\nexport class VisionRuntimeTestSuite {\n name = \"vision-runtime-tests\";\n description = \"Real runtime tests for vision plugin functionality\";\n\n tests = [\n {\n name: \"Vision service initialization\",\n fn: async (runtime: IAgentRuntime) => {\n logger.info(\"[Test] Testing vision service initialization...\");\n\n const visionService = runtime.getService<VisionService>(\n VisionServiceType.VISION,\n );\n if (!visionService) {\n throw new Error(\"Vision service not found in runtime\");\n }\n\n // Check if service is properly initialized\n if (typeof visionService.isActive !== \"function\") {\n throw new Error(\"Vision service missing isActive method\");\n }\n\n const isActive = visionService.isActive();\n logger.info(`[Test] Vision service active: ${isActive}`);\n\n // Service should be active after initialization\n if (!isActive && runtime.getSetting(\"VISION_MODE\") !== VisionMode.OFF) {\n throw new Error(\"Vision service should be active but is not\");\n }\n\n logger.info(\"[Test] ✅ Vision service initialization test passed\");\n },\n },\n\n {\n name: \"Scene description functionality\",\n fn: async (runtime: IAgentRuntime) => {\n logger.info(\"[Test] Testing scene description...\");\n\n const visionService = runtime.getService<VisionService>(\n VisionServiceType.VISION,\n );\n if (!visionService) {\n throw new Error(\"Vision service not found\");\n }\n\n // Get current scene description\n const scene = await visionService.getSceneDescription();\n\n if (!scene) {\n logger.warn(\n \"[Test] No scene description available (camera might not be connected)\",\n );\n return; // Don't fail if no camera\n }\n\n // Validate scene structure\n if (typeof scene.timestamp !== \"number\") {\n throw new Error(\"Scene description missing timestamp\");\n }\n\n if (typeof scene.description !== \"string\") {\n throw new Error(\"Scene description missing description text\");\n }\n\n if (!Array.isArray(scene.objects)) {\n throw new Error(\"Scene description missing objects array\");\n }\n\n if (!Array.isArray(scene.people)) {\n throw new Error(\"Scene description missing people array\");\n }\n\n logger.info(`[Test] Scene: ${scene.description.substring(0, 100)}...`);\n logger.info(\n `[Test] Objects: ${scene.objects.length}, People: ${scene.people.length}`,\n );\n logger.info(\"[Test] ✅ Scene description test passed\");\n },\n },\n\n {\n name: \"Vision mode switching\",\n fn: async (runtime: IAgentRuntime) => {\n logger.info(\"[Test] Testing vision mode switching...\");\n\n const visionService = runtime.getService<VisionService>(\n VisionServiceType.VISION,\n );\n if (!visionService) {\n throw new Error(\"Vision service not found\");\n }\n\n // Get current mode\n const originalMode = visionService.getVisionMode();\n logger.info(`[Test] Original mode: ${originalMode}`);\n\n // Test switching modes\n const testModes: VisionMode[] = [\n VisionMode.CAMERA,\n VisionMode.SCREEN,\n VisionMode.BOTH,\n VisionMode.OFF,\n ];\n\n for (const mode of testModes) {\n logger.info(`[Test] Switching to mode: ${mode}`);\n await visionService.setVisionMode(mode);\n\n const currentMode = visionService.getVisionMode();\n if (currentMode !== mode) {\n throw new Error(\n `Failed to switch to mode ${mode}, current mode is ${currentMode}`,\n );\n }\n }\n\n // Restore original mode\n await visionService.setVisionMode(originalMode);\n logger.info(\"[Test] ✅ Vision mode switching test passed\");\n },\n },\n\n {\n name: \"VISION action describe op execution\",\n fn: async (runtime: IAgentRuntime) => {\n logger.info(\"[Test] Testing VISION action with op=describe...\");\n\n // Find the action\n const action = (runtime.actions as Action[]).find(\n (a) => a.name === \"VISION\",\n );\n if (!action) {\n throw new Error(\"VISION action not found\");\n }\n\n // Create test message\n const message = {\n id: `test-msg-${Date.now()}`,\n entityId: \"test-entity\",\n roomId: \"test-room\",\n content: {\n text: \"Describe what you see\",\n source: \"test\",\n },\n createdAt: Date.now(),\n };\n\n // Validate action\n const isValid = await action.validate(runtime, message);\n if (!isValid) {\n throw new Error(\"VISION action validation failed\");\n }\n\n // Execute action\n let responseReceived = false;\n const callback = async (response: Content) => {\n if (response.text && response.text.length > 0) {\n responseReceived = true;\n logger.info(\n `[Test] Action response: ${response.text.substring(0, 100)}...`,\n );\n }\n return [];\n };\n\n await action.handler(\n runtime,\n message,\n { values: {}, data: {}, text: \"\" },\n { parameters: { op: \"describe\" } },\n callback,\n );\n\n if (!responseReceived) {\n throw new Error(\n \"VISION action with op=describe did not produce a response\",\n );\n }\n\n logger.info(\"[Test] ✅ VISION action describe op test passed\");\n },\n },\n\n {\n name: \"Vision provider integration\",\n fn: async (runtime: IAgentRuntime) => {\n logger.info(\"[Test] Testing vision provider...\");\n\n // Find the vision provider\n const provider = (runtime.providers as Provider[]).find(\n (p) => p.name === \"visionProvider\",\n );\n if (!provider) {\n throw new Error(\"Vision provider not found\");\n }\n\n // Create test message and state\n const message = {\n id: `test-msg-${Date.now()}`,\n entityId: \"test-entity\",\n roomId: \"test-room\",\n content: { text: \"test\", source: \"test\" },\n createdAt: Date.now(),\n };\n\n const state = {\n values: {},\n data: {},\n text: \"\",\n };\n\n // Get provider data\n const result = await provider.get(runtime, message, state);\n\n if (!result || typeof result !== \"object\") {\n throw new Error(\"Vision provider returned invalid result\");\n }\n\n // Check if provider returns vision data when available\n if (result.text?.includes(\"I can see\")) {\n logger.info(\n `[Test] Provider text: ${result.text.substring(0, 100)}...`,\n );\n }\n\n logger.info(\"[Test] ✅ Vision provider test passed\");\n },\n },\n\n {\n name: \"Florence-2 model initialization\",\n fn: async (runtime: IAgentRuntime) => {\n logger.info(\"[Test] Testing Florence-2 model...\");\n\n const visionService = runtime.getService<VisionService>(\n VisionServiceType.VISION,\n );\n if (!visionService) {\n throw new Error(\"Vision service not found\");\n }\n\n // Check if Florence-2 is enabled\n const florence2Enabled =\n runtime.getSetting(\"FLORENCE2_ENABLED\") === \"true\" ||\n runtime.getSetting(\"VISION_FLORENCE2_ENABLED\") === \"true\";\n\n if (!florence2Enabled) {\n logger.info(\"[Test] Florence-2 is disabled, skipping test\");\n return;\n }\n\n // If screen mode is enabled, Florence-2 should be initialized\n const mode = visionService.getVisionMode();\n if (mode === VisionMode.SCREEN || mode === VisionMode.BOTH) {\n // Try to get screen capture\n const screenCapture = await visionService.getScreenCapture();\n if (screenCapture) {\n logger.info(\"[Test] Screen capture available\");\n logger.info(\n `[Test] Screen size: ${screenCapture.width}x${screenCapture.height}`,\n );\n logger.info(`[Test] Tiles: ${screenCapture.tiles.length}`);\n }\n }\n\n logger.info(\"[Test] ✅ Florence-2 model test passed\");\n },\n },\n\n {\n name: \"OCR service functionality\",\n fn: async (runtime: IAgentRuntime) => {\n logger.info(\"[Test] Testing OCR service...\");\n\n const visionService = runtime.getService<VisionService>(\n VisionServiceType.VISION,\n );\n if (!visionService) {\n throw new Error(\"Vision service not found\");\n }\n\n // Check if OCR is enabled\n const ocrEnabled =\n runtime.getSetting(\"OCR_ENABLED\") === \"true\" ||\n runtime.getSetting(\"VISION_OCR_ENABLED\") === \"true\";\n\n if (!ocrEnabled) {\n logger.info(\"[Test] OCR is disabled, skipping test\");\n return;\n }\n\n // If screen mode is enabled, OCR should work\n const mode = visionService.getVisionMode();\n if (mode === VisionMode.SCREEN || mode === VisionMode.BOTH) {\n const enhancedScene =\n await visionService.getEnhancedSceneDescription();\n if (enhancedScene?.screenAnalysis) {\n const ocrText = enhancedScene.screenAnalysis.fullScreenOCR;\n if (ocrText) {\n logger.info(`[Test] OCR extracted ${ocrText.length} characters`);\n logger.info(`[Test] OCR sample: ${ocrText.substring(0, 100)}...`);\n }\n }\n }\n\n logger.info(\"[Test] ✅ OCR service test passed\");\n },\n },\n\n {\n name: \"Entity tracking system\",\n fn: async (runtime: IAgentRuntime) => {\n logger.info(\"[Test] Testing entity tracking...\");\n\n const visionService = runtime.getService<VisionService>(\n VisionServiceType.VISION,\n );\n if (!visionService) {\n throw new Error(\"Vision service not found\");\n }\n\n // Get entity tracker\n const entityTracker = visionService.getEntityTracker();\n if (!entityTracker) {\n throw new Error(\"Entity tracker not found\");\n }\n\n // Get current entities\n const entities = entityTracker.getActiveEntities();\n logger.info(`[Test] Active entities: ${entities.length}`);\n\n // Check entity structure if any exist\n for (const entity of entities) {\n if (!entity.id || !entity.entityType || !entity.lastSeen) {\n throw new Error(\"Entity missing required fields\");\n }\n\n logger.info(\n `[Test] Entity ${entity.id}: type=${entity.entityType}, tracked=${entity.lastSeen - entity.firstSeen}ms`,\n );\n }\n\n logger.info(\"[Test] ✅ Entity tracking test passed\");\n },\n },\n ];\n}\n\n// Export default instance for test runner\nexport default new VisionRuntimeTestSuite();\n",
|
|
26
|
-
"import { exec } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport type { IAgentRuntime } from \"@elizaos/core\";\nimport type { VisionService } from \"../../service\";\nimport { VisionServiceType } from \"../../types\";\nimport {\n generateComplexPattern,\n generateQuadrantPattern,\n savePattern,\n verifyQuadrantNumbers,\n} from \"../test-pattern-generator\";\n\nconst execAsync = promisify(exec);\n\nexport class VisionWorkerE2ETestSuite {\n name = \"plugin-vision-workers-e2e\";\n description =\n \"E2E tests for multi-threaded vision system with worker threads\";\n\n tests = [\n {\n name: \"Should access vision service through runtime\",\n fn: async (runtime: IAgentRuntime) => {\n console.log(\"Testing vision service access through runtime...\");\n\n // Get vision service from runtime\n const visionService = runtime.getService<VisionService>(\n VisionServiceType.VISION,\n );\n\n if (!visionService) {\n throw new Error(\"Vision service not found in runtime\");\n }\n\n console.log(\"✓ Vision service found in runtime\");\n\n // Check if service is active\n const isActive = visionService.isActive();\n console.log(`✓ Vision service active: ${isActive}`);\n\n // Get vision mode\n const mode = visionService.getVisionMode();\n console.log(`✓ Vision mode: ${mode}`);\n\n // Get enhanced scene description (which uses worker manager if available)\n const scene = await visionService.getEnhancedSceneDescription();\n if (scene) {\n console.log(\"✓ Enhanced scene available\");\n if (scene.screenAnalysis) {\n console.log(\" - Screen analysis present\");\n }\n }\n },\n },\n\n {\n name: \"Should capture screen at high FPS through service\",\n fn: async (runtime: IAgentRuntime) => {\n console.log(\"Testing high-FPS screen capture through service...\");\n\n const visionService = runtime.getService<VisionService>(\n VisionServiceType.VISION,\n );\n if (!visionService) {\n throw new Error(\"Vision service not found\");\n }\n\n // Monitor for 5 seconds\n console.log(\"Monitoring screen capture for 5 seconds...\");\n const startTime = Date.now();\n let frameCount = 0;\n let lastTimestamp = 0;\n\n while (Date.now() - startTime < 5000) {\n const scene = await visionService.getEnhancedSceneDescription();\n if (scene && scene.timestamp !== lastTimestamp) {\n frameCount++;\n lastTimestamp = scene.timestamp;\n }\n\n // Non-blocking check\n await new Promise((resolve) => setImmediate(resolve));\n }\n\n const totalTime = (Date.now() - startTime) / 1000;\n const avgFPS = frameCount / totalTime;\n console.log(\n `✓ Captured ${frameCount} unique frames in ${totalTime.toFixed(2)}s (${avgFPS.toFixed(2)} FPS)`,\n );\n\n if (avgFPS < 1) {\n console.warn(\n \"⚠️ FPS is lower than expected - workers may not be enabled\",\n );\n }\n },\n },\n\n {\n name: \"Should detect quadrant numbers using OCR through service\",\n fn: async (runtime: IAgentRuntime) => {\n console.log(\"Testing quadrant number detection through service...\");\n\n const visionService = runtime.getService<VisionService>(\n VisionServiceType.VISION,\n );\n if (!visionService) {\n throw new Error(\"Vision service not found\");\n }\n\n // Generate test pattern\n const pattern = await generateQuadrantPattern({\n width: 1920,\n height: 1080,\n fontSize: 72,\n includeGrid: true,\n });\n\n const patternPath = await savePattern(pattern, \"quadrant-test.png\");\n console.log(`✓ Test pattern saved to ${patternPath}`);\n\n // Display the pattern\n await displayTestPattern(patternPath);\n\n try {\n // Wait for OCR to process\n console.log(\"Waiting for OCR processing...\");\n await new Promise((resolve) => setTimeout(resolve, 3000));\n\n // Get enhanced scene with OCR results\n const scene = await visionService.getEnhancedSceneDescription();\n const ocrText = scene?.screenAnalysis?.fullScreenOCR || \"\";\n\n console.log(`OCR detected text: \"${ocrText.substring(0, 100)}...\"`);\n\n // Verify quadrant numbers\n const verification = verifyQuadrantNumbers(ocrText);\n console.log(`Found numbers: ${verification.foundNumbers.join(\", \")}`);\n\n if (verification.success) {\n console.log(\"✓ All quadrant numbers detected correctly\");\n } else {\n console.warn(\n `⚠️ Missing numbers: ${verification.missingNumbers.join(\", \")}`,\n );\n }\n\n await closeTestPattern();\n } catch (error) {\n await closeTestPattern();\n throw error;\n }\n },\n },\n\n {\n name: \"Should handle multiple displays through service\",\n fn: async (runtime: IAgentRuntime) => {\n console.log(\"Testing multi-display support through service...\");\n\n const visionService = runtime.getService<VisionService>(\n VisionServiceType.VISION,\n );\n if (!visionService) {\n throw new Error(\"Vision service not found\");\n }\n\n // Get display count\n const displayCount = await getDisplayCount();\n console.log(`Found ${displayCount} display(s)`);\n\n if (displayCount <= 1) {\n console.log(\"⚠️ Only one display found, skipping multi-display test\");\n return;\n }\n\n // Run for 10 seconds to cycle through displays\n console.log(\"Monitoring displays for 10 seconds...\");\n const startTime = Date.now();\n\n while (Date.now() - startTime < 10000) {\n const scene = await visionService.getEnhancedSceneDescription();\n if (scene?.screenCapture) {\n // Log current screen info\n console.log(\n ` Screen: ${scene.screenCapture.width}x${scene.screenCapture.height}`,\n );\n }\n\n await new Promise((resolve) => setTimeout(resolve, 500));\n }\n\n console.log(`✓ Monitored ${displayCount} displays`);\n },\n },\n\n {\n name: \"Should process Florence-2 and OCR in parallel through service\",\n fn: async (runtime: IAgentRuntime) => {\n console.log(\n \"Testing parallel processing performance through service...\",\n );\n\n const visionService = runtime.getService<VisionService>(\n VisionServiceType.VISION,\n );\n if (!visionService) {\n throw new Error(\"Vision service not found\");\n }\n\n // Generate complex pattern\n const pattern = await generateComplexPattern({\n width: 1920,\n height: 1080,\n });\n\n const patternPath = await savePattern(pattern, \"complex-test.png\");\n await displayTestPattern(patternPath);\n\n try {\n // Monitor performance for 10 seconds\n console.log(\"Running parallel processing test for 10 seconds...\");\n const startTime = Date.now();\n const stats = {\n frames: 0,\n ocrDetections: 0,\n florence2Detections: 0,\n };\n\n while (Date.now() - startTime < 10000) {\n const scene = await visionService.getEnhancedSceneDescription();\n\n if (scene) {\n stats.frames++;\n\n if (scene.screenAnalysis?.fullScreenOCR) {\n stats.ocrDetections++;\n }\n\n if (scene.screenAnalysis?.activeTile?.florence2) {\n stats.florence2Detections++;\n }\n }\n\n // Log every 2 seconds\n if ((Date.now() - startTime) % 2000 < 100) {\n console.log(\"\\nCurrent stats:\");\n console.log(` Frames: ${stats.frames}`);\n console.log(` OCR detections: ${stats.ocrDetections}`);\n console.log(\n ` Florence-2 detections: ${stats.florence2Detections}`,\n );\n }\n\n await new Promise((resolve) => setTimeout(resolve, 100));\n }\n\n const totalTime = (Date.now() - startTime) / 1000;\n console.log(\"\\nFinal statistics:\");\n console.log(` Total frames: ${stats.frames}`);\n console.log(\n ` Average FPS: ${(stats.frames / totalTime).toFixed(2)}`,\n );\n console.log(\n ` OCR success rate: ${((stats.ocrDetections / stats.frames) * 100).toFixed(1)}%`,\n );\n console.log(\n ` Florence-2 success rate: ${((stats.florence2Detections / stats.frames) * 100).toFixed(1)}%`,\n );\n\n await closeTestPattern();\n } catch (error) {\n await closeTestPattern();\n throw error;\n }\n },\n },\n ];\n}\n\n// Helper functions\n\nasync function getDisplayCount(): Promise<number> {\n const platform = process.platform;\n\n try {\n if (platform === \"darwin\") {\n const { stdout } = await execAsync(\n \"system_profiler SPDisplaysDataType -json\",\n );\n const data = JSON.parse(stdout);\n return data.SPDisplaysDataType?.[0]?._items?.length || 1;\n } else if (platform === \"linux\") {\n const { stdout } = await execAsync(\n 'xrandr --query | grep \" connected\" | wc -l',\n );\n return parseInt(stdout.trim(), 10) || 1;\n } else if (platform === \"win32\") {\n const { stdout } = await execAsync(\n 'wmic path Win32_DesktopMonitor get DeviceID /format:csv | find /c \"DISPLAY\"',\n );\n return parseInt(stdout.trim(), 10) || 1;\n }\n } catch (error) {\n console.error(\"Failed to get display count:\", error);\n }\n\n return 1;\n}\n\nasync function displayTestPattern(imagePath: string): Promise<void> {\n const platform = process.platform;\n\n try {\n if (platform === \"darwin\") {\n // Open in Preview\n await execAsync(`open \"${imagePath}\"`);\n } else if (platform === \"linux\") {\n // Try common image viewers\n try {\n await execAsync(`xdg-open \"${imagePath}\"`);\n } catch {\n await execAsync(`display \"${imagePath}\"`);\n }\n } else if (platform === \"win32\") {\n // Open with default image viewer\n await execAsync(`start \"\" \"${imagePath}\"`);\n }\n\n // Give time for window to open\n await new Promise((resolve) => setTimeout(resolve, 1000));\n } catch (error) {\n console.warn(\"Could not display test pattern:\", error);\n }\n}\n\nasync function closeTestPattern(): Promise<void> {\n const platform = process.platform;\n\n try {\n if (platform === \"darwin\") {\n // Close Preview\n await execAsync(\"osascript -e 'tell application \\\"Preview\\\" to quit'\");\n } else if (platform === \"linux\") {\n // Close common viewers\n await execAsync(\n 'pkill -f \"display.*test-patterns\" || pkill -f \"eog.*test-patterns\" || true',\n );\n } else if (platform === \"win32\") {\n // Close Photos app\n await execAsync(\"taskkill /IM Microsoft.Photos.exe /F 2>nul || exit 0\");\n }\n } catch (_error) {\n // Ignore errors when closing\n }\n}\n\nexport default new VisionWorkerE2ETestSuite();\n",
|
|
27
|
-
"import * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { logger } from \"@elizaos/core\";\nimport sharp from \"sharp\";\n\nexport interface TestPatternConfig {\n width: number;\n height: number;\n backgroundColor?: string;\n textColor?: string;\n fontSize?: number;\n includeGrid?: boolean;\n includeTimestamp?: boolean;\n displayIndex?: number;\n}\n\n/**\n * Generate grid lines for the pattern\n */\nfunction generateGrid(\n width: number,\n height: number,\n spacing: number = 100,\n): string {\n const lines: string[] = [];\n\n // Vertical lines\n for (let x = spacing; x < width; x += spacing) {\n lines.push(\n `<line x1=\"${x}\" y1=\"0\" x2=\"${x}\" y2=\"${height}\" stroke=\"#eeeeee\" stroke-width=\"1\"/>`,\n );\n }\n\n // Horizontal lines\n for (let y = spacing; y < height; y += spacing) {\n lines.push(\n `<line x1=\"0\" y1=\"${y}\" x2=\"${width}\" y2=\"${y}\" stroke=\"#eeeeee\" stroke-width=\"1\"/>`,\n );\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Generate a test pattern with numbers in each quadrant and center\n */\nexport async function generateQuadrantPattern(\n config: TestPatternConfig,\n): Promise<Buffer> {\n const {\n width,\n height,\n backgroundColor = \"#ffffff\",\n textColor = \"#000000\",\n fontSize = 48,\n includeGrid = true,\n includeTimestamp = true,\n displayIndex = 0,\n } = config;\n\n // Create SVG with test pattern\n const svg = `\n <svg width=\"${width}\" height=\"${height}\" xmlns=\"http://www.w3.org/2000/svg\">\n <!-- Background -->\n <rect width=\"${width}\" height=\"${height}\" fill=\"${backgroundColor}\"/>\n \n ${includeGrid ? generateGrid(width, height) : \"\"}\n \n <!-- Quadrant dividers -->\n <line x1=\"${width / 2}\" y1=\"0\" x2=\"${width / 2}\" y2=\"${height}\" stroke=\"#cccccc\" stroke-width=\"2\"/>\n <line x1=\"0\" y1=\"${height / 2}\" x2=\"${width}\" y2=\"${height / 2}\" stroke=\"#cccccc\" stroke-width=\"2\"/>\n \n <!-- Quadrant numbers -->\n <text x=\"${width / 4}\" y=\"${height / 4}\" font-family=\"Arial\" font-size=\"${fontSize}\" fill=\"${textColor}\" text-anchor=\"middle\" dominant-baseline=\"middle\">1</text>\n <text x=\"${(3 * width) / 4}\" y=\"${height / 4}\" font-family=\"Arial\" font-size=\"${fontSize}\" fill=\"${textColor}\" text-anchor=\"middle\" dominant-baseline=\"middle\">2</text>\n <text x=\"${width / 4}\" y=\"${(3 * height) / 4}\" font-family=\"Arial\" font-size=\"${fontSize}\" fill=\"${textColor}\" text-anchor=\"middle\" dominant-baseline=\"middle\">3</text>\n <text x=\"${(3 * width) / 4}\" y=\"${(3 * height) / 4}\" font-family=\"Arial\" font-size=\"${fontSize}\" fill=\"${textColor}\" text-anchor=\"middle\" dominant-baseline=\"middle\">4</text>\n \n <!-- Center number -->\n <circle cx=\"${width / 2}\" cy=\"${height / 2}\" r=\"${fontSize}\" fill=\"#ff0000\" opacity=\"0.3\"/>\n <text x=\"${width / 2}\" y=\"${height / 2}\" font-family=\"Arial\" font-size=\"${fontSize}\" fill=\"${textColor}\" text-anchor=\"middle\" dominant-baseline=\"middle\">5</text>\n \n <!-- Display info -->\n <text x=\"20\" y=\"30\" font-family=\"Arial\" font-size=\"16\" fill=\"${textColor}\">Display ${displayIndex}</text>\n <text x=\"20\" y=\"50\" font-family=\"Arial\" font-size=\"16\" fill=\"${textColor}\">${width}x${height}</text>\n \n ${includeTimestamp ? `<text x=\"20\" y=\"70\" font-family=\"Arial\" font-size=\"16\" fill=\"${textColor}\">Time: ${new Date().toISOString()}</text>` : \"\"}\n \n <!-- Corner markers -->\n <circle cx=\"10\" cy=\"10\" r=\"5\" fill=\"#ff0000\"/>\n <circle cx=\"${width - 10}\" cy=\"10\" r=\"5\" fill=\"#00ff00\"/>\n <circle cx=\"10\" cy=\"${height - 10}\" r=\"5\" fill=\"#0000ff\"/>\n <circle cx=\"${width - 10}\" cy=\"${height - 10}\" r=\"5\" fill=\"#ffff00\"/>\n </svg>\n `;\n\n // Convert SVG to PNG\n const buffer = await sharp(Buffer.from(svg)).png().toBuffer();\n\n return buffer;\n}\n\n/**\n * Generate a complex test pattern with multiple text regions\n */\nexport async function generateComplexPattern(\n config: TestPatternConfig,\n): Promise<Buffer> {\n const {\n width,\n height,\n backgroundColor = \"#f0f0f0\",\n textColor = \"#000000\",\n fontSize = 24,\n displayIndex = 0,\n } = config;\n\n // Sample text for OCR testing\n const sampleTexts = [\n \"The quick brown fox jumps over the lazy dog\",\n \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\",\n \"abcdefghijklmnopqrstuvwxyz\",\n \"0123456789\",\n \"!@#$%^&*()_+-=[]{}|;:,.<>?\",\n ];\n\n const svg = `\n <svg width=\"${width}\" height=\"${height}\" xmlns=\"http://www.w3.org/2000/svg\">\n <!-- Background -->\n <rect width=\"${width}\" height=\"${height}\" fill=\"${backgroundColor}\"/>\n \n <!-- Title -->\n <text x=\"${width / 2}\" y=\"50\" font-family=\"Arial\" font-size=\"32\" fill=\"${textColor}\" text-anchor=\"middle\">Vision Test Pattern - Display ${displayIndex}</text>\n \n <!-- Text regions for OCR testing -->\n ${sampleTexts\n .map(\n (text, i) => `\n <rect x=\"50\" y=\"${150 + i * 80}\" width=\"${width - 100}\" height=\"60\" fill=\"white\" stroke=\"#333\" stroke-width=\"1\"/>\n <text x=\"70\" y=\"${185 + i * 80}\" font-family=\"Arial\" font-size=\"${fontSize}\" fill=\"${textColor}\">${text}</text>\n `,\n )\n .join(\"\")}\n \n <!-- UI Elements -->\n <rect x=\"50\" y=\"${height - 200}\" width=\"150\" height=\"40\" fill=\"#007bff\" rx=\"5\"/>\n <text x=\"125\" y=\"${height - 175}\" font-family=\"Arial\" font-size=\"16\" fill=\"white\" text-anchor=\"middle\">Button</text>\n \n <rect x=\"220\" y=\"${height - 200}\" width=\"200\" height=\"30\" fill=\"white\" stroke=\"#333\" stroke-width=\"1\"/>\n <text x=\"230\" y=\"${height - 180}\" font-family=\"Arial\" font-size=\"14\" fill=\"#666\">Input Field</text>\n \n <!-- Timestamp -->\n <text x=\"${width - 20}\" y=\"${height - 20}\" font-family=\"Arial\" font-size=\"12\" fill=\"#666\" text-anchor=\"end\">${new Date().toISOString()}</text>\n </svg>\n `;\n\n const buffer = await sharp(Buffer.from(svg)).png().toBuffer();\n\n return buffer;\n}\n\n/**\n * Save test pattern to file\n */\nexport async function savePattern(\n buffer: Buffer,\n filename: string,\n): Promise<string> {\n const outputDir = path.join(process.cwd(), \"test-patterns\");\n await fs.mkdir(outputDir, { recursive: true });\n\n const filepath = path.join(outputDir, filename);\n await fs.writeFile(filepath, buffer);\n\n logger.info(`[TestPatternGenerator] Saved test pattern to ${filepath}`);\n return filepath;\n}\n\n/**\n * Generate patterns for all displays\n */\nexport async function generatePatternsForAllDisplays(\n displayCount: number,\n): Promise<Map<number, Buffer>> {\n const patterns = new Map<number, Buffer>();\n\n for (let i = 0; i < displayCount; i++) {\n const pattern = await generateQuadrantPattern({\n width: 1920,\n height: 1080,\n displayIndex: i,\n includeTimestamp: true,\n });\n\n patterns.set(i, pattern);\n }\n\n return patterns;\n}\n\n/**\n * Verify OCR results match expected quadrant numbers\n */\nexport function verifyQuadrantNumbers(ocrText: string): {\n success: boolean;\n foundNumbers: number[];\n missingNumbers: number[];\n} {\n const expectedNumbers = [1, 2, 3, 4, 5];\n const foundNumbers: number[] = [];\n\n // Extract all numbers from OCR text\n const matches = ocrText.match(/\\d+/g);\n if (matches) {\n matches.forEach((match) => {\n const num = parseInt(match, 10);\n if (expectedNumbers.includes(num) && !foundNumbers.includes(num)) {\n foundNumbers.push(num);\n }\n });\n }\n\n const missingNumbers = expectedNumbers.filter(\n (n) => !foundNumbers.includes(n),\n );\n\n return {\n success: missingNumbers.length === 0,\n foundNumbers,\n missingNumbers,\n };\n}\n",
|
|
28
|
-
"// Export all E2E test suites\n\nexport { default as ScreenVisionE2ETestSuite } from \"./screen-vision\";\nexport { default as VisionBasicE2ETestSuite } from \"./vision-basic\";\nexport { default as VisionCaptureLogTestSuite } from \"./vision-capture-log\";\nexport { default as VisionRuntimeTestSuite } from \"./vision-runtime\";\nexport { default as VisionWorkerE2ETestSuite } from \"./vision-worker-tests\";\n\nimport ScreenVisionE2ETestSuite from \"./screen-vision\";\n// Export as array for convenience\nimport VisionBasicE2ETestSuite from \"./vision-basic\";\nimport VisionCaptureLogTestSuite from \"./vision-capture-log\";\nimport VisionRuntimeTestSuite from \"./vision-runtime\";\nimport VisionWorkerE2ETestSuite from \"./vision-worker-tests\";\n\nexport const testSuites = [\n VisionRuntimeTestSuite, // Real runtime tests first\n VisionBasicE2ETestSuite,\n VisionCaptureLogTestSuite,\n ScreenVisionE2ETestSuite,\n VisionWorkerE2ETestSuite, // Worker-based tests\n];\n\nexport default testSuites;\n"
|
|
42
|
+
"import * as path from \"node:path\";\nimport { TextDecoder } from \"node:util\";\nimport { Worker } from \"node:worker_threads\";\nimport { logger } from \"@elizaos/core\";\nimport type {\n EnhancedSceneDescription,\n OCRResult,\n ScreenCapture,\n VisionConfig,\n} from \"./types\";\n\ninterface WorkerStats {\n fps: number;\n frameCount: number;\n lastUpdate: number;\n}\n\nexport class VisionWorkerManager {\n private config: VisionConfig;\n\n private screenCaptureWorker: Worker | null = null;\n private ocrWorker: Worker | null = null;\n\n private screenBuffer: SharedArrayBuffer;\n private ocrResultsBuffer: SharedArrayBuffer;\n\n private screenAtomicState: Int32Array;\n private ocrResultsView: DataView;\n\n private readonly SCREEN_BUFFER_SIZE = 50 * 1024 * 1024;\n private readonly OCR_RESULTS_SIZE = 5 * 1024 * 1024;\n\n private readonly FRAME_ID_INDEX = 0;\n private readonly WIDTH_INDEX = 2;\n private readonly HEIGHT_INDEX = 3;\n private readonly DISPLAY_INDEX = 4;\n private readonly TIMESTAMP_INDEX = 5;\n\n private workerStats = new Map<string, WorkerStats>();\n\n private latestScreenCapture: ScreenCapture | null = null;\n private latestOCRResult: OCRResult | null = null;\n private lastProcessedFrameId = -1;\n\n private restartAttempts = new Map<string, number>();\n private readonly MAX_RESTART_ATTEMPTS = 3;\n\n constructor(config: VisionConfig) {\n this.config = config;\n\n this.screenBuffer = new SharedArrayBuffer(this.SCREEN_BUFFER_SIZE);\n this.ocrResultsBuffer = new SharedArrayBuffer(this.OCR_RESULTS_SIZE);\n\n this.screenAtomicState = new Int32Array(this.screenBuffer, 0, 6);\n this.ocrResultsView = new DataView(this.ocrResultsBuffer);\n }\n\n async initialize(): Promise<void> {\n logger.info(\"[VisionWorkerManager] Initializing worker threads...\");\n\n try {\n await this.startScreenCaptureWorker();\n\n if (this.config.ocrEnabled) {\n await this.startOCRWorker();\n }\n\n logger.info(\"[VisionWorkerManager] All workers initialized\");\n } catch (error) {\n logger.error(\n { error },\n \"[VisionWorkerManager] Failed to initialize workers:\",\n );\n throw error;\n }\n }\n\n private async startScreenCaptureWorker(): Promise<void> {\n const workerPath = path.join(\n __dirname,\n \"workers\",\n \"screen-capture-worker.js\",\n );\n\n this.screenCaptureWorker = new Worker(workerPath, {\n workerData: {\n config: {\n displayIndex: this.config.displayIndex,\n captureAllDisplays: this.config.captureAllDisplays,\n targetFPS: this.config.targetScreenFPS,\n sharedBufferSize: this.SCREEN_BUFFER_SIZE,\n },\n sharedBuffer: this.screenBuffer,\n },\n });\n\n this.screenCaptureWorker.on(\"message\", (msg) => {\n if (msg.type === \"fps\") {\n this.workerStats.set(\"screenCapture\", {\n fps: msg.fps,\n frameCount: msg.frameCount,\n lastUpdate: Date.now(),\n });\n } else if (msg.type === \"error\") {\n logger.error(\"[ScreenCaptureWorker] Error:\", msg.error);\n } else if (msg.type === \"log\") {\n this.handleWorkerLog(\"ScreenCaptureWorker\", msg);\n }\n });\n\n this.screenCaptureWorker.on(\"error\", (error) => {\n logger.error(\n \"[ScreenCaptureWorker] Worker error:\",\n error instanceof Error ? error.message : String(error),\n );\n setTimeout(() => this.restartScreenCaptureWorker(), 1000);\n });\n\n this.screenCaptureWorker.on(\"exit\", (code) => {\n if (code !== 0) {\n logger.error(\n `[ScreenCaptureWorker] Worker stopped with exit code ${code}`,\n );\n setTimeout(() => this.restartScreenCaptureWorker(), 1000);\n }\n });\n }\n\n private async startOCRWorker(): Promise<void> {\n const workerPath = path.join(__dirname, \"workers\", \"ocr-worker.js\");\n\n this.ocrWorker = new Worker(workerPath, {\n workerData: {\n config: {\n processFullScreen: true,\n tileSize: this.config.tileSize || 256,\n textRegions: this.config.textRegions,\n },\n sharedBuffer: this.screenBuffer,\n resultsBuffer: this.ocrResultsBuffer,\n },\n });\n\n this.ocrWorker.on(\"message\", (msg) => {\n if (msg.type === \"fps\") {\n this.workerStats.set(\"ocr\", {\n fps: msg.fps,\n frameCount: msg.frameCount,\n lastUpdate: Date.now(),\n });\n } else if (msg.type === \"ocr_complete\") {\n this.updateOCRCache(msg);\n } else if (msg.type === \"error\") {\n logger.error(\"[OCRWorker] Error:\", msg.error);\n } else if (msg.type === \"log\") {\n this.handleWorkerLog(\"OCRWorker\", msg);\n }\n });\n\n this.ocrWorker.on(\"error\", (error) => {\n logger.error(\n \"[OCRWorker] Worker error:\",\n error instanceof Error ? error.message : String(error),\n );\n setTimeout(() => this.restartOCRWorker(), 1000);\n });\n\n this.ocrWorker.on(\"exit\", (code) => {\n if (code !== 0) {\n logger.error(`[OCRWorker] Worker stopped with exit code ${code}`);\n setTimeout(() => this.restartOCRWorker(), 1000);\n }\n });\n }\n\n private updateOCRCache(_msg: unknown): void {\n try {\n const result = this.readOCRResult();\n if (result) {\n this.latestOCRResult = result;\n }\n } catch (error) {\n logger.error(\n { error },\n \"[VisionWorkerManager] Failed to update OCR cache:\",\n );\n }\n }\n\n private readOCRResult(): OCRResult | null {\n try {\n const RESULTS_HEADER_SIZE = 16;\n const offset = RESULTS_HEADER_SIZE;\n\n const length = this.ocrResultsView.getUint32(offset, true);\n if (length === 0) {\n return null;\n }\n\n const _frameId = this.ocrResultsView.getUint32(offset + 4, true);\n const _timestamp = this.ocrResultsView.getFloat64(offset + 8, true);\n\n const dataOffset = offset + 16;\n const bytes = new Uint8Array(Math.min(length, 65536));\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = this.ocrResultsView.getUint8(dataOffset + i);\n }\n\n const json = new TextDecoder().decode(bytes);\n return JSON.parse(json);\n } catch (error) {\n logger.error(\n { error },\n \"[VisionWorkerManager] Failed to read OCR result:\",\n );\n return null;\n }\n }\n\n getLatestScreenCapture(): ScreenCapture | null {\n const frameId = Atomics.load(this.screenAtomicState, this.FRAME_ID_INDEX);\n\n if (frameId <= this.lastProcessedFrameId) {\n return this.latestScreenCapture;\n }\n\n try {\n const width = Atomics.load(this.screenAtomicState, this.WIDTH_INDEX);\n const height = Atomics.load(this.screenAtomicState, this.HEIGHT_INDEX);\n const _displayIndex = Atomics.load(\n this.screenAtomicState,\n this.DISPLAY_INDEX,\n );\n const timestamp = Atomics.load(\n this.screenAtomicState,\n this.TIMESTAMP_INDEX,\n );\n\n this.latestScreenCapture = {\n timestamp,\n width,\n height,\n data: Buffer.alloc(0),\n tiles: this.generateTiles(width, height),\n };\n\n this.lastProcessedFrameId = frameId;\n } catch (error) {\n logger.error(\n { error },\n \"[VisionWorkerManager] Failed to read screen capture:\",\n );\n }\n\n return this.latestScreenCapture;\n }\n\n getLatestEnhancedScene(): EnhancedSceneDescription {\n const screenCapture = this.getLatestScreenCapture();\n\n return {\n timestamp: Date.now(),\n description: this.latestOCRResult?.fullText ?? \"\",\n objects: [],\n people: [],\n sceneChanged: true,\n changePercentage: 100,\n screenCapture: this.latestScreenCapture || undefined,\n screenAnalysis: {\n fullScreenOCR: this.latestOCRResult?.fullText,\n activeTile: {\n timestamp: Date.now(),\n ocr: this.latestOCRResult || undefined,\n },\n gridSummary: `${screenCapture?.tiles.length || 0} tiles analyzed`,\n uiElements: [],\n },\n };\n }\n\n private generateTiles(\n width: number,\n height: number,\n ): Array<{\n id: string;\n row: number;\n col: number;\n x: number;\n y: number;\n width: number;\n height: number;\n }> {\n const tileSize = this.config.tileSize || 256;\n const tiles: Array<{\n id: string;\n row: number;\n col: number;\n x: number;\n y: number;\n width: number;\n height: number;\n }> = [];\n\n for (let row = 0; row < Math.ceil(height / tileSize); row++) {\n for (let col = 0; col < Math.ceil(width / tileSize); col++) {\n const x = col * tileSize;\n const y = row * tileSize;\n tiles.push({\n id: `tile-${row}-${col}`,\n row,\n col,\n x,\n y,\n width: Math.min(tileSize, width - x),\n height: Math.min(tileSize, height - y),\n });\n }\n }\n\n return tiles;\n }\n\n getWorkerStats(): Map<string, WorkerStats> {\n return new Map(this.workerStats);\n }\n\n async setDisplayIndex(index: number): Promise<void> {\n if (this.screenCaptureWorker) {\n this.screenCaptureWorker.postMessage({\n type: \"set_display\",\n displayIndex: index,\n });\n }\n }\n\n async setTextRegions(\n regions: Array<{ x: number; y: number; width: number; height: number }>,\n ): Promise<void> {\n if (this.ocrWorker) {\n this.ocrWorker.postMessage({\n type: \"update_regions\",\n regions,\n });\n }\n }\n\n async stop(): Promise<void> {\n logger.info(\"[VisionWorkerManager] Stopping all workers...\");\n\n const stopPromises: Promise<void>[] = [];\n\n if (this.screenCaptureWorker) {\n stopPromises.push(\n new Promise((resolve) => {\n this.screenCaptureWorker?.once(\"exit\", () => resolve());\n this.screenCaptureWorker?.postMessage({ type: \"stop\" });\n }),\n );\n }\n\n if (this.ocrWorker) {\n stopPromises.push(\n new Promise((resolve) => {\n this.ocrWorker?.once(\"exit\", () => resolve());\n this.ocrWorker?.postMessage({ type: \"stop\" });\n }),\n );\n }\n\n await Promise.all(stopPromises);\n logger.info(\"[VisionWorkerManager] All workers stopped\");\n }\n\n private handleWorkerLog(\n workerName: string,\n msg: { level: string; message: string; args: unknown[] },\n ): void {\n const { level, message, args } = msg;\n const formattedMessage = `[${workerName}] ${message}`;\n const stringArgs = args.map((arg) => String(arg));\n\n switch (level) {\n case \"info\":\n logger.info(formattedMessage, ...stringArgs);\n break;\n case \"warn\":\n logger.warn(formattedMessage, ...stringArgs);\n break;\n case \"error\":\n logger.error(formattedMessage, ...stringArgs);\n break;\n case \"debug\":\n logger.debug(formattedMessage, ...stringArgs);\n break;\n }\n }\n\n private async restartScreenCaptureWorker(): Promise<void> {\n const attempts = this.restartAttempts.get(\"screenCapture\") || 0;\n\n if (attempts >= this.MAX_RESTART_ATTEMPTS) {\n logger.error(\n \"[VisionWorkerManager] Max restart attempts reached for screen capture worker\",\n );\n return;\n }\n\n this.restartAttempts.set(\"screenCapture\", attempts + 1);\n logger.info(\n `[VisionWorkerManager] Restarting screen capture worker (attempt ${attempts + 1})`,\n );\n\n try {\n if (this.screenCaptureWorker) {\n this.screenCaptureWorker.removeAllListeners();\n this.screenCaptureWorker = null;\n }\n\n await this.startScreenCaptureWorker();\n\n this.restartAttempts.set(\"screenCapture\", 0);\n } catch (error) {\n logger.error(\n { error },\n \"[VisionWorkerManager] Failed to restart screen capture worker:\",\n );\n }\n }\n\n private async restartOCRWorker(): Promise<void> {\n const attempts = this.restartAttempts.get(\"ocr\") || 0;\n\n if (attempts >= this.MAX_RESTART_ATTEMPTS) {\n logger.error(\n \"[VisionWorkerManager] Max restart attempts reached for OCR worker\",\n );\n return;\n }\n\n this.restartAttempts.set(\"ocr\", attempts + 1);\n logger.info(\n `[VisionWorkerManager] Restarting OCR worker (attempt ${attempts + 1})`,\n );\n\n try {\n if (this.ocrWorker) {\n this.ocrWorker.removeAllListeners();\n this.ocrWorker = null;\n }\n\n await this.startOCRWorker();\n\n this.restartAttempts.set(\"ocr\", 0);\n } catch (error) {\n logger.error(\n { error },\n \"[VisionWorkerManager] Failed to restart OCR worker:\",\n );\n }\n }\n}\n",
|
|
43
|
+
"/**\n * Bridge plugin-vision's Set-of-Marks fusion into plugin-computeruse's\n * `SetOfMarksProvider` registry seam (#9170 M9).\n *\n * Mirrors `computeruse-ocr-bridge.ts`: plugin-vision owns the GGUF YOLO icon\n * detector and the OCR engines; plugin-computeruse exposes a registration slot\n * and consumes whatever is registered from `detect_elements`, with NO hard\n * dependency on plugin-vision. The provider is built here and registered at\n * boot via a best-effort dynamic import (see `index.ts`).\n *\n * Pure + injectable: the YOLO detector and OCR resolver are passed in, so the\n * fusion wiring is unit-testable with fakes and degrades gracefully when the\n * GGUF detector or OCR engine is unavailable (icons or text simply absent).\n */\n\nimport { getOcrWithCoordsService } from \"./ocr-with-coords.js\";\nimport {\n buildSceneSetOfMarks,\n type DetectedObjectLike,\n type OcrBlockLike,\n renderSetOfMarksOverlay,\n type SetOfMarksOptions,\n type SomMark,\n} from \"./som.js\";\n\n/** Structural shape of computeruse's `SetOfMarksInput`. */\nexport interface SetOfMarksInputLike {\n readonly displayId: string;\n readonly sourceX: number;\n readonly sourceY: number;\n readonly pngBytes: Uint8Array;\n readonly renderOverlay?: boolean;\n}\n\n/** Structural shape of computeruse's `SetOfMarksResult`. */\nexport interface SetOfMarksResultLike {\n readonly marks: ReadonlyArray<SomMark>;\n readonly overlayPngBase64?: string;\n}\n\n/** Structural shape of computeruse's `SetOfMarksProvider`. */\nexport interface SetOfMarksProviderLike {\n readonly name: string;\n describe(input: SetOfMarksInputLike): Promise<SetOfMarksResultLike>;\n}\n\nexport type RegisterSetOfMarksProvider = (\n provider: SetOfMarksProviderLike | null,\n) => void;\n\nexport const VISION_SET_OF_MARKS_BRIDGE_NAME = \"vision-set-of-marks-bridge\";\n\nexport interface SetOfMarksProviderDeps {\n /**\n * Detect icon-ish boxes from PNG bytes (GGUF YOLO). Returns `[]` when the\n * detector is unavailable — Set-of-Marks then falls back to text-only marks.\n */\n readonly detectIcons?: (\n pngBytes: Uint8Array,\n ) => Promise<DetectedObjectLike[]>;\n /** Resolve the OCR-with-coords service (defaults to the registered one). */\n readonly resolveOcr?: typeof getOcrWithCoordsService;\n /** Fusion tuning forwarded to `buildSetOfMarks`. */\n readonly options?: SetOfMarksOptions;\n}\n\n/**\n * Lazily-instantiated default GGUF YOLO icon detector. Best-effort: if the\n * native bindings or GGUF weights are missing, every call resolves to `[]` so\n * Set-of-Marks degrades to OCR-only text marks instead of throwing.\n */\nexport function createDefaultIconDetector(): (\n pngBytes: Uint8Array,\n) => Promise<DetectedObjectLike[]> {\n let detector: {\n detect: (buf: Buffer) => Promise<DetectedObjectLike[]>;\n } | null = null;\n let unavailable = false;\n return async (pngBytes: Uint8Array): Promise<DetectedObjectLike[]> => {\n if (unavailable) return [];\n try {\n if (!detector) {\n const { YOLODetector } = await import(\"./yolo-detector.js\");\n if (!(await YOLODetector.isAvailable())) {\n unavailable = true;\n return [];\n }\n const d = new YOLODetector();\n await d.initialize();\n detector = d;\n }\n return await detector.detect(Buffer.from(pngBytes));\n } catch {\n // One failure marks the detector unavailable for the process lifetime —\n // re-probing on every detect would be wasteful when weights are missing.\n unavailable = true;\n return [];\n }\n };\n}\n\n/**\n * Build a `SetOfMarksProvider`-shaped bridge that fuses GGUF YOLO icon\n * detections + OCR text blocks into a numbered mark set (and optional overlay).\n */\nexport function buildVisionSetOfMarksProvider(\n deps: SetOfMarksProviderDeps = {},\n): SetOfMarksProviderLike {\n const detectIcons = deps.detectIcons ?? createDefaultIconDetector();\n const resolveOcr = deps.resolveOcr ?? getOcrWithCoordsService;\n return {\n name: VISION_SET_OF_MARKS_BRIDGE_NAME,\n async describe(input: SetOfMarksInputLike): Promise<SetOfMarksResultLike> {\n const ocr = resolveOcr();\n const [detections, ocrResult] = await Promise.all([\n detectIcons(input.pngBytes),\n ocr\n ? ocr.describe({\n displayId: input.displayId,\n sourceX: input.sourceX,\n sourceY: input.sourceY,\n pngBytes: input.pngBytes,\n })\n : Promise.resolve({ blocks: [] as OcrBlockLike[] }),\n ]);\n\n const marks = buildSceneSetOfMarks(\n {\n detections,\n ocrBlocks: ocrResult.blocks as readonly OcrBlockLike[],\n },\n deps.options,\n );\n\n if (!input.renderOverlay || marks.length === 0) {\n return { marks };\n }\n const overlay = await renderSetOfMarksOverlay(input.pngBytes, marks);\n return { marks, overlayPngBase64: overlay.toString(\"base64\") };\n },\n };\n}\n\n/**\n * Register the vision Set-of-Marks bridge into computeruse's seam. Idempotent\n * (last-call-wins). Returns true once registered.\n */\nexport function wireComputerUseSetOfMarksBridge(\n register: RegisterSetOfMarksProvider,\n deps?: SetOfMarksProviderDeps,\n): boolean {\n register(buildVisionSetOfMarksProvider(deps));\n return true;\n}\n"
|
|
29
44
|
],
|
|
30
|
-
"mappings": "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",
|
|
31
|
-
"debugId": "
|
|
45
|
+
"mappings": "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AAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,mBAAmB;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,oBAAoB;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,uBAAuB;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,2BAA2B;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA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",
|
|
46
|
+
"debugId": "18E078EBE3D7834B64756E2164756E21",
|
|
32
47
|
"names": []
|
|
33
48
|
}
|