@glassly/engine 0.3.5-beta.734 → 0.3.5-beta.760

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/build/engine.d.ts +3 -0
  2. package/build/engine.d.ts.map +1 -1
  3. package/build/engine.js +4 -0
  4. package/build/engine.js.map +1 -1
  5. package/build/facades/glasses.d.ts +5 -1
  6. package/build/facades/glasses.d.ts.map +1 -1
  7. package/build/facades/glasses.js +5 -0
  8. package/build/facades/glasses.js.map +1 -1
  9. package/build/generated/releaseMetadata.js +3 -3
  10. package/build/generated/releaseMetadata.js.map +1 -1
  11. package/build/services/GestureDotsService.d.ts.map +1 -1
  12. package/build/services/GestureDotsService.js +2 -1
  13. package/build/services/GestureDotsService.js.map +1 -1
  14. package/build/services/GlassesTouchInput.d.ts +2 -1
  15. package/build/services/GlassesTouchInput.d.ts.map +1 -1
  16. package/build/services/GlassesTouchInput.js +64 -26
  17. package/build/services/GlassesTouchInput.js.map +1 -1
  18. package/build/services/LocalLlmModelManager.d.ts +3 -1
  19. package/build/services/LocalLlmModelManager.d.ts.map +1 -1
  20. package/build/services/LocalLlmModelManager.js +13 -5
  21. package/build/services/LocalLlmModelManager.js.map +1 -1
  22. package/build/services/LocalLlmPrompt.d.ts +10 -9
  23. package/build/services/LocalLlmPrompt.d.ts.map +1 -1
  24. package/build/services/LocalLlmPrompt.js +43 -32
  25. package/build/services/LocalLlmPrompt.js.map +1 -1
  26. package/build/services/LocalLlmProvider.d.ts.map +1 -1
  27. package/build/services/LocalLlmProvider.js +39 -20
  28. package/build/services/LocalLlmProvider.js.map +1 -1
  29. package/build/services/LocalMiniappRuntime.d.ts +19 -4
  30. package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
  31. package/build/services/LocalMiniappRuntime.js +68 -125
  32. package/build/services/LocalMiniappRuntime.js.map +1 -1
  33. package/build/services/SceneRenderer.d.ts.map +1 -1
  34. package/build/services/SceneRenderer.js +3 -1
  35. package/build/services/SceneRenderer.js.map +1 -1
  36. package/build/services/actionInvoke.d.ts +37 -0
  37. package/build/services/actionInvoke.d.ts.map +1 -0
  38. package/build/services/actionInvoke.js +89 -0
  39. package/build/services/actionInvoke.js.map +1 -0
  40. package/build/services/appleWatch/AppleWatchLink.d.ts +42 -0
  41. package/build/services/appleWatch/AppleWatchLink.d.ts.map +1 -0
  42. package/build/services/appleWatch/AppleWatchLink.js +259 -0
  43. package/build/services/appleWatch/AppleWatchLink.js.map +1 -0
  44. package/build/services/controllers.d.ts.map +1 -1
  45. package/build/services/controllers.js +16 -0
  46. package/build/services/controllers.js.map +1 -1
  47. package/build/services/settingsBridge.d.ts +4 -4
  48. package/build/services/settingsBridge.d.ts.map +1 -1
  49. package/build/services/settingsBridge.js +9 -4
  50. package/build/services/settingsBridge.js.map +1 -1
  51. package/build/stores/bluetoothSettingKeys.d.ts +2 -0
  52. package/build/stores/bluetoothSettingKeys.d.ts.map +1 -1
  53. package/build/stores/bluetoothSettingKeys.js +17 -0
  54. package/build/stores/bluetoothSettingKeys.js.map +1 -1
  55. package/build/stores/settings.d.ts.map +1 -1
  56. package/build/stores/settings.js +32 -2
  57. package/build/stores/settings.js.map +1 -1
  58. package/build/types/capabilities/rayneo-io.d.ts.map +1 -1
  59. package/build/types/capabilities/rayneo-io.js +2 -0
  60. package/build/types/capabilities/rayneo-io.js.map +1 -1
  61. package/build/types/enums.d.ts +2 -1
  62. package/build/types/enums.d.ts.map +1 -1
  63. package/build/types/enums.js +1 -0
  64. package/build/types/enums.js.map +1 -1
  65. package/build/utils/display/scene/index.d.ts +1 -1
  66. package/build/utils/display/scene/index.d.ts.map +1 -1
  67. package/build/utils/display/scene/index.js.map +1 -1
  68. package/build/utils/display/scene/process.d.ts.map +1 -1
  69. package/build/utils/display/scene/process.js +20 -1
  70. package/build/utils/display/scene/process.js.map +1 -1
  71. package/build/utils/display/scene/types.d.ts +1 -1
  72. package/build/utils/display/scene/types.d.ts.map +1 -1
  73. package/build/utils/display/scene/types.js.map +1 -1
  74. package/package.json +7 -7
  75. package/src/engine.ts +4 -0
  76. package/src/facades/glasses.ts +7 -0
  77. package/src/generated/releaseMetadata.ts +3 -3
  78. package/src/services/GestureDotsService.ts +2 -1
  79. package/src/services/GlassesTouchInput.ts +69 -23
  80. package/src/services/LocalLlmModelManager.ts +16 -6
  81. package/src/services/LocalLlmPrompt.ts +56 -37
  82. package/src/services/LocalLlmProvider.ts +49 -22
  83. package/src/services/LocalMiniappRuntime.ts +103 -125
  84. package/src/services/SceneRenderer.ts +3 -1
  85. package/src/services/actionInvoke.ts +105 -0
  86. package/src/services/appleWatch/AppleWatchLink.ts +297 -0
  87. package/src/services/controllers.ts +17 -0
  88. package/src/services/settingsBridge.ts +9 -4
  89. package/src/stores/bluetoothSettingKeys.ts +20 -0
  90. package/src/stores/settings.ts +34 -2
  91. package/src/types/capabilities/rayneo-io.ts +2 -0
  92. package/src/types/enums.ts +1 -0
  93. package/src/utils/display/scene/index.ts +1 -0
  94. package/src/utils/display/scene/process.ts +17 -1
  95. package/src/utils/display/scene/types.ts +1 -0
