@beeos-ai/device-agent 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.pi/extensions/android-tools.ts +139 -0
- package/.pi/skills/.gitkeep +0 -0
- package/.pi/skills/ground-mobile-fallback/SKILL.md +50 -0
- package/LICENSE +201 -0
- package/dist/action/handler.d.ts +9 -0
- package/dist/action/handler.js +124 -0
- package/dist/action/handler.js.map +1 -0
- package/dist/adapters/agent-gateway-client.d.ts +256 -0
- package/dist/adapters/agent-gateway-client.js +332 -0
- package/dist/adapters/agent-gateway-client.js.map +1 -0
- package/dist/adapters/agentcore-inner-loop.d.ts +29 -0
- package/dist/adapters/agentcore-inner-loop.js +72 -0
- package/dist/adapters/agentcore-inner-loop.js.map +1 -0
- package/dist/adapters/agentcore-pi.d.ts +215 -0
- package/dist/adapters/agentcore-pi.js +464 -0
- package/dist/adapters/agentcore-pi.js.map +1 -0
- package/dist/adapters/agentcore-runner.d.ts +70 -0
- package/dist/adapters/agentcore-runner.js +255 -0
- package/dist/adapters/agentcore-runner.js.map +1 -0
- package/dist/adapters/device-android-adb.d.ts +41 -0
- package/dist/adapters/device-android-adb.js +279 -0
- package/dist/adapters/device-android-adb.js.map +1 -0
- package/dist/adapters/device-desktop.d.ts +37 -0
- package/dist/adapters/device-desktop.js +101 -0
- package/dist/adapters/device-desktop.js.map +1 -0
- package/dist/adapters/identity-file.d.ts +30 -0
- package/dist/adapters/identity-file.js +50 -0
- package/dist/adapters/identity-file.js.map +1 -0
- package/dist/adapters/transport-bridge-ws.d.ts +39 -0
- package/dist/adapters/transport-bridge-ws.js +49 -0
- package/dist/adapters/transport-bridge-ws.js.map +1 -0
- package/dist/adapters/vlm-inner-loop.d.ts +88 -0
- package/dist/adapters/vlm-inner-loop.js +199 -0
- package/dist/adapters/vlm-inner-loop.js.map +1 -0
- package/dist/agent-runtime/adapters/base.d.ts +145 -0
- package/dist/agent-runtime/adapters/base.js +29 -0
- package/dist/agent-runtime/adapters/base.js.map +1 -0
- package/dist/agent-runtime/adapters/index.d.ts +17 -0
- package/dist/agent-runtime/adapters/index.js +17 -0
- package/dist/agent-runtime/adapters/index.js.map +1 -0
- package/dist/agent-runtime/adapters/mock.d.ts +44 -0
- package/dist/agent-runtime/adapters/mock.js +54 -0
- package/dist/agent-runtime/adapters/mock.js.map +1 -0
- package/dist/agent-runtime/adapters/openai.d.ts +63 -0
- package/dist/agent-runtime/adapters/openai.js +302 -0
- package/dist/agent-runtime/adapters/openai.js.map +1 -0
- package/dist/agent-runtime/adapters/registry.d.ts +49 -0
- package/dist/agent-runtime/adapters/registry.js +129 -0
- package/dist/agent-runtime/adapters/registry.js.map +1 -0
- package/dist/agent-runtime/adapters/ui-tars.d.ts +13 -0
- package/dist/agent-runtime/adapters/ui-tars.js +22 -0
- package/dist/agent-runtime/adapters/ui-tars.js.map +1 -0
- package/dist/agent-runtime/agent-runner.d.ts +149 -0
- package/dist/agent-runtime/agent-runner.js +356 -0
- package/dist/agent-runtime/agent-runner.js.map +1 -0
- package/dist/agent-runtime/core.d.ts +170 -0
- package/dist/agent-runtime/core.js +624 -0
- package/dist/agent-runtime/core.js.map +1 -0
- package/dist/agent-runtime/index.d.ts +16 -0
- package/dist/agent-runtime/index.js +17 -0
- package/dist/agent-runtime/index.js.map +1 -0
- package/dist/agent-runtime/plan-executor.d.ts +118 -0
- package/dist/agent-runtime/plan-executor.js +501 -0
- package/dist/agent-runtime/plan-executor.js.map +1 -0
- package/dist/agent-runtime/planner/base.d.ts +128 -0
- package/dist/agent-runtime/planner/base.js +157 -0
- package/dist/agent-runtime/planner/base.js.map +1 -0
- package/dist/agent-runtime/planner/llm-planner.d.ts +58 -0
- package/dist/agent-runtime/planner/llm-planner.js +112 -0
- package/dist/agent-runtime/planner/llm-planner.js.map +1 -0
- package/dist/agent-runtime/planner/noop-planner.d.ts +13 -0
- package/dist/agent-runtime/planner/noop-planner.js +30 -0
- package/dist/agent-runtime/planner/noop-planner.js.map +1 -0
- package/dist/agent-runtime/planner/prompts.d.ts +33 -0
- package/dist/agent-runtime/planner/prompts.js +165 -0
- package/dist/agent-runtime/planner/prompts.js.map +1 -0
- package/dist/agent-runtime/reflection.d.ts +81 -0
- package/dist/agent-runtime/reflection.js +189 -0
- package/dist/agent-runtime/reflection.js.map +1 -0
- package/dist/agent-runtime/reflectors/action-reflector.d.ts +97 -0
- package/dist/agent-runtime/reflectors/action-reflector.js +233 -0
- package/dist/agent-runtime/reflectors/action-reflector.js.map +1 -0
- package/dist/agent-runtime/reflectors/policy.d.ts +53 -0
- package/dist/agent-runtime/reflectors/policy.js +106 -0
- package/dist/agent-runtime/reflectors/policy.js.map +1 -0
- package/dist/agent-runtime/reflectors/trajectory-reflector.d.ts +94 -0
- package/dist/agent-runtime/reflectors/trajectory-reflector.js +223 -0
- package/dist/agent-runtime/reflectors/trajectory-reflector.js.map +1 -0
- package/dist/agent-runtime/skills/embedding.d.ts +53 -0
- package/dist/agent-runtime/skills/embedding.js +134 -0
- package/dist/agent-runtime/skills/embedding.js.map +1 -0
- package/dist/agent-runtime/skills/fs-store.d.ts +88 -0
- package/dist/agent-runtime/skills/fs-store.js +483 -0
- package/dist/agent-runtime/skills/fs-store.js.map +1 -0
- package/dist/agent-runtime/skills/index.d.ts +10 -0
- package/dist/agent-runtime/skills/index.js +10 -0
- package/dist/agent-runtime/skills/index.js.map +1 -0
- package/dist/agent-runtime/skills/matcher-evolver.d.ts +88 -0
- package/dist/agent-runtime/skills/matcher-evolver.js +110 -0
- package/dist/agent-runtime/skills/matcher-evolver.js.map +1 -0
- package/dist/agent-runtime/skills/memory-store.d.ts +23 -0
- package/dist/agent-runtime/skills/memory-store.js +94 -0
- package/dist/agent-runtime/skills/memory-store.js.map +1 -0
- package/dist/agent-runtime/skills/normalise.d.ts +40 -0
- package/dist/agent-runtime/skills/normalise.js +152 -0
- package/dist/agent-runtime/skills/normalise.js.map +1 -0
- package/dist/agent-runtime/skills/replay.d.ts +46 -0
- package/dist/agent-runtime/skills/replay.js +106 -0
- package/dist/agent-runtime/skills/replay.js.map +1 -0
- package/dist/agent-runtime/skills/sqlite-store.d.ts +60 -0
- package/dist/agent-runtime/skills/sqlite-store.js +234 -0
- package/dist/agent-runtime/skills/sqlite-store.js.map +1 -0
- package/dist/agent-runtime/skills/types.d.ts +99 -0
- package/dist/agent-runtime/skills/types.js +14 -0
- package/dist/agent-runtime/skills/types.js.map +1 -0
- package/dist/agent.d.ts +110 -0
- package/dist/agent.js +162 -0
- package/dist/agent.js.map +1 -0
- package/dist/api.d.ts +27 -0
- package/dist/api.js +48 -0
- package/dist/api.js.map +1 -0
- package/dist/app/agent-host.d.ts +59 -0
- package/dist/app/agent-host.js +263 -0
- package/dist/app/agent-host.js.map +1 -0
- package/dist/app/device-manager.d.ts +28 -0
- package/dist/app/device-manager.js +64 -0
- package/dist/app/device-manager.js.map +1 -0
- package/dist/app/message-store.d.ts +55 -0
- package/dist/app/message-store.js +99 -0
- package/dist/app/message-store.js.map +1 -0
- package/dist/app/session-manager.d.ts +132 -0
- package/dist/app/session-manager.js +350 -0
- package/dist/app/session-manager.js.map +1 -0
- package/dist/bootstrap.d.ts +94 -0
- package/dist/bootstrap.js +459 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/chat.d.ts +16 -0
- package/dist/chat.js +175 -0
- package/dist/chat.js.map +1 -0
- package/dist/config/loader.d.ts +77 -0
- package/dist/config/loader.js +292 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +162 -0
- package/dist/config/schema.js +243 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/core/actions.d.ts +60 -0
- package/dist/core/actions.js +120 -0
- package/dist/core/actions.js.map +1 -0
- package/dist/core/errors.d.ts +8 -0
- package/dist/core/errors.js +9 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/screen.d.ts +7 -0
- package/dist/core/screen.js +8 -0
- package/dist/core/screen.js.map +1 -0
- package/dist/core/session.d.ts +42 -0
- package/dist/core/session.js +29 -0
- package/dist/core/session.js.map +1 -0
- package/dist/debug/dump-system-prompt.d.ts +1 -0
- package/dist/debug/dump-system-prompt.js +34 -0
- package/dist/debug/dump-system-prompt.js.map +1 -0
- package/dist/device/android.d.ts +25 -0
- package/dist/device/android.js +231 -0
- package/dist/device/android.js.map +1 -0
- package/dist/device/apps.d.ts +3 -0
- package/dist/device/apps.js +77 -0
- package/dist/device/apps.js.map +1 -0
- package/dist/device/base.d.ts +20 -0
- package/dist/device/base.js +2 -0
- package/dist/device/base.js.map +1 -0
- package/dist/device/ui-xml.d.ts +29 -0
- package/dist/device/ui-xml.js +194 -0
- package/dist/device/ui-xml.js.map +1 -0
- package/dist/fleet/adapters/process/node-process-manager.d.ts +157 -0
- package/dist/fleet/adapters/process/node-process-manager.js +664 -0
- package/dist/fleet/adapters/process/node-process-manager.js.map +1 -0
- package/dist/fleet/adapters/sources/local-adb.d.ts +105 -0
- package/dist/fleet/adapters/sources/local-adb.js +353 -0
- package/dist/fleet/adapters/sources/local-adb.js.map +1 -0
- package/dist/fleet/adapters/sources/remote-adb.d.ts +97 -0
- package/dist/fleet/adapters/sources/remote-adb.js +138 -0
- package/dist/fleet/adapters/sources/remote-adb.js.map +1 -0
- package/dist/fleet/adapters/state/beeos-cli-store.d.ts +72 -0
- package/dist/fleet/adapters/state/beeos-cli-store.js +250 -0
- package/dist/fleet/adapters/state/beeos-cli-store.js.map +1 -0
- package/dist/fleet/adapters/state/port-allocator.d.ts +43 -0
- package/dist/fleet/adapters/state/port-allocator.js +173 -0
- package/dist/fleet/adapters/state/port-allocator.js.map +1 -0
- package/dist/fleet/domain/device.d.ts +138 -0
- package/dist/fleet/domain/device.js +49 -0
- package/dist/fleet/domain/device.js.map +1 -0
- package/dist/fleet/domain/events.d.ts +102 -0
- package/dist/fleet/domain/events.js +15 -0
- package/dist/fleet/domain/events.js.map +1 -0
- package/dist/fleet/domain/fsm.d.ts +122 -0
- package/dist/fleet/domain/fsm.js +475 -0
- package/dist/fleet/domain/fsm.js.map +1 -0
- package/dist/fleet/http/status-client.d.ts +31 -0
- package/dist/fleet/http/status-client.js +115 -0
- package/dist/fleet/http/status-client.js.map +1 -0
- package/dist/fleet/http/status-server.d.ts +64 -0
- package/dist/fleet/http/status-server.js +200 -0
- package/dist/fleet/http/status-server.js.map +1 -0
- package/dist/fleet/index.d.ts +27 -0
- package/dist/fleet/index.js +17 -0
- package/dist/fleet/index.js.map +1 -0
- package/dist/fleet/installer/index.d.ts +12 -0
- package/dist/fleet/installer/index.js +13 -0
- package/dist/fleet/installer/index.js.map +1 -0
- package/dist/fleet/installer/launchd-mac.d.ts +73 -0
- package/dist/fleet/installer/launchd-mac.js +291 -0
- package/dist/fleet/installer/launchd-mac.js.map +1 -0
- package/dist/fleet/installer/service-spec.d.ts +70 -0
- package/dist/fleet/installer/service-spec.js +43 -0
- package/dist/fleet/installer/service-spec.js.map +1 -0
- package/dist/fleet/installer/spawn-env.d.ts +45 -0
- package/dist/fleet/installer/spawn-env.js +224 -0
- package/dist/fleet/installer/spawn-env.js.map +1 -0
- package/dist/fleet/ports/clock.d.ts +19 -0
- package/dist/fleet/ports/clock.js +26 -0
- package/dist/fleet/ports/clock.js.map +1 -0
- package/dist/fleet/ports/device-source.d.ts +28 -0
- package/dist/fleet/ports/device-source.js +18 -0
- package/dist/fleet/ports/device-source.js.map +1 -0
- package/dist/fleet/ports/process-manager.d.ts +110 -0
- package/dist/fleet/ports/process-manager.js +27 -0
- package/dist/fleet/ports/process-manager.js.map +1 -0
- package/dist/fleet/ports/state-registry.d.ts +49 -0
- package/dist/fleet/ports/state-registry.js +12 -0
- package/dist/fleet/ports/state-registry.js.map +1 -0
- package/dist/fleet/supervisor.d.ts +107 -0
- package/dist/fleet/supervisor.js +508 -0
- package/dist/fleet/supervisor.js.map +1 -0
- package/dist/grounding/grounder.d.ts +46 -0
- package/dist/grounding/grounder.js +82 -0
- package/dist/grounding/grounder.js.map +1 -0
- package/dist/inbound/acp/handlers/device.d.ts +43 -0
- package/dist/inbound/acp/handlers/device.js +153 -0
- package/dist/inbound/acp/handlers/device.js.map +1 -0
- package/dist/inbound/acp/handlers/initialize.d.ts +71 -0
- package/dist/inbound/acp/handlers/initialize.js +53 -0
- package/dist/inbound/acp/handlers/initialize.js.map +1 -0
- package/dist/inbound/acp/handlers/models.d.ts +16 -0
- package/dist/inbound/acp/handlers/models.js +23 -0
- package/dist/inbound/acp/handlers/models.js.map +1 -0
- package/dist/inbound/acp/handlers/session.d.ts +51 -0
- package/dist/inbound/acp/handlers/session.js +61 -0
- package/dist/inbound/acp/handlers/session.js.map +1 -0
- package/dist/inbound/acp/handlers/skills.d.ts +8 -0
- package/dist/inbound/acp/handlers/skills.js +9 -0
- package/dist/inbound/acp/handlers/skills.js.map +1 -0
- package/dist/inbound/acp/notifier.d.ts +35 -0
- package/dist/inbound/acp/notifier.js +45 -0
- package/dist/inbound/acp/notifier.js.map +1 -0
- package/dist/inbound/acp/router.d.ts +67 -0
- package/dist/inbound/acp/router.js +179 -0
- package/dist/inbound/acp/router.js.map +1 -0
- package/dist/inbound/cli/fleet-command.d.ts +34 -0
- package/dist/inbound/cli/fleet-command.js +792 -0
- package/dist/inbound/cli/fleet-command.js.map +1 -0
- package/dist/inbound/cli/main.d.ts +38 -0
- package/dist/inbound/cli/main.js +364 -0
- package/dist/inbound/cli/main.js.map +1 -0
- package/dist/inbound/cli/run-command.d.ts +101 -0
- package/dist/inbound/cli/run-command.js +405 -0
- package/dist/inbound/cli/run-command.js.map +1 -0
- package/dist/inbound/cli/skills-command.d.ts +39 -0
- package/dist/inbound/cli/skills-command.js +333 -0
- package/dist/inbound/cli/skills-command.js.map +1 -0
- package/dist/inbound/http/server.d.ts +7 -0
- package/dist/inbound/http/server.js +8 -0
- package/dist/inbound/http/server.js.map +1 -0
- package/dist/index.d.ts +66 -0
- package/dist/index.js +48 -0
- package/dist/index.js.map +1 -0
- package/dist/logger/index.d.ts +37 -0
- package/dist/logger/index.js +84 -0
- package/dist/logger/index.js.map +1 -0
- package/dist/mcp-client/autospawn.d.ts +67 -0
- package/dist/mcp-client/autospawn.js +173 -0
- package/dist/mcp-client/autospawn.js.map +1 -0
- package/dist/mcp-client/client.d.ts +78 -0
- package/dist/mcp-client/client.js +168 -0
- package/dist/mcp-client/client.js.map +1 -0
- package/dist/mcp-client/index.d.ts +7 -0
- package/dist/mcp-client/index.js +4 -0
- package/dist/mcp-client/index.js.map +1 -0
- package/dist/mcp-client/inproc.d.ts +47 -0
- package/dist/mcp-client/inproc.js +229 -0
- package/dist/mcp-client/inproc.js.map +1 -0
- package/dist/mcp-client/runtime.d.ts +34 -0
- package/dist/mcp-client/runtime.js +15 -0
- package/dist/mcp-client/runtime.js.map +1 -0
- package/dist/model/adapters/autoglm.d.ts +31 -0
- package/dist/model/adapters/autoglm.js +409 -0
- package/dist/model/adapters/autoglm.js.map +1 -0
- package/dist/model/adapters/base.d.ts +13 -0
- package/dist/model/adapters/base.js +27 -0
- package/dist/model/adapters/base.js.map +1 -0
- package/dist/model/adapters/guiowl.d.ts +1 -0
- package/dist/model/adapters/guiowl.js +253 -0
- package/dist/model/adapters/guiowl.js.map +1 -0
- package/dist/model/adapters/index.d.ts +6 -0
- package/dist/model/adapters/index.js +8 -0
- package/dist/model/adapters/index.js.map +1 -0
- package/dist/model/adapters/maiui.d.ts +1 -0
- package/dist/model/adapters/maiui.js +117 -0
- package/dist/model/adapters/maiui.js.map +1 -0
- package/dist/model/adapters/qwenvl.d.ts +1 -0
- package/dist/model/adapters/qwenvl.js +108 -0
- package/dist/model/adapters/qwenvl.js.map +1 -0
- package/dist/model/adapters/showui.d.ts +1 -0
- package/dist/model/adapters/showui.js +132 -0
- package/dist/model/adapters/showui.js.map +1 -0
- package/dist/model/adapters/tool-call.d.ts +6 -0
- package/dist/model/adapters/tool-call.js +102 -0
- package/dist/model/adapters/tool-call.js.map +1 -0
- package/dist/model/adapters/uitars.d.ts +1 -0
- package/dist/model/adapters/uitars.js +180 -0
- package/dist/model/adapters/uitars.js.map +1 -0
- package/dist/model/base.d.ts +32 -0
- package/dist/model/base.js +2 -0
- package/dist/model/base.js.map +1 -0
- package/dist/model/client.d.ts +26 -0
- package/dist/model/client.js +300 -0
- package/dist/model/client.js.map +1 -0
- package/dist/model/image/compress.d.ts +53 -0
- package/dist/model/image/compress.js +89 -0
- package/dist/model/image/compress.js.map +1 -0
- package/dist/model/image/transport.d.ts +134 -0
- package/dist/model/image/transport.js +154 -0
- package/dist/model/image/transport.js.map +1 -0
- package/dist/orchestrator-system-prompt.d.ts +6 -0
- package/dist/orchestrator-system-prompt.js +81 -0
- package/dist/orchestrator-system-prompt.js.map +1 -0
- package/dist/pi-context.d.ts +82 -0
- package/dist/pi-context.js +62 -0
- package/dist/pi-context.js.map +1 -0
- package/dist/pi-local-skills.d.ts +17 -0
- package/dist/pi-local-skills.js +24 -0
- package/dist/pi-local-skills.js.map +1 -0
- package/dist/plugins/acp/index.d.ts +46 -0
- package/dist/plugins/acp/index.js +111 -0
- package/dist/plugins/acp/index.js.map +1 -0
- package/dist/plugins/agent-sync/index.d.ts +40 -0
- package/dist/plugins/agent-sync/index.js +98 -0
- package/dist/plugins/agent-sync/index.js.map +1 -0
- package/dist/plugins/http-debug/index.d.ts +30 -0
- package/dist/plugins/http-debug/index.js +64 -0
- package/dist/plugins/http-debug/index.js.map +1 -0
- package/dist/plugins/http-debug/server.d.ts +92 -0
- package/dist/plugins/http-debug/server.js +464 -0
- package/dist/plugins/http-debug/server.js.map +1 -0
- package/dist/ports/agent-core.d.ts +158 -0
- package/dist/ports/agent-core.js +2 -0
- package/dist/ports/agent-core.js.map +1 -0
- package/dist/ports/agent-host.d.ts +125 -0
- package/dist/ports/agent-host.js +23 -0
- package/dist/ports/agent-host.js.map +1 -0
- package/dist/ports/device.d.ts +53 -0
- package/dist/ports/device.js +13 -0
- package/dist/ports/device.js.map +1 -0
- package/dist/ports/identity.d.ts +22 -0
- package/dist/ports/identity.js +9 -0
- package/dist/ports/identity.js.map +1 -0
- package/dist/ports/plugin.d.ts +62 -0
- package/dist/ports/plugin.js +35 -0
- package/dist/ports/plugin.js.map +1 -0
- package/dist/ports/transport.d.ts +32 -0
- package/dist/ports/transport.js +12 -0
- package/dist/ports/transport.js.map +1 -0
- package/dist/ports/vlm.d.ts +59 -0
- package/dist/ports/vlm.js +14 -0
- package/dist/ports/vlm.js.map +1 -0
- package/dist/test-lan-autoglm.d.ts +7 -0
- package/dist/test-lan-autoglm.js +46 -0
- package/dist/test-lan-autoglm.js.map +1 -0
- package/dist/test-mem-breakdown.d.ts +1 -0
- package/dist/test-mem-breakdown.js +103 -0
- package/dist/test-mem-breakdown.js.map +1 -0
- package/dist/test-mem.d.ts +1 -0
- package/dist/test-mem.js +60 -0
- package/dist/test-mem.js.map +1 -0
- package/dist/test-mobile-use.d.ts +1 -0
- package/dist/test-mobile-use.js +18 -0
- package/dist/test-mobile-use.js.map +1 -0
- package/dist/test-screenshot-loop.d.ts +1 -0
- package/dist/test-screenshot-loop.js +43 -0
- package/dist/test-screenshot-loop.js.map +1 -0
- package/dist/test-screenshot.d.ts +1 -0
- package/dist/test-screenshot.js +10 -0
- package/dist/test-screenshot.js.map +1 -0
- package/dist/test-ui-xml-dump.d.ts +15 -0
- package/dist/test-ui-xml-dump.js +49 -0
- package/dist/test-ui-xml-dump.js.map +1 -0
- package/dist/types.d.ts +69 -0
- package/dist/types.js +23 -0
- package/dist/types.js.map +1 -0
- package/package.json +94 -0
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import OpenAI from "openai";
|
|
2
|
+
import { detectAdapter, getAdapter } from "./adapters/base.js";
|
|
3
|
+
import "./adapters/index.js"; // register all adapters
|
|
4
|
+
const ACTION_MARKERS = ["finish(message=", "do(action=", "<tool_call>", "<answer>"];
|
|
5
|
+
export class OpenAIClient {
|
|
6
|
+
openai;
|
|
7
|
+
config;
|
|
8
|
+
adapter;
|
|
9
|
+
constructor(opts = {}) {
|
|
10
|
+
this.config = {
|
|
11
|
+
baseUrl: normalizeBaseUrl(opts.baseUrl ?? process.env.GUI_AGENT_BASE_URL ?? "https://api.openai.com/v1"),
|
|
12
|
+
apiKey: opts.apiKey ?? process.env.GUI_AGENT_API_KEY ?? "EMPTY",
|
|
13
|
+
modelName: opts.modelName ?? process.env.GUI_AGENT_MODEL ?? "gpt-4o",
|
|
14
|
+
maxTokens: opts.maxTokens ?? 3000,
|
|
15
|
+
temperature: opts.temperature ?? 0,
|
|
16
|
+
topP: opts.topP ?? 0.85,
|
|
17
|
+
};
|
|
18
|
+
this.openai = new OpenAI({
|
|
19
|
+
baseURL: this.config.baseUrl,
|
|
20
|
+
apiKey: this.config.apiKey,
|
|
21
|
+
timeout: 120_000,
|
|
22
|
+
maxRetries: 4,
|
|
23
|
+
});
|
|
24
|
+
this.adapter =
|
|
25
|
+
typeof opts.adapter === "string" ? getAdapter(opts.adapter)
|
|
26
|
+
: opts.adapter instanceof Object && "name" in opts.adapter ? opts.adapter
|
|
27
|
+
: detectAdapter(this.config.modelName);
|
|
28
|
+
}
|
|
29
|
+
get modelName() { return this.config.modelName; }
|
|
30
|
+
get adapterName() { return this.adapter.name; }
|
|
31
|
+
buildMessages(task, screenInfo, context, isFirst, lang) {
|
|
32
|
+
return this.adapter.buildMessages(task, screenInfo, context, isFirst, lang);
|
|
33
|
+
}
|
|
34
|
+
async request(messages, verboseOrOptions = false, signalArg) {
|
|
35
|
+
const opts = typeof verboseOrOptions === "boolean"
|
|
36
|
+
? { verbose: verboseOrOptions, signal: signalArg }
|
|
37
|
+
: { ...verboseOrOptions, signal: verboseOrOptions.signal ?? signalArg };
|
|
38
|
+
const verbose = opts.verbose ?? false;
|
|
39
|
+
const signal = opts.signal;
|
|
40
|
+
const onTextDelta = opts.onTextDelta;
|
|
41
|
+
const emitDelta = (s) => {
|
|
42
|
+
if (!s || !onTextDelta)
|
|
43
|
+
return;
|
|
44
|
+
try {
|
|
45
|
+
const ret = onTextDelta(s);
|
|
46
|
+
if (ret && typeof ret.then === "function") {
|
|
47
|
+
ret.catch(() => { });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// hook failures must not abort the model stream
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
// Some providers (e.g. Zhipu) occasionally RESET long streaming responses.
|
|
55
|
+
// Allow disabling streaming via env for robustness.
|
|
56
|
+
const useStream = process.env.GUI_AGENT_STREAM !== "0";
|
|
57
|
+
if (!useStream) {
|
|
58
|
+
const resp = await this.openai.chat.completions.create({
|
|
59
|
+
model: this.config.modelName,
|
|
60
|
+
messages: messages,
|
|
61
|
+
max_tokens: this.config.maxTokens,
|
|
62
|
+
temperature: this.config.temperature,
|
|
63
|
+
top_p: this.config.topP,
|
|
64
|
+
}, { signal });
|
|
65
|
+
const rawContent = resp.choices?.[0]?.message?.content ?? "";
|
|
66
|
+
if (verbose)
|
|
67
|
+
process.stdout.write(rawContent);
|
|
68
|
+
emitDelta(rawContent);
|
|
69
|
+
const [thinking, action] = splitRaw(rawContent);
|
|
70
|
+
return { rawContent, thinking, action };
|
|
71
|
+
}
|
|
72
|
+
// ── streaming path with chunk-level watchdog ───────────────────────────
|
|
73
|
+
//
|
|
74
|
+
// ARouter / OpenRouter occasionally hold a request in `: OPENROUTER PROCESSING`
|
|
75
|
+
// SSE-comment heartbeats while the upstream model is stuck. The OpenAI SDK's
|
|
76
|
+
// socket timeout never fires (bytes ARE flowing — they're just comments the
|
|
77
|
+
// SSE parser discards), and the `for await` yields zero chunks indefinitely.
|
|
78
|
+
// To bound the worst case we layer two watchdog timers on top of the SDK:
|
|
79
|
+
//
|
|
80
|
+
// • first-chunk: aborts if no SSE chunk (delta-bearing or empty) lands within
|
|
81
|
+
// `GUI_AGENT_FIRST_CHUNK_TIMEOUT_MS` (default 30s).
|
|
82
|
+
// • inter-chunk: once the first chunk lands, aborts if subsequent chunks
|
|
83
|
+
// stall for `GUI_AGENT_INTER_CHUNK_TIMEOUT_MS` (default 60s).
|
|
84
|
+
//
|
|
85
|
+
// Both are converted to `Error("model stream stalled …")` so upstream
|
|
86
|
+
// `agent-runtime/adapters/openai.ts` logs `vlm.predict.failed` and the
|
|
87
|
+
// SessionManager `onError` fallback surfaces a `task:notice` to the UI
|
|
88
|
+
// instead of leaving the worker silently parked.
|
|
89
|
+
const FIRST_CHUNK_TIMEOUT_MS = readPositiveInt(process.env.GUI_AGENT_FIRST_CHUNK_TIMEOUT_MS, 30_000);
|
|
90
|
+
const INTER_CHUNK_TIMEOUT_MS = readPositiveInt(process.env.GUI_AGENT_INTER_CHUNK_TIMEOUT_MS, 60_000);
|
|
91
|
+
// The watchdog runs side-by-side with the iterator: every `iter.next()`
|
|
92
|
+
// (and the initial `create()`) is wrapped in `withStallTimeout` which
|
|
93
|
+
// fires a `setTimeout` and races it against the underlying promise. If
|
|
94
|
+
// the timer wins, the wrapper rejects with a stall error AND aborts the
|
|
95
|
+
// SDK's signal — both paths are needed because some iterators (mocks,
|
|
96
|
+
// and providers that send `: OPENROUTER PROCESSING` SSE comments to
|
|
97
|
+
// keep sockets warm) don't surface AbortSignal cancellation cleanly,
|
|
98
|
+
// so the bare SDK idle timer never fires.
|
|
99
|
+
const controller = new AbortController();
|
|
100
|
+
const externalAbortHandler = () => {
|
|
101
|
+
controller.abort(signal.reason);
|
|
102
|
+
};
|
|
103
|
+
if (signal) {
|
|
104
|
+
if (signal.aborted) {
|
|
105
|
+
controller.abort(signal.reason);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
signal.addEventListener("abort", externalAbortHandler, { once: true });
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
let phase = "first";
|
|
112
|
+
const cleanup = () => {
|
|
113
|
+
signal?.removeEventListener("abort", externalAbortHandler);
|
|
114
|
+
};
|
|
115
|
+
const withStallTimeout = (work) => {
|
|
116
|
+
const ms = phase === "first" ? FIRST_CHUNK_TIMEOUT_MS : INTER_CHUNK_TIMEOUT_MS;
|
|
117
|
+
return new Promise((resolve, reject) => {
|
|
118
|
+
let settled = false;
|
|
119
|
+
const timer = setTimeout(() => {
|
|
120
|
+
if (settled)
|
|
121
|
+
return;
|
|
122
|
+
settled = true;
|
|
123
|
+
const reason = phase === "first"
|
|
124
|
+
? `model stream stalled: no chunk within ${ms}ms (first-chunk timeout)`
|
|
125
|
+
: `model stream stalled: no chunk within ${ms}ms after partial output (inter-chunk timeout)`;
|
|
126
|
+
const err = new Error(reason);
|
|
127
|
+
controller.abort(err);
|
|
128
|
+
reject(err);
|
|
129
|
+
}, ms);
|
|
130
|
+
work.then((v) => {
|
|
131
|
+
if (settled)
|
|
132
|
+
return;
|
|
133
|
+
settled = true;
|
|
134
|
+
clearTimeout(timer);
|
|
135
|
+
resolve(v);
|
|
136
|
+
}, (e) => {
|
|
137
|
+
if (settled)
|
|
138
|
+
return;
|
|
139
|
+
settled = true;
|
|
140
|
+
clearTimeout(timer);
|
|
141
|
+
reject(e);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
};
|
|
145
|
+
let stream;
|
|
146
|
+
try {
|
|
147
|
+
stream = (await withStallTimeout(this.openai.chat.completions.create({
|
|
148
|
+
model: this.config.modelName,
|
|
149
|
+
messages: messages,
|
|
150
|
+
max_tokens: this.config.maxTokens,
|
|
151
|
+
temperature: this.config.temperature,
|
|
152
|
+
top_p: this.config.topP,
|
|
153
|
+
stream: true,
|
|
154
|
+
}, { signal: controller.signal })));
|
|
155
|
+
}
|
|
156
|
+
catch (e) {
|
|
157
|
+
cleanup();
|
|
158
|
+
throw e;
|
|
159
|
+
}
|
|
160
|
+
let rawContent = "";
|
|
161
|
+
let buffer = "";
|
|
162
|
+
let inAction = false;
|
|
163
|
+
const iter = stream[Symbol.asyncIterator]();
|
|
164
|
+
try {
|
|
165
|
+
while (true) {
|
|
166
|
+
const result = await withStallTimeout(iter.next());
|
|
167
|
+
if (result.done)
|
|
168
|
+
break;
|
|
169
|
+
const chunk = result.value;
|
|
170
|
+
// Any SSE chunk (even an empty role-only frame) means the upstream is
|
|
171
|
+
// still alive — swap to the inter-chunk budget for the next wait.
|
|
172
|
+
phase = "inter";
|
|
173
|
+
if (signal?.aborted) {
|
|
174
|
+
const e = new Error("aborted");
|
|
175
|
+
e.name = "AbortError";
|
|
176
|
+
throw e;
|
|
177
|
+
}
|
|
178
|
+
if (!chunk.choices.length)
|
|
179
|
+
continue;
|
|
180
|
+
const delta = chunk.choices[0].delta;
|
|
181
|
+
// Reasoning models (MAI-UI etc.) emit reasoning_content before content
|
|
182
|
+
const reasoning = delta.reasoning_content;
|
|
183
|
+
if (typeof reasoning === "string" && reasoning) {
|
|
184
|
+
rawContent += reasoning;
|
|
185
|
+
if (!inAction) {
|
|
186
|
+
if (verbose)
|
|
187
|
+
process.stdout.write(reasoning);
|
|
188
|
+
emitDelta(reasoning);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
const content = delta.content ?? "";
|
|
192
|
+
if (!content)
|
|
193
|
+
continue;
|
|
194
|
+
rawContent += content;
|
|
195
|
+
if (inAction)
|
|
196
|
+
continue;
|
|
197
|
+
buffer += content;
|
|
198
|
+
let markerFound = false;
|
|
199
|
+
for (const marker of ACTION_MARKERS) {
|
|
200
|
+
if (buffer.includes(marker)) {
|
|
201
|
+
const pre = buffer.slice(0, buffer.indexOf(marker));
|
|
202
|
+
if (verbose) {
|
|
203
|
+
process.stdout.write(pre);
|
|
204
|
+
process.stdout.write("\n");
|
|
205
|
+
}
|
|
206
|
+
emitDelta(pre);
|
|
207
|
+
inAction = true;
|
|
208
|
+
markerFound = true;
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if (!markerFound) {
|
|
213
|
+
// Only flush buffer if no partial marker at end
|
|
214
|
+
const partialMatch = ACTION_MARKERS.some((m) => Array.from({ length: m.length - 1 }, (_, k) => k + 1)
|
|
215
|
+
.some((k) => buffer.endsWith(m.slice(0, k))));
|
|
216
|
+
if (!partialMatch) {
|
|
217
|
+
if (verbose)
|
|
218
|
+
process.stdout.write(buffer);
|
|
219
|
+
emitDelta(buffer);
|
|
220
|
+
buffer = "";
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
catch (e) {
|
|
226
|
+
cleanup();
|
|
227
|
+
// Best-effort cancel the underlying stream so the SDK / fetch socket
|
|
228
|
+
// is freed even when our watchdog fires while the iterator is still
|
|
229
|
+
// parked.
|
|
230
|
+
try {
|
|
231
|
+
await iter.return?.(undefined);
|
|
232
|
+
}
|
|
233
|
+
catch { /* ignore */ }
|
|
234
|
+
throw e;
|
|
235
|
+
}
|
|
236
|
+
cleanup();
|
|
237
|
+
const [thinking, action] = splitRaw(rawContent);
|
|
238
|
+
return { rawContent, thinking, action };
|
|
239
|
+
}
|
|
240
|
+
parseResponse(raw) {
|
|
241
|
+
return this.adapter.parseResponse(raw);
|
|
242
|
+
}
|
|
243
|
+
updateContext(context, response, parsed) {
|
|
244
|
+
return this.adapter.updateContext(context, response, parsed);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Ensure the OpenAI baseURL ends with a versioned API path. A bare host
|
|
249
|
+
* like `https://api.arouter.ai` causes the SDK to POST `/chat/completions`,
|
|
250
|
+
* which ARouter's edge maps to the wrong upstream and surfaces as
|
|
251
|
+
* `HTTP 502 status code (no body)`. The canonical OpenAI-compatible path
|
|
252
|
+
* is `/v1/chat/completions`, so when the supplied baseURL has no path
|
|
253
|
+
* (just origin), append `/v1`. Anything that already has a path
|
|
254
|
+
* (e.g. custom `/api/v2`, Azure deployments) is left untouched.
|
|
255
|
+
*/
|
|
256
|
+
function normalizeBaseUrl(input) {
|
|
257
|
+
if (!input)
|
|
258
|
+
return input;
|
|
259
|
+
let url;
|
|
260
|
+
try {
|
|
261
|
+
url = new URL(input);
|
|
262
|
+
}
|
|
263
|
+
catch {
|
|
264
|
+
return input;
|
|
265
|
+
}
|
|
266
|
+
const path = url.pathname.replace(/\/+$/, "");
|
|
267
|
+
if (path === "" || path === "/") {
|
|
268
|
+
url.pathname = "/v1";
|
|
269
|
+
return url.toString().replace(/\/+$/, "");
|
|
270
|
+
}
|
|
271
|
+
return input.replace(/\/+$/, "");
|
|
272
|
+
}
|
|
273
|
+
function readPositiveInt(raw, fallback) {
|
|
274
|
+
if (!raw)
|
|
275
|
+
return fallback;
|
|
276
|
+
const n = Number(raw);
|
|
277
|
+
if (!Number.isFinite(n) || n <= 0)
|
|
278
|
+
return fallback;
|
|
279
|
+
return Math.floor(n);
|
|
280
|
+
}
|
|
281
|
+
function splitRaw(content) {
|
|
282
|
+
const tcM = content.match(/<tool_call>([\s\S]*?)<\/tool_call>/);
|
|
283
|
+
if (tcM)
|
|
284
|
+
return [content.slice(0, tcM.index).trim(), tcM[0]];
|
|
285
|
+
if (content.includes("<answer>")) {
|
|
286
|
+
const [pre, post] = content.split("<answer>", 2);
|
|
287
|
+
return [pre.replace(/<\/?think>/g, "").trim(), post.replace("</answer>", "").trim()];
|
|
288
|
+
}
|
|
289
|
+
const lastDo = content.lastIndexOf("do(action=");
|
|
290
|
+
const lastFin = content.lastIndexOf("finish(message=");
|
|
291
|
+
const idx = lastDo >= 0 && lastFin >= 0 ? Math.max(lastDo, lastFin)
|
|
292
|
+
: lastDo >= 0 ? lastDo
|
|
293
|
+
: lastFin >= 0 ? lastFin
|
|
294
|
+
: -1;
|
|
295
|
+
if (idx >= 0) {
|
|
296
|
+
return [content.slice(0, idx).trim(), content.slice(idx)];
|
|
297
|
+
}
|
|
298
|
+
return ["", content];
|
|
299
|
+
}
|
|
300
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/model/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VLM image compression — single-purpose utility that produces an
|
|
3
|
+
* ARouter / llama.cpp friendly JPEG from raw screenshot bytes.
|
|
4
|
+
*
|
|
5
|
+
* Why this lives here and not in `device-mcp-server`:
|
|
6
|
+
* - mcp-server is a protocol-layer service. Other consumers (debug
|
|
7
|
+
* viewers, e2e recordings, research tools) want 1:1 high-fidelity
|
|
8
|
+
* captures. Compression is a VLM-specific application-layer concern.
|
|
9
|
+
* - The boundary `mcp-server v0.2.3` deliberately defaults
|
|
10
|
+
* `SS_MAX_EDGE=Infinity` to push compression up the stack — this
|
|
11
|
+
* module fulfils that contract on the device-agent side.
|
|
12
|
+
*
|
|
13
|
+
* Why 1280-edge JPEG q80:
|
|
14
|
+
* - AutoGLM-Phone-9B (= GLM-4.1V-9B-Thinking) vision encoder uses 14-px
|
|
15
|
+
* patches with `image_size=336` and dynamic resize. A 1280-edge input
|
|
16
|
+
* is already past the model's effective perception ceiling — bigger
|
|
17
|
+
* bytes are pure waste.
|
|
18
|
+
* - mozjpeg q80 yields ~20× compression vs raw PNG with no measurable
|
|
19
|
+
* visual loss for UI screenshots (high-frequency text rendering is
|
|
20
|
+
* the worst case and stays sharp at q80).
|
|
21
|
+
* - The combination keeps post-base64 body under ~330KB, well below
|
|
22
|
+
* ARouter's 5MB body limit and llama.cpp's 10MB image cap.
|
|
23
|
+
*/
|
|
24
|
+
export interface CompressedImage {
|
|
25
|
+
bytes: Buffer;
|
|
26
|
+
mime: "image/jpeg";
|
|
27
|
+
width: number;
|
|
28
|
+
height: number;
|
|
29
|
+
}
|
|
30
|
+
export interface CompressOptions {
|
|
31
|
+
/** Override `BEEOS_VLM_MAX_EDGE` env (default 1280). */
|
|
32
|
+
maxEdge?: number;
|
|
33
|
+
/** Override `BEEOS_VLM_JPEG_QUALITY` env (default 80, range 1-100). */
|
|
34
|
+
jpegQuality?: number;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Resize (long edge ≤ `maxEdge`) and re-encode an image as mozjpeg
|
|
38
|
+
* `image/jpeg`. Idempotent on already-compressed JPEGs that fit under
|
|
39
|
+
* `maxEdge`: sharp will still re-encode but bytes converge fast.
|
|
40
|
+
*
|
|
41
|
+
* Inputs are accepted in any sharp-readable format (PNG, JPEG, WebP, ...).
|
|
42
|
+
* Output MIME is always `image/jpeg` — this is intentional, see module
|
|
43
|
+
* docstring.
|
|
44
|
+
*
|
|
45
|
+
* Resilience: if `sharp` cannot decode the input (e.g. truncated bytes,
|
|
46
|
+
* corrupt frames, or test-fixture sentinels like `"AAAA"`), the
|
|
47
|
+
* function returns the input bytes unchanged tagged as `image/jpeg`
|
|
48
|
+
* with `width=height=0`. The caller's transport then ships them as-is
|
|
49
|
+
* — letting the upstream model surface the decoding error rather than
|
|
50
|
+
* silently dropping the screenshot. This matches the legacy
|
|
51
|
+
* "wrap-and-forward" semantics of pre-A1 device-agent.
|
|
52
|
+
*/
|
|
53
|
+
export declare function compressForVlm(buf: Buffer, opts?: CompressOptions): Promise<CompressedImage>;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VLM image compression — single-purpose utility that produces an
|
|
3
|
+
* ARouter / llama.cpp friendly JPEG from raw screenshot bytes.
|
|
4
|
+
*
|
|
5
|
+
* Why this lives here and not in `device-mcp-server`:
|
|
6
|
+
* - mcp-server is a protocol-layer service. Other consumers (debug
|
|
7
|
+
* viewers, e2e recordings, research tools) want 1:1 high-fidelity
|
|
8
|
+
* captures. Compression is a VLM-specific application-layer concern.
|
|
9
|
+
* - The boundary `mcp-server v0.2.3` deliberately defaults
|
|
10
|
+
* `SS_MAX_EDGE=Infinity` to push compression up the stack — this
|
|
11
|
+
* module fulfils that contract on the device-agent side.
|
|
12
|
+
*
|
|
13
|
+
* Why 1280-edge JPEG q80:
|
|
14
|
+
* - AutoGLM-Phone-9B (= GLM-4.1V-9B-Thinking) vision encoder uses 14-px
|
|
15
|
+
* patches with `image_size=336` and dynamic resize. A 1280-edge input
|
|
16
|
+
* is already past the model's effective perception ceiling — bigger
|
|
17
|
+
* bytes are pure waste.
|
|
18
|
+
* - mozjpeg q80 yields ~20× compression vs raw PNG with no measurable
|
|
19
|
+
* visual loss for UI screenshots (high-frequency text rendering is
|
|
20
|
+
* the worst case and stays sharp at q80).
|
|
21
|
+
* - The combination keeps post-base64 body under ~330KB, well below
|
|
22
|
+
* ARouter's 5MB body limit and llama.cpp's 10MB image cap.
|
|
23
|
+
*/
|
|
24
|
+
import sharp from "sharp";
|
|
25
|
+
const DEFAULT_MAX_EDGE = 1280;
|
|
26
|
+
const DEFAULT_JPEG_QUALITY = 80;
|
|
27
|
+
/**
|
|
28
|
+
* Resize (long edge ≤ `maxEdge`) and re-encode an image as mozjpeg
|
|
29
|
+
* `image/jpeg`. Idempotent on already-compressed JPEGs that fit under
|
|
30
|
+
* `maxEdge`: sharp will still re-encode but bytes converge fast.
|
|
31
|
+
*
|
|
32
|
+
* Inputs are accepted in any sharp-readable format (PNG, JPEG, WebP, ...).
|
|
33
|
+
* Output MIME is always `image/jpeg` — this is intentional, see module
|
|
34
|
+
* docstring.
|
|
35
|
+
*
|
|
36
|
+
* Resilience: if `sharp` cannot decode the input (e.g. truncated bytes,
|
|
37
|
+
* corrupt frames, or test-fixture sentinels like `"AAAA"`), the
|
|
38
|
+
* function returns the input bytes unchanged tagged as `image/jpeg`
|
|
39
|
+
* with `width=height=0`. The caller's transport then ships them as-is
|
|
40
|
+
* — letting the upstream model surface the decoding error rather than
|
|
41
|
+
* silently dropping the screenshot. This matches the legacy
|
|
42
|
+
* "wrap-and-forward" semantics of pre-A1 device-agent.
|
|
43
|
+
*/
|
|
44
|
+
export async function compressForVlm(buf, opts = {}) {
|
|
45
|
+
const maxEdge = resolveInt(opts.maxEdge, "BEEOS_VLM_MAX_EDGE", DEFAULT_MAX_EDGE);
|
|
46
|
+
const jpegQuality = clampQuality(resolveInt(opts.jpegQuality, "BEEOS_VLM_JPEG_QUALITY", DEFAULT_JPEG_QUALITY));
|
|
47
|
+
try {
|
|
48
|
+
const meta = await sharp(buf, { failOn: "none" }).metadata();
|
|
49
|
+
const srcW = meta.width ?? 0;
|
|
50
|
+
const srcH = meta.height ?? 0;
|
|
51
|
+
const longEdge = Math.max(srcW, srcH);
|
|
52
|
+
let pipeline = sharp(buf, { failOn: "none" });
|
|
53
|
+
if (longEdge > maxEdge) {
|
|
54
|
+
pipeline = srcW >= srcH
|
|
55
|
+
? pipeline.resize({ width: maxEdge, withoutEnlargement: true })
|
|
56
|
+
: pipeline.resize({ height: maxEdge, withoutEnlargement: true });
|
|
57
|
+
}
|
|
58
|
+
const bytes = await pipeline.jpeg({ quality: jpegQuality, mozjpeg: true }).toBuffer();
|
|
59
|
+
const out = await sharp(bytes).metadata();
|
|
60
|
+
return {
|
|
61
|
+
bytes,
|
|
62
|
+
mime: "image/jpeg",
|
|
63
|
+
width: out.width ?? srcW,
|
|
64
|
+
height: out.height ?? srcH,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return { bytes: buf, mime: "image/jpeg", width: 0, height: 0 };
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function resolveInt(explicit, envKey, fallback) {
|
|
72
|
+
if (typeof explicit === "number" && Number.isFinite(explicit) && explicit > 0)
|
|
73
|
+
return explicit;
|
|
74
|
+
const raw = process.env[envKey];
|
|
75
|
+
if (!raw)
|
|
76
|
+
return fallback;
|
|
77
|
+
const parsed = parseInt(raw, 10);
|
|
78
|
+
if (!Number.isFinite(parsed) || parsed <= 0)
|
|
79
|
+
return fallback;
|
|
80
|
+
return parsed;
|
|
81
|
+
}
|
|
82
|
+
function clampQuality(q) {
|
|
83
|
+
if (q < 1)
|
|
84
|
+
return 1;
|
|
85
|
+
if (q > 100)
|
|
86
|
+
return 100;
|
|
87
|
+
return Math.round(q);
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=compress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compress.js","sourceRoot":"","sources":["../../../src/model/image/compress.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ImageTransport — strategy abstraction for delivering a compressed VLM
|
|
3
|
+
* image to the model.
|
|
4
|
+
*
|
|
5
|
+
* bytes ──▶ Transport ──▶ ImageRef
|
|
6
|
+
*
|
|
7
|
+
* Two concrete strategies live in the codebase:
|
|
8
|
+
* - `DataUrlTransport` (Phase A) → inline `data:<mime>;base64,...`
|
|
9
|
+
* - `HttpUrlTransport` (Phase B) → presign + PUT to S3, return signed
|
|
10
|
+
* GET URL
|
|
11
|
+
*
|
|
12
|
+
* `FallbackTransport` composes any two strategies so production traffic
|
|
13
|
+
* can be configured to "prefer http-url, gracefully degrade to data-url
|
|
14
|
+
* on transient upload failure" — keeping a hard correctness floor while
|
|
15
|
+
* still gaining the body-size win when everything is healthy.
|
|
16
|
+
*/
|
|
17
|
+
import { type AgentGatewayIdentity, type PresignFilePair } from "../../adapters/agent-gateway-client.js";
|
|
18
|
+
import type { ImageRef } from "../../types.js";
|
|
19
|
+
export type ImageMime = "image/jpeg" | "image/png";
|
|
20
|
+
export interface ImageTransport {
|
|
21
|
+
/** Stable, log-friendly identifier — useful for metrics/labels. */
|
|
22
|
+
readonly name: string;
|
|
23
|
+
send(bytes: Buffer, mime: ImageMime): Promise<ImageRef>;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Inline-base64 transport. Always succeeds (modulo OOM); the body bloat
|
|
27
|
+
* is bounded only by the input bytes — pair this with `compressForVlm`
|
|
28
|
+
* upstream to stay below ARouter's 5MB body cap.
|
|
29
|
+
*/
|
|
30
|
+
export declare class DataUrlTransport implements ImageTransport {
|
|
31
|
+
readonly name = "data-url";
|
|
32
|
+
send(bytes: Buffer, mime: ImageMime): Promise<ImageRef>;
|
|
33
|
+
}
|
|
34
|
+
export interface HttpUrlFileClient {
|
|
35
|
+
presignFileUpload(args: {
|
|
36
|
+
fileName: string;
|
|
37
|
+
mimeType: string;
|
|
38
|
+
}): Promise<PresignFilePair>;
|
|
39
|
+
putPresignedBytes(args: {
|
|
40
|
+
uploadUrl: string;
|
|
41
|
+
bytes: Uint8Array;
|
|
42
|
+
mimeType: string;
|
|
43
|
+
}): Promise<void>;
|
|
44
|
+
}
|
|
45
|
+
export interface HttpUrlTransportOptions {
|
|
46
|
+
/**
|
|
47
|
+
* Object-name prefix passed as `fileName` to `presignFileUpload`.
|
|
48
|
+
* Defaults to `vlm-screenshots/`. Lifecycle rules in Phase B8 attach
|
|
49
|
+
* to this prefix for automatic 24h cleanup.
|
|
50
|
+
*/
|
|
51
|
+
keyPrefix?: string;
|
|
52
|
+
/** Test seam — defaults to `crypto.randomUUID()`. */
|
|
53
|
+
randomUUID?: () => string;
|
|
54
|
+
/** Test seam — defaults to `Date.now()`. */
|
|
55
|
+
now?: () => number;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Adapter implementation of `HttpUrlFileClient` that hits the live
|
|
59
|
+
* Agent Gateway over HTTP/1.1 with Ed25519 auth. Suitable for
|
|
60
|
+
* production wiring; tests should pass a mock `HttpUrlFileClient`.
|
|
61
|
+
*/
|
|
62
|
+
export declare class AgentGatewayFileClient implements HttpUrlFileClient {
|
|
63
|
+
private readonly opts;
|
|
64
|
+
constructor(opts: {
|
|
65
|
+
agentGatewayUrl: string;
|
|
66
|
+
identity: AgentGatewayIdentity;
|
|
67
|
+
timeoutMs?: number;
|
|
68
|
+
});
|
|
69
|
+
presignFileUpload(args: {
|
|
70
|
+
fileName: string;
|
|
71
|
+
mimeType: string;
|
|
72
|
+
}): Promise<PresignFilePair>;
|
|
73
|
+
putPresignedBytes(args: {
|
|
74
|
+
uploadUrl: string;
|
|
75
|
+
bytes: Uint8Array;
|
|
76
|
+
mimeType: string;
|
|
77
|
+
}): Promise<void>;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Resource-link transport — pre-signs an S3/MinIO PUT URL via Agent
|
|
81
|
+
* Gateway, uploads the (already-compressed) image bytes, and returns
|
|
82
|
+
* the paired pre-signed GET URL as an `kind: "http-url"` `ImageRef`.
|
|
83
|
+
*
|
|
84
|
+
* Why this exists:
|
|
85
|
+
*
|
|
86
|
+
* - ARouter / Cloudfront / nginx in front of `llama.cpp` cap request
|
|
87
|
+
* bodies at ≈5 MB. A raw 1080×1920 PNG screenshot base64-encoded
|
|
88
|
+
* in a chat-completion message routinely overflows that cap, so
|
|
89
|
+
* the only robust path for production traffic is to ship a URL,
|
|
90
|
+
* not bytes.
|
|
91
|
+
* - `llama.cpp`'s vision server fetches `image_url`s natively
|
|
92
|
+
* (subject to its own ≈10 MB / 10 s download caps), making this a
|
|
93
|
+
* transport-only change — no model-side adapter rewrite required.
|
|
94
|
+
*
|
|
95
|
+
* Errors:
|
|
96
|
+
* - Both steps surface `AgentGatewayError`. Compose with
|
|
97
|
+
* `FallbackTransport(http, data)` if the caller wants a graceful
|
|
98
|
+
* degradation to inline base64 on transient upload failure.
|
|
99
|
+
*
|
|
100
|
+
* Body sigv4 caveat: the `Content-Type` MUST equal what was passed at
|
|
101
|
+
* presign time, otherwise S3 returns 403 (signature mismatch). We
|
|
102
|
+
* forward `mime` to both calls so this is automatic.
|
|
103
|
+
*/
|
|
104
|
+
export declare class HttpUrlTransport implements ImageTransport {
|
|
105
|
+
private readonly client;
|
|
106
|
+
readonly name = "http-url";
|
|
107
|
+
private readonly keyPrefix;
|
|
108
|
+
private readonly randomUUID;
|
|
109
|
+
private readonly now;
|
|
110
|
+
constructor(client: HttpUrlFileClient, opts?: HttpUrlTransportOptions);
|
|
111
|
+
send(bytes: Buffer, mime: ImageMime): Promise<ImageRef>;
|
|
112
|
+
}
|
|
113
|
+
export interface FallbackTransportLogger {
|
|
114
|
+
warn(msg: string, fields?: Record<string, unknown>): void;
|
|
115
|
+
}
|
|
116
|
+
export interface FallbackTransportOptions {
|
|
117
|
+
logger?: FallbackTransportLogger;
|
|
118
|
+
/** Hook for monitoring — invoked once per fallback path taken. */
|
|
119
|
+
onFallback?: (reason: unknown) => void;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Try `primary`; if it throws, log and fall back to `fallback`. The
|
|
123
|
+
* second transport's failure propagates to the caller — we never silently
|
|
124
|
+
* swallow a degraded-mode error.
|
|
125
|
+
*/
|
|
126
|
+
export declare class FallbackTransport implements ImageTransport {
|
|
127
|
+
private readonly primary;
|
|
128
|
+
private readonly fallback;
|
|
129
|
+
readonly name: string;
|
|
130
|
+
private readonly logger;
|
|
131
|
+
private readonly onFallback?;
|
|
132
|
+
constructor(primary: ImageTransport, fallback: ImageTransport, opts?: FallbackTransportOptions);
|
|
133
|
+
send(bytes: Buffer, mime: ImageMime): Promise<ImageRef>;
|
|
134
|
+
}
|