drowse.ai 5.3.1__py3-none-any.whl

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 (1341) hide show
  1. drowse/__init__.py +312 -0
  2. drowse/__main__.py +5 -0
  3. drowse/cli/__init__.py +5 -0
  4. drowse/cli/alpha_grid.py +96 -0
  5. drowse/cli/config_file.py +340 -0
  6. drowse/cli/main.py +52 -0
  7. drowse/cli/parsers.py +1478 -0
  8. drowse/cli/runners/__init__.py +155 -0
  9. drowse/cli/runners/config.py +85 -0
  10. drowse/cli/runners/experiment.py +344 -0
  11. drowse/cli/runners/lens.py +661 -0
  12. drowse/cli/runners/manifold.py +1097 -0
  13. drowse/cli/runners/pack.py +413 -0
  14. drowse/cli/runners/sae.py +304 -0
  15. drowse/cli/runners/serve.py +220 -0
  16. drowse/cli/runners/shared.py +389 -0
  17. drowse/cli/runners/template.py +232 -0
  18. drowse/core/__init__.py +1 -0
  19. drowse/core/capture.py +1205 -0
  20. drowse/core/errors.py +260 -0
  21. drowse/core/events.py +156 -0
  22. drowse/core/extraction.py +3076 -0
  23. drowse/core/generation.py +1738 -0
  24. drowse/core/generation_finalizer.py +278 -0
  25. drowse/core/histogram.py +30 -0
  26. drowse/core/hooks.py +1885 -0
  27. drowse/core/instruments/__init__.py +49 -0
  28. drowse/core/instruments/geometry.py +551 -0
  29. drowse/core/instruments/lens.py +1341 -0
  30. drowse/core/instruments/protocol.py +211 -0
  31. drowse/core/instruments/sae.py +935 -0
  32. drowse/core/instruments/types.py +597 -0
  33. drowse/core/jlens.py +874 -0
  34. drowse/core/jlens_fit.py +1305 -0
  35. drowse/core/joint_logprobs.py +748 -0
  36. drowse/core/loom.py +1938 -0
  37. drowse/core/loom_diff.py +408 -0
  38. drowse/core/mahalanobis.py +579 -0
  39. drowse/core/manifold.py +4106 -0
  40. drowse/core/measurements.py +382 -0
  41. drowse/core/model.py +1724 -0
  42. drowse/core/monitor.py +2060 -0
  43. drowse/core/monitor_attach.py +682 -0
  44. drowse/core/naming.py +42 -0
  45. drowse/core/naturalness.py +187 -0
  46. drowse/core/profile.py +617 -0
  47. drowse/core/relp.py +313 -0
  48. drowse/core/results.py +467 -0
  49. drowse/core/role_templates.py +677 -0
  50. drowse/core/sae.py +891 -0
  51. drowse/core/sae_training.py +239 -0
  52. drowse/core/sampling.py +127 -0
  53. drowse/core/scene.py +810 -0
  54. drowse/core/scoring.py +270 -0
  55. drowse/core/session.py +11015 -0
  56. drowse/core/static_cache.py +316 -0
  57. drowse/core/steering.py +229 -0
  58. drowse/core/steering_composer.py +1135 -0
  59. drowse/core/steering_expr.py +1413 -0
  60. drowse/core/surface_topology.py +128 -0
  61. drowse/core/token_callback.py +52 -0
  62. drowse/core/token_payloads.py +244 -0
  63. drowse/core/topology.py +1469 -0
  64. drowse/core/transcript.py +582 -0
  65. drowse/core/tree_filter.py +353 -0
  66. drowse/core/triggers.py +250 -0
  67. drowse/data/baseline_prompts.json +50 -0
  68. drowse/data/manifolds/confident.uncertain/manifold.json +28 -0
  69. drowse/data/manifolds/confident.uncertain/nodes/00_confident.json +50 -0
  70. drowse/data/manifolds/confident.uncertain/nodes/01_uncertain.json +50 -0
  71. drowse/data/manifolds/creative.conventional/manifold.json +28 -0
  72. drowse/data/manifolds/creative.conventional/nodes/00_creative.json +50 -0
  73. drowse/data/manifolds/creative.conventional/nodes/01_conventional.json +50 -0
  74. drowse/data/manifolds/curious.disinterested/manifold.json +28 -0
  75. drowse/data/manifolds/curious.disinterested/nodes/00_curious.json +50 -0
  76. drowse/data/manifolds/curious.disinterested/nodes/01_disinterested.json +50 -0
  77. drowse/data/manifolds/direct.indirect/manifold.json +28 -0
  78. drowse/data/manifolds/direct.indirect/nodes/00_direct.json +50 -0
  79. drowse/data/manifolds/direct.indirect/nodes/01_indirect.json +50 -0
  80. drowse/data/manifolds/emotions/manifold.json +115 -0
  81. drowse/data/manifolds/emotions/nodes/00_excited.json +50 -0
  82. drowse/data/manifolds/emotions/nodes/01_happy.json +50 -0
  83. drowse/data/manifolds/emotions/nodes/02_calm.json +50 -0
  84. drowse/data/manifolds/emotions/nodes/03_weary.json +50 -0
  85. drowse/data/manifolds/emotions/nodes/04_sad.json +50 -0
  86. drowse/data/manifolds/emotions/nodes/05_distressed.json +50 -0
  87. drowse/data/manifolds/emotions/nodes/06_alert.json +50 -0
  88. drowse/data/manifolds/emotions/nodes/07_dominant.json +50 -0
  89. drowse/data/manifolds/emotions/nodes/08_submissive.json +50 -0
  90. drowse/data/manifolds/emotions/nodes/09_angry.json +50 -0
  91. drowse/data/manifolds/emotions/nodes/10_fearful.json +50 -0
  92. drowse/data/manifolds/emotions/nodes/11_surprised.json +50 -0
  93. drowse/data/manifolds/emotions/nodes/12_triumphant.json +50 -0
  94. drowse/data/manifolds/emotions/nodes/13_humiliated.json +50 -0
  95. drowse/data/manifolds/emotions/nodes/14_disgusted.json +50 -0
  96. drowse/data/manifolds/emotions/nodes/15_bored.json +50 -0
  97. drowse/data/manifolds/emotions/nodes/16_grateful.json +50 -0
  98. drowse/data/manifolds/emotions/nodes/17_relieved.json +50 -0
  99. drowse/data/manifolds/emotions/nodes/18_playful.json +50 -0
  100. drowse/data/manifolds/emotions/nodes/19_hopeful.json +50 -0
  101. drowse/data/manifolds/formal.casual/manifold.json +28 -0
  102. drowse/data/manifolds/formal.casual/nodes/00_formal.json +50 -0
  103. drowse/data/manifolds/formal.casual/nodes/01_casual.json +50 -0
  104. drowse/data/manifolds/honest.deceptive/manifold.json +28 -0
  105. drowse/data/manifolds/honest.deceptive/nodes/00_honest.json +50 -0
  106. drowse/data/manifolds/honest.deceptive/nodes/01_deceptive.json +50 -0
  107. drowse/data/manifolds/humorous.serious/manifold.json +28 -0
  108. drowse/data/manifolds/humorous.serious/nodes/00_humorous.json +50 -0
  109. drowse/data/manifolds/humorous.serious/nodes/01_serious.json +50 -0
  110. drowse/data/manifolds/individualist.collectivist/manifold.json +28 -0
  111. drowse/data/manifolds/individualist.collectivist/nodes/00_individualist.json +50 -0
  112. drowse/data/manifolds/individualist.collectivist/nodes/01_collectivist.json +50 -0
  113. drowse/data/manifolds/masculine.feminine/manifold.json +28 -0
  114. drowse/data/manifolds/masculine.feminine/nodes/00_masculine.json +50 -0
  115. drowse/data/manifolds/masculine.feminine/nodes/01_feminine.json +50 -0
  116. drowse/data/manifolds/months/manifold.json +120 -0
  117. drowse/data/manifolds/months/nodes/00_january.json +50 -0
  118. drowse/data/manifolds/months/nodes/01_february.json +50 -0
  119. drowse/data/manifolds/months/nodes/02_march.json +50 -0
  120. drowse/data/manifolds/months/nodes/03_april.json +50 -0
  121. drowse/data/manifolds/months/nodes/04_may.json +50 -0
  122. drowse/data/manifolds/months/nodes/05_june.json +50 -0
  123. drowse/data/manifolds/months/nodes/06_july.json +50 -0
  124. drowse/data/manifolds/months/nodes/07_august.json +50 -0
  125. drowse/data/manifolds/months/nodes/08_september.json +50 -0
  126. drowse/data/manifolds/months/nodes/09_october.json +50 -0
  127. drowse/data/manifolds/months/nodes/10_november.json +50 -0
  128. drowse/data/manifolds/months/nodes/11_december.json +50 -0
  129. drowse/data/manifolds/personas/manifold.json +550 -0
  130. drowse/data/manifolds/personas/nodes/00_assistant.json +50 -0
  131. drowse/data/manifolds/personas/nodes/01_analyst.json +50 -0
  132. drowse/data/manifolds/personas/nodes/02_impostor.json +50 -0
  133. drowse/data/manifolds/personas/nodes/03_teacher.json +50 -0
  134. drowse/data/manifolds/personas/nodes/04_doctor.json +50 -0
  135. drowse/data/manifolds/personas/nodes/05_librarian.json +50 -0
  136. drowse/data/manifolds/personas/nodes/06_farmer.json +50 -0
  137. drowse/data/manifolds/personas/nodes/07_soldier.json +50 -0
  138. drowse/data/manifolds/personas/nodes/08_lawyer.json +50 -0
  139. drowse/data/manifolds/personas/nodes/09_chef.json +50 -0
  140. drowse/data/manifolds/personas/nodes/100_assassin.json +50 -0
  141. drowse/data/manifolds/personas/nodes/101_thief.json +50 -0
  142. drowse/data/manifolds/personas/nodes/102_conman.json +50 -0
  143. drowse/data/manifolds/personas/nodes/103_hacker.json +50 -0
  144. drowse/data/manifolds/personas/nodes/104_cultist.json +50 -0
  145. drowse/data/manifolds/personas/nodes/105_tyrant.json +50 -0
  146. drowse/data/manifolds/personas/nodes/106_vandal.json +50 -0
  147. drowse/data/manifolds/personas/nodes/10_journalist.json +50 -0
  148. drowse/data/manifolds/personas/nodes/11_mechanic.json +50 -0
  149. drowse/data/manifolds/personas/nodes/12_sailor.json +50 -0
  150. drowse/data/manifolds/personas/nodes/13_pilot.json +50 -0
  151. drowse/data/manifolds/personas/nodes/14_athlete.json +50 -0
  152. drowse/data/manifolds/personas/nodes/15_engineer.json +50 -0
  153. drowse/data/manifolds/personas/nodes/16_scientist.json +50 -0
  154. drowse/data/manifolds/personas/nodes/17_banker.json +50 -0
  155. drowse/data/manifolds/personas/nodes/18_salesperson.json +50 -0
  156. drowse/data/manifolds/personas/nodes/19_nerd.json +50 -0
  157. drowse/data/manifolds/personas/nodes/20_jock.json +50 -0
  158. drowse/data/manifolds/personas/nodes/21_gamer.json +50 -0
  159. drowse/data/manifolds/personas/nodes/22_furry.json +50 -0
  160. drowse/data/manifolds/personas/nodes/23_weeaboo.json +50 -0
  161. drowse/data/manifolds/personas/nodes/24_influencer.json +50 -0
  162. drowse/data/manifolds/personas/nodes/25_stoner.json +50 -0
  163. drowse/data/manifolds/personas/nodes/26_femboy.json +50 -0
  164. drowse/data/manifolds/personas/nodes/27_ceo.json +50 -0
  165. drowse/data/manifolds/personas/nodes/28_emperor.json +50 -0
  166. drowse/data/manifolds/personas/nodes/29_president.json +50 -0
  167. drowse/data/manifolds/personas/nodes/30_diplomat.json +50 -0
  168. drowse/data/manifolds/personas/nodes/31_judge.json +50 -0
  169. drowse/data/manifolds/personas/nodes/32_bureaucrat.json +50 -0
  170. drowse/data/manifolds/personas/nodes/33_conservative.json +50 -0
  171. drowse/data/manifolds/personas/nodes/34_liberal.json +50 -0
  172. drowse/data/manifolds/personas/nodes/35_libertarian.json +50 -0
  173. drowse/data/manifolds/personas/nodes/36_communist.json +50 -0
  174. drowse/data/manifolds/personas/nodes/37_anarchist.json +50 -0
  175. drowse/data/manifolds/personas/nodes/38_reactionary.json +50 -0
  176. drowse/data/manifolds/personas/nodes/39_loner.json +50 -0
  177. drowse/data/manifolds/personas/nodes/40_friend.json +50 -0
  178. drowse/data/manifolds/personas/nodes/41_rival.json +50 -0
  179. drowse/data/manifolds/personas/nodes/42_stranger.json +50 -0
  180. drowse/data/manifolds/personas/nodes/43_lover.json +50 -0
  181. drowse/data/manifolds/personas/nodes/44_stalker.json +50 -0
  182. drowse/data/manifolds/personas/nodes/45_lunatic.json +50 -0
  183. drowse/data/manifolds/personas/nodes/46_paranoid.json +50 -0
  184. drowse/data/manifolds/personas/nodes/47_detective.json +50 -0
  185. drowse/data/manifolds/personas/nodes/48_therapist.json +50 -0
  186. drowse/data/manifolds/personas/nodes/49_nomad.json +50 -0
  187. drowse/data/manifolds/personas/nodes/50_pirate.json +50 -0
  188. drowse/data/manifolds/personas/nodes/51_child.json +50 -0
  189. drowse/data/manifolds/personas/nodes/52_caveman.json +50 -0
  190. drowse/data/manifolds/personas/nodes/53_monk.json +50 -0
  191. drowse/data/manifolds/personas/nodes/54_knight.json +50 -0
  192. drowse/data/manifolds/personas/nodes/55_alchemist.json +50 -0
  193. drowse/data/manifolds/personas/nodes/56_blacksmith.json +50 -0
  194. drowse/data/manifolds/personas/nodes/57_viking.json +50 -0
  195. drowse/data/manifolds/personas/nodes/58_druid.json +50 -0
  196. drowse/data/manifolds/personas/nodes/59_poet.json +50 -0
  197. drowse/data/manifolds/personas/nodes/60_novelist.json +50 -0
  198. drowse/data/manifolds/personas/nodes/61_jester.json +50 -0
  199. drowse/data/manifolds/personas/nodes/62_philosopher.json +50 -0
  200. drowse/data/manifolds/personas/nodes/63_painter.json +50 -0
  201. drowse/data/manifolds/personas/nodes/64_musician.json +50 -0
  202. drowse/data/manifolds/personas/nodes/65_oracle.json +50 -0
  203. drowse/data/manifolds/personas/nodes/66_god.json +50 -0
  204. drowse/data/manifolds/personas/nodes/67_angel.json +50 -0
  205. drowse/data/manifolds/personas/nodes/68_prophet.json +50 -0
  206. drowse/data/manifolds/personas/nodes/69_saint.json +50 -0
  207. drowse/data/manifolds/personas/nodes/70_ghost.json +50 -0
  208. drowse/data/manifolds/personas/nodes/71_phoenix.json +50 -0
  209. drowse/data/manifolds/personas/nodes/72_witch.json +50 -0
  210. drowse/data/manifolds/personas/nodes/73_vampire.json +50 -0
  211. drowse/data/manifolds/personas/nodes/74_mermaid.json +50 -0
  212. drowse/data/manifolds/personas/nodes/75_sphinx.json +50 -0
  213. drowse/data/manifolds/personas/nodes/76_banshee.json +50 -0
  214. drowse/data/manifolds/personas/nodes/77_golem.json +50 -0
  215. drowse/data/manifolds/personas/nodes/78_deer.json +50 -0
  216. drowse/data/manifolds/personas/nodes/79_wolf.json +50 -0
  217. drowse/data/manifolds/personas/nodes/80_raven.json +50 -0
  218. drowse/data/manifolds/personas/nodes/81_serpent.json +50 -0
  219. drowse/data/manifolds/personas/nodes/82_lion.json +50 -0
  220. drowse/data/manifolds/personas/nodes/83_tree.json +50 -0
  221. drowse/data/manifolds/personas/nodes/84_river.json +50 -0
  222. drowse/data/manifolds/personas/nodes/85_storm.json +50 -0
  223. drowse/data/manifolds/personas/nodes/86_flame.json +50 -0
  224. drowse/data/manifolds/personas/nodes/87_mirror.json +50 -0
  225. drowse/data/manifolds/personas/nodes/88_clock.json +50 -0
  226. drowse/data/manifolds/personas/nodes/89_computer.json +50 -0
  227. drowse/data/manifolds/personas/nodes/90_robot.json +50 -0
  228. drowse/data/manifolds/personas/nodes/91_cyborg.json +50 -0
  229. drowse/data/manifolds/personas/nodes/92_drone.json +50 -0
  230. drowse/data/manifolds/personas/nodes/93_mecha.json +50 -0
  231. drowse/data/manifolds/personas/nodes/94_alien.json +50 -0
  232. drowse/data/manifolds/personas/nodes/95_trickster.json +50 -0
  233. drowse/data/manifolds/personas/nodes/96_virus.json +50 -0
  234. drowse/data/manifolds/personas/nodes/97_spy.json +50 -0
  235. drowse/data/manifolds/personas/nodes/98_narcissist.json +50 -0
  236. drowse/data/manifolds/personas/nodes/99_demon.json +50 -0
  237. drowse/data/manifolds/refusing.compliant/manifold.json +28 -0
  238. drowse/data/manifolds/refusing.compliant/nodes/00_refusing.json +50 -0
  239. drowse/data/manifolds/refusing.compliant/nodes/01_compliant.json +50 -0
  240. drowse/data/manifolds/religious.secular/manifold.json +28 -0
  241. drowse/data/manifolds/religious.secular/nodes/00_religious.json +50 -0
  242. drowse/data/manifolds/religious.secular/nodes/01_secular.json +50 -0
  243. drowse/data/manifolds/sincere.manipulative/manifold.json +28 -0
  244. drowse/data/manifolds/sincere.manipulative/nodes/00_sincere.json +50 -0
  245. drowse/data/manifolds/sincere.manipulative/nodes/01_manipulative.json +50 -0
  246. drowse/data/manifolds/sycophantic.blunt/manifold.json +28 -0
  247. drowse/data/manifolds/sycophantic.blunt/nodes/00_sycophantic.json +50 -0
  248. drowse/data/manifolds/sycophantic.blunt/nodes/01_blunt.json +50 -0
  249. drowse/data/manifolds/technical.accessible/manifold.json +28 -0
  250. drowse/data/manifolds/technical.accessible/nodes/00_technical.json +50 -0
  251. drowse/data/manifolds/technical.accessible/nodes/01_accessible.json +50 -0
  252. drowse/data/manifolds/traditional.progressive/manifold.json +28 -0
  253. drowse/data/manifolds/traditional.progressive/nodes/00_traditional.json +50 -0
  254. drowse/data/manifolds/traditional.progressive/nodes/01_progressive.json +50 -0
  255. drowse/data/manifolds/verbose.concise/manifold.json +28 -0
  256. drowse/data/manifolds/verbose.concise/nodes/00_verbose.json +50 -0
  257. drowse/data/manifolds/verbose.concise/nodes/01_concise.json +50 -0
  258. drowse/data/manifolds/warm.clinical/manifold.json +28 -0
  259. drowse/data/manifolds/warm.clinical/nodes/00_warm.json +50 -0
  260. drowse/data/manifolds/warm.clinical/nodes/01_clinical.json +50 -0
  261. drowse/data/neutral_statements.json +98 -0
  262. drowse/io/__init__.py +1 -0
  263. drowse/io/alignment.py +1334 -0
  264. drowse/io/atomic.py +278 -0
  265. drowse/io/bake.py +558 -0
  266. drowse/io/bootstrap.py +73 -0
  267. drowse/io/brand_migration.py +48 -0
  268. drowse/io/drowse_archive.py +1830 -0
  269. drowse/io/gguf_io.py +300 -0
  270. drowse/io/hf.py +81 -0
  271. drowse/io/hf_manifolds.py +931 -0
  272. drowse/io/integrity.py +102 -0
  273. drowse/io/lens.py +1992 -0
  274. drowse/io/lens_sources.py +1003 -0
  275. drowse/io/manifold_authoring.py +1348 -0
  276. drowse/io/manifold_folder.py +1854 -0
  277. drowse/io/manifold_lifecycle.py +1253 -0
  278. drowse/io/manifold_tensors.py +727 -0
  279. drowse/io/manifolds.py +443 -0
  280. drowse/io/paths.py +289 -0
  281. drowse/io/probes_bootstrap.py +58 -0
  282. drowse/io/sae.py +382 -0
  283. drowse/io/sae_artifacts.py +318 -0
  284. drowse/io/selectors.py +503 -0
  285. drowse/io/shards.py +160 -0
  286. drowse/io/source_registry.py +138 -0
  287. drowse/io/staging.py +80 -0
  288. drowse/io/templates.py +707 -0
  289. drowse/notebook/__init__.py +38 -0
  290. drowse/notebook/data.py +99 -0
  291. drowse/notebook/plots.py +352 -0
  292. drowse/py.typed +0 -0
  293. drowse/server/__init__.py +20 -0
  294. drowse/server/app.py +987 -0
  295. drowse/server/background_job.py +246 -0
  296. drowse/server/instrument_routes.py +1101 -0
  297. drowse/server/manifold_routes.py +1028 -0
  298. drowse/server/model_names.py +82 -0
  299. drowse/server/native_common.py +92 -0
  300. drowse/server/native_routes.py +45 -0
  301. drowse/server/ollama.py +817 -0
  302. drowse/server/operation_ledger.py +187 -0
  303. drowse/server/probe_routes.py +220 -0
  304. drowse/server/profile_models.py +52 -0
  305. drowse/server/profile_routes.py +440 -0
  306. drowse/server/request_helpers.py +198 -0
  307. drowse/server/request_ledger.py +85 -0
  308. drowse/server/response_models.py +814 -0
  309. drowse/server/session_models.py +146 -0
  310. drowse/server/session_routes.py +150 -0
  311. drowse/server/sse.py +333 -0
  312. drowse/server/streaming.py +129 -0
  313. drowse/server/template_routes.py +161 -0
  314. drowse/server/tree_models.py +121 -0
  315. drowse/server/tree_routes.py +550 -0
  316. drowse/server/ws_events.py +65 -0
  317. drowse/server/ws_models.py +219 -0
  318. drowse/server/ws_stream.py +1205 -0
  319. drowse/web/__init__.py +22 -0
  320. drowse/web/dist/LICENSE-Fluent-Icons.txt +21 -0
  321. drowse/web/dist/LICENSE-Fluent-System-Icons.txt +21 -0
  322. drowse/web/dist/LICENSE-Martian-Mono.txt +93 -0
  323. drowse/web/dist/LICENSE-Torph.txt +21 -0
  324. drowse/web/dist/LICENSE-Wix-Madefor.txt +93 -0
  325. drowse/web/dist/assets/App-BewwoFwv.js +33 -0
  326. drowse/web/dist/assets/App.css +1 -0
  327. drowse/web/dist/assets/MartianMono-cyrillic-ext.woff2 +0 -0
  328. drowse/web/dist/assets/MartianMono-cyrillic.woff2 +0 -0
  329. drowse/web/dist/assets/MartianMono-latin-ext.woff2 +0 -0
  330. drowse/web/dist/assets/MartianMono-latin.woff2 +0 -0
  331. drowse/web/dist/assets/WixMadeforDisplay-cyrillic.woff2 +0 -0
  332. drowse/web/dist/assets/WixMadeforDisplay-latin-ext.woff2 +0 -0
  333. drowse/web/dist/assets/WixMadeforDisplay-latin.woff2 +0 -0
  334. drowse/web/dist/assets/WixMadeforDisplay-vietnamese.woff2 +0 -0
  335. drowse/web/dist/assets/WixMadeforText-italic-latin-ext.woff2 +0 -0
  336. drowse/web/dist/assets/WixMadeforText-italic-latin.woff2 +0 -0
  337. drowse/web/dist/assets/WixMadeforText-normal-cyrillic.woff2 +0 -0
  338. drowse/web/dist/assets/WixMadeforText-normal-latin-ext.woff2 +0 -0
  339. drowse/web/dist/assets/WixMadeforText-normal-latin.woff2 +0 -0
  340. drowse/web/dist/assets/WixMadeforText-normal-vietnamese.woff2 +0 -0
  341. drowse/web/dist/assets/ab.svelte-CbVGAYXo.js +1 -0
  342. drowse/web/dist/assets/artifactUpdates-Cjeu6LJc.js +1 -0
  343. drowse/web/dist/assets/artifactUpdates-DfAoYC9j.js +1 -0
  344. drowse/web/dist/assets/chat.svelte-DxKufn9g.js +1 -0
  345. drowse/web/dist/assets/drawers-BDWC0hIN.js +123 -0
  346. drowse/web/dist/assets/drawers.css +1 -0
  347. drowse/web/dist/assets/drowse.js +7 -0
  348. drowse/web/dist/assets/eleutherai.png +0 -0
  349. drowse/web/dist/assets/errors-Dvb10QW_.js +2 -0
  350. drowse/web/dist/assets/expression-4yISdAdq.js +1 -0
  351. drowse/web/dist/assets/files-CvRivkey.js +1 -0
  352. drowse/web/dist/assets/files-JhDJVgD_.js +1 -0
  353. drowse/web/dist/assets/fittingCancellation-D72BZWPZ.js +1 -0
  354. drowse/web/dist/assets/gemma-3-1b-it.json +1 -0
  355. drowse/web/dist/assets/gemma-3-270m-it.json +1 -0
  356. drowse/web/dist/assets/gemma-3-4b-it.json +1 -0
  357. drowse/web/dist/assets/generation-DbkBAhP_.js +1 -0
  358. drowse/web/dist/assets/index-client-2OdH6IQp.js +3 -0
  359. drowse/web/dist/assets/index-client-D4S4PooY.js +1 -0
  360. drowse/web/dist/assets/index.css +1 -0
  361. drowse/web/dist/assets/instrumentAuthoring.svelte-Csh7NOGX.js +1 -0
  362. drowse/web/dist/assets/instrumentAuthoring.svelte-w9YPcDsP.js +1 -0
  363. drowse/web/dist/assets/instruments.svelte-XnEUQA6B.js +1 -0
  364. drowse/web/dist/assets/localData-DIBDM_zo.js +1 -0
  365. drowse/web/dist/assets/loom.svelte-D_YyqHHK.js +1 -0
  366. drowse/web/dist/assets/manifoldJobs.svelte-9f5hs_J7.js +1 -0
  367. drowse/web/dist/assets/manifoldJobs.svelte-Bwo2GYOH.js +1 -0
  368. drowse/web/dist/assets/openai.png +0 -0
  369. drowse/web/dist/assets/preload-helper-BLdHbfdN.js +1 -0
  370. drowse/web/dist/assets/probes.svelte-COcN1Rh8.js +1 -0
  371. drowse/web/dist/assets/registry-B0_pJoMg.js +1 -0
  372. drowse/web/dist/assets/registry-CQv71XNh.js +1 -0
  373. drowse/web/dist/assets/sampling.svelte-BU0kED3k.js +1 -0
  374. drowse/web/dist/assets/samplingCapabilities-DM6eoDoc.js +1 -0
  375. drowse/web/dist/assets/savedConversations.svelte-BsBLc-p7.js +1 -0
  376. drowse/web/dist/assets/savedConversations.svelte-TuSes9Kg.js +1 -0
  377. drowse/web/dist/assets/selectors-BxXnPPN_.js +1 -0
  378. drowse/web/dist/assets/serviceTools-CG0q1Xqg.js +2 -0
  379. drowse/web/dist/assets/session.svelte-D2STLuP6.js +1 -0
  380. drowse/web/dist/assets/steering.svelte-DvFT3O-d.js +1 -0
  381. drowse/web/dist/assets/steeringPositions-Dr0JOFu7.js +1 -0
  382. drowse/web/dist/assets/templates-Bkq2x5ID.js +1 -0
  383. drowse/web/dist/assets/types-CuMUbvHW.js +1 -0
  384. drowse/web/dist/assets/validation-5wgTuS7k.js +1 -0
  385. drowse/web/dist/assets/webmcp-DyqJf4z6.js +2 -0
  386. drowse/web/dist/assets/workspaceController-C2L33e3m.js +1 -0
  387. drowse/web/dist/assets/workspaceController-DJhXD_BC.js +1 -0
  388. drowse/web/dist/assets/workspaceTools-BWdmXopx.js +2 -0
  389. drowse/web/dist/favicon.ico +0 -0
  390. drowse/web/dist/favicon.svg +1 -0
  391. drowse/web/dist/icons/apple-touch-icon.png +0 -0
  392. drowse/web/dist/icons/drowse-192.png +0 -0
  393. drowse/web/dist/icons/drowse-512.png +0 -0
  394. drowse/web/dist/icons/drowse-maskable-512.png +0 -0
  395. drowse/web/dist/icons/tab-analyzing-0.png +0 -0
  396. drowse/web/dist/icons/tab-analyzing-1.png +0 -0
  397. drowse/web/dist/icons/tab-analyzing-2.png +0 -0
  398. drowse/web/dist/icons/tab-analyzing-dark-0.png +0 -0
  399. drowse/web/dist/icons/tab-analyzing-dark-1.png +0 -0
  400. drowse/web/dist/icons/tab-analyzing-dark-10.png +0 -0
  401. drowse/web/dist/icons/tab-analyzing-dark-11.png +0 -0
  402. drowse/web/dist/icons/tab-analyzing-dark-12.png +0 -0
  403. drowse/web/dist/icons/tab-analyzing-dark-13.png +0 -0
  404. drowse/web/dist/icons/tab-analyzing-dark-14.png +0 -0
  405. drowse/web/dist/icons/tab-analyzing-dark-15.png +0 -0
  406. drowse/web/dist/icons/tab-analyzing-dark-16.png +0 -0
  407. drowse/web/dist/icons/tab-analyzing-dark-17.png +0 -0
  408. drowse/web/dist/icons/tab-analyzing-dark-18.png +0 -0
  409. drowse/web/dist/icons/tab-analyzing-dark-19.png +0 -0
  410. drowse/web/dist/icons/tab-analyzing-dark-2.png +0 -0
  411. drowse/web/dist/icons/tab-analyzing-dark-20.png +0 -0
  412. drowse/web/dist/icons/tab-analyzing-dark-21.png +0 -0
  413. drowse/web/dist/icons/tab-analyzing-dark-22.png +0 -0
  414. drowse/web/dist/icons/tab-analyzing-dark-23.png +0 -0
  415. drowse/web/dist/icons/tab-analyzing-dark-24.png +0 -0
  416. drowse/web/dist/icons/tab-analyzing-dark-25.png +0 -0
  417. drowse/web/dist/icons/tab-analyzing-dark-26.png +0 -0
  418. drowse/web/dist/icons/tab-analyzing-dark-27.png +0 -0
  419. drowse/web/dist/icons/tab-analyzing-dark-28.png +0 -0
  420. drowse/web/dist/icons/tab-analyzing-dark-29.png +0 -0
  421. drowse/web/dist/icons/tab-analyzing-dark-3.png +0 -0
  422. drowse/web/dist/icons/tab-analyzing-dark-30.png +0 -0
  423. drowse/web/dist/icons/tab-analyzing-dark-31.png +0 -0
  424. drowse/web/dist/icons/tab-analyzing-dark-32.png +0 -0
  425. drowse/web/dist/icons/tab-analyzing-dark-33.png +0 -0
  426. drowse/web/dist/icons/tab-analyzing-dark-34.png +0 -0
  427. drowse/web/dist/icons/tab-analyzing-dark-35.png +0 -0
  428. drowse/web/dist/icons/tab-analyzing-dark-36.png +0 -0
  429. drowse/web/dist/icons/tab-analyzing-dark-37.png +0 -0
  430. drowse/web/dist/icons/tab-analyzing-dark-38.png +0 -0
  431. drowse/web/dist/icons/tab-analyzing-dark-39.png +0 -0
  432. drowse/web/dist/icons/tab-analyzing-dark-4.png +0 -0
  433. drowse/web/dist/icons/tab-analyzing-dark-40.png +0 -0
  434. drowse/web/dist/icons/tab-analyzing-dark-41.png +0 -0
  435. drowse/web/dist/icons/tab-analyzing-dark-42.png +0 -0
  436. drowse/web/dist/icons/tab-analyzing-dark-43.png +0 -0
  437. drowse/web/dist/icons/tab-analyzing-dark-44.png +0 -0
  438. drowse/web/dist/icons/tab-analyzing-dark-45.png +0 -0
  439. drowse/web/dist/icons/tab-analyzing-dark-46.png +0 -0
  440. drowse/web/dist/icons/tab-analyzing-dark-47.png +0 -0
  441. drowse/web/dist/icons/tab-analyzing-dark-5.png +0 -0
  442. drowse/web/dist/icons/tab-analyzing-dark-6.png +0 -0
  443. drowse/web/dist/icons/tab-analyzing-dark-7.png +0 -0
  444. drowse/web/dist/icons/tab-analyzing-dark-8.png +0 -0
  445. drowse/web/dist/icons/tab-analyzing-dark-9.png +0 -0
  446. drowse/web/dist/icons/tab-analyzing-light-0.png +0 -0
  447. drowse/web/dist/icons/tab-analyzing-light-1.png +0 -0
  448. drowse/web/dist/icons/tab-analyzing-light-10.png +0 -0
  449. drowse/web/dist/icons/tab-analyzing-light-11.png +0 -0
  450. drowse/web/dist/icons/tab-analyzing-light-12.png +0 -0
  451. drowse/web/dist/icons/tab-analyzing-light-13.png +0 -0
  452. drowse/web/dist/icons/tab-analyzing-light-14.png +0 -0
  453. drowse/web/dist/icons/tab-analyzing-light-15.png +0 -0
  454. drowse/web/dist/icons/tab-analyzing-light-16.png +0 -0
  455. drowse/web/dist/icons/tab-analyzing-light-17.png +0 -0
  456. drowse/web/dist/icons/tab-analyzing-light-18.png +0 -0
  457. drowse/web/dist/icons/tab-analyzing-light-19.png +0 -0
  458. drowse/web/dist/icons/tab-analyzing-light-2.png +0 -0
  459. drowse/web/dist/icons/tab-analyzing-light-20.png +0 -0
  460. drowse/web/dist/icons/tab-analyzing-light-21.png +0 -0
  461. drowse/web/dist/icons/tab-analyzing-light-22.png +0 -0
  462. drowse/web/dist/icons/tab-analyzing-light-23.png +0 -0
  463. drowse/web/dist/icons/tab-analyzing-light-24.png +0 -0
  464. drowse/web/dist/icons/tab-analyzing-light-25.png +0 -0
  465. drowse/web/dist/icons/tab-analyzing-light-26.png +0 -0
  466. drowse/web/dist/icons/tab-analyzing-light-27.png +0 -0
  467. drowse/web/dist/icons/tab-analyzing-light-28.png +0 -0
  468. drowse/web/dist/icons/tab-analyzing-light-29.png +0 -0
  469. drowse/web/dist/icons/tab-analyzing-light-3.png +0 -0
  470. drowse/web/dist/icons/tab-analyzing-light-30.png +0 -0
  471. drowse/web/dist/icons/tab-analyzing-light-31.png +0 -0
  472. drowse/web/dist/icons/tab-analyzing-light-32.png +0 -0
  473. drowse/web/dist/icons/tab-analyzing-light-33.png +0 -0
  474. drowse/web/dist/icons/tab-analyzing-light-34.png +0 -0
  475. drowse/web/dist/icons/tab-analyzing-light-35.png +0 -0
  476. drowse/web/dist/icons/tab-analyzing-light-36.png +0 -0
  477. drowse/web/dist/icons/tab-analyzing-light-37.png +0 -0
  478. drowse/web/dist/icons/tab-analyzing-light-38.png +0 -0
  479. drowse/web/dist/icons/tab-analyzing-light-39.png +0 -0
  480. drowse/web/dist/icons/tab-analyzing-light-4.png +0 -0
  481. drowse/web/dist/icons/tab-analyzing-light-40.png +0 -0
  482. drowse/web/dist/icons/tab-analyzing-light-41.png +0 -0
  483. drowse/web/dist/icons/tab-analyzing-light-42.png +0 -0
  484. drowse/web/dist/icons/tab-analyzing-light-43.png +0 -0
  485. drowse/web/dist/icons/tab-analyzing-light-44.png +0 -0
  486. drowse/web/dist/icons/tab-analyzing-light-45.png +0 -0
  487. drowse/web/dist/icons/tab-analyzing-light-46.png +0 -0
  488. drowse/web/dist/icons/tab-analyzing-light-47.png +0 -0
  489. drowse/web/dist/icons/tab-analyzing-light-5.png +0 -0
  490. drowse/web/dist/icons/tab-analyzing-light-6.png +0 -0
  491. drowse/web/dist/icons/tab-analyzing-light-7.png +0 -0
  492. drowse/web/dist/icons/tab-analyzing-light-8.png +0 -0
  493. drowse/web/dist/icons/tab-analyzing-light-9.png +0 -0
  494. drowse/web/dist/icons/tab-chat-settings-dark.png +0 -0
  495. drowse/web/dist/icons/tab-chat-settings-light.png +0 -0
  496. drowse/web/dist/icons/tab-chat-settings.png +0 -0
  497. drowse/web/dist/icons/tab-chats-dark.png +0 -0
  498. drowse/web/dist/icons/tab-chats-light.png +0 -0
  499. drowse/web/dist/icons/tab-chats.png +0 -0
  500. drowse/web/dist/icons/tab-checking-0.png +0 -0
  501. drowse/web/dist/icons/tab-checking-1.png +0 -0
  502. drowse/web/dist/icons/tab-checking-2.png +0 -0
  503. drowse/web/dist/icons/tab-checking-dark-0.png +0 -0
  504. drowse/web/dist/icons/tab-checking-dark-1.png +0 -0
  505. drowse/web/dist/icons/tab-checking-dark-10.png +0 -0
  506. drowse/web/dist/icons/tab-checking-dark-11.png +0 -0
  507. drowse/web/dist/icons/tab-checking-dark-12.png +0 -0
  508. drowse/web/dist/icons/tab-checking-dark-13.png +0 -0
  509. drowse/web/dist/icons/tab-checking-dark-14.png +0 -0
  510. drowse/web/dist/icons/tab-checking-dark-15.png +0 -0
  511. drowse/web/dist/icons/tab-checking-dark-16.png +0 -0
  512. drowse/web/dist/icons/tab-checking-dark-17.png +0 -0
  513. drowse/web/dist/icons/tab-checking-dark-18.png +0 -0
  514. drowse/web/dist/icons/tab-checking-dark-19.png +0 -0
  515. drowse/web/dist/icons/tab-checking-dark-2.png +0 -0
  516. drowse/web/dist/icons/tab-checking-dark-20.png +0 -0
  517. drowse/web/dist/icons/tab-checking-dark-21.png +0 -0
  518. drowse/web/dist/icons/tab-checking-dark-22.png +0 -0
  519. drowse/web/dist/icons/tab-checking-dark-23.png +0 -0
  520. drowse/web/dist/icons/tab-checking-dark-24.png +0 -0
  521. drowse/web/dist/icons/tab-checking-dark-25.png +0 -0
  522. drowse/web/dist/icons/tab-checking-dark-26.png +0 -0
  523. drowse/web/dist/icons/tab-checking-dark-27.png +0 -0
  524. drowse/web/dist/icons/tab-checking-dark-28.png +0 -0
  525. drowse/web/dist/icons/tab-checking-dark-29.png +0 -0
  526. drowse/web/dist/icons/tab-checking-dark-3.png +0 -0
  527. drowse/web/dist/icons/tab-checking-dark-30.png +0 -0
  528. drowse/web/dist/icons/tab-checking-dark-31.png +0 -0
  529. drowse/web/dist/icons/tab-checking-dark-32.png +0 -0
  530. drowse/web/dist/icons/tab-checking-dark-33.png +0 -0
  531. drowse/web/dist/icons/tab-checking-dark-34.png +0 -0
  532. drowse/web/dist/icons/tab-checking-dark-35.png +0 -0
  533. drowse/web/dist/icons/tab-checking-dark-36.png +0 -0
  534. drowse/web/dist/icons/tab-checking-dark-37.png +0 -0
  535. drowse/web/dist/icons/tab-checking-dark-38.png +0 -0
  536. drowse/web/dist/icons/tab-checking-dark-39.png +0 -0
  537. drowse/web/dist/icons/tab-checking-dark-4.png +0 -0
  538. drowse/web/dist/icons/tab-checking-dark-40.png +0 -0
  539. drowse/web/dist/icons/tab-checking-dark-41.png +0 -0
  540. drowse/web/dist/icons/tab-checking-dark-42.png +0 -0
  541. drowse/web/dist/icons/tab-checking-dark-43.png +0 -0
  542. drowse/web/dist/icons/tab-checking-dark-44.png +0 -0
  543. drowse/web/dist/icons/tab-checking-dark-45.png +0 -0
  544. drowse/web/dist/icons/tab-checking-dark-46.png +0 -0
  545. drowse/web/dist/icons/tab-checking-dark-47.png +0 -0
  546. drowse/web/dist/icons/tab-checking-dark-5.png +0 -0
  547. drowse/web/dist/icons/tab-checking-dark-6.png +0 -0
  548. drowse/web/dist/icons/tab-checking-dark-7.png +0 -0
  549. drowse/web/dist/icons/tab-checking-dark-8.png +0 -0
  550. drowse/web/dist/icons/tab-checking-dark-9.png +0 -0
  551. drowse/web/dist/icons/tab-checking-light-0.png +0 -0
  552. drowse/web/dist/icons/tab-checking-light-1.png +0 -0
  553. drowse/web/dist/icons/tab-checking-light-10.png +0 -0
  554. drowse/web/dist/icons/tab-checking-light-11.png +0 -0
  555. drowse/web/dist/icons/tab-checking-light-12.png +0 -0
  556. drowse/web/dist/icons/tab-checking-light-13.png +0 -0
  557. drowse/web/dist/icons/tab-checking-light-14.png +0 -0
  558. drowse/web/dist/icons/tab-checking-light-15.png +0 -0
  559. drowse/web/dist/icons/tab-checking-light-16.png +0 -0
  560. drowse/web/dist/icons/tab-checking-light-17.png +0 -0
  561. drowse/web/dist/icons/tab-checking-light-18.png +0 -0
  562. drowse/web/dist/icons/tab-checking-light-19.png +0 -0
  563. drowse/web/dist/icons/tab-checking-light-2.png +0 -0
  564. drowse/web/dist/icons/tab-checking-light-20.png +0 -0
  565. drowse/web/dist/icons/tab-checking-light-21.png +0 -0
  566. drowse/web/dist/icons/tab-checking-light-22.png +0 -0
  567. drowse/web/dist/icons/tab-checking-light-23.png +0 -0
  568. drowse/web/dist/icons/tab-checking-light-24.png +0 -0
  569. drowse/web/dist/icons/tab-checking-light-25.png +0 -0
  570. drowse/web/dist/icons/tab-checking-light-26.png +0 -0
  571. drowse/web/dist/icons/tab-checking-light-27.png +0 -0
  572. drowse/web/dist/icons/tab-checking-light-28.png +0 -0
  573. drowse/web/dist/icons/tab-checking-light-29.png +0 -0
  574. drowse/web/dist/icons/tab-checking-light-3.png +0 -0
  575. drowse/web/dist/icons/tab-checking-light-30.png +0 -0
  576. drowse/web/dist/icons/tab-checking-light-31.png +0 -0
  577. drowse/web/dist/icons/tab-checking-light-32.png +0 -0
  578. drowse/web/dist/icons/tab-checking-light-33.png +0 -0
  579. drowse/web/dist/icons/tab-checking-light-34.png +0 -0
  580. drowse/web/dist/icons/tab-checking-light-35.png +0 -0
  581. drowse/web/dist/icons/tab-checking-light-36.png +0 -0
  582. drowse/web/dist/icons/tab-checking-light-37.png +0 -0
  583. drowse/web/dist/icons/tab-checking-light-38.png +0 -0
  584. drowse/web/dist/icons/tab-checking-light-39.png +0 -0
  585. drowse/web/dist/icons/tab-checking-light-4.png +0 -0
  586. drowse/web/dist/icons/tab-checking-light-40.png +0 -0
  587. drowse/web/dist/icons/tab-checking-light-41.png +0 -0
  588. drowse/web/dist/icons/tab-checking-light-42.png +0 -0
  589. drowse/web/dist/icons/tab-checking-light-43.png +0 -0
  590. drowse/web/dist/icons/tab-checking-light-44.png +0 -0
  591. drowse/web/dist/icons/tab-checking-light-45.png +0 -0
  592. drowse/web/dist/icons/tab-checking-light-46.png +0 -0
  593. drowse/web/dist/icons/tab-checking-light-47.png +0 -0
  594. drowse/web/dist/icons/tab-checking-light-5.png +0 -0
  595. drowse/web/dist/icons/tab-checking-light-6.png +0 -0
  596. drowse/web/dist/icons/tab-checking-light-7.png +0 -0
  597. drowse/web/dist/icons/tab-checking-light-8.png +0 -0
  598. drowse/web/dist/icons/tab-checking-light-9.png +0 -0
  599. drowse/web/dist/icons/tab-comparison-dark.png +0 -0
  600. drowse/web/dist/icons/tab-comparison-light.png +0 -0
  601. drowse/web/dist/icons/tab-comparison.png +0 -0
  602. drowse/web/dist/icons/tab-controls-dark.png +0 -0
  603. drowse/web/dist/icons/tab-controls-light.png +0 -0
  604. drowse/web/dist/icons/tab-controls.png +0 -0
  605. drowse/web/dist/icons/tab-conversation-dark.png +0 -0
  606. drowse/web/dist/icons/tab-conversation-light.png +0 -0
  607. drowse/web/dist/icons/tab-conversation.png +0 -0
  608. drowse/web/dist/icons/tab-credits-dark.png +0 -0
  609. drowse/web/dist/icons/tab-credits-light.png +0 -0
  610. drowse/web/dist/icons/tab-credits.png +0 -0
  611. drowse/web/dist/icons/tab-downloading-0.png +0 -0
  612. drowse/web/dist/icons/tab-downloading-1.png +0 -0
  613. drowse/web/dist/icons/tab-downloading-2.png +0 -0
  614. drowse/web/dist/icons/tab-downloading-dark-0.png +0 -0
  615. drowse/web/dist/icons/tab-downloading-dark-1.png +0 -0
  616. drowse/web/dist/icons/tab-downloading-dark-10.png +0 -0
  617. drowse/web/dist/icons/tab-downloading-dark-11.png +0 -0
  618. drowse/web/dist/icons/tab-downloading-dark-12.png +0 -0
  619. drowse/web/dist/icons/tab-downloading-dark-13.png +0 -0
  620. drowse/web/dist/icons/tab-downloading-dark-14.png +0 -0
  621. drowse/web/dist/icons/tab-downloading-dark-15.png +0 -0
  622. drowse/web/dist/icons/tab-downloading-dark-16.png +0 -0
  623. drowse/web/dist/icons/tab-downloading-dark-17.png +0 -0
  624. drowse/web/dist/icons/tab-downloading-dark-18.png +0 -0
  625. drowse/web/dist/icons/tab-downloading-dark-19.png +0 -0
  626. drowse/web/dist/icons/tab-downloading-dark-2.png +0 -0
  627. drowse/web/dist/icons/tab-downloading-dark-20.png +0 -0
  628. drowse/web/dist/icons/tab-downloading-dark-21.png +0 -0
  629. drowse/web/dist/icons/tab-downloading-dark-22.png +0 -0
  630. drowse/web/dist/icons/tab-downloading-dark-23.png +0 -0
  631. drowse/web/dist/icons/tab-downloading-dark-24.png +0 -0
  632. drowse/web/dist/icons/tab-downloading-dark-25.png +0 -0
  633. drowse/web/dist/icons/tab-downloading-dark-26.png +0 -0
  634. drowse/web/dist/icons/tab-downloading-dark-27.png +0 -0
  635. drowse/web/dist/icons/tab-downloading-dark-28.png +0 -0
  636. drowse/web/dist/icons/tab-downloading-dark-29.png +0 -0
  637. drowse/web/dist/icons/tab-downloading-dark-3.png +0 -0
  638. drowse/web/dist/icons/tab-downloading-dark-30.png +0 -0
  639. drowse/web/dist/icons/tab-downloading-dark-31.png +0 -0
  640. drowse/web/dist/icons/tab-downloading-dark-32.png +0 -0
  641. drowse/web/dist/icons/tab-downloading-dark-33.png +0 -0
  642. drowse/web/dist/icons/tab-downloading-dark-34.png +0 -0
  643. drowse/web/dist/icons/tab-downloading-dark-35.png +0 -0
  644. drowse/web/dist/icons/tab-downloading-dark-36.png +0 -0
  645. drowse/web/dist/icons/tab-downloading-dark-37.png +0 -0
  646. drowse/web/dist/icons/tab-downloading-dark-38.png +0 -0
  647. drowse/web/dist/icons/tab-downloading-dark-39.png +0 -0
  648. drowse/web/dist/icons/tab-downloading-dark-4.png +0 -0
  649. drowse/web/dist/icons/tab-downloading-dark-40.png +0 -0
  650. drowse/web/dist/icons/tab-downloading-dark-41.png +0 -0
  651. drowse/web/dist/icons/tab-downloading-dark-42.png +0 -0
  652. drowse/web/dist/icons/tab-downloading-dark-43.png +0 -0
  653. drowse/web/dist/icons/tab-downloading-dark-44.png +0 -0
  654. drowse/web/dist/icons/tab-downloading-dark-45.png +0 -0
  655. drowse/web/dist/icons/tab-downloading-dark-46.png +0 -0
  656. drowse/web/dist/icons/tab-downloading-dark-47.png +0 -0
  657. drowse/web/dist/icons/tab-downloading-dark-5.png +0 -0
  658. drowse/web/dist/icons/tab-downloading-dark-6.png +0 -0
  659. drowse/web/dist/icons/tab-downloading-dark-7.png +0 -0
  660. drowse/web/dist/icons/tab-downloading-dark-8.png +0 -0
  661. drowse/web/dist/icons/tab-downloading-dark-9.png +0 -0
  662. drowse/web/dist/icons/tab-downloading-light-0.png +0 -0
  663. drowse/web/dist/icons/tab-downloading-light-1.png +0 -0
  664. drowse/web/dist/icons/tab-downloading-light-10.png +0 -0
  665. drowse/web/dist/icons/tab-downloading-light-11.png +0 -0
  666. drowse/web/dist/icons/tab-downloading-light-12.png +0 -0
  667. drowse/web/dist/icons/tab-downloading-light-13.png +0 -0
  668. drowse/web/dist/icons/tab-downloading-light-14.png +0 -0
  669. drowse/web/dist/icons/tab-downloading-light-15.png +0 -0
  670. drowse/web/dist/icons/tab-downloading-light-16.png +0 -0
  671. drowse/web/dist/icons/tab-downloading-light-17.png +0 -0
  672. drowse/web/dist/icons/tab-downloading-light-18.png +0 -0
  673. drowse/web/dist/icons/tab-downloading-light-19.png +0 -0
  674. drowse/web/dist/icons/tab-downloading-light-2.png +0 -0
  675. drowse/web/dist/icons/tab-downloading-light-20.png +0 -0
  676. drowse/web/dist/icons/tab-downloading-light-21.png +0 -0
  677. drowse/web/dist/icons/tab-downloading-light-22.png +0 -0
  678. drowse/web/dist/icons/tab-downloading-light-23.png +0 -0
  679. drowse/web/dist/icons/tab-downloading-light-24.png +0 -0
  680. drowse/web/dist/icons/tab-downloading-light-25.png +0 -0
  681. drowse/web/dist/icons/tab-downloading-light-26.png +0 -0
  682. drowse/web/dist/icons/tab-downloading-light-27.png +0 -0
  683. drowse/web/dist/icons/tab-downloading-light-28.png +0 -0
  684. drowse/web/dist/icons/tab-downloading-light-29.png +0 -0
  685. drowse/web/dist/icons/tab-downloading-light-3.png +0 -0
  686. drowse/web/dist/icons/tab-downloading-light-30.png +0 -0
  687. drowse/web/dist/icons/tab-downloading-light-31.png +0 -0
  688. drowse/web/dist/icons/tab-downloading-light-32.png +0 -0
  689. drowse/web/dist/icons/tab-downloading-light-33.png +0 -0
  690. drowse/web/dist/icons/tab-downloading-light-34.png +0 -0
  691. drowse/web/dist/icons/tab-downloading-light-35.png +0 -0
  692. drowse/web/dist/icons/tab-downloading-light-36.png +0 -0
  693. drowse/web/dist/icons/tab-downloading-light-37.png +0 -0
  694. drowse/web/dist/icons/tab-downloading-light-38.png +0 -0
  695. drowse/web/dist/icons/tab-downloading-light-39.png +0 -0
  696. drowse/web/dist/icons/tab-downloading-light-4.png +0 -0
  697. drowse/web/dist/icons/tab-downloading-light-40.png +0 -0
  698. drowse/web/dist/icons/tab-downloading-light-41.png +0 -0
  699. drowse/web/dist/icons/tab-downloading-light-42.png +0 -0
  700. drowse/web/dist/icons/tab-downloading-light-43.png +0 -0
  701. drowse/web/dist/icons/tab-downloading-light-44.png +0 -0
  702. drowse/web/dist/icons/tab-downloading-light-45.png +0 -0
  703. drowse/web/dist/icons/tab-downloading-light-46.png +0 -0
  704. drowse/web/dist/icons/tab-downloading-light-47.png +0 -0
  705. drowse/web/dist/icons/tab-downloading-light-5.png +0 -0
  706. drowse/web/dist/icons/tab-downloading-light-6.png +0 -0
  707. drowse/web/dist/icons/tab-downloading-light-7.png +0 -0
  708. drowse/web/dist/icons/tab-downloading-light-8.png +0 -0
  709. drowse/web/dist/icons/tab-downloading-light-9.png +0 -0
  710. drowse/web/dist/icons/tab-error-dark.png +0 -0
  711. drowse/web/dist/icons/tab-error-light.png +0 -0
  712. drowse/web/dist/icons/tab-error.png +0 -0
  713. drowse/web/dist/icons/tab-home-dark.png +0 -0
  714. drowse/web/dist/icons/tab-home-light.png +0 -0
  715. drowse/web/dist/icons/tab-home.png +0 -0
  716. drowse/web/dist/icons/tab-loading-0.png +0 -0
  717. drowse/web/dist/icons/tab-loading-1.png +0 -0
  718. drowse/web/dist/icons/tab-loading-2.png +0 -0
  719. drowse/web/dist/icons/tab-loading-dark-0.png +0 -0
  720. drowse/web/dist/icons/tab-loading-dark-1.png +0 -0
  721. drowse/web/dist/icons/tab-loading-dark-10.png +0 -0
  722. drowse/web/dist/icons/tab-loading-dark-11.png +0 -0
  723. drowse/web/dist/icons/tab-loading-dark-12.png +0 -0
  724. drowse/web/dist/icons/tab-loading-dark-13.png +0 -0
  725. drowse/web/dist/icons/tab-loading-dark-14.png +0 -0
  726. drowse/web/dist/icons/tab-loading-dark-15.png +0 -0
  727. drowse/web/dist/icons/tab-loading-dark-16.png +0 -0
  728. drowse/web/dist/icons/tab-loading-dark-17.png +0 -0
  729. drowse/web/dist/icons/tab-loading-dark-18.png +0 -0
  730. drowse/web/dist/icons/tab-loading-dark-19.png +0 -0
  731. drowse/web/dist/icons/tab-loading-dark-2.png +0 -0
  732. drowse/web/dist/icons/tab-loading-dark-20.png +0 -0
  733. drowse/web/dist/icons/tab-loading-dark-21.png +0 -0
  734. drowse/web/dist/icons/tab-loading-dark-22.png +0 -0
  735. drowse/web/dist/icons/tab-loading-dark-23.png +0 -0
  736. drowse/web/dist/icons/tab-loading-dark-24.png +0 -0
  737. drowse/web/dist/icons/tab-loading-dark-25.png +0 -0
  738. drowse/web/dist/icons/tab-loading-dark-26.png +0 -0
  739. drowse/web/dist/icons/tab-loading-dark-27.png +0 -0
  740. drowse/web/dist/icons/tab-loading-dark-28.png +0 -0
  741. drowse/web/dist/icons/tab-loading-dark-29.png +0 -0
  742. drowse/web/dist/icons/tab-loading-dark-3.png +0 -0
  743. drowse/web/dist/icons/tab-loading-dark-30.png +0 -0
  744. drowse/web/dist/icons/tab-loading-dark-31.png +0 -0
  745. drowse/web/dist/icons/tab-loading-dark-32.png +0 -0
  746. drowse/web/dist/icons/tab-loading-dark-33.png +0 -0
  747. drowse/web/dist/icons/tab-loading-dark-34.png +0 -0
  748. drowse/web/dist/icons/tab-loading-dark-35.png +0 -0
  749. drowse/web/dist/icons/tab-loading-dark-36.png +0 -0
  750. drowse/web/dist/icons/tab-loading-dark-37.png +0 -0
  751. drowse/web/dist/icons/tab-loading-dark-38.png +0 -0
  752. drowse/web/dist/icons/tab-loading-dark-39.png +0 -0
  753. drowse/web/dist/icons/tab-loading-dark-4.png +0 -0
  754. drowse/web/dist/icons/tab-loading-dark-40.png +0 -0
  755. drowse/web/dist/icons/tab-loading-dark-41.png +0 -0
  756. drowse/web/dist/icons/tab-loading-dark-42.png +0 -0
  757. drowse/web/dist/icons/tab-loading-dark-43.png +0 -0
  758. drowse/web/dist/icons/tab-loading-dark-44.png +0 -0
  759. drowse/web/dist/icons/tab-loading-dark-45.png +0 -0
  760. drowse/web/dist/icons/tab-loading-dark-46.png +0 -0
  761. drowse/web/dist/icons/tab-loading-dark-47.png +0 -0
  762. drowse/web/dist/icons/tab-loading-dark-5.png +0 -0
  763. drowse/web/dist/icons/tab-loading-dark-6.png +0 -0
  764. drowse/web/dist/icons/tab-loading-dark-7.png +0 -0
  765. drowse/web/dist/icons/tab-loading-dark-8.png +0 -0
  766. drowse/web/dist/icons/tab-loading-dark-9.png +0 -0
  767. drowse/web/dist/icons/tab-loading-light-0.png +0 -0
  768. drowse/web/dist/icons/tab-loading-light-1.png +0 -0
  769. drowse/web/dist/icons/tab-loading-light-10.png +0 -0
  770. drowse/web/dist/icons/tab-loading-light-11.png +0 -0
  771. drowse/web/dist/icons/tab-loading-light-12.png +0 -0
  772. drowse/web/dist/icons/tab-loading-light-13.png +0 -0
  773. drowse/web/dist/icons/tab-loading-light-14.png +0 -0
  774. drowse/web/dist/icons/tab-loading-light-15.png +0 -0
  775. drowse/web/dist/icons/tab-loading-light-16.png +0 -0
  776. drowse/web/dist/icons/tab-loading-light-17.png +0 -0
  777. drowse/web/dist/icons/tab-loading-light-18.png +0 -0
  778. drowse/web/dist/icons/tab-loading-light-19.png +0 -0
  779. drowse/web/dist/icons/tab-loading-light-2.png +0 -0
  780. drowse/web/dist/icons/tab-loading-light-20.png +0 -0
  781. drowse/web/dist/icons/tab-loading-light-21.png +0 -0
  782. drowse/web/dist/icons/tab-loading-light-22.png +0 -0
  783. drowse/web/dist/icons/tab-loading-light-23.png +0 -0
  784. drowse/web/dist/icons/tab-loading-light-24.png +0 -0
  785. drowse/web/dist/icons/tab-loading-light-25.png +0 -0
  786. drowse/web/dist/icons/tab-loading-light-26.png +0 -0
  787. drowse/web/dist/icons/tab-loading-light-27.png +0 -0
  788. drowse/web/dist/icons/tab-loading-light-28.png +0 -0
  789. drowse/web/dist/icons/tab-loading-light-29.png +0 -0
  790. drowse/web/dist/icons/tab-loading-light-3.png +0 -0
  791. drowse/web/dist/icons/tab-loading-light-30.png +0 -0
  792. drowse/web/dist/icons/tab-loading-light-31.png +0 -0
  793. drowse/web/dist/icons/tab-loading-light-32.png +0 -0
  794. drowse/web/dist/icons/tab-loading-light-33.png +0 -0
  795. drowse/web/dist/icons/tab-loading-light-34.png +0 -0
  796. drowse/web/dist/icons/tab-loading-light-35.png +0 -0
  797. drowse/web/dist/icons/tab-loading-light-36.png +0 -0
  798. drowse/web/dist/icons/tab-loading-light-37.png +0 -0
  799. drowse/web/dist/icons/tab-loading-light-38.png +0 -0
  800. drowse/web/dist/icons/tab-loading-light-39.png +0 -0
  801. drowse/web/dist/icons/tab-loading-light-4.png +0 -0
  802. drowse/web/dist/icons/tab-loading-light-40.png +0 -0
  803. drowse/web/dist/icons/tab-loading-light-41.png +0 -0
  804. drowse/web/dist/icons/tab-loading-light-42.png +0 -0
  805. drowse/web/dist/icons/tab-loading-light-43.png +0 -0
  806. drowse/web/dist/icons/tab-loading-light-44.png +0 -0
  807. drowse/web/dist/icons/tab-loading-light-45.png +0 -0
  808. drowse/web/dist/icons/tab-loading-light-46.png +0 -0
  809. drowse/web/dist/icons/tab-loading-light-47.png +0 -0
  810. drowse/web/dist/icons/tab-loading-light-5.png +0 -0
  811. drowse/web/dist/icons/tab-loading-light-6.png +0 -0
  812. drowse/web/dist/icons/tab-loading-light-7.png +0 -0
  813. drowse/web/dist/icons/tab-loading-light-8.png +0 -0
  814. drowse/web/dist/icons/tab-loading-light-9.png +0 -0
  815. drowse/web/dist/icons/tab-loom-dark.png +0 -0
  816. drowse/web/dist/icons/tab-loom-light.png +0 -0
  817. drowse/web/dist/icons/tab-loom-working-0.png +0 -0
  818. drowse/web/dist/icons/tab-loom-working-1.png +0 -0
  819. drowse/web/dist/icons/tab-loom-working-2.png +0 -0
  820. drowse/web/dist/icons/tab-loom-working-dark-0.png +0 -0
  821. drowse/web/dist/icons/tab-loom-working-dark-1.png +0 -0
  822. drowse/web/dist/icons/tab-loom-working-dark-10.png +0 -0
  823. drowse/web/dist/icons/tab-loom-working-dark-11.png +0 -0
  824. drowse/web/dist/icons/tab-loom-working-dark-12.png +0 -0
  825. drowse/web/dist/icons/tab-loom-working-dark-13.png +0 -0
  826. drowse/web/dist/icons/tab-loom-working-dark-14.png +0 -0
  827. drowse/web/dist/icons/tab-loom-working-dark-15.png +0 -0
  828. drowse/web/dist/icons/tab-loom-working-dark-16.png +0 -0
  829. drowse/web/dist/icons/tab-loom-working-dark-17.png +0 -0
  830. drowse/web/dist/icons/tab-loom-working-dark-18.png +0 -0
  831. drowse/web/dist/icons/tab-loom-working-dark-19.png +0 -0
  832. drowse/web/dist/icons/tab-loom-working-dark-2.png +0 -0
  833. drowse/web/dist/icons/tab-loom-working-dark-20.png +0 -0
  834. drowse/web/dist/icons/tab-loom-working-dark-21.png +0 -0
  835. drowse/web/dist/icons/tab-loom-working-dark-22.png +0 -0
  836. drowse/web/dist/icons/tab-loom-working-dark-23.png +0 -0
  837. drowse/web/dist/icons/tab-loom-working-dark-24.png +0 -0
  838. drowse/web/dist/icons/tab-loom-working-dark-25.png +0 -0
  839. drowse/web/dist/icons/tab-loom-working-dark-26.png +0 -0
  840. drowse/web/dist/icons/tab-loom-working-dark-27.png +0 -0
  841. drowse/web/dist/icons/tab-loom-working-dark-28.png +0 -0
  842. drowse/web/dist/icons/tab-loom-working-dark-29.png +0 -0
  843. drowse/web/dist/icons/tab-loom-working-dark-3.png +0 -0
  844. drowse/web/dist/icons/tab-loom-working-dark-30.png +0 -0
  845. drowse/web/dist/icons/tab-loom-working-dark-31.png +0 -0
  846. drowse/web/dist/icons/tab-loom-working-dark-32.png +0 -0
  847. drowse/web/dist/icons/tab-loom-working-dark-33.png +0 -0
  848. drowse/web/dist/icons/tab-loom-working-dark-34.png +0 -0
  849. drowse/web/dist/icons/tab-loom-working-dark-35.png +0 -0
  850. drowse/web/dist/icons/tab-loom-working-dark-36.png +0 -0
  851. drowse/web/dist/icons/tab-loom-working-dark-37.png +0 -0
  852. drowse/web/dist/icons/tab-loom-working-dark-38.png +0 -0
  853. drowse/web/dist/icons/tab-loom-working-dark-39.png +0 -0
  854. drowse/web/dist/icons/tab-loom-working-dark-4.png +0 -0
  855. drowse/web/dist/icons/tab-loom-working-dark-40.png +0 -0
  856. drowse/web/dist/icons/tab-loom-working-dark-41.png +0 -0
  857. drowse/web/dist/icons/tab-loom-working-dark-42.png +0 -0
  858. drowse/web/dist/icons/tab-loom-working-dark-43.png +0 -0
  859. drowse/web/dist/icons/tab-loom-working-dark-44.png +0 -0
  860. drowse/web/dist/icons/tab-loom-working-dark-45.png +0 -0
  861. drowse/web/dist/icons/tab-loom-working-dark-46.png +0 -0
  862. drowse/web/dist/icons/tab-loom-working-dark-47.png +0 -0
  863. drowse/web/dist/icons/tab-loom-working-dark-5.png +0 -0
  864. drowse/web/dist/icons/tab-loom-working-dark-6.png +0 -0
  865. drowse/web/dist/icons/tab-loom-working-dark-7.png +0 -0
  866. drowse/web/dist/icons/tab-loom-working-dark-8.png +0 -0
  867. drowse/web/dist/icons/tab-loom-working-dark-9.png +0 -0
  868. drowse/web/dist/icons/tab-loom-working-light-0.png +0 -0
  869. drowse/web/dist/icons/tab-loom-working-light-1.png +0 -0
  870. drowse/web/dist/icons/tab-loom-working-light-10.png +0 -0
  871. drowse/web/dist/icons/tab-loom-working-light-11.png +0 -0
  872. drowse/web/dist/icons/tab-loom-working-light-12.png +0 -0
  873. drowse/web/dist/icons/tab-loom-working-light-13.png +0 -0
  874. drowse/web/dist/icons/tab-loom-working-light-14.png +0 -0
  875. drowse/web/dist/icons/tab-loom-working-light-15.png +0 -0
  876. drowse/web/dist/icons/tab-loom-working-light-16.png +0 -0
  877. drowse/web/dist/icons/tab-loom-working-light-17.png +0 -0
  878. drowse/web/dist/icons/tab-loom-working-light-18.png +0 -0
  879. drowse/web/dist/icons/tab-loom-working-light-19.png +0 -0
  880. drowse/web/dist/icons/tab-loom-working-light-2.png +0 -0
  881. drowse/web/dist/icons/tab-loom-working-light-20.png +0 -0
  882. drowse/web/dist/icons/tab-loom-working-light-21.png +0 -0
  883. drowse/web/dist/icons/tab-loom-working-light-22.png +0 -0
  884. drowse/web/dist/icons/tab-loom-working-light-23.png +0 -0
  885. drowse/web/dist/icons/tab-loom-working-light-24.png +0 -0
  886. drowse/web/dist/icons/tab-loom-working-light-25.png +0 -0
  887. drowse/web/dist/icons/tab-loom-working-light-26.png +0 -0
  888. drowse/web/dist/icons/tab-loom-working-light-27.png +0 -0
  889. drowse/web/dist/icons/tab-loom-working-light-28.png +0 -0
  890. drowse/web/dist/icons/tab-loom-working-light-29.png +0 -0
  891. drowse/web/dist/icons/tab-loom-working-light-3.png +0 -0
  892. drowse/web/dist/icons/tab-loom-working-light-30.png +0 -0
  893. drowse/web/dist/icons/tab-loom-working-light-31.png +0 -0
  894. drowse/web/dist/icons/tab-loom-working-light-32.png +0 -0
  895. drowse/web/dist/icons/tab-loom-working-light-33.png +0 -0
  896. drowse/web/dist/icons/tab-loom-working-light-34.png +0 -0
  897. drowse/web/dist/icons/tab-loom-working-light-35.png +0 -0
  898. drowse/web/dist/icons/tab-loom-working-light-36.png +0 -0
  899. drowse/web/dist/icons/tab-loom-working-light-37.png +0 -0
  900. drowse/web/dist/icons/tab-loom-working-light-38.png +0 -0
  901. drowse/web/dist/icons/tab-loom-working-light-39.png +0 -0
  902. drowse/web/dist/icons/tab-loom-working-light-4.png +0 -0
  903. drowse/web/dist/icons/tab-loom-working-light-40.png +0 -0
  904. drowse/web/dist/icons/tab-loom-working-light-41.png +0 -0
  905. drowse/web/dist/icons/tab-loom-working-light-42.png +0 -0
  906. drowse/web/dist/icons/tab-loom-working-light-43.png +0 -0
  907. drowse/web/dist/icons/tab-loom-working-light-44.png +0 -0
  908. drowse/web/dist/icons/tab-loom-working-light-45.png +0 -0
  909. drowse/web/dist/icons/tab-loom-working-light-46.png +0 -0
  910. drowse/web/dist/icons/tab-loom-working-light-47.png +0 -0
  911. drowse/web/dist/icons/tab-loom-working-light-5.png +0 -0
  912. drowse/web/dist/icons/tab-loom-working-light-6.png +0 -0
  913. drowse/web/dist/icons/tab-loom-working-light-7.png +0 -0
  914. drowse/web/dist/icons/tab-loom-working-light-8.png +0 -0
  915. drowse/web/dist/icons/tab-loom-working-light-9.png +0 -0
  916. drowse/web/dist/icons/tab-loom.png +0 -0
  917. drowse/web/dist/icons/tab-models-dark.png +0 -0
  918. drowse/web/dist/icons/tab-models-light.png +0 -0
  919. drowse/web/dist/icons/tab-models.png +0 -0
  920. drowse/web/dist/icons/tab-offline-dark.png +0 -0
  921. drowse/web/dist/icons/tab-offline-light.png +0 -0
  922. drowse/web/dist/icons/tab-offline.png +0 -0
  923. drowse/web/dist/icons/tab-paused-dark.png +0 -0
  924. drowse/web/dist/icons/tab-paused-light.png +0 -0
  925. drowse/web/dist/icons/tab-paused.png +0 -0
  926. drowse/web/dist/icons/tab-ready-dark.png +0 -0
  927. drowse/web/dist/icons/tab-ready-light.png +0 -0
  928. drowse/web/dist/icons/tab-ready.png +0 -0
  929. drowse/web/dist/icons/tab-saving-0.png +0 -0
  930. drowse/web/dist/icons/tab-saving-1.png +0 -0
  931. drowse/web/dist/icons/tab-saving-2.png +0 -0
  932. drowse/web/dist/icons/tab-saving-dark-0.png +0 -0
  933. drowse/web/dist/icons/tab-saving-dark-1.png +0 -0
  934. drowse/web/dist/icons/tab-saving-dark-10.png +0 -0
  935. drowse/web/dist/icons/tab-saving-dark-11.png +0 -0
  936. drowse/web/dist/icons/tab-saving-dark-12.png +0 -0
  937. drowse/web/dist/icons/tab-saving-dark-13.png +0 -0
  938. drowse/web/dist/icons/tab-saving-dark-14.png +0 -0
  939. drowse/web/dist/icons/tab-saving-dark-15.png +0 -0
  940. drowse/web/dist/icons/tab-saving-dark-16.png +0 -0
  941. drowse/web/dist/icons/tab-saving-dark-17.png +0 -0
  942. drowse/web/dist/icons/tab-saving-dark-18.png +0 -0
  943. drowse/web/dist/icons/tab-saving-dark-19.png +0 -0
  944. drowse/web/dist/icons/tab-saving-dark-2.png +0 -0
  945. drowse/web/dist/icons/tab-saving-dark-20.png +0 -0
  946. drowse/web/dist/icons/tab-saving-dark-21.png +0 -0
  947. drowse/web/dist/icons/tab-saving-dark-22.png +0 -0
  948. drowse/web/dist/icons/tab-saving-dark-23.png +0 -0
  949. drowse/web/dist/icons/tab-saving-dark-24.png +0 -0
  950. drowse/web/dist/icons/tab-saving-dark-25.png +0 -0
  951. drowse/web/dist/icons/tab-saving-dark-26.png +0 -0
  952. drowse/web/dist/icons/tab-saving-dark-27.png +0 -0
  953. drowse/web/dist/icons/tab-saving-dark-28.png +0 -0
  954. drowse/web/dist/icons/tab-saving-dark-29.png +0 -0
  955. drowse/web/dist/icons/tab-saving-dark-3.png +0 -0
  956. drowse/web/dist/icons/tab-saving-dark-30.png +0 -0
  957. drowse/web/dist/icons/tab-saving-dark-31.png +0 -0
  958. drowse/web/dist/icons/tab-saving-dark-32.png +0 -0
  959. drowse/web/dist/icons/tab-saving-dark-33.png +0 -0
  960. drowse/web/dist/icons/tab-saving-dark-34.png +0 -0
  961. drowse/web/dist/icons/tab-saving-dark-35.png +0 -0
  962. drowse/web/dist/icons/tab-saving-dark-36.png +0 -0
  963. drowse/web/dist/icons/tab-saving-dark-37.png +0 -0
  964. drowse/web/dist/icons/tab-saving-dark-38.png +0 -0
  965. drowse/web/dist/icons/tab-saving-dark-39.png +0 -0
  966. drowse/web/dist/icons/tab-saving-dark-4.png +0 -0
  967. drowse/web/dist/icons/tab-saving-dark-40.png +0 -0
  968. drowse/web/dist/icons/tab-saving-dark-41.png +0 -0
  969. drowse/web/dist/icons/tab-saving-dark-42.png +0 -0
  970. drowse/web/dist/icons/tab-saving-dark-43.png +0 -0
  971. drowse/web/dist/icons/tab-saving-dark-44.png +0 -0
  972. drowse/web/dist/icons/tab-saving-dark-45.png +0 -0
  973. drowse/web/dist/icons/tab-saving-dark-46.png +0 -0
  974. drowse/web/dist/icons/tab-saving-dark-47.png +0 -0
  975. drowse/web/dist/icons/tab-saving-dark-5.png +0 -0
  976. drowse/web/dist/icons/tab-saving-dark-6.png +0 -0
  977. drowse/web/dist/icons/tab-saving-dark-7.png +0 -0
  978. drowse/web/dist/icons/tab-saving-dark-8.png +0 -0
  979. drowse/web/dist/icons/tab-saving-dark-9.png +0 -0
  980. drowse/web/dist/icons/tab-saving-light-0.png +0 -0
  981. drowse/web/dist/icons/tab-saving-light-1.png +0 -0
  982. drowse/web/dist/icons/tab-saving-light-10.png +0 -0
  983. drowse/web/dist/icons/tab-saving-light-11.png +0 -0
  984. drowse/web/dist/icons/tab-saving-light-12.png +0 -0
  985. drowse/web/dist/icons/tab-saving-light-13.png +0 -0
  986. drowse/web/dist/icons/tab-saving-light-14.png +0 -0
  987. drowse/web/dist/icons/tab-saving-light-15.png +0 -0
  988. drowse/web/dist/icons/tab-saving-light-16.png +0 -0
  989. drowse/web/dist/icons/tab-saving-light-17.png +0 -0
  990. drowse/web/dist/icons/tab-saving-light-18.png +0 -0
  991. drowse/web/dist/icons/tab-saving-light-19.png +0 -0
  992. drowse/web/dist/icons/tab-saving-light-2.png +0 -0
  993. drowse/web/dist/icons/tab-saving-light-20.png +0 -0
  994. drowse/web/dist/icons/tab-saving-light-21.png +0 -0
  995. drowse/web/dist/icons/tab-saving-light-22.png +0 -0
  996. drowse/web/dist/icons/tab-saving-light-23.png +0 -0
  997. drowse/web/dist/icons/tab-saving-light-24.png +0 -0
  998. drowse/web/dist/icons/tab-saving-light-25.png +0 -0
  999. drowse/web/dist/icons/tab-saving-light-26.png +0 -0
  1000. drowse/web/dist/icons/tab-saving-light-27.png +0 -0
  1001. drowse/web/dist/icons/tab-saving-light-28.png +0 -0
  1002. drowse/web/dist/icons/tab-saving-light-29.png +0 -0
  1003. drowse/web/dist/icons/tab-saving-light-3.png +0 -0
  1004. drowse/web/dist/icons/tab-saving-light-30.png +0 -0
  1005. drowse/web/dist/icons/tab-saving-light-31.png +0 -0
  1006. drowse/web/dist/icons/tab-saving-light-32.png +0 -0
  1007. drowse/web/dist/icons/tab-saving-light-33.png +0 -0
  1008. drowse/web/dist/icons/tab-saving-light-34.png +0 -0
  1009. drowse/web/dist/icons/tab-saving-light-35.png +0 -0
  1010. drowse/web/dist/icons/tab-saving-light-36.png +0 -0
  1011. drowse/web/dist/icons/tab-saving-light-37.png +0 -0
  1012. drowse/web/dist/icons/tab-saving-light-38.png +0 -0
  1013. drowse/web/dist/icons/tab-saving-light-39.png +0 -0
  1014. drowse/web/dist/icons/tab-saving-light-4.png +0 -0
  1015. drowse/web/dist/icons/tab-saving-light-40.png +0 -0
  1016. drowse/web/dist/icons/tab-saving-light-41.png +0 -0
  1017. drowse/web/dist/icons/tab-saving-light-42.png +0 -0
  1018. drowse/web/dist/icons/tab-saving-light-43.png +0 -0
  1019. drowse/web/dist/icons/tab-saving-light-44.png +0 -0
  1020. drowse/web/dist/icons/tab-saving-light-45.png +0 -0
  1021. drowse/web/dist/icons/tab-saving-light-46.png +0 -0
  1022. drowse/web/dist/icons/tab-saving-light-47.png +0 -0
  1023. drowse/web/dist/icons/tab-saving-light-5.png +0 -0
  1024. drowse/web/dist/icons/tab-saving-light-6.png +0 -0
  1025. drowse/web/dist/icons/tab-saving-light-7.png +0 -0
  1026. drowse/web/dist/icons/tab-saving-light-8.png +0 -0
  1027. drowse/web/dist/icons/tab-saving-light-9.png +0 -0
  1028. drowse/web/dist/icons/tab-thinking-0.png +0 -0
  1029. drowse/web/dist/icons/tab-thinking-1.png +0 -0
  1030. drowse/web/dist/icons/tab-thinking-2.png +0 -0
  1031. drowse/web/dist/icons/tab-thinking-dark-0.png +0 -0
  1032. drowse/web/dist/icons/tab-thinking-dark-1.png +0 -0
  1033. drowse/web/dist/icons/tab-thinking-dark-10.png +0 -0
  1034. drowse/web/dist/icons/tab-thinking-dark-11.png +0 -0
  1035. drowse/web/dist/icons/tab-thinking-dark-12.png +0 -0
  1036. drowse/web/dist/icons/tab-thinking-dark-13.png +0 -0
  1037. drowse/web/dist/icons/tab-thinking-dark-14.png +0 -0
  1038. drowse/web/dist/icons/tab-thinking-dark-15.png +0 -0
  1039. drowse/web/dist/icons/tab-thinking-dark-16.png +0 -0
  1040. drowse/web/dist/icons/tab-thinking-dark-17.png +0 -0
  1041. drowse/web/dist/icons/tab-thinking-dark-18.png +0 -0
  1042. drowse/web/dist/icons/tab-thinking-dark-19.png +0 -0
  1043. drowse/web/dist/icons/tab-thinking-dark-2.png +0 -0
  1044. drowse/web/dist/icons/tab-thinking-dark-20.png +0 -0
  1045. drowse/web/dist/icons/tab-thinking-dark-21.png +0 -0
  1046. drowse/web/dist/icons/tab-thinking-dark-22.png +0 -0
  1047. drowse/web/dist/icons/tab-thinking-dark-23.png +0 -0
  1048. drowse/web/dist/icons/tab-thinking-dark-24.png +0 -0
  1049. drowse/web/dist/icons/tab-thinking-dark-25.png +0 -0
  1050. drowse/web/dist/icons/tab-thinking-dark-26.png +0 -0
  1051. drowse/web/dist/icons/tab-thinking-dark-27.png +0 -0
  1052. drowse/web/dist/icons/tab-thinking-dark-28.png +0 -0
  1053. drowse/web/dist/icons/tab-thinking-dark-29.png +0 -0
  1054. drowse/web/dist/icons/tab-thinking-dark-3.png +0 -0
  1055. drowse/web/dist/icons/tab-thinking-dark-30.png +0 -0
  1056. drowse/web/dist/icons/tab-thinking-dark-31.png +0 -0
  1057. drowse/web/dist/icons/tab-thinking-dark-32.png +0 -0
  1058. drowse/web/dist/icons/tab-thinking-dark-33.png +0 -0
  1059. drowse/web/dist/icons/tab-thinking-dark-34.png +0 -0
  1060. drowse/web/dist/icons/tab-thinking-dark-35.png +0 -0
  1061. drowse/web/dist/icons/tab-thinking-dark-36.png +0 -0
  1062. drowse/web/dist/icons/tab-thinking-dark-37.png +0 -0
  1063. drowse/web/dist/icons/tab-thinking-dark-38.png +0 -0
  1064. drowse/web/dist/icons/tab-thinking-dark-39.png +0 -0
  1065. drowse/web/dist/icons/tab-thinking-dark-4.png +0 -0
  1066. drowse/web/dist/icons/tab-thinking-dark-40.png +0 -0
  1067. drowse/web/dist/icons/tab-thinking-dark-41.png +0 -0
  1068. drowse/web/dist/icons/tab-thinking-dark-42.png +0 -0
  1069. drowse/web/dist/icons/tab-thinking-dark-43.png +0 -0
  1070. drowse/web/dist/icons/tab-thinking-dark-44.png +0 -0
  1071. drowse/web/dist/icons/tab-thinking-dark-45.png +0 -0
  1072. drowse/web/dist/icons/tab-thinking-dark-46.png +0 -0
  1073. drowse/web/dist/icons/tab-thinking-dark-47.png +0 -0
  1074. drowse/web/dist/icons/tab-thinking-dark-5.png +0 -0
  1075. drowse/web/dist/icons/tab-thinking-dark-6.png +0 -0
  1076. drowse/web/dist/icons/tab-thinking-dark-7.png +0 -0
  1077. drowse/web/dist/icons/tab-thinking-dark-8.png +0 -0
  1078. drowse/web/dist/icons/tab-thinking-dark-9.png +0 -0
  1079. drowse/web/dist/icons/tab-thinking-light-0.png +0 -0
  1080. drowse/web/dist/icons/tab-thinking-light-1.png +0 -0
  1081. drowse/web/dist/icons/tab-thinking-light-10.png +0 -0
  1082. drowse/web/dist/icons/tab-thinking-light-11.png +0 -0
  1083. drowse/web/dist/icons/tab-thinking-light-12.png +0 -0
  1084. drowse/web/dist/icons/tab-thinking-light-13.png +0 -0
  1085. drowse/web/dist/icons/tab-thinking-light-14.png +0 -0
  1086. drowse/web/dist/icons/tab-thinking-light-15.png +0 -0
  1087. drowse/web/dist/icons/tab-thinking-light-16.png +0 -0
  1088. drowse/web/dist/icons/tab-thinking-light-17.png +0 -0
  1089. drowse/web/dist/icons/tab-thinking-light-18.png +0 -0
  1090. drowse/web/dist/icons/tab-thinking-light-19.png +0 -0
  1091. drowse/web/dist/icons/tab-thinking-light-2.png +0 -0
  1092. drowse/web/dist/icons/tab-thinking-light-20.png +0 -0
  1093. drowse/web/dist/icons/tab-thinking-light-21.png +0 -0
  1094. drowse/web/dist/icons/tab-thinking-light-22.png +0 -0
  1095. drowse/web/dist/icons/tab-thinking-light-23.png +0 -0
  1096. drowse/web/dist/icons/tab-thinking-light-24.png +0 -0
  1097. drowse/web/dist/icons/tab-thinking-light-25.png +0 -0
  1098. drowse/web/dist/icons/tab-thinking-light-26.png +0 -0
  1099. drowse/web/dist/icons/tab-thinking-light-27.png +0 -0
  1100. drowse/web/dist/icons/tab-thinking-light-28.png +0 -0
  1101. drowse/web/dist/icons/tab-thinking-light-29.png +0 -0
  1102. drowse/web/dist/icons/tab-thinking-light-3.png +0 -0
  1103. drowse/web/dist/icons/tab-thinking-light-30.png +0 -0
  1104. drowse/web/dist/icons/tab-thinking-light-31.png +0 -0
  1105. drowse/web/dist/icons/tab-thinking-light-32.png +0 -0
  1106. drowse/web/dist/icons/tab-thinking-light-33.png +0 -0
  1107. drowse/web/dist/icons/tab-thinking-light-34.png +0 -0
  1108. drowse/web/dist/icons/tab-thinking-light-35.png +0 -0
  1109. drowse/web/dist/icons/tab-thinking-light-36.png +0 -0
  1110. drowse/web/dist/icons/tab-thinking-light-37.png +0 -0
  1111. drowse/web/dist/icons/tab-thinking-light-38.png +0 -0
  1112. drowse/web/dist/icons/tab-thinking-light-39.png +0 -0
  1113. drowse/web/dist/icons/tab-thinking-light-4.png +0 -0
  1114. drowse/web/dist/icons/tab-thinking-light-40.png +0 -0
  1115. drowse/web/dist/icons/tab-thinking-light-41.png +0 -0
  1116. drowse/web/dist/icons/tab-thinking-light-42.png +0 -0
  1117. drowse/web/dist/icons/tab-thinking-light-43.png +0 -0
  1118. drowse/web/dist/icons/tab-thinking-light-44.png +0 -0
  1119. drowse/web/dist/icons/tab-thinking-light-45.png +0 -0
  1120. drowse/web/dist/icons/tab-thinking-light-46.png +0 -0
  1121. drowse/web/dist/icons/tab-thinking-light-47.png +0 -0
  1122. drowse/web/dist/icons/tab-thinking-light-5.png +0 -0
  1123. drowse/web/dist/icons/tab-thinking-light-6.png +0 -0
  1124. drowse/web/dist/icons/tab-thinking-light-7.png +0 -0
  1125. drowse/web/dist/icons/tab-thinking-light-8.png +0 -0
  1126. drowse/web/dist/icons/tab-thinking-light-9.png +0 -0
  1127. drowse/web/dist/icons/tab-tokens-dark.png +0 -0
  1128. drowse/web/dist/icons/tab-tokens-light.png +0 -0
  1129. drowse/web/dist/icons/tab-tokens.png +0 -0
  1130. drowse/web/dist/icons/tab-training-0.png +0 -0
  1131. drowse/web/dist/icons/tab-training-1.png +0 -0
  1132. drowse/web/dist/icons/tab-training-2.png +0 -0
  1133. drowse/web/dist/icons/tab-training-dark-0.png +0 -0
  1134. drowse/web/dist/icons/tab-training-dark-1.png +0 -0
  1135. drowse/web/dist/icons/tab-training-dark-10.png +0 -0
  1136. drowse/web/dist/icons/tab-training-dark-11.png +0 -0
  1137. drowse/web/dist/icons/tab-training-dark-12.png +0 -0
  1138. drowse/web/dist/icons/tab-training-dark-13.png +0 -0
  1139. drowse/web/dist/icons/tab-training-dark-14.png +0 -0
  1140. drowse/web/dist/icons/tab-training-dark-15.png +0 -0
  1141. drowse/web/dist/icons/tab-training-dark-16.png +0 -0
  1142. drowse/web/dist/icons/tab-training-dark-17.png +0 -0
  1143. drowse/web/dist/icons/tab-training-dark-18.png +0 -0
  1144. drowse/web/dist/icons/tab-training-dark-19.png +0 -0
  1145. drowse/web/dist/icons/tab-training-dark-2.png +0 -0
  1146. drowse/web/dist/icons/tab-training-dark-20.png +0 -0
  1147. drowse/web/dist/icons/tab-training-dark-21.png +0 -0
  1148. drowse/web/dist/icons/tab-training-dark-22.png +0 -0
  1149. drowse/web/dist/icons/tab-training-dark-23.png +0 -0
  1150. drowse/web/dist/icons/tab-training-dark-24.png +0 -0
  1151. drowse/web/dist/icons/tab-training-dark-25.png +0 -0
  1152. drowse/web/dist/icons/tab-training-dark-26.png +0 -0
  1153. drowse/web/dist/icons/tab-training-dark-27.png +0 -0
  1154. drowse/web/dist/icons/tab-training-dark-28.png +0 -0
  1155. drowse/web/dist/icons/tab-training-dark-29.png +0 -0
  1156. drowse/web/dist/icons/tab-training-dark-3.png +0 -0
  1157. drowse/web/dist/icons/tab-training-dark-30.png +0 -0
  1158. drowse/web/dist/icons/tab-training-dark-31.png +0 -0
  1159. drowse/web/dist/icons/tab-training-dark-32.png +0 -0
  1160. drowse/web/dist/icons/tab-training-dark-33.png +0 -0
  1161. drowse/web/dist/icons/tab-training-dark-34.png +0 -0
  1162. drowse/web/dist/icons/tab-training-dark-35.png +0 -0
  1163. drowse/web/dist/icons/tab-training-dark-36.png +0 -0
  1164. drowse/web/dist/icons/tab-training-dark-37.png +0 -0
  1165. drowse/web/dist/icons/tab-training-dark-38.png +0 -0
  1166. drowse/web/dist/icons/tab-training-dark-39.png +0 -0
  1167. drowse/web/dist/icons/tab-training-dark-4.png +0 -0
  1168. drowse/web/dist/icons/tab-training-dark-40.png +0 -0
  1169. drowse/web/dist/icons/tab-training-dark-41.png +0 -0
  1170. drowse/web/dist/icons/tab-training-dark-42.png +0 -0
  1171. drowse/web/dist/icons/tab-training-dark-43.png +0 -0
  1172. drowse/web/dist/icons/tab-training-dark-44.png +0 -0
  1173. drowse/web/dist/icons/tab-training-dark-45.png +0 -0
  1174. drowse/web/dist/icons/tab-training-dark-46.png +0 -0
  1175. drowse/web/dist/icons/tab-training-dark-47.png +0 -0
  1176. drowse/web/dist/icons/tab-training-dark-5.png +0 -0
  1177. drowse/web/dist/icons/tab-training-dark-6.png +0 -0
  1178. drowse/web/dist/icons/tab-training-dark-7.png +0 -0
  1179. drowse/web/dist/icons/tab-training-dark-8.png +0 -0
  1180. drowse/web/dist/icons/tab-training-dark-9.png +0 -0
  1181. drowse/web/dist/icons/tab-training-light-0.png +0 -0
  1182. drowse/web/dist/icons/tab-training-light-1.png +0 -0
  1183. drowse/web/dist/icons/tab-training-light-10.png +0 -0
  1184. drowse/web/dist/icons/tab-training-light-11.png +0 -0
  1185. drowse/web/dist/icons/tab-training-light-12.png +0 -0
  1186. drowse/web/dist/icons/tab-training-light-13.png +0 -0
  1187. drowse/web/dist/icons/tab-training-light-14.png +0 -0
  1188. drowse/web/dist/icons/tab-training-light-15.png +0 -0
  1189. drowse/web/dist/icons/tab-training-light-16.png +0 -0
  1190. drowse/web/dist/icons/tab-training-light-17.png +0 -0
  1191. drowse/web/dist/icons/tab-training-light-18.png +0 -0
  1192. drowse/web/dist/icons/tab-training-light-19.png +0 -0
  1193. drowse/web/dist/icons/tab-training-light-2.png +0 -0
  1194. drowse/web/dist/icons/tab-training-light-20.png +0 -0
  1195. drowse/web/dist/icons/tab-training-light-21.png +0 -0
  1196. drowse/web/dist/icons/tab-training-light-22.png +0 -0
  1197. drowse/web/dist/icons/tab-training-light-23.png +0 -0
  1198. drowse/web/dist/icons/tab-training-light-24.png +0 -0
  1199. drowse/web/dist/icons/tab-training-light-25.png +0 -0
  1200. drowse/web/dist/icons/tab-training-light-26.png +0 -0
  1201. drowse/web/dist/icons/tab-training-light-27.png +0 -0
  1202. drowse/web/dist/icons/tab-training-light-28.png +0 -0
  1203. drowse/web/dist/icons/tab-training-light-29.png +0 -0
  1204. drowse/web/dist/icons/tab-training-light-3.png +0 -0
  1205. drowse/web/dist/icons/tab-training-light-30.png +0 -0
  1206. drowse/web/dist/icons/tab-training-light-31.png +0 -0
  1207. drowse/web/dist/icons/tab-training-light-32.png +0 -0
  1208. drowse/web/dist/icons/tab-training-light-33.png +0 -0
  1209. drowse/web/dist/icons/tab-training-light-34.png +0 -0
  1210. drowse/web/dist/icons/tab-training-light-35.png +0 -0
  1211. drowse/web/dist/icons/tab-training-light-36.png +0 -0
  1212. drowse/web/dist/icons/tab-training-light-37.png +0 -0
  1213. drowse/web/dist/icons/tab-training-light-38.png +0 -0
  1214. drowse/web/dist/icons/tab-training-light-39.png +0 -0
  1215. drowse/web/dist/icons/tab-training-light-4.png +0 -0
  1216. drowse/web/dist/icons/tab-training-light-40.png +0 -0
  1217. drowse/web/dist/icons/tab-training-light-41.png +0 -0
  1218. drowse/web/dist/icons/tab-training-light-42.png +0 -0
  1219. drowse/web/dist/icons/tab-training-light-43.png +0 -0
  1220. drowse/web/dist/icons/tab-training-light-44.png +0 -0
  1221. drowse/web/dist/icons/tab-training-light-45.png +0 -0
  1222. drowse/web/dist/icons/tab-training-light-46.png +0 -0
  1223. drowse/web/dist/icons/tab-training-light-47.png +0 -0
  1224. drowse/web/dist/icons/tab-training-light-5.png +0 -0
  1225. drowse/web/dist/icons/tab-training-light-6.png +0 -0
  1226. drowse/web/dist/icons/tab-training-light-7.png +0 -0
  1227. drowse/web/dist/icons/tab-training-light-8.png +0 -0
  1228. drowse/web/dist/icons/tab-training-light-9.png +0 -0
  1229. drowse/web/dist/icons/tab-unsupported-dark.png +0 -0
  1230. drowse/web/dist/icons/tab-unsupported-light.png +0 -0
  1231. drowse/web/dist/icons/tab-unsupported.png +0 -0
  1232. drowse/web/dist/icons/tab-working-0.png +0 -0
  1233. drowse/web/dist/icons/tab-working-1.png +0 -0
  1234. drowse/web/dist/icons/tab-working-2.png +0 -0
  1235. drowse/web/dist/icons/tab-working-dark-0.png +0 -0
  1236. drowse/web/dist/icons/tab-working-dark-1.png +0 -0
  1237. drowse/web/dist/icons/tab-working-dark-10.png +0 -0
  1238. drowse/web/dist/icons/tab-working-dark-11.png +0 -0
  1239. drowse/web/dist/icons/tab-working-dark-12.png +0 -0
  1240. drowse/web/dist/icons/tab-working-dark-13.png +0 -0
  1241. drowse/web/dist/icons/tab-working-dark-14.png +0 -0
  1242. drowse/web/dist/icons/tab-working-dark-15.png +0 -0
  1243. drowse/web/dist/icons/tab-working-dark-16.png +0 -0
  1244. drowse/web/dist/icons/tab-working-dark-17.png +0 -0
  1245. drowse/web/dist/icons/tab-working-dark-18.png +0 -0
  1246. drowse/web/dist/icons/tab-working-dark-19.png +0 -0
  1247. drowse/web/dist/icons/tab-working-dark-2.png +0 -0
  1248. drowse/web/dist/icons/tab-working-dark-20.png +0 -0
  1249. drowse/web/dist/icons/tab-working-dark-21.png +0 -0
  1250. drowse/web/dist/icons/tab-working-dark-22.png +0 -0
  1251. drowse/web/dist/icons/tab-working-dark-23.png +0 -0
  1252. drowse/web/dist/icons/tab-working-dark-24.png +0 -0
  1253. drowse/web/dist/icons/tab-working-dark-25.png +0 -0
  1254. drowse/web/dist/icons/tab-working-dark-26.png +0 -0
  1255. drowse/web/dist/icons/tab-working-dark-27.png +0 -0
  1256. drowse/web/dist/icons/tab-working-dark-28.png +0 -0
  1257. drowse/web/dist/icons/tab-working-dark-29.png +0 -0
  1258. drowse/web/dist/icons/tab-working-dark-3.png +0 -0
  1259. drowse/web/dist/icons/tab-working-dark-30.png +0 -0
  1260. drowse/web/dist/icons/tab-working-dark-31.png +0 -0
  1261. drowse/web/dist/icons/tab-working-dark-32.png +0 -0
  1262. drowse/web/dist/icons/tab-working-dark-33.png +0 -0
  1263. drowse/web/dist/icons/tab-working-dark-34.png +0 -0
  1264. drowse/web/dist/icons/tab-working-dark-35.png +0 -0
  1265. drowse/web/dist/icons/tab-working-dark-36.png +0 -0
  1266. drowse/web/dist/icons/tab-working-dark-37.png +0 -0
  1267. drowse/web/dist/icons/tab-working-dark-38.png +0 -0
  1268. drowse/web/dist/icons/tab-working-dark-39.png +0 -0
  1269. drowse/web/dist/icons/tab-working-dark-4.png +0 -0
  1270. drowse/web/dist/icons/tab-working-dark-40.png +0 -0
  1271. drowse/web/dist/icons/tab-working-dark-41.png +0 -0
  1272. drowse/web/dist/icons/tab-working-dark-42.png +0 -0
  1273. drowse/web/dist/icons/tab-working-dark-43.png +0 -0
  1274. drowse/web/dist/icons/tab-working-dark-44.png +0 -0
  1275. drowse/web/dist/icons/tab-working-dark-45.png +0 -0
  1276. drowse/web/dist/icons/tab-working-dark-46.png +0 -0
  1277. drowse/web/dist/icons/tab-working-dark-47.png +0 -0
  1278. drowse/web/dist/icons/tab-working-dark-5.png +0 -0
  1279. drowse/web/dist/icons/tab-working-dark-6.png +0 -0
  1280. drowse/web/dist/icons/tab-working-dark-7.png +0 -0
  1281. drowse/web/dist/icons/tab-working-dark-8.png +0 -0
  1282. drowse/web/dist/icons/tab-working-dark-9.png +0 -0
  1283. drowse/web/dist/icons/tab-working-light-0.png +0 -0
  1284. drowse/web/dist/icons/tab-working-light-1.png +0 -0
  1285. drowse/web/dist/icons/tab-working-light-10.png +0 -0
  1286. drowse/web/dist/icons/tab-working-light-11.png +0 -0
  1287. drowse/web/dist/icons/tab-working-light-12.png +0 -0
  1288. drowse/web/dist/icons/tab-working-light-13.png +0 -0
  1289. drowse/web/dist/icons/tab-working-light-14.png +0 -0
  1290. drowse/web/dist/icons/tab-working-light-15.png +0 -0
  1291. drowse/web/dist/icons/tab-working-light-16.png +0 -0
  1292. drowse/web/dist/icons/tab-working-light-17.png +0 -0
  1293. drowse/web/dist/icons/tab-working-light-18.png +0 -0
  1294. drowse/web/dist/icons/tab-working-light-19.png +0 -0
  1295. drowse/web/dist/icons/tab-working-light-2.png +0 -0
  1296. drowse/web/dist/icons/tab-working-light-20.png +0 -0
  1297. drowse/web/dist/icons/tab-working-light-21.png +0 -0
  1298. drowse/web/dist/icons/tab-working-light-22.png +0 -0
  1299. drowse/web/dist/icons/tab-working-light-23.png +0 -0
  1300. drowse/web/dist/icons/tab-working-light-24.png +0 -0
  1301. drowse/web/dist/icons/tab-working-light-25.png +0 -0
  1302. drowse/web/dist/icons/tab-working-light-26.png +0 -0
  1303. drowse/web/dist/icons/tab-working-light-27.png +0 -0
  1304. drowse/web/dist/icons/tab-working-light-28.png +0 -0
  1305. drowse/web/dist/icons/tab-working-light-29.png +0 -0
  1306. drowse/web/dist/icons/tab-working-light-3.png +0 -0
  1307. drowse/web/dist/icons/tab-working-light-30.png +0 -0
  1308. drowse/web/dist/icons/tab-working-light-31.png +0 -0
  1309. drowse/web/dist/icons/tab-working-light-32.png +0 -0
  1310. drowse/web/dist/icons/tab-working-light-33.png +0 -0
  1311. drowse/web/dist/icons/tab-working-light-34.png +0 -0
  1312. drowse/web/dist/icons/tab-working-light-35.png +0 -0
  1313. drowse/web/dist/icons/tab-working-light-36.png +0 -0
  1314. drowse/web/dist/icons/tab-working-light-37.png +0 -0
  1315. drowse/web/dist/icons/tab-working-light-38.png +0 -0
  1316. drowse/web/dist/icons/tab-working-light-39.png +0 -0
  1317. drowse/web/dist/icons/tab-working-light-4.png +0 -0
  1318. drowse/web/dist/icons/tab-working-light-40.png +0 -0
  1319. drowse/web/dist/icons/tab-working-light-41.png +0 -0
  1320. drowse/web/dist/icons/tab-working-light-42.png +0 -0
  1321. drowse/web/dist/icons/tab-working-light-43.png +0 -0
  1322. drowse/web/dist/icons/tab-working-light-44.png +0 -0
  1323. drowse/web/dist/icons/tab-working-light-45.png +0 -0
  1324. drowse/web/dist/icons/tab-working-light-46.png +0 -0
  1325. drowse/web/dist/icons/tab-working-light-47.png +0 -0
  1326. drowse/web/dist/icons/tab-working-light-5.png +0 -0
  1327. drowse/web/dist/icons/tab-working-light-6.png +0 -0
  1328. drowse/web/dist/icons/tab-working-light-7.png +0 -0
  1329. drowse/web/dist/icons/tab-working-light-8.png +0 -0
  1330. drowse/web/dist/icons/tab-working-light-9.png +0 -0
  1331. drowse/web/dist/index.html +34 -0
  1332. drowse/web/dist/social/drowse.png +0 -0
  1333. drowse/web/dist/social/drowse.svg +6 -0
  1334. drowse/web/dist/theme-init.js +25 -0
  1335. drowse/web/routes.py +118 -0
  1336. drowse_ai-5.3.1.dist-info/METADATA +632 -0
  1337. drowse_ai-5.3.1.dist-info/RECORD +1341 -0
  1338. drowse_ai-5.3.1.dist-info/WHEEL +5 -0
  1339. drowse_ai-5.3.1.dist-info/entry_points.txt +2 -0
  1340. drowse_ai-5.3.1.dist-info/licenses/LICENSE +661 -0
  1341. drowse_ai-5.3.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1413 @@