@@ -1 +1 @@
1
- {"version":3,"file":"LocalLlmPrompt.js","sourceRoot":"","sources":["../../src/services/LocalLlmPrompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAC,UAAU,EAAC,MAAM,YAAY,CAAA;AAoBrC,uFAAuF;AACvF,MAAM,CAAC,MAAM,qBAAqB,GAChC,yGAAyG,CAAA;AAE3G;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAIrC;IACC,MAAM,GAAG,GAAsB,EAAE,CAAA;IACjC,MAAM,WAAW,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,MAAM,CACvG,CAAC,IAAI,EAAkB,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CACxC,CAAA;IACD,IAAI,WAAW,CAAC,MAAM;QAAE,GAAG,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,EAAC,CAAC,CAAA;IAErF,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACvC,IAAI,OAAO,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YACjC,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,EAAE,GAAG,CAAmB,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;gBACpE,EAAE,EAAE,IAAI,CAAC,EAAE;gBACX,IAAI,EAAE,UAAU;gBAChB,QAAQ,EAAE,EAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,EAAC;aACnD,CAAC,CAAC,CAAA;YACH,GAAG,CAAC,IAAI,CACN,SAAS,EAAE,MAAM;gBACf,CAAC,CAAC,EAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAC;gBACtE,CAAC,CAAC,EAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAC,CAClD,CAAA;YACD,SAAQ;QACV,CAAC;QACD,KAAK,MAAM,MAAM,IAAI,OAAO,CAAC,WAAW,IAAI,EAAE,EAAE,CAAC;YAC/C,GAAG,CAAC,IAAI,CAAC;gBACP,IAAI,EAAE,MAAM;gBACZ,YAAY,EAAE,MAAM,CAAC,UAAU;gBAC/B,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO;aACtE,CAAC,CAAA;QACJ,CAAC;QACD,IAAI,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,CAAC;YACtE,GAAG,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAC,CAAC,CAAA;QACpD,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAiB;IAC/C,IAAI,CAAC,KAAK,EAAE,MAAM;QAAE,OAAO,SAAS,CAAA;IACpC,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC1B,IAAI,EAAE,UAAU;QAChB,QAAQ,EAAE,EAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,UAAU,EAAE,IAAI,CAAC,WAAW,EAAC;KACzF,CAAC,CAAC,CAAA;AACL,CAAC;AAED,6EAA6E;AAC7E,MAAM,eAAe,GAAG,GAAG,CAAA;AAC3B,sEAAsE;AACtE,MAAM,kBAAkB,GAAG,CAAC,CAAA;AAE5B,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,eAAe,CAAC,CAAA;AACjD,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,OAAwB;IAC5D,IAAI,KAAK,GAAG,kBAAkB,GAAG,cAAc,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;IAChE,IAAI,OAAO,CAAC,IAAI,KAAK,WAAW,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;QACvD,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,UAAU;YAAE,KAAK,IAAI,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAA;IACnG,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,MAAM,sBAAsB,GAAG,KAAK,CAAA;AAEpC;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,QAA2B,EAAE,YAAoB,EAAE,UAAU,GAAG,CAAC;IAC3F,MAAM,KAAK,GAAG,CAAC,IAAuB,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,qBAAqB,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAA;IAC9G,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;IAClE,MAAM,KAAK,GAAwB,EAAE,CAAA;IACrC,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;QACpD,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAA;;YACnE,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAC7C,CAAC;IAED,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,CAAC,GAAG,MAAM,EAAE,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,YAAY,EAAE,CAAC;QAC9E,KAAK,CAAC,KAAK,EAAE,CAAA;IACf,CAAC;IAED,IAAI,MAAM,GAAG,CAAC,GAAG,MAAM,EAAE,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,CAAA;IACzC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,YAAY,EAAE,CAAC;QACjC,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACxB,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,GAAG,sBAAsB;YAC5D,CAAC,CAAC,EAAC,GAAG,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,sBAAsB,CAAC,gBAAgB,EAAC;YAChF,CAAC,CAAC,CAAC,CACN,CAAA;IACH,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,kCAAkC,EAAE,EAAE,CAAC,CAAA;IACpE,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,OAAO,CAAA;IACpC,OAAO,IAAI,CAAC,OAAO,CAAC,sBAAsB,EAAE,EAAE,CAAC,CAAC,SAAS,EAAE,CAAA;AAC7D,CAAC;AAED,MAAM,YAAY,GAAG,4CAA4C,CAAA;AAEjE,gGAAgG;AAChG,MAAM,UAAU,cAAc,CAC5B,IAAY,EACZ,MAAiC;IAEjC,MAAM,SAAS,GAAkB,EAAE,CAAA;IACnC,IAAI,KAAK,GAAG,CAAC,CAAA;IACb,MAAM,SAAS,GAAG,IAAI;SACnB,OAAO,CAAC,YAAY,EAAE,CAAC,MAAM,EAAE,IAAY,EAAE,EAAE;QAC9C,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,CAAC,CAAA;QACnC,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,OAAQ,MAA2B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAClG,MAAM,EAAC,IAAI,EAAE,SAAS,EAAE,IAAI,EAAC,GAAG,MAA6C,CAAA;YAC7E,SAAS,CAAC,IAAI,CAAC;gBACb,EAAE,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;gBACnB,IAAI;gBACJ,KAAK,EAAE,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAE,IAAgC,CAAC,CAAC,CAAC,EAAE;aACzG,CAAC,CAAA;QACJ,CAAC;QACD,OAAO,EAAE,CAAA;IACX,CAAC,CAAC;SACD,IAAI,EAAE,CAAA;IACT,OAAO,EAAC,SAAS,EAAE,IAAI,EAAE,SAAS,EAAC,CAAA;AACrC,CAAC;AAED,SAAS,cAAc,CAAC,IAAY;IAClC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAA;QACrC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,SAAS,CAAA;QAClB,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;IAC3D,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IACnC,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,IAAI,CAAA;IAC1B,MAAM,GAAG,GAAG,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;IACrC,MAAM,SAAS,GAAG,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IACtF,IAAI,CAAC;QACH,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;QACrB,OAAO,SAAS,CAAA;IAClB,CAAC;IAAC,MAAM,CAAC;QACP,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,UAAU,CAAC,SAAS,CAAC,CAAA;YACtC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA;YACpB,OAAO,QAAQ,CAAA;QACjB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAA;QACb,CAAC;IACH,CAAC;AACH,CAAC;AAgBD,2CAA2C;AAC3C,MAAM,UAAU,mBAAmB,CACjC,UAA2B,EAC3B,IAA2F;IAE3F,MAAM,KAAK,GAAG,EAAC,WAAW,EAAE,UAAU,CAAC,YAAY,EAAE,YAAY,EAAE,UAAU,CAAC,eAAe,EAAC,CAAA;IAC9F,IAAI,IAAI,GAAG,aAAa,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;IAEzC,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;QACtB,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,cAAc,CAAC,CAAA;QACxD,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;YAC5B,OAAO,EAAC,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,KAAK,EAAC,CAAA;QACxF,CAAC;QACD,IAAI,GAAG,MAAM,CAAC,IAAI,CAAA;IACpB,CAAC;IAED,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClB,IAAI,GAAG,iBAAiB,CAAC,IAAI,CAAC,IAAI,IAAI,CAAA;IACxC,CAAC;IAED,MAAM,UAAU,GAAkB,UAAU,CAAC,eAAe,IAAI,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,UAAU,CAAA;IACnH,OAAO,EAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,KAAK,EAAC,CAAA;AAC/C,CAAC","sourcesContent":["/**\n * LocalLlmPrompt — the pure half of the on-device LLM path: turning a neutral\n * session.ai request into chat-template messages, fitting them into the\n * model's context, and reading the model's text back into the neutral result\n * (tool calls, JSON mode, stop reason). No native imports, so it is\n * bun-testable; LocalLlmProvider owns the runner.\n *\n * Written against Qwen3's chat template: tools are advertised by the\n * template itself, calls come back as `<tool_call>{json}</tool_call>`, and\n * thinking is a `<think>…</think>` block we never ask for but still strip.\n */\nimport {jsonrepair} from \"jsonrepair\"\n\nimport type {LlmMessage, LlmStopReason, LlmTool, LlmToolCall} from \"@glassly/cloud-protocol/llm\"\n\nexport interface TemplateToolCall {\n id: string\n type: \"function\"\n function: {name: string; arguments: Record<string, unknown>}\n}\n\nexport type TemplateMessage =\n | {role: \"system\" | \"user\"; content: string}\n | {role: \"assistant\"; content: string; tool_calls?: TemplateToolCall[]}\n | {role: \"tool\"; content: string; name?: string; tool_call_id?: string}\n\nexport interface TemplateTool {\n type: \"function\"\n function: {name: string; description: string; parameters: Record<string, unknown>}\n}\n\n/** Appended to the system prompt under `jsonMode`; small models need it said twice. */\nexport const JSON_MODE_INSTRUCTION =\n \"Respond with exactly one JSON object and nothing else: no prose before or after it, no markdown fences.\"\n\n/**\n * Neutral messages → template messages. A user turn carrying toolResults\n * becomes one `tool` message per result (the template groups consecutive\n * tool messages into a single user block), followed by the user text if any.\n */\nexport function buildTemplateMessages(request: {\n messages: LlmMessage[]\n system?: string\n jsonMode?: boolean\n}): TemplateMessage[] {\n const out: TemplateMessage[] = []\n const systemParts = [request.system?.trim(), request.jsonMode ? JSON_MODE_INSTRUCTION : undefined].filter(\n (part): part is string => Boolean(part),\n )\n if (systemParts.length) out.push({role: \"system\", content: systemParts.join(\"\\n\\n\")})\n\n for (const message of request.messages) {\n if (message.role === \"assistant\") {\n const toolCalls = message.toolCalls?.map<TemplateToolCall>((call) => ({\n id: call.id,\n type: \"function\",\n function: {name: call.name, arguments: call.input},\n }))\n out.push(\n toolCalls?.length\n ? {role: \"assistant\", content: message.content, tool_calls: toolCalls}\n : {role: \"assistant\", content: message.content},\n )\n continue\n }\n for (const result of message.toolResults ?? []) {\n out.push({\n role: \"tool\",\n tool_call_id: result.toolCallId,\n content: result.isError ? `Error: ${result.content}` : result.content,\n })\n }\n if (message.content.trim().length > 0 || !message.toolResults?.length) {\n out.push({role: \"user\", content: message.content})\n }\n }\n return out\n}\n\nexport function toTemplateTools(tools?: LlmTool[]): TemplateTool[] | undefined {\n if (!tools?.length) return undefined\n return tools.map((tool) => ({\n type: \"function\",\n function: {name: tool.name, description: tool.description, parameters: tool.inputSchema},\n }))\n}\n\n/** Rough tokens-per-character for a BPE vocabulary over mixed prose/JSON. */\nconst CHARS_PER_TOKEN = 3.2\n/** Template framing per message (`<|im_start|>role … <|im_end|>`). */\nconst TOKENS_PER_MESSAGE = 6\n\nexport function estimateTokens(text: string): number {\n return Math.ceil(text.length / CHARS_PER_TOKEN)\n}\n\nexport function estimateMessageTokens(message: TemplateMessage): number {\n let total = TOKENS_PER_MESSAGE + estimateTokens(message.content)\n if (message.role === \"assistant\" && message.tool_calls) {\n for (const call of message.tool_calls) total += estimateTokens(JSON.stringify(call.function)) + 8\n }\n return total\n}\n\nconst MIN_TOOL_CONTENT_CHARS = 1_200\n\n/**\n * Fit the conversation into `budgetTokens`. History is grouped into turns\n * (a user message plus everything up to the next user message, so a tool\n * round stays with the question it answers); the oldest turns go first and\n * the last turn is never dropped — the model must at least see the question.\n * When that last turn alone still does not fit, tool outputs are cut to\n * their head.\n */\nexport function fitToBudget(messages: TemplateMessage[], budgetTokens: number, toolTokens = 0): TemplateMessage[] {\n const total = (list: TemplateMessage[]) => list.reduce((sum, m) => sum + estimateMessageTokens(m), toolTokens)\n const system = messages[0]?.role === \"system\" ? [messages[0]] : []\n const turns: TemplateMessage[][] = []\n for (const message of messages.slice(system.length)) {\n if (message.role === \"user\" || turns.length === 0) turns.push([message])\n else turns[turns.length - 1]!.push(message)\n }\n\n while (turns.length > 1 && total([...system, ...turns.flat()]) > budgetTokens) {\n turns.shift()\n }\n\n let fitted = [...system, ...turns.flat()]\n if (total(fitted) > budgetTokens) {\n fitted = fitted.map((m) =>\n m.role === \"tool\" && m.content.length > MIN_TOOL_CONTENT_CHARS\n ? {...m, content: `${m.content.slice(0, MIN_TOOL_CONTENT_CHARS)}\\n…[truncated]`}\n : m,\n )\n }\n return fitted\n}\n\n/** Remove a leading `<think>…</think>` block (or an unterminated one). */\nexport function stripThinking(text: string): string {\n const trimmed = text.replace(/^\\s*<think>[\\s\\S]*?<\\/think>\\s*/u, \"\")\n if (trimmed !== text) return trimmed\n return text.replace(/^\\s*<think>[\\s\\S]*$/u, \"\").trimStart()\n}\n\nconst TOOL_CALL_RE = /<tool_call>\\s*([\\s\\S]*?)\\s*<\\/tool_call>/gu\n\n/** Pull `<tool_call>` blocks out of the reply. Unparseable blocks are dropped, not surfaced. */\nexport function parseToolCalls(\n text: string,\n makeId: (index: number) => string,\n): {toolCalls: LlmToolCall[]; text: string} {\n const toolCalls: LlmToolCall[] = []\n let index = 0\n const remaining = text\n .replace(TOOL_CALL_RE, (_match, body: string) => {\n const parsed = parseJsonLoose(body)\n if (parsed && typeof parsed === \"object\" && typeof (parsed as {name?: unknown}).name === \"string\") {\n const {name, arguments: args} = parsed as {name: string; arguments?: unknown}\n toolCalls.push({\n id: makeId(index++),\n name,\n input: args && typeof args === \"object\" && !Array.isArray(args) ? (args as Record<string, unknown>) : {},\n })\n }\n return \"\"\n })\n .trim()\n return {toolCalls, text: remaining}\n}\n\nfunction parseJsonLoose(body: string): unknown {\n try {\n return JSON.parse(body)\n } catch {\n try {\n return JSON.parse(jsonrepair(body))\n } catch {\n return undefined\n }\n }\n}\n\n/**\n * The first JSON object in the reply, repaired if the model left it slightly\n * broken (trailing commas, single quotes, a dropped brace). Null when there\n * is nothing object-shaped: the caller keeps the raw text and the miniapp's\n * own parser decides.\n */\nexport function extractJsonObject(text: string): string | null {\n const unfenced = text.replace(/```(?:json)?/giu, \"\").trim()\n const start = unfenced.indexOf(\"{\")\n if (start < 0) return null\n const end = unfenced.lastIndexOf(\"}\")\n const candidate = end > start ? unfenced.slice(start, end + 1) : unfenced.slice(start)\n try {\n JSON.parse(candidate)\n return candidate\n } catch {\n try {\n const repaired = jsonrepair(candidate)\n JSON.parse(repaired)\n return repaired\n } catch {\n return null\n }\n }\n}\n\nexport interface LocalGeneration {\n text: string\n promptTokens: number\n generatedTokens: number\n maxNewTokens: number\n}\n\nexport interface LocalCompletion {\n text: string\n stopReason: LlmStopReason\n toolCalls?: LlmToolCall[]\n usage: {inputTokens: number; outputTokens: number}\n}\n\n/** Raw generation → neutral completion. */\nexport function finalizeLocalResult(\n generation: LocalGeneration,\n opts: {jsonMode: boolean; toolsOffered: boolean; makeToolCallId: (index: number) => string},\n): LocalCompletion {\n const usage = {inputTokens: generation.promptTokens, outputTokens: generation.generatedTokens}\n let text = stripThinking(generation.text)\n\n if (opts.toolsOffered) {\n const parsed = parseToolCalls(text, opts.makeToolCallId)\n if (parsed.toolCalls.length) {\n return {text: parsed.text, stopReason: \"tool_use\", toolCalls: parsed.toolCalls, usage}\n }\n text = parsed.text\n }\n\n if (opts.jsonMode) {\n text = extractJsonObject(text) ?? text\n }\n\n const stopReason: LlmStopReason = generation.generatedTokens >= generation.maxNewTokens ? \"max_tokens\" : \"end_turn\"\n return {text: text.trim(), stopReason, usage}\n}\n"]}
1
+ {"version":3,"file":"LocalLlmPrompt.js","sourceRoot":"","sources":["../../src/services/LocalLlmPrompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAC,UAAU,EAAC,MAAM,YAAY,CAAA;AAoBrC,uFAAuF;AACvF,MAAM,CAAC,MAAM,qBAAqB,GAChC,yGAAyG,CAAA;AAE3G;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAIrC;IACC,MAAM,GAAG,GAAsB,EAAE,CAAA;IACjC,MAAM,WAAW,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,MAAM,CACvG,CAAC,IAAI,EAAkB,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CACxC,CAAA;IACD,IAAI,WAAW,CAAC,MAAM;QAAE,GAAG,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,EAAC,CAAC,CAAA;IAErF,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACvC,IAAI,OAAO,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YACjC,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,EAAE,GAAG,CAAmB,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;gBACpE,EAAE,EAAE,IAAI,CAAC,EAAE;gBACX,IAAI,EAAE,UAAU;gBAChB,QAAQ,EAAE,EAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,EAAC;aACnD,CAAC,CAAC,CAAA;YACH,GAAG,CAAC,IAAI,CACN,SAAS,EAAE,MAAM;gBACf,CAAC,CAAC,EAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAC;gBACtE,CAAC,CAAC,EAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAC,CAClD,CAAA;YACD,SAAQ;QACV,CAAC;QACD,KAAK,MAAM,MAAM,IAAI,OAAO,CAAC,WAAW,IAAI,EAAE,EAAE,CAAC;YAC/C,GAAG,CAAC,IAAI,CAAC;gBACP,IAAI,EAAE,MAAM;gBACZ,YAAY,EAAE,MAAM,CAAC,UAAU;gBAC/B,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO;aACtE,CAAC,CAAA;QACJ,CAAC;QACD,IAAI,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,CAAC;YACtE,GAAG,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAC,CAAC,CAAA;QACpD,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAiB;IAC/C,IAAI,CAAC,KAAK,EAAE,MAAM;QAAE,OAAO,SAAS,CAAA;IACpC,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC1B,IAAI,EAAE,UAAU;QAChB,QAAQ,EAAE,EAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,UAAU,EAAE,IAAI,CAAC,WAAW,EAAC;KACzF,CAAC,CAAC,CAAA;AACL,CAAC;AAQD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,QAA2B,EAC3B,YAAoB,EACpB,MAA+C,EAC/C,WAAgD;IAEhD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,YAAY,CAAC,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;QACxD,MAAM,IAAI,KAAK,CAAC,wEAAwE,CAAC,CAAA;IAC3F,CAAC;IACD,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;IAClE,MAAM,KAAK,GAAwB,EAAE,CAAA;IACrC,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;QACpD,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAA;;YACnE,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAC7C,CAAC;IACD,IAAI,MAAM,GAAG,CAAC,GAAG,MAAM,EAAE,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,CAAA;IACzC,IAAI,SAAS,GAAG,KAAK,CAAA;IACrB,MAAM,MAAM,GAAG,mBAAmB,CAAA;IAClC,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAA;QAC7B,MAAM,YAAY,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,CAAA;QAC9C,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,YAAY,CAAC,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;YACxD,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAA;QAC/E,CAAC;QACD,IAAI,YAAY,IAAI,YAAY;YAAE,OAAO,EAAC,MAAM,EAAE,YAAY,EAAE,SAAS,EAAC,CAAA;QAC1E,SAAS,GAAG,IAAI,CAAA;QAChB,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrB,KAAK,CAAC,KAAK,EAAE,CAAA;YACb,MAAM,GAAG,CAAC,GAAG,MAAM,EAAE,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,CAAA;YACrC,SAAQ;QACV,CAAC;QACD,yEAAyE;QACzE,MAAM,UAAU,GAAG,MAAM;aACtB,GAAG,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,EAAC,OAAO,EAAE,KAAK,EAAC,CAAC,CAAC;aAC3C,MAAM,CAAC,CAAC,EAAC,OAAO,EAAC,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;aAC1G,IAAI,CACH,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACP,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,KAAK,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,KAAK,MAAM,CAAC;YACrE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CACtD,CAAA;QACH,MAAM,SAAS,GAAG,UAAU,CAAC,CAAC,CAAC,CAAA;QAC/B,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CACb,iFAAiF,YAAY,MAAM,YAAY,UAAU,CAC1H,CAAA;QACH,CAAC;QACD,wEAAwE;QACxE,4EAA4E;QAC5E,sEAAsE;QACtE,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;QACnD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;QACzC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG;YACxB,GAAG,SAAS,CAAC,OAAO;YACpB,OAAO,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE;SACnF,CAAA;IACH,CAAC;AACH,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,kCAAkC,EAAE,EAAE,CAAC,CAAA;IACpE,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,OAAO,CAAA;IACpC,OAAO,IAAI,CAAC,OAAO,CAAC,sBAAsB,EAAE,EAAE,CAAC,CAAC,SAAS,EAAE,CAAA;AAC7D,CAAC;AAED,MAAM,YAAY,GAAG,4CAA4C,CAAA;AAEjE,gGAAgG;AAChG,MAAM,UAAU,cAAc,CAC5B,IAAY,EACZ,MAAiC;IAEjC,MAAM,SAAS,GAAkB,EAAE,CAAA;IACnC,IAAI,KAAK,GAAG,CAAC,CAAA;IACb,MAAM,SAAS,GAAG,IAAI;SACnB,OAAO,CAAC,YAAY,EAAE,CAAC,MAAM,EAAE,IAAY,EAAE,EAAE;QAC9C,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,CAAC,CAAA;QACnC,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,OAAQ,MAA2B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAClG,MAAM,EAAC,IAAI,EAAE,SAAS,EAAE,IAAI,EAAC,GAAG,MAA6C,CAAA;YAC7E,SAAS,CAAC,IAAI,CAAC;gBACb,EAAE,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;gBACnB,IAAI;gBACJ,KAAK,EAAE,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAE,IAAgC,CAAC,CAAC,CAAC,EAAE;aACzG,CAAC,CAAA;QACJ,CAAC;QACD,OAAO,EAAE,CAAA;IACX,CAAC,CAAC;SACD,IAAI,EAAE,CAAA;IACT,OAAO,EAAC,SAAS,EAAE,IAAI,EAAE,SAAS,EAAC,CAAA;AACrC,CAAC;AAED,SAAS,cAAc,CAAC,IAAY;IAClC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAA;QACrC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,SAAS,CAAA;QAClB,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;IAC3D,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IACnC,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,IAAI,CAAA;IAC1B,MAAM,GAAG,GAAG,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;IACrC,MAAM,SAAS,GAAG,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IACtF,IAAI,CAAC;QACH,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;QACrB,OAAO,SAAS,CAAA;IAClB,CAAC;IAAC,MAAM,CAAC;QACP,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,UAAU,CAAC,SAAS,CAAC,CAAA;YACtC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA;YACpB,OAAO,QAAQ,CAAA;QACjB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAA;QACb,CAAC;IACH,CAAC;AACH,CAAC;AAgBD,2CAA2C;AAC3C,MAAM,UAAU,mBAAmB,CACjC,UAA2B,EAC3B,IAA2F;IAE3F,MAAM,KAAK,GAAG,EAAC,WAAW,EAAE,UAAU,CAAC,YAAY,EAAE,YAAY,EAAE,UAAU,CAAC,eAAe,EAAC,CAAA;IAC9F,IAAI,IAAI,GAAG,aAAa,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;IAEzC,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;QACtB,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,cAAc,CAAC,CAAA;QACxD,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;YAC5B,OAAO,EAAC,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,KAAK,EAAC,CAAA;QACxF,CAAC;QACD,IAAI,GAAG,MAAM,CAAC,IAAI,CAAA;IACpB,CAAC;IAED,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClB,IAAI,GAAG,iBAAiB,CAAC,IAAI,CAAC,IAAI,IAAI,CAAA;IACxC,CAAC;IAED,MAAM,UAAU,GAAkB,UAAU,CAAC,eAAe,IAAI,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,UAAU,CAAA;IACnH,OAAO,EAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,KAAK,EAAC,CAAA;AAC/C,CAAC","sourcesContent":["/**\n * LocalLlmPrompt — the pure half of the on-device LLM path: turning a neutral\n * session.ai request into chat-template messages, fitting them into the\n * model's context, and reading the model's text back into the neutral result\n * (tool calls, JSON mode, stop reason). No native imports, so it is\n * bun-testable; LocalLlmProvider owns the runner.\n *\n * Written against Qwen3's chat template: tools are advertised by the\n * template itself, calls come back as `<tool_call>{json}</tool_call>`, and\n * thinking is a `<think>…</think>` block we never ask for but still strip.\n */\nimport {jsonrepair} from \"jsonrepair\"\n\nimport type {LlmMessage, LlmStopReason, LlmTool, LlmToolCall} from \"@glassly/cloud-protocol/llm\"\n\nexport interface TemplateToolCall {\n id: string\n type: \"function\"\n function: {name: string; arguments: Record<string, unknown>}\n}\n\nexport type TemplateMessage =\n | {role: \"system\" | \"user\"; content: string}\n | {role: \"assistant\"; content: string; tool_calls?: TemplateToolCall[]}\n | {role: \"tool\"; content: string; name?: string; tool_call_id?: string}\n\nexport interface TemplateTool {\n type: \"function\"\n function: {name: string; description: string; parameters: Record<string, unknown>}\n}\n\n/** Appended to the system prompt under `jsonMode`; small models need it said twice. */\nexport const JSON_MODE_INSTRUCTION =\n \"Respond with exactly one JSON object and nothing else: no prose before or after it, no markdown fences.\"\n\n/**\n * Neutral messages → template messages. A user turn carrying toolResults\n * becomes one `tool` message per result (the template groups consecutive\n * tool messages into a single user block), followed by the user text if any.\n */\nexport function buildTemplateMessages(request: {\n messages: LlmMessage[]\n system?: string\n jsonMode?: boolean\n}): TemplateMessage[] {\n const out: TemplateMessage[] = []\n const systemParts = [request.system?.trim(), request.jsonMode ? JSON_MODE_INSTRUCTION : undefined].filter(\n (part): part is string => Boolean(part),\n )\n if (systemParts.length) out.push({role: \"system\", content: systemParts.join(\"\\n\\n\")})\n\n for (const message of request.messages) {\n if (message.role === \"assistant\") {\n const toolCalls = message.toolCalls?.map<TemplateToolCall>((call) => ({\n id: call.id,\n type: \"function\",\n function: {name: call.name, arguments: call.input},\n }))\n out.push(\n toolCalls?.length\n ? {role: \"assistant\", content: message.content, tool_calls: toolCalls}\n : {role: \"assistant\", content: message.content},\n )\n continue\n }\n for (const result of message.toolResults ?? []) {\n out.push({\n role: \"tool\",\n tool_call_id: result.toolCallId,\n content: result.isError ? `Error: ${result.content}` : result.content,\n })\n }\n if (message.content.trim().length > 0 || !message.toolResults?.length) {\n out.push({role: \"user\", content: message.content})\n }\n }\n return out\n}\n\nexport function toTemplateTools(tools?: LlmTool[]): TemplateTool[] | undefined {\n if (!tools?.length) return undefined\n return tools.map((tool) => ({\n type: \"function\",\n function: {name: tool.name, description: tool.description, parameters: tool.inputSchema},\n }))\n}\n\nexport interface FittedLocalPrompt {\n prompt: string\n promptTokens: number\n truncated: boolean\n}\n\n/**\n * Measure the complete rendered prompt with the model's tokenizer, including\n * template framing, system instructions and tool schemas. Drop old turns first,\n * then shorten tool results / message text in the final turn. Never cut template\n * delimiters, system instructions, or structured tool calls to make them fit.\n */\nexport async function fitPromptToContext(\n messages: TemplateMessage[],\n budgetTokens: number,\n render: (messages: TemplateMessage[]) => string,\n countTokens: (prompt: string) => Promise<number>,\n): Promise<FittedLocalPrompt> {\n if (!Number.isInteger(budgetTokens) || budgetTokens < 1) {\n throw new Error(\"On-device model has no room for a prompt after reserving output tokens\")\n }\n const system = messages[0]?.role === \"system\" ? [messages[0]] : []\n const turns: TemplateMessage[][] = []\n for (const message of messages.slice(system.length)) {\n if (message.role === \"user\" || turns.length === 0) turns.push([message])\n else turns[turns.length - 1]!.push(message)\n }\n let fitted = [...system, ...turns.flat()]\n let truncated = false\n const marker = \"\\n…[truncated]…\\n\"\n while (true) {\n const prompt = render(fitted)\n const promptTokens = await countTokens(prompt)\n if (!Number.isInteger(promptTokens) || promptTokens < 1) {\n throw new Error(\"On-device tokenizer returned an invalid prompt token count\")\n }\n if (promptTokens <= budgetTokens) return {prompt, promptTokens, truncated}\n truncated = true\n if (turns.length > 1) {\n turns.shift()\n fitted = [...system, ...turns.flat()]\n continue\n }\n // Preserve the user's question while tool output can still be shortened.\n const candidates = fitted\n .map((message, index) => ({message, index}))\n .filter(({message}) => message.role !== \"system\" && Array.from(message.content).length > marker.length * 2)\n .sort(\n (a, b) =>\n Number(b.message.role === \"tool\") - Number(a.message.role === \"tool\") ||\n b.message.content.length - a.message.content.length,\n )\n const candidate = candidates[0]\n if (!candidate) {\n throw new Error(\n `On-device prompt instructions and tool definitions exceed the context budget (${promptTokens} > ${budgetTokens} tokens)`,\n )\n }\n // Keep both ends of long transcripts and questions, without splitting a\n // Unicode code point. Each pass shrinks strictly, then remeasures the whole\n // rendered prompt; character ratios are never used as a safety check.\n const chars = Array.from(candidate.message.content)\n const keep = Math.floor(chars.length / 4)\n fitted[candidate.index] = {\n ...candidate.message,\n content: `${chars.slice(0, keep).join(\"\")}${marker}${chars.slice(-keep).join(\"\")}`,\n }\n }\n}\n\n/** Remove a leading `<think>…</think>` block (or an unterminated one). */\nexport function stripThinking(text: string): string {\n const trimmed = text.replace(/^\\s*<think>[\\s\\S]*?<\\/think>\\s*/u, \"\")\n if (trimmed !== text) return trimmed\n return text.replace(/^\\s*<think>[\\s\\S]*$/u, \"\").trimStart()\n}\n\nconst TOOL_CALL_RE = /<tool_call>\\s*([\\s\\S]*?)\\s*<\\/tool_call>/gu\n\n/** Pull `<tool_call>` blocks out of the reply. Unparseable blocks are dropped, not surfaced. */\nexport function parseToolCalls(\n text: string,\n makeId: (index: number) => string,\n): {toolCalls: LlmToolCall[]; text: string} {\n const toolCalls: LlmToolCall[] = []\n let index = 0\n const remaining = text\n .replace(TOOL_CALL_RE, (_match, body: string) => {\n const parsed = parseJsonLoose(body)\n if (parsed && typeof parsed === \"object\" && typeof (parsed as {name?: unknown}).name === \"string\") {\n const {name, arguments: args} = parsed as {name: string; arguments?: unknown}\n toolCalls.push({\n id: makeId(index++),\n name,\n input: args && typeof args === \"object\" && !Array.isArray(args) ? (args as Record<string, unknown>) : {},\n })\n }\n return \"\"\n })\n .trim()\n return {toolCalls, text: remaining}\n}\n\nfunction parseJsonLoose(body: string): unknown {\n try {\n return JSON.parse(body)\n } catch {\n try {\n return JSON.parse(jsonrepair(body))\n } catch {\n return undefined\n }\n }\n}\n\n/**\n * The first JSON object in the reply, repaired if the model left it slightly\n * broken (trailing commas, single quotes, a dropped brace). Null when there\n * is nothing object-shaped: the caller keeps the raw text and the miniapp's\n * own parser decides.\n */\nexport function extractJsonObject(text: string): string | null {\n const unfenced = text.replace(/```(?:json)?/giu, \"\").trim()\n const start = unfenced.indexOf(\"{\")\n if (start < 0) return null\n const end = unfenced.lastIndexOf(\"}\")\n const candidate = end > start ? unfenced.slice(start, end + 1) : unfenced.slice(start)\n try {\n JSON.parse(candidate)\n return candidate\n } catch {\n try {\n const repaired = jsonrepair(candidate)\n JSON.parse(repaired)\n return repaired\n } catch {\n return null\n }\n }\n}\n\nexport interface LocalGeneration {\n text: string\n promptTokens: number\n generatedTokens: number\n maxNewTokens: number\n}\n\nexport interface LocalCompletion {\n text: string\n stopReason: LlmStopReason\n toolCalls?: LlmToolCall[]\n usage: {inputTokens: number; outputTokens: number}\n}\n\n/** Raw generation → neutral completion. */\nexport function finalizeLocalResult(\n generation: LocalGeneration,\n opts: {jsonMode: boolean; toolsOffered: boolean; makeToolCallId: (index: number) => string},\n): LocalCompletion {\n const usage = {inputTokens: generation.promptTokens, outputTokens: generation.generatedTokens}\n let text = stripThinking(generation.text)\n\n if (opts.toolsOffered) {\n const parsed = parseToolCalls(text, opts.makeToolCallId)\n if (parsed.toolCalls.length) {\n return {text: parsed.text, stopReason: \"tool_use\", toolCalls: parsed.toolCalls, usage}\n }\n text = parsed.text\n }\n\n if (opts.jsonMode) {\n text = extractJsonObject(text) ?? text\n }\n\n const stopReason: LlmStopReason = generation.generatedTokens >= generation.maxNewTokens ? \"max_tokens\" : \"end_turn\"\n return {text: text.trim(), stopReason, usage}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"LocalLlmProvider.d.ts","sourceRoot":"","sources":["../../src/services/LocalLlmProvider.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,6BAA6B,CAAA;AAEnE,OAA6B,EAAC,KAAK,eAAe,EAAC,MAAM,wBAAwB,CAAA;AACjF,OAAO,EAML,KAAK,eAAe,EACrB,MAAM,kBAAkB,CAAA;AAmCzB,MAAM,WAAW,sBAAuB,SAAQ,eAAe;IAC7D,OAAO,EAAE,eAAe,CAAA;CACzB;AAqBD,cAAM,gBAAgB;IACpB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAkB;IAEzC,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,OAAO,CAAoC;IACnD,OAAO,CAAC,KAAK,CAAsC;IACnD,OAAO,CAAC,SAAS,CAAsB;IACvC,OAAO,CAAC,GAAG,CAAmB;IAE9B,OAAO;IAUP,MAAM,CAAC,WAAW,IAAI,gBAAgB;IAKtC,mFAAmF;IACnF,QAAQ,IAAI,OAAO;IAInB,aAAa,IAAI,eAAe,GAAG,IAAI;IAIvC,oGAAoG;IACpG,QAAQ,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAMtE,kGAAkG;IAC5F,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAe7B,yEAAyE;IACzE,OAAO,CAAC,aAAa;YAWP,aAAa;YA6Db,YAAY;YAgBZ,IAAI;YA6BJ,OAAO;IASrB,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,cAAc;CAMvB;AAED,QAAA,MAAM,gBAAgB,kBAAiC,CAAA;AACvD,OAAO,EAAC,gBAAgB,EAAC,CAAA;AACzB,eAAe,gBAAgB,CAAA"}
1
+ {"version":3,"file":"LocalLlmProvider.d.ts","sourceRoot":"","sources":["../../src/services/LocalLlmProvider.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,6BAA6B,CAAA;AAEnE,OAA6B,EAAC,KAAK,eAAe,EAAC,MAAM,wBAAwB,CAAA;AACjF,OAAO,EAKL,KAAK,eAAe,EACrB,MAAM,kBAAkB,CAAA;AAsCzB,MAAM,WAAW,sBAAuB,SAAQ,eAAe;IAC7D,OAAO,EAAE,eAAe,CAAA;CACzB;AA0BD,cAAM,gBAAgB;IACpB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAkB;IAEzC,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,OAAO,CAAoC;IACnD,OAAO,CAAC,KAAK,CAAsC;IACnD,OAAO,CAAC,SAAS,CAAsB;IACvC,OAAO,CAAC,GAAG,CAAmB;IAE9B,OAAO;IAUP,MAAM,CAAC,WAAW,IAAI,gBAAgB;IAKtC,mFAAmF;IACnF,QAAQ,IAAI,OAAO;IAInB,aAAa,IAAI,eAAe,GAAG,IAAI;IAIvC,oGAAoG;IACpG,QAAQ,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAMtE,kGAAkG;IAC5F,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAe7B,yEAAyE;IACzE,OAAO,CAAC,aAAa;YAaP,aAAa;YAmEb,YAAY;YAgBZ,IAAI;YAyCJ,OAAO;IASrB,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,cAAc;CAMvB;AAED,QAAA,MAAM,gBAAgB,kBAAiC,CAAA;AACvD,OAAO,EAAC,gBAAgB,EAAC,CAAA;AACzB,eAAe,gBAAgB,CAAA"}
@@ -18,7 +18,7 @@ import * as RNFS from "@dr.pogodin/react-native-fs";
18
18
  import { Template } from "@huggingface/jinja";
19
19
  import { BgTimer } from "../utils/timers";
20
20
  import localLlmModelManager from "./LocalLlmModelManager";
21
- import { buildTemplateMessages, estimateTokens, finalizeLocalResult, fitToBudget, toTemplateTools, } from "./LocalLlmPrompt";
21
+ import { buildTemplateMessages, finalizeLocalResult, fitPromptToContext, toTemplateTools, } from "./LocalLlmPrompt";
22
22
  import { SETTINGS, useSettingsStore } from "../stores/settings";
23
23
  const LOG_TAG = "LOCAL_LLM";
24
24
  /** Drop the resident model after this long without a request. */
@@ -27,7 +27,7 @@ const IDLE_UNLOAD_MS = 5 * 60_000;
27
27
  const GENERATION_DEADLINE_MS = 100_000;
28
28
  const DEFAULT_MAX_NEW_TOKENS = 512;
29
29
  const MAX_NEW_TOKENS_CEILING = 1_024;
30
- /** Headroom between the estimated prompt and the context end; estimates are rough. */
30
+ /** Reserve space for runner-added BOS/EOS tokens and context boundary bookkeeping. */
31
31
  const CONTEXT_MARGIN_TOKENS = 96;
32
32
  /**
33
33
  * Runs on ExecuTorch's worklet runtime: `runner.generate` blocks its thread
@@ -43,6 +43,10 @@ function generateWorklet(runner, prompt, config, stopTokens) {
43
43
  });
44
44
  return { text, stats };
45
45
  }
46
+ function countTokensWorklet(tokenizer, prompt) {
47
+ "worklet";
48
+ return tokenizer.encode(prompt).length;
49
+ }
46
50
  class LocalLlmProvider {
47
51
  static instance;
48
52
  loaded = null;
@@ -102,6 +106,9 @@ class LocalLlmProvider {
102
106
  catch (error) {
103
107
  console.warn(`${LOG_TAG}: runner dispose failed:`, error);
104
108
  }
109
+ finally {
110
+ loaded.tokenizer.dispose();
111
+ }
105
112
  }
106
113
  async completeInner(request) {
107
114
  this.clearIdleTimer();
@@ -109,16 +116,10 @@ class LocalLlmProvider {
109
116
  const model = await this.ensureLoaded();
110
117
  const jsonMode = request.jsonMode === true;
111
118
  const tools = toTemplateTools(request.tools);
112
- const toolTokens = tools ? estimateTokens(JSON.stringify(tools)) + 64 : 0;
113
119
  const maxNewTokens = Math.max(16, Math.min(request.maxTokens ?? DEFAULT_MAX_NEW_TOKENS, MAX_NEW_TOKENS_CEILING, Math.floor(model.maxSeqLen / 4)));
114
120
  const promptBudget = model.maxSeqLen - maxNewTokens - CONTEXT_MARGIN_TOKENS;
115
- const messages = fitToBudget(buildTemplateMessages({ ...request, jsonMode }), promptBudget, toolTokens);
116
- const prompt = model.template.render({
117
- messages,
118
- tools,
119
- add_generation_prompt: true,
120
- enable_thinking: false,
121
- });
121
+ const { prompt, promptTokens, truncated } = await fitPromptToContext(buildTemplateMessages({ ...request, jsonMode }), promptBudget, (messages) => model.template.render({ messages, tools, add_generation_prompt: true, enable_thinking: false }), (text) => model.countTokens(model.tokenizer, text));
122
+ console.log(`${LOG_TAG}: ${model.modelId} prompt=${promptTokens} budget=${promptBudget} context=${model.maxSeqLen} maxNewTokens=${maxNewTokens} truncated=${truncated}`);
122
123
  model.runner.reset(0);
123
124
  const deadline = BgTimer.setTimeout(() => {
124
125
  console.warn(`${LOG_TAG}: generation deadline hit, stopping`);
@@ -129,6 +130,10 @@ class LocalLlmProvider {
129
130
  try {
130
131
  generated = await model.generate(model.runner, prompt, { maxNewTokens, temperature: request.temperature ?? 0.7 }, model.stopTokens);
131
132
  }
133
+ catch (error) {
134
+ console.warn(`${LOG_TAG}: generation failed: model=${model.modelId} prompt=${promptTokens} context=${model.maxSeqLen} maxNewTokens=${maxNewTokens}`, error);
135
+ throw error;
136
+ }
132
137
  finally {
133
138
  BgTimer.clearTimeout(deadline);
134
139
  }
@@ -177,16 +182,30 @@ class LocalLlmProvider {
177
182
  const startedAt = Date.now();
178
183
  const createRunner = rne.wrapAsync(rne.llm.createLLMRunner);
179
184
  const runner = await createRunner(paths.model, paths.tokenizer, []);
180
- const maxSeqLen = runner.getKVCacheState().maxSeqLen;
181
- console.log(`${LOG_TAG}: loaded ${modelId} (context ${maxSeqLen}) in ${Date.now() - startedAt} ms`);
182
- return {
183
- modelId,
184
- runner,
185
- template,
186
- stopTokens: [...tokenizerConfig.stopTokens],
187
- maxSeqLen,
188
- generate: rne.wrapAsync(generateWorklet),
189
- };
185
+ let tokenizer;
186
+ try {
187
+ const maxSeqLen = runner.getKVCacheState().maxSeqLen;
188
+ if (!Number.isInteger(maxSeqLen) || maxSeqLen <= CONTEXT_MARGIN_TOKENS + 16) {
189
+ throw new Error(`On-device model ${modelId} reported an invalid context size: ${maxSeqLen}`);
190
+ }
191
+ tokenizer = await rne.wrapAsync(rne.nlp.loadTokenizer)(paths.tokenizer);
192
+ console.log(`${LOG_TAG}: loaded ${modelId} (context ${maxSeqLen}) in ${Date.now() - startedAt} ms`);
193
+ return {
194
+ modelId,
195
+ runner,
196
+ tokenizer,
197
+ countTokens: rne.wrapAsync(countTokensWorklet),
198
+ template,
199
+ stopTokens: [...tokenizerConfig.stopTokens],
200
+ maxSeqLen,
201
+ generate: rne.wrapAsync(generateWorklet),
202
+ };
203
+ }
204
+ catch (error) {
205
+ tokenizer?.dispose();
206
+ runner.dispose();
207
+ throw error;
208
+ }
190
209
  }
191
210
  async runtime() {
192
211
  if (this.rne)
@@ -1 +1 @@
1
- {"version":3,"file":"LocalLlmProvider.js","sourceRoot":"","sources":["../../src/services/LocalLlmProvider.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * LocalLlmProvider — session.ai.complete served by the phone itself: an\n * ExecuTorch runner (react-native-executorch) over the Qwen3 export that\n * LocalLlmModelManager downloaded. Stateless per request like the vendor\n * providers: every call renders the whole conversation through the model's\n * chat template, resets the KV cache, and generates on ExecuTorch's worklet\n * thread so the JS thread stays free.\n *\n * The runner is loaded on the first request and kept resident while calls\n * keep coming (loading a 1–3 GB model is seconds, not milliseconds); it is\n * dropped after an idle period and whenever the selected model changes.\n * Requests are serialized — one model, one KV cache.\n *\n * react-native-executorch is imported lazily so the engine module graph\n * loads without the native runtime (bun tests, hosts without the dependency).\n */\nimport * as RNFS from \"@dr.pogodin/react-native-fs\"\nimport {Template} from \"@huggingface/jinja\"\n\nimport type {LlmCompleteRequest} from \"@glassly/cloud-protocol/llm\"\nimport {BgTimer} from \"../utils/timers\"\nimport localLlmModelManager, {type LocalLlmModelId} from \"./LocalLlmModelManager\"\nimport {\n buildTemplateMessages,\n estimateTokens,\n finalizeLocalResult,\n fitToBudget,\n toTemplateTools,\n type LocalCompletion,\n} from \"./LocalLlmPrompt\"\nimport {SETTINGS, useSettingsStore} from \"../stores/settings\"\n\ntype Rne = typeof import(\"react-native-executorch\")\n// The runner API lives on the `llm` namespace; derive its types from there so\n// the import stays a type-only reference (no native module at load time).\ntype LLMRunner = ReturnType<Rne[\"llm\"][\"createLLMRunner\"]>\ntype LLMGenerationStats = ReturnType<LLMRunner[\"generate\"]>\ntype LLMGenerationConfig = NonNullable<Parameters<LLMRunner[\"generate\"]>[1]>\n\nconst LOG_TAG = \"LOCAL_LLM\"\n\n/** Drop the resident model after this long without a request. */\nconst IDLE_UNLOAD_MS = 5 * 60_000\n/** Hard stop on one generation — the SDK request times out at 120 s anyway. */\nconst GENERATION_DEADLINE_MS = 100_000\nconst DEFAULT_MAX_NEW_TOKENS = 512\nconst MAX_NEW_TOKENS_CEILING = 1_024\n/** Headroom between the estimated prompt and the context end; estimates are rough. */\nconst CONTEXT_MARGIN_TOKENS = 96\n\ninterface LoadedModel {\n modelId: LocalLlmModelId\n runner: LLMRunner\n template: Template\n stopTokens: string[]\n maxSeqLen: number\n generate: (\n runner: LLMRunner,\n prompt: string,\n config: LLMGenerationConfig,\n stopTokens: string[],\n ) => Promise<{text: string; stats: LLMGenerationStats}>\n}\n\nexport interface LocalLlmCompleteResult extends LocalCompletion {\n modelId: LocalLlmModelId\n}\n\n/**\n * Runs on ExecuTorch's worklet runtime: `runner.generate` blocks its thread\n * until EOS, `maxNewTokens`, or `runner.stop()` from the JS thread.\n */\nfunction generateWorklet(\n runner: LLMRunner,\n prompt: string,\n config: LLMGenerationConfig,\n stopTokens: string[],\n): {text: string; stats: LLMGenerationStats} {\n \"worklet\"\n let text = \"\"\n const stats = runner.generate(prompt, config, (token: string) => {\n if (stopTokens.includes(token)) return\n text += token\n })\n return {text, stats}\n}\n\nclass LocalLlmProvider {\n private static instance: LocalLlmProvider\n\n private loaded: LoadedModel | null = null\n private loading: Promise<LoadedModel> | null = null\n private queue: Promise<unknown> = Promise.resolve()\n private idleTimer: number | null = null\n private rne: Rne | null = null\n\n private constructor() {\n // A different model picked in Settings invalidates the resident runner.\n useSettingsStore.subscribe(\n (state) => state.settings[SETTINGS.local_llm_model.key],\n () => {\n void this.unload()\n },\n )\n }\n\n static getInstance(): LocalLlmProvider {\n if (!LocalLlmProvider.instance) LocalLlmProvider.instance = new LocalLlmProvider()\n return LocalLlmProvider.instance\n }\n\n /** Whether a runner is resident right now (diagnostics; not a readiness check). */\n isLoaded(): boolean {\n return this.loaded !== null\n }\n\n loadedModelId(): LocalLlmModelId | null {\n return this.loaded?.modelId ?? null\n }\n\n /** Serve one neutral completion on-device. Throws when the model is missing or generation fails. */\n complete(request: LlmCompleteRequest): Promise<LocalLlmCompleteResult> {\n const run = this.queue.then(() => this.completeInner(request))\n this.queue = run.catch(() => undefined)\n return run\n }\n\n /** Release the resident runner (idle, model switch, memory pressure). Safe to call repeatedly. */\n async unload(): Promise<void> {\n this.clearIdleTimer()\n // Never dispose under a running generation: let the queue drain first.\n await this.queue\n const pending = this.loading\n if (pending) {\n try {\n await pending\n } catch {\n // A failed load left nothing to release.\n }\n }\n this.releaseRunner()\n }\n\n /** Synchronous dispose; callers guarantee no generation is in flight. */\n private releaseRunner(): void {\n const loaded = this.loaded\n this.loaded = null\n if (!loaded) return\n try {\n loaded.runner.dispose()\n } catch (error) {\n console.warn(`${LOG_TAG}: runner dispose failed:`, error)\n }\n }\n\n private async completeInner(request: LlmCompleteRequest): Promise<LocalLlmCompleteResult> {\n this.clearIdleTimer()\n try {\n const model = await this.ensureLoaded()\n const jsonMode = request.jsonMode === true\n const tools = toTemplateTools(request.tools)\n const toolTokens = tools ? estimateTokens(JSON.stringify(tools)) + 64 : 0\n\n const maxNewTokens = Math.max(\n 16,\n Math.min(request.maxTokens ?? DEFAULT_MAX_NEW_TOKENS, MAX_NEW_TOKENS_CEILING, Math.floor(model.maxSeqLen / 4)),\n )\n const promptBudget = model.maxSeqLen - maxNewTokens - CONTEXT_MARGIN_TOKENS\n const messages = fitToBudget(buildTemplateMessages({...request, jsonMode}), promptBudget, toolTokens)\n\n const prompt = model.template.render({\n messages,\n tools,\n add_generation_prompt: true,\n enable_thinking: false,\n })\n\n model.runner.reset(0)\n const deadline = BgTimer.setTimeout(() => {\n console.warn(`${LOG_TAG}: generation deadline hit, stopping`)\n model.runner.stop()\n }, GENERATION_DEADLINE_MS)\n let generated: {text: string; stats: LLMGenerationStats}\n const startedAt = Date.now()\n try {\n generated = await model.generate(\n model.runner,\n prompt,\n {maxNewTokens, temperature: request.temperature ?? 0.7},\n model.stopTokens,\n )\n } finally {\n BgTimer.clearTimeout(deadline)\n }\n\n const elapsedMs = Date.now() - startedAt\n console.log(\n `${LOG_TAG}: ${model.modelId} prompt=${generated.stats.numPromptTokens} out=${generated.stats.numGeneratedTokens} tokens in ${elapsedMs} ms`,\n )\n\n const seed = `${Date.now().toString(36)}${Math.random().toString(36).slice(2, 6)}`\n const completion = finalizeLocalResult(\n {\n text: generated.text,\n promptTokens: generated.stats.numPromptTokens,\n generatedTokens: generated.stats.numGeneratedTokens,\n maxNewTokens,\n },\n {jsonMode, toolsOffered: Boolean(tools), makeToolCallId: (index) => `local_${seed}_${index}`},\n )\n return {...completion, modelId: model.modelId}\n } finally {\n this.armIdleTimer()\n }\n }\n\n private async ensureLoaded(): Promise<LoadedModel> {\n const modelId = localLlmModelManager.selectedModelId()\n if (this.loaded?.modelId === modelId) return this.loaded\n if (this.loading) return this.loading\n\n this.loading = this.load(modelId)\n .then((model) => {\n this.loaded = model\n return model\n })\n .finally(() => {\n this.loading = null\n })\n return this.loading\n }\n\n private async load(modelId: LocalLlmModelId): Promise<LoadedModel> {\n // Runs inside the request queue, so nothing is generating; unload() would\n // wait on that same queue.\n this.releaseRunner()\n if (!(await localLlmModelManager.isModelAvailable(modelId))) {\n throw new Error(`on-device model ${modelId} is not downloaded`)\n }\n const rne = await this.runtime()\n const paths = localLlmModelManager.paths(modelId)\n\n const tokenizerConfig = rne.llm.parseTokenizerConfig(JSON.parse(await RNFS.readFile(paths.tokenizerConfig, \"utf8\")))\n const template = new Template(tokenizerConfig.chatTemplate)\n\n const startedAt = Date.now()\n const createRunner = rne.wrapAsync(rne.llm.createLLMRunner)\n const runner = await createRunner(paths.model, paths.tokenizer, [])\n const maxSeqLen = runner.getKVCacheState().maxSeqLen\n console.log(`${LOG_TAG}: loaded ${modelId} (context ${maxSeqLen}) in ${Date.now() - startedAt} ms`)\n\n return {\n modelId,\n runner,\n template,\n stopTokens: [...tokenizerConfig.stopTokens],\n maxSeqLen,\n generate: rne.wrapAsync(generateWorklet),\n }\n }\n\n private async runtime(): Promise<Rne> {\n if (this.rne) return this.rne\n const rne: Rne = await import(\"react-native-executorch\")\n // Software Mansion's anonymous download analytics; the host has its own telemetry.\n rne.setTelemetryEnabled(false)\n this.rne = rne\n return rne\n }\n\n private armIdleTimer(): void {\n this.clearIdleTimer()\n this.idleTimer = BgTimer.setTimeout(() => {\n this.idleTimer = null\n console.log(`${LOG_TAG}: idle, unloading ${this.loaded?.modelId ?? \"nothing\"}`)\n void this.unload()\n }, IDLE_UNLOAD_MS)\n }\n\n private clearIdleTimer(): void {\n if (this.idleTimer) {\n BgTimer.clearTimeout(this.idleTimer)\n this.idleTimer = null\n }\n }\n}\n\nconst localLlmProvider = LocalLlmProvider.getInstance()\nexport {LocalLlmProvider}\nexport default localLlmProvider\n"]}
1
+ {"version":3,"file":"LocalLlmProvider.js","sourceRoot":"","sources":["../../src/services/LocalLlmProvider.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * LocalLlmProvider — session.ai.complete served by the phone itself: an\n * ExecuTorch runner (react-native-executorch) over the Qwen3 export that\n * LocalLlmModelManager downloaded. Stateless per request like the vendor\n * providers: every call renders the whole conversation through the model's\n * chat template, resets the KV cache, and generates on ExecuTorch's worklet\n * thread so the JS thread stays free.\n *\n * The runner is loaded on the first request and kept resident while calls\n * keep coming (loading a 1–3 GB model is seconds, not milliseconds); it is\n * dropped after an idle period and whenever the selected model changes.\n * Requests are serialized — one model, one KV cache.\n *\n * react-native-executorch is imported lazily so the engine module graph\n * loads without the native runtime (bun tests, hosts without the dependency).\n */\nimport * as RNFS from \"@dr.pogodin/react-native-fs\"\nimport {Template} from \"@huggingface/jinja\"\n\nimport type {LlmCompleteRequest} from \"@glassly/cloud-protocol/llm\"\nimport {BgTimer} from \"../utils/timers\"\nimport localLlmModelManager, {type LocalLlmModelId} from \"./LocalLlmModelManager\"\nimport {\n buildTemplateMessages,\n finalizeLocalResult,\n fitPromptToContext,\n toTemplateTools,\n type LocalCompletion,\n} from \"./LocalLlmPrompt\"\nimport {SETTINGS, useSettingsStore} from \"../stores/settings\"\n\ntype Rne = typeof import(\"react-native-executorch\")\n// The runner API lives on the `llm` namespace; derive its types from there so\n// the import stays a type-only reference (no native module at load time).\ntype Tokenizer = ReturnType<Rne[\"nlp\"][\"loadTokenizer\"]>\ntype LLMRunner = ReturnType<Rne[\"llm\"][\"createLLMRunner\"]>\ntype LLMGenerationStats = ReturnType<LLMRunner[\"generate\"]>\ntype LLMGenerationConfig = NonNullable<Parameters<LLMRunner[\"generate\"]>[1]>\n\nconst LOG_TAG = \"LOCAL_LLM\"\n\n/** Drop the resident model after this long without a request. */\nconst IDLE_UNLOAD_MS = 5 * 60_000\n/** Hard stop on one generation — the SDK request times out at 120 s anyway. */\nconst GENERATION_DEADLINE_MS = 100_000\nconst DEFAULT_MAX_NEW_TOKENS = 512\nconst MAX_NEW_TOKENS_CEILING = 1_024\n/** Reserve space for runner-added BOS/EOS tokens and context boundary bookkeeping. */\nconst CONTEXT_MARGIN_TOKENS = 96\n\ninterface LoadedModel {\n modelId: LocalLlmModelId\n runner: LLMRunner\n tokenizer: Tokenizer\n countTokens: (tokenizer: Tokenizer, prompt: string) => Promise<number>\n template: Template\n stopTokens: string[]\n maxSeqLen: number\n generate: (\n runner: LLMRunner,\n prompt: string,\n config: LLMGenerationConfig,\n stopTokens: string[],\n ) => Promise<{text: string; stats: LLMGenerationStats}>\n}\n\nexport interface LocalLlmCompleteResult extends LocalCompletion {\n modelId: LocalLlmModelId\n}\n\n/**\n * Runs on ExecuTorch's worklet runtime: `runner.generate` blocks its thread\n * until EOS, `maxNewTokens`, or `runner.stop()` from the JS thread.\n */\nfunction generateWorklet(\n runner: LLMRunner,\n prompt: string,\n config: LLMGenerationConfig,\n stopTokens: string[],\n): {text: string; stats: LLMGenerationStats} {\n \"worklet\"\n let text = \"\"\n const stats = runner.generate(prompt, config, (token: string) => {\n if (stopTokens.includes(token)) return\n text += token\n })\n return {text, stats}\n}\n\nfunction countTokensWorklet(tokenizer: Tokenizer, prompt: string): number {\n \"worklet\"\n return tokenizer.encode(prompt).length\n}\n\nclass LocalLlmProvider {\n private static instance: LocalLlmProvider\n\n private loaded: LoadedModel | null = null\n private loading: Promise<LoadedModel> | null = null\n private queue: Promise<unknown> = Promise.resolve()\n private idleTimer: number | null = null\n private rne: Rne | null = null\n\n private constructor() {\n // A different model picked in Settings invalidates the resident runner.\n useSettingsStore.subscribe(\n (state) => state.settings[SETTINGS.local_llm_model.key],\n () => {\n void this.unload()\n },\n )\n }\n\n static getInstance(): LocalLlmProvider {\n if (!LocalLlmProvider.instance) LocalLlmProvider.instance = new LocalLlmProvider()\n return LocalLlmProvider.instance\n }\n\n /** Whether a runner is resident right now (diagnostics; not a readiness check). */\n isLoaded(): boolean {\n return this.loaded !== null\n }\n\n loadedModelId(): LocalLlmModelId | null {\n return this.loaded?.modelId ?? null\n }\n\n /** Serve one neutral completion on-device. Throws when the model is missing or generation fails. */\n complete(request: LlmCompleteRequest): Promise<LocalLlmCompleteResult> {\n const run = this.queue.then(() => this.completeInner(request))\n this.queue = run.catch(() => undefined)\n return run\n }\n\n /** Release the resident runner (idle, model switch, memory pressure). Safe to call repeatedly. */\n async unload(): Promise<void> {\n this.clearIdleTimer()\n // Never dispose under a running generation: let the queue drain first.\n await this.queue\n const pending = this.loading\n if (pending) {\n try {\n await pending\n } catch {\n // A failed load left nothing to release.\n }\n }\n this.releaseRunner()\n }\n\n /** Synchronous dispose; callers guarantee no generation is in flight. */\n private releaseRunner(): void {\n const loaded = this.loaded\n this.loaded = null\n if (!loaded) return\n try {\n loaded.runner.dispose()\n } catch (error) {\n console.warn(`${LOG_TAG}: runner dispose failed:`, error)\n } finally {\n loaded.tokenizer.dispose()\n }\n }\n\n private async completeInner(request: LlmCompleteRequest): Promise<LocalLlmCompleteResult> {\n this.clearIdleTimer()\n try {\n const model = await this.ensureLoaded()\n const jsonMode = request.jsonMode === true\n const tools = toTemplateTools(request.tools)\n\n const maxNewTokens = Math.max(\n 16,\n Math.min(request.maxTokens ?? DEFAULT_MAX_NEW_TOKENS, MAX_NEW_TOKENS_CEILING, Math.floor(model.maxSeqLen / 4)),\n )\n const promptBudget = model.maxSeqLen - maxNewTokens - CONTEXT_MARGIN_TOKENS\n const {prompt, promptTokens, truncated} = await fitPromptToContext(\n buildTemplateMessages({...request, jsonMode}),\n promptBudget,\n (messages) => model.template.render({messages, tools, add_generation_prompt: true, enable_thinking: false}),\n (text) => model.countTokens(model.tokenizer, text),\n )\n console.log(\n `${LOG_TAG}: ${model.modelId} prompt=${promptTokens} budget=${promptBudget} context=${model.maxSeqLen} maxNewTokens=${maxNewTokens} truncated=${truncated}`,\n )\n\n model.runner.reset(0)\n const deadline = BgTimer.setTimeout(() => {\n console.warn(`${LOG_TAG}: generation deadline hit, stopping`)\n model.runner.stop()\n }, GENERATION_DEADLINE_MS)\n let generated: {text: string; stats: LLMGenerationStats}\n const startedAt = Date.now()\n try {\n generated = await model.generate(\n model.runner,\n prompt,\n {maxNewTokens, temperature: request.temperature ?? 0.7},\n model.stopTokens,\n )\n } catch (error) {\n console.warn(\n `${LOG_TAG}: generation failed: model=${model.modelId} prompt=${promptTokens} context=${model.maxSeqLen} maxNewTokens=${maxNewTokens}`,\n error,\n )\n throw error\n } finally {\n BgTimer.clearTimeout(deadline)\n }\n\n const elapsedMs = Date.now() - startedAt\n console.log(\n `${LOG_TAG}: ${model.modelId} prompt=${generated.stats.numPromptTokens} out=${generated.stats.numGeneratedTokens} tokens in ${elapsedMs} ms`,\n )\n\n const seed = `${Date.now().toString(36)}${Math.random().toString(36).slice(2, 6)}`\n const completion = finalizeLocalResult(\n {\n text: generated.text,\n promptTokens: generated.stats.numPromptTokens,\n generatedTokens: generated.stats.numGeneratedTokens,\n maxNewTokens,\n },\n {jsonMode, toolsOffered: Boolean(tools), makeToolCallId: (index) => `local_${seed}_${index}`},\n )\n return {...completion, modelId: model.modelId}\n } finally {\n this.armIdleTimer()\n }\n }\n\n private async ensureLoaded(): Promise<LoadedModel> {\n const modelId = localLlmModelManager.selectedModelId()\n if (this.loaded?.modelId === modelId) return this.loaded\n if (this.loading) return this.loading\n\n this.loading = this.load(modelId)\n .then((model) => {\n this.loaded = model\n return model\n })\n .finally(() => {\n this.loading = null\n })\n return this.loading\n }\n\n private async load(modelId: LocalLlmModelId): Promise<LoadedModel> {\n // Runs inside the request queue, so nothing is generating; unload() would\n // wait on that same queue.\n this.releaseRunner()\n if (!(await localLlmModelManager.isModelAvailable(modelId))) {\n throw new Error(`on-device model ${modelId} is not downloaded`)\n }\n const rne = await this.runtime()\n const paths = localLlmModelManager.paths(modelId)\n\n const tokenizerConfig = rne.llm.parseTokenizerConfig(JSON.parse(await RNFS.readFile(paths.tokenizerConfig, \"utf8\")))\n const template = new Template(tokenizerConfig.chatTemplate)\n\n const startedAt = Date.now()\n const createRunner = rne.wrapAsync(rne.llm.createLLMRunner)\n const runner = await createRunner(paths.model, paths.tokenizer, [])\n let tokenizer: Tokenizer | undefined\n try {\n const maxSeqLen = runner.getKVCacheState().maxSeqLen\n if (!Number.isInteger(maxSeqLen) || maxSeqLen <= CONTEXT_MARGIN_TOKENS + 16) {\n throw new Error(`On-device model ${modelId} reported an invalid context size: ${maxSeqLen}`)\n }\n tokenizer = await rne.wrapAsync(rne.nlp.loadTokenizer)(paths.tokenizer)\n console.log(`${LOG_TAG}: loaded ${modelId} (context ${maxSeqLen}) in ${Date.now() - startedAt} ms`)\n return {\n modelId,\n runner,\n tokenizer,\n countTokens: rne.wrapAsync(countTokensWorklet),\n template,\n stopTokens: [...tokenizerConfig.stopTokens],\n maxSeqLen,\n generate: rne.wrapAsync(generateWorklet),\n }\n } catch (error) {\n tokenizer?.dispose()\n runner.dispose()\n throw error\n }\n }\n\n private async runtime(): Promise<Rne> {\n if (this.rne) return this.rne\n const rne: Rne = await import(\"react-native-executorch\")\n // Software Mansion's anonymous download analytics; the host has its own telemetry.\n rne.setTelemetryEnabled(false)\n this.rne = rne\n return rne\n }\n\n private armIdleTimer(): void {\n this.clearIdleTimer()\n this.idleTimer = BgTimer.setTimeout(() => {\n this.idleTimer = null\n console.log(`${LOG_TAG}: idle, unloading ${this.loaded?.modelId ?? \"nothing\"}`)\n void this.unload()\n }, IDLE_UNLOAD_MS)\n }\n\n private clearIdleTimer(): void {\n if (this.idleTimer) {\n BgTimer.clearTimeout(this.idleTimer)\n this.idleTimer = null\n }\n }\n}\n\nconst localLlmProvider = LocalLlmProvider.getInstance()\nexport {LocalLlmProvider}\nexport default localLlmProvider\n"]}
@@ -765,12 +765,27 @@ declare class LocalMiniappRuntime {
765
765
  private onWidgetPartyGone;
766
766
  /** True iff `value` serializes larger than the action payload cap. */
767
767
  private actionPayloadTooLarge;
768
+ /** Floored at 6s: a freshly-woken target buffers an undelivered ACTION_CALL for 5s (HANDLER_WAIT_MS in @glassly/miniapp's actions module) + 1s for the reply. Keep in sync. */
769
+ private static clampActionTimeout;
770
+ /** Caller identity the host presents for host-initiated actions (a system caller). */
771
+ private static readonly HOST_ACTION_CALLER;
772
+ /** Installed, compatible, and declares the action — the same gates `invokeActionFromHost` applies up front. */
773
+ hostActionAvailable(targetPackageName: string, actionId: string): boolean;
774
+ /**
775
+ * Host-initiated action call (e.g. the watch remote): same gates, headless
776
+ * wake and ACTION_CALL/ACTION_RESULT correlation as a miniapp's
777
+ * session.actions.invoke, with the host as a system caller.
778
+ * Rejects with an Error whose `code` is a MiniappErrorCode.
779
+ */
780
+ invokeActionFromHost(targetPackageName: string, actionId: string, params?: Record<string, unknown>, timeoutMs?: number): Promise<unknown>;
781
+ /** session.actions.invoke → run the call, then relay the outcome to the caller's pending request. */
782
+ private handleActionInvoke;
768
783
  /**
769
- * session.actions.invoke → wake the target headlessly, deliver an ACTION_CALL,
770
- * and correlate its ACTION_RESULT back to the caller's pending request.
784
+ * Gate, wake the target headlessly, deliver an ACTION_CALL, and resolve when
785
+ * its ACTION_RESULT (or the timeout) arrives. Never rejects.
771
786
  */
772
- private handleActionInvoke;
773
- /** Target → host: forward an ACTION_RESULT back to the caller's pending invoke. */
787
+ private runActionInvoke;
788
+ /** Target → host: settle the pending invoke for this ACTION_RESULT. */
774
789
  private handleActionResult;
775
790
  private sendResult;
776
791
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"LocalMiniappRuntime.d.ts","sourceRoot":"","sources":["../../src/services/LocalMiniappRuntime.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"LocalMiniappRuntime.d.ts","sourceRoot":"","sources":["../../src/services/LocalMiniappRuntime.ts"],"names":[],"mappings":"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"}
@@ -82,6 +82,7 @@ import { invokeScanQrSeam } from "../runtime/scanQrSeam";
82
82
  import { invokeWebLoginSeam } from "../runtime/webLoginSeam";
83
83
  import { normalizeStreamAudioConfig, normalizeStreamVideoConfig } from "../runtime/streamConfig";
84
84
  import { visibleActionRows } from "./manifestActions";
85
+ import { actionFailure, appDeclaresAction, checkActionAccess, PendingActionCalls, } from "./actionInvoke";
85
86
  import { toLanguageHint } from "@glassly/cloud-protocol/languages";
86
87
  import { buildMiniappManifestSnapshot } from "../utils/miniappDiagnostics";
87
88
  import ttsModelManager from "./TTSModelManager";
@@ -5253,7 +5254,7 @@ class LocalMiniappRuntime {
5253
5254
  /** Max serialized size of an action call's params / result (256 KB). */
5254
5255
  static ACTION_PAYLOAD_CAP = 256 * 1024;
5255
5256
  /** Outstanding action invocations, keyed by host-generated callId. */
5256
- actionCalls = new Map();
5257
+ actionCalls = new PendingActionCalls(BgTimer, (value) => this.actionPayloadTooLarge(value));
5257
5258
  actionCallSeq = 0;
5258
5259
  interopApps() {
5259
5260
  return useAppStatusStore.getState().apps;
@@ -5785,104 +5786,82 @@ class LocalMiniappRuntime {
5785
5786
  return false;
5786
5787
  }
5787
5788
  }
5789
+ /** Floored at 6s: a freshly-woken target buffers an undelivered ACTION_CALL for 5s (HANDLER_WAIT_MS in @glassly/miniapp's actions module) + 1s for the reply. Keep in sync. */
5790
+ static clampActionTimeout(raw) {
5791
+ return Math.min(Math.max(Number(raw) || 30_000, 6_000), 120_000);
5792
+ }
5793
+ /** Caller identity the host presents for host-initiated actions (a system caller). */
5794
+ static HOST_ACTION_CALLER = "host";
5795
+ /** Installed, compatible, and declares the action — the same gates `invokeActionFromHost` applies up front. */
5796
+ hostActionAvailable(targetPackageName, actionId) {
5797
+ return appDeclaresAction(this.interopApps().find((a) => a.packageName === targetPackageName), actionId);
5798
+ }
5788
5799
  /**
5789
- * session.actions.invoke → wake the target headlessly, deliver an ACTION_CALL,
5790
- * and correlate its ACTION_RESULT back to the caller's pending request.
5800
+ * Host-initiated action call (e.g. the watch remote): same gates, headless
5801
+ * wake and ACTION_CALL/ACTION_RESULT correlation as a miniapp's
5802
+ * session.actions.invoke, with the host as a system caller.
5803
+ * Rejects with an Error whose `code` is a MiniappErrorCode.
5791
5804
  */
5805
+ async invokeActionFromHost(targetPackageName, actionId, params = {}, timeoutMs) {
5806
+ const outcome = await this.runActionInvoke(LocalMiniappRuntime.HOST_ACTION_CALLER, true, targetPackageName, actionId, params, LocalMiniappRuntime.clampActionTimeout(timeoutMs));
5807
+ if (outcome.ok)
5808
+ return outcome.data;
5809
+ throw Object.assign(new Error(outcome.error.message), { code: outcome.error.code });
5810
+ }
5811
+ /** session.actions.invoke → run the call, then relay the outcome to the caller's pending request. */
5792
5812
  async handleActionInvoke(callerPackageName, payload, requestId) {
5793
- const target = payload.targetPackageName;
5794
- const actionId = payload.actionId;
5795
- const params = payload.params ?? {};
5796
- // Floor the timeout at 6s so the host never rejects with ACTION_TIMEOUT before
5797
- // the target SDK's handler-registration window closes. A freshly-woken miniapp
5798
- // buffers an undelivered ACTION_CALL for HANDLER_WAIT_MS (5s in @glassly/miniapp's
5799
- // actions module) waiting for session.actions.handle; a shorter host timeout
5800
- // could fire while the target is still registering, then the action would run
5801
- // with no caller left to receive its result. 6s = that 5s buffer + 1s for the
5802
- // ACTION_RESULT/NO_ACTION_HANDLER reply to travel back. Keep these in sync.
5803
- const timeoutMs = Math.min(Math.max(Number(payload.timeoutMs) || 30_000, 6_000), 120_000);
5813
+ const outcome = await this.runActionInvoke(callerPackageName, this.isSystemPackage(callerPackageName), payload.targetPackageName, payload.actionId, payload.params ?? {}, LocalMiniappRuntime.clampActionTimeout(payload.timeoutMs));
5814
+ if (outcome.ok)
5815
+ this.sendResult(callerPackageName, requestId, true, outcome.data);
5816
+ else
5817
+ this.sendResult(callerPackageName, requestId, false, undefined, outcome.error);
5818
+ }
5819
+ /**
5820
+ * Gate, wake the target headlessly, deliver an ACTION_CALL, and resolve when
5821
+ * its ACTION_RESULT (or the timeout) arrives. Never rejects.
5822
+ */
5823
+ async runActionInvoke(callerPackageName, callerIsSystem, target, actionId, params, timeoutMs) {
5824
+ const fail = actionFailure;
5804
5825
  if (this.actionPayloadTooLarge(params)) {
5805
- this.sendResult(callerPackageName, requestId, false, undefined, {
5806
- code: MiniappErrorCode.PAYLOAD_TOO_LARGE,
5807
- message: "action params exceeded the 256 KB cap",
5808
- });
5809
- return;
5826
+ return fail(MiniappErrorCode.PAYLOAD_TOO_LARGE, "action params exceeded the 256 KB cap");
5810
5827
  }
5811
5828
  const app = target ? this.interopApps().find((a) => a.packageName === target) : undefined;
5812
- if (!target || !app) {
5813
- this.sendResult(callerPackageName, requestId, false, undefined, {
5814
- code: MiniappErrorCode.APP_NOT_FOUND,
5815
- message: `Miniapp not found: ${target ?? "(missing targetPackageName)"}`,
5816
- });
5817
- return;
5818
- }
5819
- if (!actionId) {
5820
- this.sendResult(callerPackageName, requestId, false, undefined, {
5821
- code: MiniappErrorCode.ACTION_NOT_FOUND,
5822
- message: "invoke requires an actionId",
5823
- });
5824
- return;
5825
- }
5826
- if (app.compatibility && app.compatibility.isCompatible === false) {
5827
- this.sendResult(callerPackageName, requestId, false, undefined, {
5828
- code: MiniappErrorCode.APP_NOT_COMPATIBLE,
5829
- message: `${target} is not compatible with the connected glasses`,
5830
- });
5831
- islandNotifications.emit({
5832
- kind: "version_incompatible",
5833
- packageName: target,
5834
- reason: `${target} is not compatible with the connected glasses`,
5835
- metadata: { missingRequired: app.compatibility.missingRequired ?? [], via: "miniapps.invoke" },
5836
- timestamp: Date.now(),
5837
- });
5838
- return;
5839
- }
5840
- // Declared-action gate: the target must declare the action in its manifest.
5841
- const declared = (app.actions ?? []).find((a) => a.id === actionId);
5842
- if (!declared) {
5843
- this.sendResult(callerPackageName, requestId, false, undefined, {
5844
- code: MiniappErrorCode.ACTION_NOT_FOUND,
5845
- message: `${target} does not declare action "${actionId}"`,
5846
- });
5847
- return;
5848
- }
5849
- // Visibility gate: declared actions are public by default; ones marked
5850
- // `visibility: "system"` stay restricted to system/dev callers.
5851
- if (declared.visibility === "system" && !this.isSystemPackage(callerPackageName)) {
5852
- this.auditInterop({
5853
- caller: callerPackageName,
5854
- op: "invoke",
5855
- target,
5856
- actionId,
5857
- ok: false,
5858
- errorCode: MiniappErrorCode.NOT_PERMITTED,
5859
- });
5860
- this.sendResult(callerPackageName, requestId, false, undefined, {
5861
- code: MiniappErrorCode.NOT_PERMITTED,
5862
- message: `Action "${actionId}" on ${target} is restricted to system apps`,
5863
- });
5864
- return;
5829
+ const denied = checkActionAccess(app, target, actionId, callerIsSystem);
5830
+ if (denied) {
5831
+ if (denied.code === MiniappErrorCode.APP_NOT_COMPATIBLE && target && app) {
5832
+ islandNotifications.emit({
5833
+ kind: "version_incompatible",
5834
+ packageName: target,
5835
+ reason: denied.message,
5836
+ metadata: { missingRequired: app.compatibility?.missingRequired ?? [], via: "miniapps.invoke" },
5837
+ timestamp: Date.now(),
5838
+ });
5839
+ }
5840
+ else if (denied.code === MiniappErrorCode.NOT_PERMITTED) {
5841
+ this.auditInterop({
5842
+ caller: callerPackageName,
5843
+ op: "invoke",
5844
+ target,
5845
+ actionId,
5846
+ ok: false,
5847
+ errorCode: MiniappErrorCode.NOT_PERMITTED,
5848
+ });
5849
+ }
5850
+ return { ok: false, error: denied };
5865
5851
  }
5852
+ if (!target || !actionId)
5853
+ return fail(MiniappErrorCode.INTERNAL, "unreachable");
5866
5854
  // Headless wake + wait for CONNECT (idempotent / fast if already connected).
5867
5855
  try {
5868
5856
  await this.wakeInteropApp(target);
5869
5857
  }
5870
5858
  catch (e) {
5871
- this.sendResult(callerPackageName, requestId, false, undefined, {
5872
- code: MiniappErrorCode.WAKE_FAILED,
5873
- message: e?.message ?? `failed to wake ${target}`,
5874
- });
5875
- return;
5859
+ return fail(MiniappErrorCode.WAKE_FAILED, e?.message ?? `failed to wake ${target}`);
5876
5860
  }
5877
5861
  // The wake waited for CONNECT, but the target could have dropped in the gap
5878
5862
  // before delivery — fail fast rather than arming a timer for a call that
5879
- // sendToMiniapp would silently drop (the caller would otherwise wait the
5880
- // full invoke timeout for an ACTION_CALL that was never delivered).
5863
+ // sendToMiniapp would silently drop.
5881
5864
  if (!this.connectedApps.has(target)) {
5882
- this.sendResult(callerPackageName, requestId, false, undefined, {
5883
- code: MiniappErrorCode.WAKE_FAILED,
5884
- message: `${target} disconnected before the action could be delivered`,
5885
- });
5886
5865
  this.auditInterop({
5887
5866
  caller: callerPackageName,
5888
5867
  op: "invoke",
@@ -5891,18 +5870,11 @@ class LocalMiniappRuntime {
5891
5870
  ok: false,
5892
5871
  errorCode: MiniappErrorCode.WAKE_FAILED,
5893
5872
  });
5894
- return;
5873
+ return fail(MiniappErrorCode.WAKE_FAILED, `${target} disconnected before the action could be delivered`);
5895
5874
  }
5896
- // Deliver the call and arm the handler timeout; ACTION_RESULT resolves it.
5875
+ // Deliver the call and arm the handler timeout; ACTION_RESULT settles it.
5897
5876
  const callId = `act-${Date.now().toString(36)}-${this.actionCallSeq++}`;
5898
- const timer = BgTimer.setTimeout(() => {
5899
- this.actionCalls.delete(callId);
5900
- this.sendResult(callerPackageName, requestId, false, undefined, {
5901
- code: MiniappErrorCode.ACTION_TIMEOUT,
5902
- message: `action "${actionId}" timed out after ${timeoutMs}ms`,
5903
- });
5904
- }, timeoutMs);
5905
- this.actionCalls.set(callId, { callerPackageName, targetPackageName: target, callerRequestId: requestId, timer });
5877
+ const outcome = this.actionCalls.register(callId, target, actionId, timeoutMs);
5906
5878
  this.sendToMiniapp(target, {
5907
5879
  type: MiniappResponseType.ACTION_CALL,
5908
5880
  callId,
@@ -5911,40 +5883,11 @@ class LocalMiniappRuntime {
5911
5883
  callerPackageName,
5912
5884
  });
5913
5885
  this.auditInterop({ caller: callerPackageName, op: "invoke", target, actionId, ok: true });
5886
+ return outcome;
5914
5887
  }
5915
- /** Target → host: forward an ACTION_RESULT back to the caller's pending invoke. */
5888
+ /** Target → host: settle the pending invoke for this ACTION_RESULT. */
5916
5889
  handleActionResult(targetPackageName, payload) {
5917
- const callId = payload.callId;
5918
- if (!callId)
5919
- return;
5920
- const pending = this.actionCalls.get(callId);
5921
- if (!pending)
5922
- return;
5923
- // Only the invoked target may resolve this call. callIds are guessable
5924
- // (timestamp + seq), so a different connected miniapp must not be able to
5925
- // spoof a result/error for someone else's invoke.
5926
- if (pending.targetPackageName !== targetPackageName)
5927
- return;
5928
- this.actionCalls.delete(callId);
5929
- BgTimer.clearTimeout(pending.timer);
5930
- if (payload.ok === true) {
5931
- const result = payload.result;
5932
- if (this.actionPayloadTooLarge(result)) {
5933
- this.sendResult(pending.callerPackageName, pending.callerRequestId, false, undefined, {
5934
- code: MiniappErrorCode.PAYLOAD_TOO_LARGE,
5935
- message: "action result exceeded the 256 KB cap",
5936
- });
5937
- return;
5938
- }
5939
- this.sendResult(pending.callerPackageName, pending.callerRequestId, true, result ?? null);
5940
- }
5941
- else {
5942
- const error = payload.error ?? {
5943
- code: MiniappErrorCode.INTERNAL,
5944
- message: "action handler error",
5945
- };
5946
- this.sendResult(pending.callerPackageName, pending.callerRequestId, false, undefined, error);
5947
- }
5890
+ this.actionCalls.handleResult(targetPackageName, payload);
5948
5891
  }
5949
5892
  sendResult(packageName, requestId, ok, data, error) {
5950
5893
  if (!requestId)