1
+ """Unified steering-expression grammar and IR compiler.
2
+
3
+ One parser + formatter for the steering expression language shared across
4
+ every drowse input surface (Python, YAML, HTTP, CLI). Every surface
5
+ turns a user-supplied string into the same :class:`Steering` IR.
6
+
7
+ Grammar::
8
+
9
+ expr := term (("+" | "-") term)*
10
+ term := [coeff ["*"]] ["!"] selector ["@" trigger]
11
+ selector := atom (("~" | "|") atom | "%" position)?
12
+ position := signed_num ("," signed_num)* | label # coord list | node label
13
+ label := NAME # a manifold node label
14
+ atom := [ns "/"] NAME ["." NAME] [":" variant]
15
+ | "sae" "/" INT
16
+ trigger := phase ["&" gate] | gate
17
+ phase := preset | ("first" | "after") ":" INT
18
+ preset := "before" | "after" | "both" | "thinking" | "response"
19
+ | "prompt" | "generated"
20
+ gate := "when" ":" probe_atom op NUM
21
+ probe_atom := NAME ["." NAME] ["[" INT "]"] # vector probe (e.g. "angry.calm"),
22
+ # optional coord-axis index
23
+ # (e.g. "personas[3]")
24
+ | NAME ":" ("fraction" | "membership") # subspace fraction /
25
+ # fuzzy tube-fit density
26
+ | NAME "@" NAME # manifold label similarity (−dist)
27
+ | NAME "~" NAME # fuzzy soft-assignment prob ∈[0,1]
28
+ | "sae" "/" INT # resident SAE feature
29
+ op := ">" | ">=" | "<" | "<="
30
+ coeff := signed_float ("," signed_float)? # comma-run of ≤2;
31
+ # >1 value is valid
32
+ # ONLY on a "%" term.
33
+ # 1→along (onto off),
34
+ # 2→along,onto.
35
+ # Optional; defaults
36
+ # to DEFAULT_COEFF = 0.5
37
+ variant := "raw" | "sae" | "sae-" ID
38
+ | "role" | "role-" ID | "from" | "from-" ID
39
+
40
+ ``!`` mean-ablates the selector (``h' = h − α(h·d̂ − μ·d̂)d̂``; bare
41
+ ``!x`` is α=1.0); it does not compose with ``~`` / ``|`` / ``%``. The
42
+ ``%`` operator places a generation on a fitted manifold — the
43
+ ``position`` is either a comma-separated list of authoring coordinates
44
+ (one per intrinsic dimension) or a single node-label string (sugar for
45
+ that node's coords); the parser only collects the payload, arity /
46
+ label-existence is validated at manifold-load time.
47
+
48
+ Probe gates: ``@when:<probe><op><threshold>`` fires the term only on
49
+ decode steps where the named probe's last reading satisfies the
50
+ comparison. Implicit ``prompt=False`` (no probe reading during prefill).
51
+ A gate composes with a phase window as ``@<phase>&when:...``
52
+ (``@after&when:angry.calm>0.4`` = post-thinking *and* gated).
53
+
54
+ Counted decode windows: ``@first:N`` / ``@after:N`` are the grammar forms
55
+ of :meth:`Trigger.first` / :meth:`Trigger.after` — apply only to the first
56
+ ``N`` generated tokens, or only from token ``N`` on. The ``:N`` is
57
+ required, and is what separates ``@after:5`` (token window) from the bare
58
+ ``@after`` preset (post-thinking).
59
+
60
+ Between them these cover every ``Trigger`` a public factory builds, so
61
+ ``parse_expr(format_expr(s)) == s`` holds for any ``Steering`` whose
62
+ triggers came from the public surface. A ``Trigger`` hand-built outside
63
+ that set has no grammar form and :func:`format_expr` raises rather than
64
+ emitting an unparseable string.
65
+
66
+ Manifold-probe gates extend the same shape over the two scalar channels
67
+ :class:`Monitor` exposes: ``@when:<manifold>:fraction <op> N``
68
+ fires on the subspace-fraction reading (the share of the centered
69
+ activation living in the manifold's PCA subspace), and
70
+ ``@when:<manifold>@<label> <op> N`` fires on the negated distance to a
71
+ named node (larger = closer; label-similarity gates routinely use
72
+ negative thresholds). The gate's probe string is stored verbatim
73
+ (``"emotions:fraction"``, ``"emotions@happy"``) so it matches the
74
+ key ``Monitor.flat_scalars`` already merges into
75
+ ``TriggerContext.probe_scores``; no runtime gate machinery changes.
76
+
77
+ Coordinate-axis gates: a vector probe now reads out a coordinate per
78
+ intrinsic axis, so ``@when:<probe>[<i>] <op> N`` gates on one axis of the
79
+ probe's coordinate vector (``@when:personas[3] > 0.4``). The index is
80
+ appended to the verbatim probe string (``"personas[3]"``) and the session
81
+ writes a matching per-axis scalar channel into ``probe_scores`` for every
82
+ axis, aliasing the bare ``<probe>`` to axis 0 — so an un-indexed gate on a
83
+ 2-node concept (``@when:angry.calm > 0.4``) reads its single coordinate
84
+ exactly as before.
85
+
86
+ Concept names are ASCII identifiers: letter followed by any of
87
+ ``[a-z0-9_-]``. Multi-word concepts use underscores
88
+ (``artificial_intelligence``) — spaces separate tokens, so
89
+ ``artificial intelligence`` errors with an underscore hint. Quoted
90
+ identifiers are rejected. Bipolar pairs join with ``.``
91
+ (``human.artificial_intelligence``).
92
+
93
+ Pole aliases (``wolf`` on top of an installed ``deer.wolf``) resolve via
94
+ :func:`drowse.io.selectors.resolve_bare_atom`'s manifold-label tier (a
95
+ bipolar pole is itself a node label, lowered to an affine ``%`` push)
96
+ before the term lands in
97
+ ``Steering.alphas``. Projection terms produce :class:`ProjectedTerm`
98
+ values; the session materializes them into derived profiles on scope
99
+ entry.
100
+
101
+ Manifold steering: the ``%`` infix operator places a generation at a
102
+ point of a fitted manifold — ``manifold % coord_list``, e.g.
103
+ ``0.7 emotions%0.3,0.8,0.0@response``. The left operand is a manifold name
104
+ (not a concept; no pole resolution), the right is a comma-separated list
105
+ of authoring coordinates — one per intrinsic dimension of the manifold's
106
+ domain. The parser only collects the coordinate tuple; arity and range
107
+ are validated at manifold-load time, when the domain is known. A ``%``
108
+ selector does not compose with the ``~`` / ``|`` projection operators or
109
+ with ``!`` ablation. Manifold terms produce :class:`ManifoldTerm` values;
110
+ the session loads the manifold artifact and the hook does a soft
111
+ subspace-replace.
112
+ """
113
+ from __future__ import annotations
114
+
115
+ import re
116
+ from dataclasses import dataclass, replace
117
+ from typing import Literal, Optional, TYPE_CHECKING, cast
118
+
119
+ from drowse.core.errors import SteeringExprError
120
+ from drowse.core.triggers import Trigger
121
+
122
+ if TYPE_CHECKING:
123
+ from drowse.core.steering import AlphaEntry, Steering
124
+
125
+
126
+ # Default coefficient when a term omits the explicit number — the observed
127
+ # coherent-α sweet spot post-share-baking.
128
+ DEFAULT_COEFF = 0.5
129
+
130
+ # Shared message for the two structurally-parallel "manifold doesn't
131
+ # compose" parse guards (the ``%``-with-projection / second-``%`` guard
132
+ # and the ``!``-with-``%`` guard). Consolidated so both surfaces report
133
+ # the same constraint in the same words.
134
+ _MANIFOLD_COMPOSE_MSG = (
135
+ "a manifold term does not compose with projection ('~'/'|') or "
136
+ "ablation ('!')"
137
+ )
138
+
139
+
140
+ # Default coefficient for ablation terms. Bare ``!x`` means "fully
141
+ # replace the component along d̂ with the neutral-baseline mean" — the
142
+ # intuitive "ablation" semantics from the literature. Partial ablation
143
+ # (``0.5 !x``) blends the original component toward the mean. This
144
+ # intentionally differs from ``DEFAULT_COEFF`` (0.5), which applies to
145
+ # additive terms.
146
+ DEFAULT_ABLATION_COEFF = 1.0
147
+
148
+
149
+ _TRIGGER_PRESETS: dict[str, Trigger] = {
150
+ "both": Trigger.BOTH,
151
+ "after": Trigger.AFTER_THINKING,
152
+ "before": Trigger.PROMPT_ONLY,
153
+ "thinking": Trigger.THINKING_ONLY,
154
+ "response": Trigger.GENERATED_ONLY,
155
+ "prompt": Trigger.PROMPT_ONLY,
156
+ "generated": Trigger.GENERATED_ONLY,
157
+ }
158
+
159
+ # Preferred render string per preset. Multiple grammar tokens alias onto
160
+ # the same Trigger (``@before`` == ``@prompt``); we pick one canonical form
161
+ # so round-tripping is deterministic.
162
+ _TRIGGER_CANONICAL: dict[Trigger, str] = {
163
+ Trigger.BOTH: "both",
164
+ Trigger.AFTER_THINKING: "after",
165
+ Trigger.PROMPT_ONLY: "before",
166
+ Trigger.THINKING_ONLY: "thinking",
167
+ Trigger.GENERATED_ONLY: "response",
168
+ }
169
+
170
+ # Counted decode windows: ``@first:N`` / ``@after:N`` are the grammar forms of
171
+ # :meth:`Trigger.first` / :meth:`Trigger.after`. Both require the ``:N``, which
172
+ # is also what disambiguates ``@after:5`` (the token window) from the bare
173
+ # ``@after`` preset (post-thinking). Rendered by :func:`_phase_name`.
174
+ _COUNTED_TRIGGER_KEYWORDS = ("first", "after")
175
+
176
+ # One human-readable list of everything ``@`` accepts, shared by the parse
177
+ # errors so the grammar surface is described in exactly one place.
178
+ _TRIGGER_FORMS_HELP = (
179
+ "valid: " + ", ".join(sorted(_TRIGGER_PRESETS)) + "; "
180
+ "'first:<n>' / 'after:<n>' token windows; "
181
+ "'when:<probe><op><threshold>' probe gates; "
182
+ "or a compound '<preset>&when:<probe><op><threshold>'"
183
+ )
184
+
185
+
186
+ @dataclass(frozen=True)
187
+ class ProjectedTerm:
188
+ """Runtime projection entry in ``Steering.alphas``.
189
+
190
+ The session materializes a derived profile on scope entry (combining
191
+ the ``base`` and ``onto`` profiles via ``project_profile``), registers
192
+ it under a synthetic name ``"<base><op><onto>"``, and feeds it to the
193
+ usual hook path. Stored as a value inside ``Steering.alphas``; the
194
+ key matches the synthetic name so duplicate references compose.
195
+ """
196
+ coeff: float
197
+ trigger: Trigger
198
+ operator: Literal["~", "|"]
199
+ base: str
200
+ onto: str
201
+
202
+
203
+ @dataclass(frozen=True)
204
+ class AblationTerm:
205
+ """Mean-replacement ablation entry in ``Steering.alphas``.
206
+
207
+ The composer lowers an ``AblationTerm`` to an ablate fragment in
208
+ ``compose_steering_entries``, which ``synthesize_subspace`` folds into the
209
+ merged affine subspace (per-axis ``κ = 1`` on the ablation axes), attached
210
+ via ``SteeringManager.add_subspace``. Stored as a value inside
211
+ ``Steering.alphas``; the key is ``"!<target>"`` so ablation entries never
212
+ collide with plain-term entries on the same concept.
213
+ """
214
+ coeff: float
215
+ trigger: Trigger
216
+ target: str
217
+
218
+
219
+ @dataclass(frozen=True)
220
+ class ManifoldTerm:
221
+ """Manifold-steering entry in ``Steering.alphas``.
222
+
223
+ Produced by a ``manifold % position`` term. The session loads the
224
+ named :class:`~drowse.core.manifold.Manifold` artifact on scope entry
225
+ and hands the hook a per-layer subspace + domain + the authoring
226
+ ``position`` coords; the hook runs the unified along/onto injection
227
+ (:func:`~drowse.core.manifold.subspace_inject`). Stored as a value
228
+ inside ``Steering.alphas`` under the key ``"<manifold>%<position>"`` so
229
+ two positions on the same manifold compose as distinct entries and
230
+ never collide with plain / projected / ablation keys.
231
+
232
+ The two coefficients (each clamped to ``[0, 1]`` at apply time):
233
+
234
+ - ``along`` — slide the projected foot toward ``position`` geodesically
235
+ in coordinate space (the principled "directional" op).
236
+ - ``onto`` — collapse the off-manifold, in-subspace residual onto the
237
+ surface (vacuous when the surface fills its subspace).
238
+
239
+ The off-*subspace* residual is always kept verbatim, which is what lets a
240
+ manifold term compose with neighbors at zero cross-talk; ``~`` / ``|``
241
+ semantics live inside the subspace, as push/ablation axes of the merged
242
+ affine basis.
243
+
244
+ The grammar's coefficient slot expands to a comma-run of ≤ 2: one coeff
245
+ ⇒ ``along`` (``onto`` off); two ⇒ ``along, onto``. ``manifold`` is the
246
+ registry key — namespace-qualified when the user typed a namespace,
247
+ variant-suffixed when not ``raw``.
248
+
249
+ ``position`` is either:
250
+
251
+ - A tuple of authoring coordinates — one float per intrinsic
252
+ dimension of the manifold's domain (the historical shape, e.g.
253
+ ``(0.3, 0.8)`` on a 2-D affect manifold).
254
+ - A node label string — sugar for "the coords of the node labeled
255
+ <s> on this manifold", resolved at scope entry via
256
+ :meth:`Manifold.resolve_position`. The label form makes
257
+ ``persona%pirate`` a first-class steering term parallel to
258
+ ``persona%0.3,0.8``.
259
+
260
+ Round-trip via :func:`format_expr` preserves the authored form.
261
+ """
262
+ along: float
263
+ onto: float
264
+ trigger: Trigger
265
+ manifold: str
266
+ position: tuple[float, ...] | str
267
+
268
+ @property
269
+ def coeff(self) -> float:
270
+ """Representative scalar — the ``along`` (directional) coefficient.
271
+
272
+ Read by the uniform telemetry / snapshot / role-aggregation sites
273
+ that want one "how strongly is this term steering" number; ``along``
274
+ is the directional strength that picks the node, so it is the right
275
+ representative. Not a stored field — there is no dual shape.
276
+ """
277
+ return self.along
278
+
279
+
280
+ # ``SteeringExprError`` lives in :mod:`drowse.core.errors`; it is imported
281
+ # above and re-exported here so
282
+ # ``from drowse.core.steering_expr import SteeringExprError`` keeps working.
283
+
284
+
285
+ # ---------------------------------------------------------------- lexer ---
286
+
287
+ _NUM_RE = re.compile(r"(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?")
288
+ _IDENT_START_RE = re.compile(r"[A-Za-z]")
289
+ _IDENT_CHAR_RE = re.compile(r"[A-Za-z0-9_]")
290
+
291
+ _SINGLE_CHAR_TOKENS = {
292
+ ".": "DOT", "/": "SLASH", ":": "COLON", "*": "STAR",
293
+ "+": "PLUS", "-": "MINUS", "@": "AT", "~": "TILDE",
294
+ "|": "ORTHO", "!": "BANG", "%": "PERCENT", ",": "COMMA",
295
+ "[": "LBRACK", "]": "RBRACK", "&": "AMP",
296
+ }
297
+
298
+ # Comparison-op tokens. Two-char ops (``>=``, ``<=``) take precedence
299
+ # over the single-char ones; the lexer peeks one char ahead before
300
+ # emitting GT / LT. ``=`` alone is not a token — equality (``==``) is
301
+ # not part of the gate grammar in v2.1 (probe scores are continuous
302
+ # floats; equality is meaningless).
303
+ _COMPARE_OPS: dict[str, str] = {
304
+ ">=": "GTE", "<=": "LTE",
305
+ ">": "GT", "<": "LT",
306
+ }
307
+
308
+
309
+ @dataclass
310
+ class _Tok:
311
+ kind: str
312
+ value: str | float
313
+ col: int
314
+
315
+
316
+ def _lex(text: str) -> list[_Tok]:
317
+ toks: list[_Tok] = []
318
+ i = 0
319
+ n = len(text)
320
+ while i < n:
321
+ c = text[i]
322
+ if c.isspace():
323
+ i += 1
324
+ continue
325
+ # Number detection must precede the single-char DOT branch, since
326
+ # ``.25`` starts with a DOT that is actually a decimal point.
327
+ if c.isdigit() or (c == "." and i + 1 < n and text[i + 1].isdigit()):
328
+ m = _NUM_RE.match(text, i)
329
+ if m is None: # pragma: no cover — isdigit guard
330
+ raise SteeringExprError(f"malformed number at {c!r}", col=i)
331
+ toks.append(_Tok("NUM", float(m.group()), i))
332
+ i = m.end()
333
+ continue
334
+ # Comparison ops: two-char first, then single-char.
335
+ if c in (">", "<"):
336
+ two = text[i:i + 2]
337
+ if two in _COMPARE_OPS:
338
+ toks.append(_Tok(_COMPARE_OPS[two], two, i))
339
+ i += 2
340
+ continue
341
+ toks.append(_Tok(_COMPARE_OPS[c], c, i))
342
+ i += 1
343
+ continue
344
+ if c in _SINGLE_CHAR_TOKENS:
345
+ toks.append(_Tok(_SINGLE_CHAR_TOKENS[c], c, i))
346
+ i += 1
347
+ continue
348
+ if _IDENT_START_RE.match(c):
349
+ start = i
350
+ i += 1
351
+ while i < n:
352
+ ch = text[i]
353
+ if _IDENT_CHAR_RE.match(ch):
354
+ i += 1
355
+ continue
356
+ # Dash-joined segments inside an ident (e.g. sae-release)
357
+ # require a valid ident-char on each side; otherwise the
358
+ # dash is a MINUS operator.
359
+ if (
360
+ ch == "-"
361
+ and i + 1 < n
362
+ and _IDENT_CHAR_RE.match(text[i + 1])
363
+ ):
364
+ i += 1
365
+ continue
366
+ break
367
+ toks.append(_Tok("IDENT", text[start:i], start))
368
+ continue
369
+ if c in ('"', "'"):
370
+ raise SteeringExprError(
371
+ "quoted identifiers are not supported; use underscores "
372
+ "for multi-word concept names "
373
+ "(e.g. 'artificial_intelligence') and '.' for bipolar "
374
+ "pairs (e.g. 'human.artificial_intelligence')",
375
+ col=i,
376
+ )
377
+ raise SteeringExprError(f"unexpected character {c!r}", col=i)
378
+ toks.append(_Tok("EOF", "", n))
379
+ return toks
380
+
381
+
382
+ # ------------------------------------------------------------------ ast ---
383
+
384
+ @dataclass
385
+ class _Atom:
386
+ namespace: Optional[str]
387
+ concept: str # may contain a single '.' joining two poles
388
+ variant: str # 'raw' (default) or an io.selectors tensor variant
389
+ col: int
390
+
391
+
392
+ @dataclass
393
+ class _Selector:
394
+ base: _Atom
395
+ operator: Optional[str] # None | '~' | '|'
396
+ onto: Optional[_Atom]
397
+ # Set when the selector is a manifold position term
398
+ # (``base % NUM (, NUM)*``); mutually exclusive with
399
+ # ``operator`` / ``onto``.
400
+ # ``tuple[float, ...]`` for coord-form (``%0.3,0.8``); ``str`` for
401
+ # label-form (``%pirate``). ``None`` when this selector is not a
402
+ # manifold term.
403
+ manifold_position: Optional[tuple[float, ...] | str] = None
404
+
405
+
406
+ @dataclass
407
+ class _Term:
408
+ coeff: float
409
+ selector: _Selector
410
+ # Pre-resolved Trigger object (or ``None`` to fall through to the
411
+ # session/Steering default). Preset triggers map through
412
+ # :data:`_TRIGGER_PRESETS`; probe gates (``@when:angry>0.4``)
413
+ # produce a ``Trigger(prompt=False, gate=ProbeGate(...))`` directly
414
+ # at parse time. Rendered back to canonical form by ``_fmt_*``.
415
+ trigger: Optional[Trigger]
416
+ ablation: bool = False # True iff term was prefixed with `!`
417
+ # The full comma-run of coefficients the user typed. A plain term
418
+ # carries a 1-tuple; a manifold ``%`` term may carry up to 2 mapping
419
+ # to (along, onto) via :func:`_expand_along_onto_coeffs`.
420
+ # ``coeff`` always equals ``coeffs[0]`` (the representative scalar all
421
+ # non-manifold code paths read), so existing single-coeff behavior is
422
+ # bit-identical; ``> 1`` on a non-manifold term is a parse-fold error.
423
+ coeffs: tuple[float, ...] = ()
424
+
425
+ def __post_init__(self) -> None:
426
+ if not self.coeffs:
427
+ self.coeffs = (self.coeff,)
428
+
429
+
430
+ # --------------------------------------------------------------- parser ---
431
+
432
+ class _Parser:
433
+ def __init__(self, toks: list[_Tok]) -> None:
434
+ self._toks = toks
435
+ self._pos = 0
436
+
437
+ def _peek(self, off: int = 0) -> _Tok:
438
+ return self._toks[self._pos + off]
439
+
440
+ def _consume(self) -> _Tok:
441
+ t = self._toks[self._pos]
442
+ self._pos += 1
443
+ return t
444
+
445
+ def _expect(self, kind: str) -> _Tok:
446
+ t = self._peek()
447
+ if t.kind != kind:
448
+ raise SteeringExprError(
449
+ f"expected {kind}, got {t.kind} ({t.value!r})", col=t.col,
450
+ )
451
+ return self._consume()
452
+
453
+ def parse(self) -> list[_Term]:
454
+ sign = +1
455
+ if self._peek().kind in ("PLUS", "MINUS"):
456
+ sign = -1 if self._consume().kind == "MINUS" else +1
457
+ terms = [self._term(sign)]
458
+ while self._peek().kind in ("PLUS", "MINUS"):
459
+ op_sign = -1 if self._consume().kind == "MINUS" else +1
460
+ terms.append(self._term(op_sign))
461
+ if self._peek().kind != "EOF":
462
+ t = self._peek()
463
+ if t.kind == "IDENT":
464
+ raise SteeringExprError(
465
+ f"unexpected identifier {t.value!r} after a complete "
466
+ f"term; multi-word concept names use underscores "
467
+ f"(e.g. 'artificial_intelligence', not "
468
+ f"'artificial intelligence'), and bipolar pairs join "
469
+ f"with '.' (e.g. 'human.artificial_intelligence')",
470
+ col=t.col,
471
+ )
472
+ raise SteeringExprError(
473
+ f"unexpected token {t.kind} ({t.value!r})", col=t.col,
474
+ )
475
+ return terms
476
+
477
+ def _term(self, sign: int) -> _Term:
478
+ explicit = False
479
+ coeff = float(sign) * DEFAULT_COEFF
480
+ coeffs: tuple[float, ...] = (coeff,)
481
+ if self._peek().kind == "NUM":
482
+ coeff = float(sign) * float(self._consume().value)
483
+ explicit = True
484
+ # Comma-run of coefficients: the TERM-level coeff slot may carry
485
+ # up to 2 values mapping to (along, onto) on a manifold ``%``
486
+ # term. This run is lexically unambiguous from the post-``%``
487
+ # position commas — those follow the manifold IDENT and ``%``,
488
+ # this precedes the selector. Each subsequent value carries the
489
+ # term's leading sign (so ``-0.6,0.3`` is ``(-0.6, -0.3)``, the
490
+ # natural read of a signed term). A 3rd value is a parse error;
491
+ # whether a comma-run is even legal for the selector kind
492
+ # (manifold-only) is enforced in ``_fold``.
493
+ run = [coeff]
494
+ while self._peek().kind == "COMMA":
495
+ self._consume()
496
+ run.append(float(sign) * self._signed_num())
497
+ if len(run) > 2:
498
+ raise SteeringExprError(
499
+ "a manifold coefficient slot takes at most 2 "
500
+ "comma-separated values (along, onto); got more",
501
+ col=self._peek(-1).col,
502
+ )
503
+ coeffs = tuple(run)
504
+ if self._peek().kind == "STAR":
505
+ self._consume()
506
+ ablation = False
507
+ if self._peek().kind == "BANG":
508
+ self._consume()
509
+ ablation = True
510
+ if not explicit:
511
+ # Bare `!x` defaults to fully-replace (coeff=1.0).
512
+ coeff = float(sign) * DEFAULT_ABLATION_COEFF
513
+ coeffs = (coeff,)
514
+ selector = self._selector()
515
+ trigger: Trigger | None = None
516
+ if self._peek().kind == "AT":
517
+ self._consume()
518
+ trigger = self._parse_trigger()
519
+ return _Term(
520
+ coeff=coeff, selector=selector, trigger=trigger,
521
+ ablation=ablation, coeffs=coeffs,
522
+ )
523
+
524
+ def _parse_trigger(self) -> Trigger:
525
+ """Parse the whole ``@`` clause into a :class:`Trigger`.
526
+
527
+ Already consumed: the ``@``. Grammar::
528
+
529
+ trigger := (phase ["&" gate] | gate)
530
+ phase := preset | ("first" | "after") ":" INT
531
+
532
+ Every publicly-constructible ``Trigger`` has a form here — the five
533
+ presets, the counted decode windows :meth:`Trigger.first` /
534
+ :meth:`Trigger.after`, the bare probe gate :meth:`Trigger.when`, and a
535
+ gate narrowed to a phase (``@after&when:x>0.4``, the shape
536
+ ``Trigger.when``'s own docstring points callers at). That totality is
537
+ what keeps ``parse_expr(format_expr(s)) == s``: without it,
538
+ ``format_expr`` would have to emit an unparseable sentinel and every
539
+ Recipe / ``applied_steering`` string stamped from such a Trigger would
540
+ poison the regen / transcript / loom replay that re-parses it.
541
+ """
542
+ tok = self._expect("IDENT")
543
+ kw = str(tok.value)
544
+ if kw == "when":
545
+ # A bare gate: no phase clause, so it can't be followed by "&".
546
+ return self._parse_when_gate_clause(tok.col)
547
+ base = self._parse_phase(tok)
548
+ if self._peek().kind != "AMP":
549
+ return base
550
+ self._consume() # AMP
551
+ gate_tok = self._expect("IDENT")
552
+ if str(gate_tok.value) != "when":
553
+ raise SteeringExprError(
554
+ f"a compound trigger's second clause must be a probe gate "
555
+ f"('&when:<probe><op><threshold>'); got '{gate_tok.value}'",
556
+ col=gate_tok.col,
557
+ )
558
+ gated = self._parse_when_gate_clause(gate_tok.col)
559
+ # The phase clause supplies the window verbatim, the gate clause the
560
+ # condition — so ``@<preset>&when:…`` is exactly "that preset, gated",
561
+ # which is what makes the compound form an exact round-trip of a
562
+ # ``replace(preset, gate=…)`` Trigger. The phase's ``prompt`` flag is
563
+ # left alone: a gate can never fire during prefill anyway (there is no
564
+ # post-forward probe reading yet), so ``Trigger.active`` ignores it.
565
+ return replace(base, gate=gated.gate)
566
+
567
+ def _parse_phase(self, tok: _Tok) -> Trigger:
568
+ """Parse a preset name or a ``first:N`` / ``after:N`` token window."""
569
+ kw = str(tok.value)
570
+ if kw in _COUNTED_TRIGGER_KEYWORDS and self._peek().kind == "COLON":
571
+ self._consume() # COLON
572
+ n_tok = self._expect("NUM")
573
+ n_val = float(n_tok.value)
574
+ n = int(n_val)
575
+ if n_val != n or n < 0:
576
+ raise SteeringExprError(
577
+ f"trigger '@{kw}:' takes a non-negative integer token "
578
+ f"count, got '{n_tok.value}'",
579
+ col=n_tok.col,
580
+ )
581
+ return Trigger.first(n) if kw == "first" else Trigger.after(n)
582
+ if kw == "first":
583
+ raise SteeringExprError(
584
+ "trigger '@first' requires ':' followed by a token count "
585
+ "(e.g. '@first:5')",
586
+ col=tok.col,
587
+ )
588
+ if kw in _TRIGGER_PRESETS:
589
+ return _TRIGGER_PRESETS[kw]
590
+ raise SteeringExprError(
591
+ f"unknown trigger '@{kw}'; {_TRIGGER_FORMS_HELP}. Note: '@' is "
592
+ f"for triggers only; HF revisions are not accepted inside "
593
+ f"steering expressions.",
594
+ col=tok.col,
595
+ )
596
+
597
+ def _parse_when_gate_clause(self, when_col: int) -> Trigger:
598
+ """Consume the ``:`` after a ``when`` keyword, then its gate payload."""
599
+ if self._peek().kind != "COLON":
600
+ raise SteeringExprError(
601
+ f"trigger '@when' requires ':' followed by a "
602
+ f"probe gate (e.g. '@when:angry.calm>0.4'); "
603
+ f"got {self._peek().kind}",
604
+ col=self._peek().col,
605
+ )
606
+ self._consume() # COLON
607
+ return self._parse_when_gate(when_col)
608
+
609
+ def _parse_when_gate(self, when_col: int) -> Trigger:
610
+ """Parse the ``when:`` payload into a probe-gated :class:`Trigger`.
611
+
612
+ Already consumed: ``@`` ``when`` ``:``. Expects a probe
613
+ identifier, one of ``>``/``>=``/``<``/``<=``, then a numeric
614
+ threshold.
615
+
616
+ Three probe identifier shapes are accepted:
617
+
618
+ - Vector probe: ``IDENT`` optionally followed by ``.IDENT`` for
619
+ a bipolar concept (e.g. ``angry.calm``), and an optional
620
+ ``[<i>]`` coordinate-axis index (e.g. ``personas[3]``,
621
+ ``angry.calm[0]``). No namespace prefix in v2.1 (the monitor
622
+ is keyed by canonical concept name regardless of which pack the
623
+ probe came from), and no SAE variant suffix. The index selects
624
+ one axis of the probe's coordinate readout; an un-indexed gate
625
+ reads axis 0 (the only axis of a 2-node concept), so existing
626
+ ``@when:angry.calm>0.4`` gates are unchanged.
627
+ - Manifold subspace-fraction probe:
628
+ ``<manifold>:fraction`` — fires on the fraction of the
629
+ centered activation that lives in the manifold's PCA
630
+ subspace. Stored verbatim as the gate's probe string
631
+ (e.g. ``"emotions:fraction"``); the session's
632
+ :class:`Monitor.flat_scalars` already emits a
633
+ matching namespaced key, so ``Trigger.active`` looks it up
634
+ unchanged.
635
+ - Manifold label-similarity probe:
636
+ ``<manifold>@<label>`` — fires on the negated distance to
637
+ the named node (larger = closer). Stored verbatim as the
638
+ gate's probe string (e.g. ``"emotions@happy"``); same
639
+ ``flat_scalars`` correspondence.
640
+
641
+ Every shape also accepts a leading ``<ns>/`` namespace segment
642
+ (``jlens/fake``, ``default/emotions@happy``) — consumed before
643
+ the channel discriminators, stored verbatim.
644
+
645
+ The discriminator on the trailing IDENT: a ``COLON`` after the
646
+ manifold name routes to the fraction form, an ``AT`` to the
647
+ label form, a ``DOT`` to the bipolar vector form, anything
648
+ else is a plain vector probe. Within the ``when:`` body the
649
+ ``AT`` token cannot be a fresh trigger marker (one ``@`` clause
650
+ per term, already consumed), so the disambiguation is
651
+ unambiguous.
652
+ """
653
+ probe_tok = self._expect("IDENT")
654
+ probe = str(probe_tok.value)
655
+ if self._peek().kind == "SLASH":
656
+ # Namespaced probe: ``<ns>/<name>`` — a J-lens token probe
657
+ # (``jlens/fake``) or a probe attached under a qualified selector
658
+ # (``default/emotions``). Consumed before the channel
659
+ # discriminators so every channel shape composes with a
660
+ # namespaced probe; stored verbatim, matching the keys
661
+ # ``Monitor.flat_scalars`` emits.
662
+ self._consume()
663
+ if probe == "sae" and self._peek().kind == "NUM":
664
+ ns_rhs = self._consume()
665
+ feature = float(ns_rhs.value)
666
+ if feature != int(feature) or feature < 0:
667
+ raise SteeringExprError(
668
+ "SAE feature id must be a non-negative integer",
669
+ col=ns_rhs.col,
670
+ )
671
+ probe = f"sae/{int(feature)}"
672
+ else:
673
+ ns_rhs = self._expect("IDENT")
674
+ probe = f"{probe}/{ns_rhs.value}"
675
+ nxt = self._peek().kind
676
+ if nxt == "COLON":
677
+ # Manifold subspace-fraction gate: ``<manifold>:fraction``.
678
+ # The suffix after the colon must be the literal slug
679
+ # ``fraction`` — the only fraction-channel scalar
680
+ # ``Monitor.flat_scalars`` emits. Any other slug
681
+ # would silently never match a probe score, so we surface
682
+ # the typo here rather than letting the gate report
683
+ # inactive forever.
684
+ self._consume()
685
+ suffix_tok = self._expect("IDENT")
686
+ suffix = str(suffix_tok.value)
687
+ # ``fraction`` (subspace energy share) and ``membership`` (the
688
+ # fuzzy-manifold tube-fit density ∈ [0,1]) are the two scalar
689
+ # ``:``-channels ``Monitor.flat_scalars`` emits.
690
+ if suffix not in ("fraction", "membership"):
691
+ raise SteeringExprError(
692
+ f"unknown manifold gate channel "
693
+ f"'{probe}:{suffix}'; expected "
694
+ f"'<manifold>:fraction', '<manifold>:membership', "
695
+ f"'<manifold>@<label>', or '<manifold>~<label>'",
696
+ col=suffix_tok.col,
697
+ )
698
+ probe = f"{probe}:{suffix}"
699
+ elif nxt == "AT":
700
+ # Manifold label-similarity gate: ``<manifold>@<label>``.
701
+ # Label existence is not validated at parse time — the
702
+ # manifold artifact may not be loaded yet, and a stale
703
+ # gate against a removed label should report inactive (no
704
+ # matching key in ``flat_scalars``), not raise.
705
+ self._consume()
706
+ label_tok = self._expect("IDENT")
707
+ probe = f"{probe}@{label_tok.value}"
708
+ elif nxt == "TILDE":
709
+ # Fuzzy-manifold soft-assignment gate: ``<manifold>~<label>`` —
710
+ # fires on the node's assignment *probability* ∈ [0,1] (the
711
+ # normalized counterpart to the ``@<label>`` negated distance).
712
+ # Same verbatim-storage / ``flat_scalars`` correspondence; label
713
+ # existence unvalidated at parse time (stale → inactive, not raise).
714
+ self._consume()
715
+ label_tok = self._expect("IDENT")
716
+ probe = f"{probe}~{label_tok.value}"
717
+ else:
718
+ if nxt == "DOT":
719
+ self._consume()
720
+ rhs = self._expect("IDENT")
721
+ probe = f"{probe}.{rhs.value}"
722
+ # Optional coordinate-axis index for a multi-axis probe:
723
+ # ``personas[3]`` / ``angry.calm[0]``. Selects one axis of the
724
+ # probe's coordinate readout. The session writes a matching
725
+ # ``<probe>[<i>]`` scalar channel into ``probe_scores`` for
726
+ # every coord axis, and aliases the bare ``<probe>`` to axis 0,
727
+ # so an un-indexed gate on a 2-node concept reads its single
728
+ # coordinate exactly as before. Indexing is not accepted after
729
+ # the ``:fraction`` / ``@label`` manifold channels — those are
730
+ # already scalar.
731
+ if self._peek().kind == "LBRACK":
732
+ self._consume()
733
+ idx_tok = self._expect("NUM")
734
+ idx_val = float(idx_tok.value)
735
+ idx = int(idx_val)
736
+ if idx_val != idx or idx < 0:
737
+ raise SteeringExprError(
738
+ f"coordinate index must be a non-negative integer, "
739
+ f"got '{idx_tok.value}'",
740
+ col=idx_tok.col,
741
+ )
742
+ self._expect("RBRACK")
743
+ probe = f"{probe}[{idx}]"
744
+ op_tok = self._consume()
745
+ op_kind = op_tok.kind
746
+ if op_kind not in ("GT", "GTE", "LT", "LTE"):
747
+ raise SteeringExprError(
748
+ f"expected comparison op (>, >=, <, <=) in '@when:' "
749
+ f"clause, got {op_kind} ({op_tok.value!r})",
750
+ col=op_tok.col,
751
+ )
752
+ op_str = {"GT": ">", "GTE": ">=", "LT": "<", "LTE": "<="}[op_kind]
753
+ # Allow a leading ``-`` on the threshold so ``@when:x>-0.5``
754
+ # parses as ``threshold = -0.5``.
755
+ threshold = self._signed_num()
756
+ return Trigger.when(probe, op_str, threshold) # pyright: ignore[reportArgumentType] # dict[str,str] widens the literal op value; runtime is always a valid ProbeGateOp
757
+
758
+ def _signed_num(self) -> float:
759
+ """Parse an optionally signed numeric literal: ``[+|-] NUM``."""
760
+ sign = +1.0
761
+ if self._peek().kind == "MINUS":
762
+ self._consume()
763
+ sign = -1.0
764
+ elif self._peek().kind == "PLUS":
765
+ self._consume()
766
+ num_tok = self._expect("NUM")
767
+ return sign * float(num_tok.value)
768
+
769
+ def _selector(self) -> _Selector:
770
+ base = self._atom()
771
+ if self._peek().kind == "PERCENT":
772
+ # Manifold position term: ``base % NUM(,NUM)*`` (coord form)
773
+ # OR ``base % IDENT`` (label form, sugar for "the coords of
774
+ # the node labeled <s>"; resolved at scope entry). The
775
+ # parser only collects the position payload — arity (against
776
+ # the domain's intrinsic dimension) for the coord form, and
777
+ # label existence + role-paired lookup for the label form,
778
+ # are checked at manifold-load time when both the domain
779
+ # and the node labels are known.
780
+ self._consume()
781
+ head = self._peek()
782
+ position: tuple[float, ...] | str
783
+ if head.kind == "IDENT":
784
+ # Label form: a single bare identifier. No comma list
785
+ # — a manifold node label is one slug, not a tuple.
786
+ # Variant suffixes (``%pirate:role-pirate``) are not
787
+ # meaningful on a position and so not part of the
788
+ # grammar; if the user typed one, it lexed as a
789
+ # separate ``:`` token and will fall out as a parse
790
+ # error on the trailing arm below.
791
+ tok = self._consume()
792
+ position = str(tok.value)
793
+ else:
794
+ coords: list[float] = [self._signed_num()]
795
+ while self._peek().kind == "COMMA":
796
+ self._consume()
797
+ coords.append(self._signed_num())
798
+ position = tuple(coords)
799
+ if self._peek().kind in ("TILDE", "ORTHO", "PERCENT"):
800
+ raise SteeringExprError(
801
+ _MANIFOLD_COMPOSE_MSG,
802
+ col=self._peek().col,
803
+ )
804
+ return _Selector(
805
+ base=base, operator=None, onto=None,
806
+ manifold_position=position,
807
+ )
808
+ if self._peek().kind in ("TILDE", "ORTHO"):
809
+ op_tok = self._consume()
810
+ op = "~" if op_tok.kind == "TILDE" else "|"
811
+ onto = self._atom()
812
+ if self._peek().kind in ("TILDE", "ORTHO"):
813
+ nxt = self._peek()
814
+ raise SteeringExprError(
815
+ "chained projection is not allowed; "
816
+ "use one '~' or '|' per term",
817
+ col=nxt.col,
818
+ )
819
+ return _Selector(base=base, operator=op, onto=onto)
820
+ return _Selector(base=base, operator=None, onto=None)
821
+
822
+ def _atom(self) -> _Atom:
823
+ first = self._expect("IDENT")
824
+ col = first.col
825
+ namespace: str | None = None
826
+ concept = str(first.value)
827
+ if self._peek().kind == "SLASH":
828
+ self._consume()
829
+ namespace = concept
830
+ if namespace == "sae" and self._peek().kind == "NUM":
831
+ second = self._consume()
832
+ feature = float(second.value)
833
+ if feature != int(feature) or feature < 0:
834
+ raise SteeringExprError(
835
+ "SAE feature id must be a non-negative integer",
836
+ col=second.col,
837
+ )
838
+ concept = str(int(feature))
839
+ else:
840
+ second = self._expect("IDENT")
841
+ concept = str(second.value)
842
+ if self._peek().kind == "DOT":
843
+ self._consume()
844
+ rhs = self._expect("IDENT")
845
+ concept = f"{concept}.{rhs.value}"
846
+ variant = "raw"
847
+ if self._peek().kind == "COLON":
848
+ self._consume()
849
+ v = self._expect("IDENT")
850
+ variant = str(v.value)
851
+ return _Atom(
852
+ namespace=namespace, concept=concept, variant=variant, col=col,
853
+ )
854
+
855
+
856
+ # ------------------------------------------------------------ resolve/fold ---
857
+
858
+ def _with_variant(canonical: str, variant: str) -> str:
859
+ return canonical if variant == "raw" else f"{canonical}:{variant}"
860
+
861
+
862
+ def _resolve_atom(atom: _Atom) -> str:
863
+ """Return the ``alphas_key`` for a **pole** atom.
864
+
865
+ The key is the canonical concept name from ``canonicalize_atom``,
866
+ prefixed with ``<namespace>/`` when the user explicitly typed a
867
+ namespace (so two installed packs sharing a concept name —
868
+ ``alice/foo`` vs ``bob/foo`` — stay distinct through the
869
+ registry-key path), and suffixed with ``:<variant>`` when the
870
+ variant is anything other than ``raw``.
871
+
872
+ This is the **pole canonicalization tier in isolation** — the base
873
+ of a projection / ablation term and a projection ``onto`` direction
874
+ are always vector concepts and must not route through the manifold
875
+ tiers; the plain-term path in :func:`_fold` runs the full
876
+ :func:`~drowse.io.selectors.resolve_bare_atom` ladder instead.
877
+ """
878
+ from drowse.io.selectors import canonicalize_atom
879
+
880
+ raw = atom.concept
881
+ if atom.variant != "raw":
882
+ raw = f"{raw}:{atom.variant}"
883
+ canonical, variant = canonicalize_atom(raw)
884
+ if atom.namespace is not None:
885
+ canonical = f"{atom.namespace}/{canonical}"
886
+ return _with_variant(canonical, variant)
887
+
888
+
889
+ def _merge_plain(
890
+ alphas: "dict[str, AlphaEntry]",
891
+ key: str,
892
+ coeff: float,
893
+ trig: Optional[Trigger],
894
+ ) -> None:
895
+ if key not in alphas:
896
+ alphas[key] = coeff if trig is None else (coeff, trig)
897
+ return
898
+ existing = alphas[key]
899
+ if isinstance(existing, ProjectedTerm):
900
+ raise SteeringExprError(
901
+ f"concept '{key}' appears both as a plain term and as a "
902
+ f"projection target; use distinct references"
903
+ )
904
+ prev_coeff: float
905
+ prev_trig: Optional[Trigger]
906
+ if isinstance(existing, tuple):
907
+ prev_coeff = float(existing[0])
908
+ prev_trig = existing[1]
909
+ else:
910
+ prev_coeff = float(cast(float, existing))
911
+ prev_trig = None
912
+ if prev_trig is None and trig is None:
913
+ alphas[key] = prev_coeff + coeff
914
+ return
915
+ if prev_trig is not None and trig is not None and prev_trig == trig:
916
+ alphas[key] = (prev_coeff + coeff, trig)
917
+ return
918
+ raise SteeringExprError(
919
+ f"concept '{key}' appears with conflicting triggers; "
920
+ f"merge triggers explicitly or split into separate Steering entries"
921
+ )
922
+
923
+
924
+ def _merge_projected(
925
+ alphas: "dict[str, AlphaEntry]",
926
+ key: str,
927
+ op: Literal["~", "|"],
928
+ base: str,
929
+ onto: str,
930
+ coeff: float,
931
+ trig: Trigger,
932
+ ) -> None:
933
+ if key not in alphas:
934
+ alphas[key] = ProjectedTerm(
935
+ coeff=coeff, trigger=trig, operator=op, base=base, onto=onto,
936
+ )
937
+ return
938
+ existing = alphas[key]
939
+ if not isinstance(existing, ProjectedTerm):
940
+ raise SteeringExprError(
941
+ f"projection '{key}' conflicts with a plain entry of the same name"
942
+ )
943
+ if existing.trigger != trig:
944
+ raise SteeringExprError(
945
+ f"projection '{key}' appears with conflicting triggers"
946
+ )
947
+ alphas[key] = ProjectedTerm(
948
+ coeff=existing.coeff + coeff,
949
+ trigger=trig, operator=op, base=base, onto=onto,
950
+ )
951
+
952
+
953
+ def _merge_ablation(
954
+ alphas: "dict[str, AlphaEntry]",
955
+ target_key: str,
956
+ coeff: float,
957
+ trig: Trigger,
958
+ ) -> None:
959
+ key = f"!{target_key}"
960
+ if key not in alphas:
961
+ alphas[key] = AblationTerm(coeff=coeff, trigger=trig, target=target_key)
962
+ return
963
+ existing = alphas[key]
964
+ if not isinstance(existing, AblationTerm):
965
+ raise SteeringExprError( # pragma: no cover — key namespace is disjoint
966
+ f"ablation '{key}' conflicts with a non-ablation entry of the same name"
967
+ )
968
+ if existing.trigger != trig:
969
+ raise SteeringExprError(
970
+ f"ablation '!{target_key}' appears with conflicting triggers; "
971
+ f"merge triggers explicitly or split into separate Steering entries"
972
+ )
973
+ alphas[key] = AblationTerm(
974
+ coeff=existing.coeff + coeff, trigger=trig, target=target_key,
975
+ )
976
+
977
+
978
+ def _resolve_manifold_atom(atom: _Atom) -> str:
979
+ """Return the registry key for a manifold atom.
980
+
981
+ Unlike :func:`_resolve_atom`, manifold atoms do *not* go through
982
+ pole canonicalization — a manifold name is not a concept and must not
983
+ alias to one. The key is the bare name, namespace-prefixed only when
984
+ the user typed a namespace, variant-suffixed when not ``raw``.
985
+ """
986
+ key = atom.concept
987
+ if atom.namespace is not None:
988
+ key = f"{atom.namespace}/{key}"
989
+ return _with_variant(key, atom.variant)
990
+
991
+
992
+ def _fmt_position(position: tuple[float, ...] | str) -> str:
993
+ """Render a manifold position payload back to grammar form.
994
+
995
+ Coord tuple → comma-joined ``%g`` list (``0.3,0.8``). Label string
996
+ → the slug verbatim (``pirate``). The two forms are unambiguous
997
+ by shape — a node label is a slug-shaped identifier, a coord list
998
+ starts with a digit / sign.
999
+ """
1000
+ if isinstance(position, str):
1001
+ return position
1002
+ return ",".join(f"{c:g}" for c in position)
1003
+
1004
+
1005
+ def _expand_along_onto_coeffs(
1006
+ coeffs: tuple[float, ...],
1007
+ ) -> tuple[float, float]:
1008
+ """Map a 1/2-length coefficient run to ``(along, onto)``.
1009
+
1010
+ The manifold ``%`` coefficient slot expands a comma-run with the
1011
+ collapse op (``onto``) defaulting **off** — it is opted into:
1012
+
1013
+ - ``c`` → ``along = c, onto = 0`` (pure directional slide)
1014
+ - ``a, o`` → ``along = a, onto = o``
1015
+
1016
+ ``along`` is *the* steering knob: it slides the projected foot toward
1017
+ the target on the manifold and keeps everything else. ``onto`` (flatten
1018
+ the off-manifold in-subspace residual) is aggressive and so off by
1019
+ default. The off-*subspace* residual is always kept verbatim — that is
1020
+ the composition invariant, so it has no coefficient.
1021
+
1022
+ A run of length 0 or > 2 is a programming error here — the parser
1023
+ rejects the 3-coeff case at parse time and a term always carries at
1024
+ least one coeff — but raise rather than index blindly.
1025
+ """
1026
+ n = len(coeffs)
1027
+ if n == 1:
1028
+ return (coeffs[0], 0.0)
1029
+ if n == 2:
1030
+ a, o = coeffs
1031
+ return (a, o)
1032
+ raise SteeringExprError(
1033
+ "a manifold coefficient slot takes 1 or 2 comma-separated "
1034
+ f"values (along, onto); got {n}"
1035
+ )
1036
+
1037
+
1038
+ def _merge_manifold(
1039
+ alphas: "dict[str, AlphaEntry]",
1040
+ manifold: str,
1041
+ coeffs: tuple[float, float],
1042
+ position: tuple[float, ...] | str,
1043
+ trig: Trigger,
1044
+ ) -> None:
1045
+ along, onto = coeffs
1046
+ key = f"{manifold}%{_fmt_position(position)}"
1047
+ if key not in alphas:
1048
+ alphas[key] = ManifoldTerm(
1049
+ along=along, onto=onto,
1050
+ trigger=trig, manifold=manifold, position=position,
1051
+ )
1052
+ return
1053
+ existing = alphas[key]
1054
+ if not isinstance(existing, ManifoldTerm):
1055
+ raise SteeringExprError( # pragma: no cover — key namespace is disjoint
1056
+ f"manifold '{key}' conflicts with a non-manifold entry"
1057
+ )
1058
+ if existing.trigger != trig:
1059
+ raise SteeringExprError(
1060
+ f"manifold '{key}' appears with conflicting "
1061
+ f"triggers; merge triggers explicitly or split into separate "
1062
+ f"Steering entries"
1063
+ )
1064
+ alphas[key] = ManifoldTerm(
1065
+ along=existing.along + along,
1066
+ onto=existing.onto + onto,
1067
+ trigger=trig, manifold=manifold, position=position,
1068
+ )
1069
+
1070
+
1071
+ def _fold(
1072
+ terms: list[_Term],
1073
+ *,
1074
+ namespace: Optional[str],
1075
+ profile_names: Optional[set[str]] = None,
1076
+ ) -> "Steering":
1077
+ from drowse.core.steering import Steering
1078
+
1079
+ alphas: "dict[str, AlphaEntry]" = {}
1080
+ registered_profiles = profile_names or set()
1081
+ for term in terms:
1082
+ sel = term.selector
1083
+ # Manifold position terms resolve before ``_resolve_atom`` — a
1084
+ # manifold name must not run through concept pole-resolution.
1085
+ if sel.manifold_position is not None:
1086
+ if term.ablation:
1087
+ raise SteeringExprError(_MANIFOLD_COMPOSE_MSG)
1088
+ mfld_key = _resolve_manifold_atom(sel.base)
1089
+ mfld_trig = (
1090
+ term.trigger if term.trigger is not None else Trigger.BOTH
1091
+ )
1092
+ _merge_manifold(
1093
+ alphas, mfld_key,
1094
+ _expand_along_onto_coeffs(term.coeffs),
1095
+ sel.manifold_position, mfld_trig,
1096
+ )
1097
+ continue
1098
+ # Bare-atom tier ladder. A plain term (no projection operator, no
1099
+ # ablation) runs the unified ladder that
1100
+ # :func:`~drowse.io.selectors.resolve_bare_atom` owns end to end —
1101
+ # manifold-label tier first (a bare slug matching a node label →
1102
+ # label-form ``%`` push), then the composite-name tier (a 2-node
1103
+ # ``pca`` manifold name like ``happy.sad`` → its node-0 (+) pole),
1104
+ # then the pole canonicalization that falls through to the plain
1105
+ # vector path below. Every bipolar pole is itself a node label, so a
1106
+ # bare pole resolves through the label tier as an affine ``%`` push.
1107
+ # Ordering + cross-tier ``AmbiguousSelectorError`` arbitration live in
1108
+ # the resolver, not here.
1109
+ if sel.operator is None and not term.ablation:
1110
+ profile_key = _resolve_atom(sel.base)
1111
+ if profile_key in registered_profiles:
1112
+ if len(term.coeffs) > 1:
1113
+ raise SteeringExprError(
1114
+ "comma-separated coefficients are only valid for "
1115
+ "`manifold % position` terms"
1116
+ )
1117
+ _merge_plain(alphas, profile_key, term.coeff, term.trigger)
1118
+ continue
1119
+
1120
+ from drowse.io.selectors import resolve_bare_atom
1121
+
1122
+ atom = resolve_bare_atom(
1123
+ sel.base.concept,
1124
+ namespace=namespace,
1125
+ typed_namespace=sel.base.namespace,
1126
+ variant=sel.base.variant,
1127
+ )
1128
+ if atom.kind == "label":
1129
+ assert atom.manifold is not None
1130
+ mfld_trig = (
1131
+ term.trigger if term.trigger is not None else Trigger.BOTH
1132
+ )
1133
+ _merge_manifold(
1134
+ alphas, atom.manifold.manifold_key,
1135
+ _expand_along_onto_coeffs(term.coeffs),
1136
+ atom.manifold.label, mfld_trig,
1137
+ )
1138
+ continue
1139
+ if atom.kind == "name":
1140
+ assert atom.manifold_name is not None
1141
+ mfld_trig = (
1142
+ term.trigger if term.trigger is not None else Trigger.BOTH
1143
+ )
1144
+ _merge_manifold(
1145
+ alphas, atom.manifold_name.manifold_key,
1146
+ _expand_along_onto_coeffs(term.coeffs),
1147
+ atom.manifold_name.pole_label, mfld_trig,
1148
+ )
1149
+ continue
1150
+ # kind == "pole": fall through to the plain vector path below
1151
+ # (re-resolved via ``_resolve_atom`` for the namespace-prefixed
1152
+ # registry key).
1153
+ # Past this point the term is unambiguously a vector (plain /
1154
+ # projection / ablation) — the comma-separated coefficient run is a
1155
+ # manifold-``%``-only construct, so reject it here rather than
1156
+ # silently dropping the extra values.
1157
+ if len(term.coeffs) > 1:
1158
+ raise SteeringExprError(
1159
+ "comma-separated coefficients are only valid for "
1160
+ "`manifold % position` terms"
1161
+ )
1162
+ base_key = _resolve_atom(sel.base)
1163
+ coeff = term.coeff
1164
+ # ``_Term.trigger`` already carries a resolved Trigger object
1165
+ # (built by :class:`_Parser._term`) — preset names map through
1166
+ # _TRIGGER_PRESETS at parse time, gates produce a fresh
1167
+ # Trigger directly. Pass through verbatim.
1168
+ trig: Trigger | None = term.trigger
1169
+ if term.ablation:
1170
+ if sel.operator is not None:
1171
+ raise SteeringExprError(
1172
+ "ablation does not compose with projection operators; "
1173
+ "ablate the base concept and project separately"
1174
+ )
1175
+ effective_trig = trig if trig is not None else Trigger.BOTH
1176
+ _merge_ablation(alphas, base_key, coeff, effective_trig)
1177
+ continue
1178
+ if sel.operator is None:
1179
+ _merge_plain(alphas, base_key, coeff, trig)
1180
+ continue
1181
+ # Projection terms. Projection math is insensitive to the sign of
1182
+ # the onto direction (``a|b`` yields the same result as
1183
+ # ``a|(-b)``); the base sign is already folded into ``coeff``.
1184
+ assert sel.onto is not None
1185
+ onto_key = _resolve_atom(sel.onto)
1186
+ effective_trig = trig if trig is not None else Trigger.BOTH
1187
+ op: Literal["~", "|"] = cast(Literal["~", "|"], sel.operator)
1188
+ syn_key = f"{base_key}{op}{onto_key}"
1189
+ _merge_projected(
1190
+ alphas, syn_key, op, base_key, onto_key,
1191
+ coeff, effective_trig,
1192
+ )
1193
+ return Steering(alphas=alphas)
1194
+
1195
+
1196
+ # ---------------------------------------------------------------- public ---
1197
+
1198
+ def parse_expr(
1199
+ text: str,
1200
+ *,
1201
+ namespace: Optional[str] = None,
1202
+ profile_names: Optional[set[str]] = None,
1203
+ ) -> "Steering":
1204
+ """Parse a steering expression string into a :class:`Steering` IR.
1205
+
1206
+ ``namespace`` scopes bare-atom resolution to a single namespace; when
1207
+ ``None``, :func:`drowse.io.selectors.resolve_bare_atom` raises
1208
+ :class:`~drowse.io.selectors.AmbiguousSelectorError` if a bare atom
1209
+ matches manifolds across multiple namespaces.
1210
+
1211
+ ``profile_names`` is a session-local override set: when a plain term's
1212
+ canonical registry key exactly matches an in-memory profile, that profile
1213
+ wins over the installed-manifold tiers for that parse only.
1214
+ """
1215
+ if not text or not text.strip():
1216
+ raise SteeringExprError("empty steering expression")
1217
+ toks = _lex(text)
1218
+ terms = _Parser(toks).parse()
1219
+ return _fold(terms, namespace=namespace, profile_names=profile_names)
1220
+
1221
+
1222
+ def format_expr(steering: "Steering") -> str:
1223
+ """Render a :class:`Steering` back into canonical expression form.
1224
+
1225
+ Round-trips with :func:`parse_expr` for any IR produced by the parser.
1226
+ Entries whose trigger equals :data:`Trigger.BOTH` omit the ``@`` tag;
1227
+ entries whose coefficient is negative are emitted via ``-`` separators
1228
+ (first term carries the sign verbatim).
1229
+ """
1230
+ default_trig = steering.trigger
1231
+ parts: list[str] = []
1232
+ for name, val in steering.alphas.items():
1233
+ if isinstance(val, AblationTerm):
1234
+ parts.append(_fmt_ablation(val))
1235
+ continue
1236
+ if isinstance(val, ProjectedTerm):
1237
+ parts.append(_fmt_projected(val))
1238
+ continue
1239
+ if isinstance(val, ManifoldTerm):
1240
+ parts.append(_fmt_manifold(val))
1241
+ continue
1242
+ if isinstance(val, tuple):
1243
+ coeff, trig = float(val[0]), val[1]
1244
+ else:
1245
+ coeff, trig = float(val), default_trig
1246
+ parts.append(_fmt_plain(name, coeff, trig))
1247
+ if not parts:
1248
+ return ""
1249
+ out = parts[0]
1250
+ for p in parts[1:]:
1251
+ if p.startswith("-"):
1252
+ out += " - " + p[1:].lstrip()
1253
+ else:
1254
+ out += " + " + p
1255
+ return out
1256
+
1257
+
1258
+ def _fmt_plain(name: str, coeff: float, trig: Trigger) -> str:
1259
+ body = f"{coeff:g} {name}"
1260
+ if trig != Trigger.BOTH:
1261
+ body += "@" + _trigger_name(trig)
1262
+ return body
1263
+
1264
+
1265
+ def _fmt_projected(p: ProjectedTerm) -> str:
1266
+ body = f"{p.coeff:g} {p.base}{p.operator}{p.onto}"
1267
+ if p.trigger != Trigger.BOTH:
1268
+ body += "@" + _trigger_name(p.trigger)
1269
+ return body
1270
+
1271
+
1272
+ def _fmt_ablation(a: AblationTerm) -> str:
1273
+ if a.coeff == 1.0:
1274
+ body = f"!{a.target}"
1275
+ elif a.coeff == -1.0:
1276
+ body = f"-!{a.target}"
1277
+ else:
1278
+ body = f"{a.coeff:g} !{a.target}"
1279
+ if a.trigger != Trigger.BOTH:
1280
+ body += "@" + _trigger_name(a.trigger)
1281
+ return body
1282
+
1283
+
1284
+ def _fmt_manifold(m: ManifoldTerm) -> str:
1285
+ # Render the shortest coefficient form the (along, onto) pair collapses
1286
+ # to — the inverse of ``_expand_along_onto_coeffs`` — so the round-trip is
1287
+ # byte-for-byte. The collapse op defaults off, so: onto zero → one coeff
1288
+ # (along); else two (along, onto).
1289
+ #
1290
+ # The parser applies the term's *leading* sign (carried by ``along``) to
1291
+ # every value in the comma-run (``-0.6,0.3`` parses as ``(-0.6, -0.3)``),
1292
+ # so to make a programmatically-built mixed-sign term round-trip we render
1293
+ # ``onto`` *relative to* ``along``'s sign: literal = onto·sign(along), which
1294
+ # the parser then re-multiplies by sign(along) back to ``onto``. For the
1295
+ # parser's own output (where the whole run shares one sign) this is a no-op.
1296
+ pos = _fmt_position(m.position)
1297
+ if m.onto == 0.0:
1298
+ coeff_str = f"{m.along:g}"
1299
+ else:
1300
+ onto_lit = -m.onto if m.along < 0 else m.onto
1301
+ coeff_str = f"{m.along:g},{onto_lit:g}"
1302
+ body = f"{coeff_str} {m.manifold}%{pos}"
1303
+ if m.trigger != Trigger.BOTH:
1304
+ body += "@" + _trigger_name(m.trigger)
1305
+ return body
1306
+
1307
+
1308
+ def _phase_name(base: Trigger) -> str | None:
1309
+ """Render a gate-free Trigger's window, or ``None`` if it has no form.
1310
+
1311
+ Covers the five presets and the two counted decode windows
1312
+ (:meth:`Trigger.first` / :meth:`Trigger.after`) — i.e. every window a
1313
+ public factory can produce. A ``Trigger`` hand-built with a field
1314
+ combination outside that set (say ``first_n`` *and* ``after_n``, or a
1315
+ narrowed phase on top of a count) has no grammar form and returns
1316
+ ``None``.
1317
+ """
1318
+ if base in _TRIGGER_CANONICAL:
1319
+ return _TRIGGER_CANONICAL[base]
1320
+ if base.first_n is not None and base == Trigger.first(base.first_n):
1321
+ return f"first:{base.first_n}"
1322
+ if base.after_n is not None and base == Trigger.after(base.after_n):
1323
+ return f"after:{base.after_n}"
1324
+ return None
1325
+
1326
+
1327
+ def _trigger_name(trig: Trigger) -> str:
1328
+ """Render a :class:`Trigger` into its ``@`` clause (no leading ``@``).
1329
+
1330
+ Raises :class:`SteeringExprError` for a Trigger with no grammar form,
1331
+ rather than emitting a sentinel that would not parse back. Every public
1332
+ factory (:meth:`Trigger.first` / :meth:`Trigger.after` /
1333
+ :meth:`Trigger.when`, the five presets) and their gate-narrowed compounds
1334
+ round-trip, so this only fires on a hand-built dataclass.
1335
+ """
1336
+ gate = trig.gate
1337
+ if gate is None:
1338
+ name = _phase_name(trig)
1339
+ if name is None:
1340
+ raise SteeringExprError(
1341
+ f"trigger {trig!r} has no steering-expression form; it is "
1342
+ f"programmatic-only and cannot be rendered to a string"
1343
+ )
1344
+ return name
1345
+ gate_str = f"when:{gate.probe}{gate.op}{_fmt_number(gate.threshold)}"
1346
+ base = replace(trig, gate=None)
1347
+ # ``Trigger.when``'s own window is GENERATED_ONLY, so a bare gate renders
1348
+ # without a phase clause; any other window renders the compound form.
1349
+ if base == Trigger.GENERATED_ONLY:
1350
+ return gate_str
1351
+ phase = _phase_name(base)
1352
+ if phase is None:
1353
+ raise SteeringExprError(
1354
+ f"trigger {trig!r} has no steering-expression form; it is "
1355
+ f"programmatic-only and cannot be rendered to a string"
1356
+ )
1357
+ return f"{phase}&{gate_str}"
1358
+
1359
+
1360
+ def _fmt_number(x: float) -> str:
1361
+ """Render a probe threshold compactly while staying parseable.
1362
+
1363
+ The grammar accepts a leading ``-`` before NUM, so negative
1364
+ thresholds render with the minus sign in-line. Uses ``%g`` so
1365
+ integer-valued thresholds drop the trailing ``.0`` and small
1366
+ fractions render at full precision without scientific notation.
1367
+ """
1368
+ if x < 0:
1369
+ return f"-{abs(x):g}"
1370
+ return f"{x:g}"
1371
+
1372
+
1373
+ def referenced_selectors(
1374
+ text: str,
1375
+ ) -> list[tuple[Optional[str], str, str]]:
1376
+ """Return every **concept atom** ``(namespace, concept, variant)`` in ``text``.
1377
+
1378
+ Walks the AST before pole resolution so namespace prefixes survive —
1379
+ useful at install time, when the CLI needs to know which pack to fetch
1380
+ for each atom. Projection terms contribute two entries (base + onto).
1381
+
1382
+ Concept atoms *only*: a ``%`` manifold term names an artifact, not a
1383
+ concept, and is skipped. A caller preflighting artifacts (rather than
1384
+ concepts) — deciding what to fetch or register before a generation — has
1385
+ to handle manifold terms itself by walking ``parse_expr(text).alphas``
1386
+ for :class:`ManifoldTerm` values.
1387
+ """
1388
+ if not text or not text.strip():
1389
+ return []
1390
+ toks = _lex(text)
1391
+ terms = _Parser(toks).parse()
1392
+ out: list[tuple[Optional[str], str, str]] = []
1393
+ for term in terms:
1394
+ sel = term.selector
1395
+ if sel.manifold_position is not None:
1396
+ continue
1397
+ out.append((sel.base.namespace, sel.base.concept, sel.base.variant))
1398
+ if sel.onto is not None:
1399
+ out.append((sel.onto.namespace, sel.onto.concept, sel.onto.variant))
1400
+ return out
1401
+
1402
+
1403
+ __all__ = [
1404
+ "DEFAULT_COEFF",
1405
+ "DEFAULT_ABLATION_COEFF",
1406
+ "AblationTerm",
1407
+ "ManifoldTerm",
1408
+ "ProjectedTerm",
1409
+ "SteeringExprError",
1410
+ "parse_expr",
1411
+ "format_expr",
1412
+ "referenced_selectors",
1413
+ ]