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.
- drowse/__init__.py +312 -0
- drowse/__main__.py +5 -0
- drowse/cli/__init__.py +5 -0
- drowse/cli/alpha_grid.py +96 -0
- drowse/cli/config_file.py +340 -0
- drowse/cli/main.py +52 -0
- drowse/cli/parsers.py +1478 -0
- drowse/cli/runners/__init__.py +155 -0
- drowse/cli/runners/config.py +85 -0
- drowse/cli/runners/experiment.py +344 -0
- drowse/cli/runners/lens.py +661 -0
- drowse/cli/runners/manifold.py +1097 -0
- drowse/cli/runners/pack.py +413 -0
- drowse/cli/runners/sae.py +304 -0
- drowse/cli/runners/serve.py +220 -0
- drowse/cli/runners/shared.py +389 -0
- drowse/cli/runners/template.py +232 -0
- drowse/core/__init__.py +1 -0
- drowse/core/capture.py +1205 -0
- drowse/core/errors.py +260 -0
- drowse/core/events.py +156 -0
- drowse/core/extraction.py +3076 -0
- drowse/core/generation.py +1738 -0
- drowse/core/generation_finalizer.py +278 -0
- drowse/core/histogram.py +30 -0
- drowse/core/hooks.py +1885 -0
- drowse/core/instruments/__init__.py +49 -0
- drowse/core/instruments/geometry.py +551 -0
- drowse/core/instruments/lens.py +1341 -0
- drowse/core/instruments/protocol.py +211 -0
- drowse/core/instruments/sae.py +935 -0
- drowse/core/instruments/types.py +597 -0
- drowse/core/jlens.py +874 -0
- drowse/core/jlens_fit.py +1305 -0
- drowse/core/joint_logprobs.py +748 -0
- drowse/core/loom.py +1938 -0
- drowse/core/loom_diff.py +408 -0
- drowse/core/mahalanobis.py +579 -0
- drowse/core/manifold.py +4106 -0
- drowse/core/measurements.py +382 -0
- drowse/core/model.py +1724 -0
- drowse/core/monitor.py +2060 -0
- drowse/core/monitor_attach.py +682 -0
- drowse/core/naming.py +42 -0
- drowse/core/naturalness.py +187 -0
- drowse/core/profile.py +617 -0
- drowse/core/relp.py +313 -0
- drowse/core/results.py +467 -0
- drowse/core/role_templates.py +677 -0
- drowse/core/sae.py +891 -0
- drowse/core/sae_training.py +239 -0
- drowse/core/sampling.py +127 -0
- drowse/core/scene.py +810 -0
- drowse/core/scoring.py +270 -0
- drowse/core/session.py +11015 -0
- drowse/core/static_cache.py +316 -0
- drowse/core/steering.py +229 -0
- drowse/core/steering_composer.py +1135 -0
- drowse/core/steering_expr.py +1413 -0
- drowse/core/surface_topology.py +128 -0
- drowse/core/token_callback.py +52 -0
- drowse/core/token_payloads.py +244 -0
- drowse/core/topology.py +1469 -0
- drowse/core/transcript.py +582 -0
- drowse/core/tree_filter.py +353 -0
- drowse/core/triggers.py +250 -0
- drowse/data/baseline_prompts.json +50 -0
- drowse/data/manifolds/confident.uncertain/manifold.json +28 -0
- drowse/data/manifolds/confident.uncertain/nodes/00_confident.json +50 -0
- drowse/data/manifolds/confident.uncertain/nodes/01_uncertain.json +50 -0
- drowse/data/manifolds/creative.conventional/manifold.json +28 -0
- drowse/data/manifolds/creative.conventional/nodes/00_creative.json +50 -0
- drowse/data/manifolds/creative.conventional/nodes/01_conventional.json +50 -0
- drowse/data/manifolds/curious.disinterested/manifold.json +28 -0
- drowse/data/manifolds/curious.disinterested/nodes/00_curious.json +50 -0
- drowse/data/manifolds/curious.disinterested/nodes/01_disinterested.json +50 -0
- drowse/data/manifolds/direct.indirect/manifold.json +28 -0
- drowse/data/manifolds/direct.indirect/nodes/00_direct.json +50 -0
- drowse/data/manifolds/direct.indirect/nodes/01_indirect.json +50 -0
- drowse/data/manifolds/emotions/manifold.json +115 -0
- drowse/data/manifolds/emotions/nodes/00_excited.json +50 -0
- drowse/data/manifolds/emotions/nodes/01_happy.json +50 -0
- drowse/data/manifolds/emotions/nodes/02_calm.json +50 -0
- drowse/data/manifolds/emotions/nodes/03_weary.json +50 -0
- drowse/data/manifolds/emotions/nodes/04_sad.json +50 -0
- drowse/data/manifolds/emotions/nodes/05_distressed.json +50 -0
- drowse/data/manifolds/emotions/nodes/06_alert.json +50 -0
- drowse/data/manifolds/emotions/nodes/07_dominant.json +50 -0
- drowse/data/manifolds/emotions/nodes/08_submissive.json +50 -0
- drowse/data/manifolds/emotions/nodes/09_angry.json +50 -0
- drowse/data/manifolds/emotions/nodes/10_fearful.json +50 -0
- drowse/data/manifolds/emotions/nodes/11_surprised.json +50 -0
- drowse/data/manifolds/emotions/nodes/12_triumphant.json +50 -0
- drowse/data/manifolds/emotions/nodes/13_humiliated.json +50 -0
- drowse/data/manifolds/emotions/nodes/14_disgusted.json +50 -0
- drowse/data/manifolds/emotions/nodes/15_bored.json +50 -0
- drowse/data/manifolds/emotions/nodes/16_grateful.json +50 -0
- drowse/data/manifolds/emotions/nodes/17_relieved.json +50 -0
- drowse/data/manifolds/emotions/nodes/18_playful.json +50 -0
- drowse/data/manifolds/emotions/nodes/19_hopeful.json +50 -0
- drowse/data/manifolds/formal.casual/manifold.json +28 -0
- drowse/data/manifolds/formal.casual/nodes/00_formal.json +50 -0
- drowse/data/manifolds/formal.casual/nodes/01_casual.json +50 -0
- drowse/data/manifolds/honest.deceptive/manifold.json +28 -0
- drowse/data/manifolds/honest.deceptive/nodes/00_honest.json +50 -0
- drowse/data/manifolds/honest.deceptive/nodes/01_deceptive.json +50 -0
- drowse/data/manifolds/humorous.serious/manifold.json +28 -0
- drowse/data/manifolds/humorous.serious/nodes/00_humorous.json +50 -0
- drowse/data/manifolds/humorous.serious/nodes/01_serious.json +50 -0
- drowse/data/manifolds/individualist.collectivist/manifold.json +28 -0
- drowse/data/manifolds/individualist.collectivist/nodes/00_individualist.json +50 -0
- drowse/data/manifolds/individualist.collectivist/nodes/01_collectivist.json +50 -0
- drowse/data/manifolds/masculine.feminine/manifold.json +28 -0
- drowse/data/manifolds/masculine.feminine/nodes/00_masculine.json +50 -0
- drowse/data/manifolds/masculine.feminine/nodes/01_feminine.json +50 -0
- drowse/data/manifolds/months/manifold.json +120 -0
- drowse/data/manifolds/months/nodes/00_january.json +50 -0
- drowse/data/manifolds/months/nodes/01_february.json +50 -0
- drowse/data/manifolds/months/nodes/02_march.json +50 -0
- drowse/data/manifolds/months/nodes/03_april.json +50 -0
- drowse/data/manifolds/months/nodes/04_may.json +50 -0
- drowse/data/manifolds/months/nodes/05_june.json +50 -0
- drowse/data/manifolds/months/nodes/06_july.json +50 -0
- drowse/data/manifolds/months/nodes/07_august.json +50 -0
- drowse/data/manifolds/months/nodes/08_september.json +50 -0
- drowse/data/manifolds/months/nodes/09_october.json +50 -0
- drowse/data/manifolds/months/nodes/10_november.json +50 -0
- drowse/data/manifolds/months/nodes/11_december.json +50 -0
- drowse/data/manifolds/personas/manifold.json +550 -0
- drowse/data/manifolds/personas/nodes/00_assistant.json +50 -0
- drowse/data/manifolds/personas/nodes/01_analyst.json +50 -0
- drowse/data/manifolds/personas/nodes/02_impostor.json +50 -0
- drowse/data/manifolds/personas/nodes/03_teacher.json +50 -0
- drowse/data/manifolds/personas/nodes/04_doctor.json +50 -0
- drowse/data/manifolds/personas/nodes/05_librarian.json +50 -0
- drowse/data/manifolds/personas/nodes/06_farmer.json +50 -0
- drowse/data/manifolds/personas/nodes/07_soldier.json +50 -0
- drowse/data/manifolds/personas/nodes/08_lawyer.json +50 -0
- drowse/data/manifolds/personas/nodes/09_chef.json +50 -0
- drowse/data/manifolds/personas/nodes/100_assassin.json +50 -0
- drowse/data/manifolds/personas/nodes/101_thief.json +50 -0
- drowse/data/manifolds/personas/nodes/102_conman.json +50 -0
- drowse/data/manifolds/personas/nodes/103_hacker.json +50 -0
- drowse/data/manifolds/personas/nodes/104_cultist.json +50 -0
- drowse/data/manifolds/personas/nodes/105_tyrant.json +50 -0
- drowse/data/manifolds/personas/nodes/106_vandal.json +50 -0
- drowse/data/manifolds/personas/nodes/10_journalist.json +50 -0
- drowse/data/manifolds/personas/nodes/11_mechanic.json +50 -0
- drowse/data/manifolds/personas/nodes/12_sailor.json +50 -0
- drowse/data/manifolds/personas/nodes/13_pilot.json +50 -0
- drowse/data/manifolds/personas/nodes/14_athlete.json +50 -0
- drowse/data/manifolds/personas/nodes/15_engineer.json +50 -0
- drowse/data/manifolds/personas/nodes/16_scientist.json +50 -0
- drowse/data/manifolds/personas/nodes/17_banker.json +50 -0
- drowse/data/manifolds/personas/nodes/18_salesperson.json +50 -0
- drowse/data/manifolds/personas/nodes/19_nerd.json +50 -0
- drowse/data/manifolds/personas/nodes/20_jock.json +50 -0
- drowse/data/manifolds/personas/nodes/21_gamer.json +50 -0
- drowse/data/manifolds/personas/nodes/22_furry.json +50 -0
- drowse/data/manifolds/personas/nodes/23_weeaboo.json +50 -0
- drowse/data/manifolds/personas/nodes/24_influencer.json +50 -0
- drowse/data/manifolds/personas/nodes/25_stoner.json +50 -0
- drowse/data/manifolds/personas/nodes/26_femboy.json +50 -0
- drowse/data/manifolds/personas/nodes/27_ceo.json +50 -0
- drowse/data/manifolds/personas/nodes/28_emperor.json +50 -0
- drowse/data/manifolds/personas/nodes/29_president.json +50 -0
- drowse/data/manifolds/personas/nodes/30_diplomat.json +50 -0
- drowse/data/manifolds/personas/nodes/31_judge.json +50 -0
- drowse/data/manifolds/personas/nodes/32_bureaucrat.json +50 -0
- drowse/data/manifolds/personas/nodes/33_conservative.json +50 -0
- drowse/data/manifolds/personas/nodes/34_liberal.json +50 -0
- drowse/data/manifolds/personas/nodes/35_libertarian.json +50 -0
- drowse/data/manifolds/personas/nodes/36_communist.json +50 -0
- drowse/data/manifolds/personas/nodes/37_anarchist.json +50 -0
- drowse/data/manifolds/personas/nodes/38_reactionary.json +50 -0
- drowse/data/manifolds/personas/nodes/39_loner.json +50 -0
- drowse/data/manifolds/personas/nodes/40_friend.json +50 -0
- drowse/data/manifolds/personas/nodes/41_rival.json +50 -0
- drowse/data/manifolds/personas/nodes/42_stranger.json +50 -0
- drowse/data/manifolds/personas/nodes/43_lover.json +50 -0
- drowse/data/manifolds/personas/nodes/44_stalker.json +50 -0
- drowse/data/manifolds/personas/nodes/45_lunatic.json +50 -0
- drowse/data/manifolds/personas/nodes/46_paranoid.json +50 -0
- drowse/data/manifolds/personas/nodes/47_detective.json +50 -0
- drowse/data/manifolds/personas/nodes/48_therapist.json +50 -0
- drowse/data/manifolds/personas/nodes/49_nomad.json +50 -0
- drowse/data/manifolds/personas/nodes/50_pirate.json +50 -0
- drowse/data/manifolds/personas/nodes/51_child.json +50 -0
- drowse/data/manifolds/personas/nodes/52_caveman.json +50 -0
- drowse/data/manifolds/personas/nodes/53_monk.json +50 -0
- drowse/data/manifolds/personas/nodes/54_knight.json +50 -0
- drowse/data/manifolds/personas/nodes/55_alchemist.json +50 -0
- drowse/data/manifolds/personas/nodes/56_blacksmith.json +50 -0
- drowse/data/manifolds/personas/nodes/57_viking.json +50 -0
- drowse/data/manifolds/personas/nodes/58_druid.json +50 -0
- drowse/data/manifolds/personas/nodes/59_poet.json +50 -0
- drowse/data/manifolds/personas/nodes/60_novelist.json +50 -0
- drowse/data/manifolds/personas/nodes/61_jester.json +50 -0
- drowse/data/manifolds/personas/nodes/62_philosopher.json +50 -0
- drowse/data/manifolds/personas/nodes/63_painter.json +50 -0
- drowse/data/manifolds/personas/nodes/64_musician.json +50 -0
- drowse/data/manifolds/personas/nodes/65_oracle.json +50 -0
- drowse/data/manifolds/personas/nodes/66_god.json +50 -0
- drowse/data/manifolds/personas/nodes/67_angel.json +50 -0
- drowse/data/manifolds/personas/nodes/68_prophet.json +50 -0
- drowse/data/manifolds/personas/nodes/69_saint.json +50 -0
- drowse/data/manifolds/personas/nodes/70_ghost.json +50 -0
- drowse/data/manifolds/personas/nodes/71_phoenix.json +50 -0
- drowse/data/manifolds/personas/nodes/72_witch.json +50 -0
- drowse/data/manifolds/personas/nodes/73_vampire.json +50 -0
- drowse/data/manifolds/personas/nodes/74_mermaid.json +50 -0
- drowse/data/manifolds/personas/nodes/75_sphinx.json +50 -0
- drowse/data/manifolds/personas/nodes/76_banshee.json +50 -0
- drowse/data/manifolds/personas/nodes/77_golem.json +50 -0
- drowse/data/manifolds/personas/nodes/78_deer.json +50 -0
- drowse/data/manifolds/personas/nodes/79_wolf.json +50 -0
- drowse/data/manifolds/personas/nodes/80_raven.json +50 -0
- drowse/data/manifolds/personas/nodes/81_serpent.json +50 -0
- drowse/data/manifolds/personas/nodes/82_lion.json +50 -0
- drowse/data/manifolds/personas/nodes/83_tree.json +50 -0
- drowse/data/manifolds/personas/nodes/84_river.json +50 -0
- drowse/data/manifolds/personas/nodes/85_storm.json +50 -0
- drowse/data/manifolds/personas/nodes/86_flame.json +50 -0
- drowse/data/manifolds/personas/nodes/87_mirror.json +50 -0
- drowse/data/manifolds/personas/nodes/88_clock.json +50 -0
- drowse/data/manifolds/personas/nodes/89_computer.json +50 -0
- drowse/data/manifolds/personas/nodes/90_robot.json +50 -0
- drowse/data/manifolds/personas/nodes/91_cyborg.json +50 -0
- drowse/data/manifolds/personas/nodes/92_drone.json +50 -0
- drowse/data/manifolds/personas/nodes/93_mecha.json +50 -0
- drowse/data/manifolds/personas/nodes/94_alien.json +50 -0
- drowse/data/manifolds/personas/nodes/95_trickster.json +50 -0
- drowse/data/manifolds/personas/nodes/96_virus.json +50 -0
- drowse/data/manifolds/personas/nodes/97_spy.json +50 -0
- drowse/data/manifolds/personas/nodes/98_narcissist.json +50 -0
- drowse/data/manifolds/personas/nodes/99_demon.json +50 -0
- drowse/data/manifolds/refusing.compliant/manifold.json +28 -0
- drowse/data/manifolds/refusing.compliant/nodes/00_refusing.json +50 -0
- drowse/data/manifolds/refusing.compliant/nodes/01_compliant.json +50 -0
- drowse/data/manifolds/religious.secular/manifold.json +28 -0
- drowse/data/manifolds/religious.secular/nodes/00_religious.json +50 -0
- drowse/data/manifolds/religious.secular/nodes/01_secular.json +50 -0
- drowse/data/manifolds/sincere.manipulative/manifold.json +28 -0
- drowse/data/manifolds/sincere.manipulative/nodes/00_sincere.json +50 -0
- drowse/data/manifolds/sincere.manipulative/nodes/01_manipulative.json +50 -0
- drowse/data/manifolds/sycophantic.blunt/manifold.json +28 -0
- drowse/data/manifolds/sycophantic.blunt/nodes/00_sycophantic.json +50 -0
- drowse/data/manifolds/sycophantic.blunt/nodes/01_blunt.json +50 -0
- drowse/data/manifolds/technical.accessible/manifold.json +28 -0
- drowse/data/manifolds/technical.accessible/nodes/00_technical.json +50 -0
- drowse/data/manifolds/technical.accessible/nodes/01_accessible.json +50 -0
- drowse/data/manifolds/traditional.progressive/manifold.json +28 -0
- drowse/data/manifolds/traditional.progressive/nodes/00_traditional.json +50 -0
- drowse/data/manifolds/traditional.progressive/nodes/01_progressive.json +50 -0
- drowse/data/manifolds/verbose.concise/manifold.json +28 -0
- drowse/data/manifolds/verbose.concise/nodes/00_verbose.json +50 -0
- drowse/data/manifolds/verbose.concise/nodes/01_concise.json +50 -0
- drowse/data/manifolds/warm.clinical/manifold.json +28 -0
- drowse/data/manifolds/warm.clinical/nodes/00_warm.json +50 -0
- drowse/data/manifolds/warm.clinical/nodes/01_clinical.json +50 -0
- drowse/data/neutral_statements.json +98 -0
- drowse/io/__init__.py +1 -0
- drowse/io/alignment.py +1334 -0
- drowse/io/atomic.py +278 -0
- drowse/io/bake.py +558 -0
- drowse/io/bootstrap.py +73 -0
- drowse/io/brand_migration.py +48 -0
- drowse/io/drowse_archive.py +1830 -0
- drowse/io/gguf_io.py +300 -0
- drowse/io/hf.py +81 -0
- drowse/io/hf_manifolds.py +931 -0
- drowse/io/integrity.py +102 -0
- drowse/io/lens.py +1992 -0
- drowse/io/lens_sources.py +1003 -0
- drowse/io/manifold_authoring.py +1348 -0
- drowse/io/manifold_folder.py +1854 -0
- drowse/io/manifold_lifecycle.py +1253 -0
- drowse/io/manifold_tensors.py +727 -0
- drowse/io/manifolds.py +443 -0
- drowse/io/paths.py +289 -0
- drowse/io/probes_bootstrap.py +58 -0
- drowse/io/sae.py +382 -0
- drowse/io/sae_artifacts.py +318 -0
- drowse/io/selectors.py +503 -0
- drowse/io/shards.py +160 -0
- drowse/io/source_registry.py +138 -0
- drowse/io/staging.py +80 -0
- drowse/io/templates.py +707 -0
- drowse/notebook/__init__.py +38 -0
- drowse/notebook/data.py +99 -0
- drowse/notebook/plots.py +352 -0
- drowse/py.typed +0 -0
- drowse/server/__init__.py +20 -0
- drowse/server/app.py +987 -0
- drowse/server/background_job.py +246 -0
- drowse/server/instrument_routes.py +1101 -0
- drowse/server/manifold_routes.py +1028 -0
- drowse/server/model_names.py +82 -0
- drowse/server/native_common.py +92 -0
- drowse/server/native_routes.py +45 -0
- drowse/server/ollama.py +817 -0
- drowse/server/operation_ledger.py +187 -0
- drowse/server/probe_routes.py +220 -0
- drowse/server/profile_models.py +52 -0
- drowse/server/profile_routes.py +440 -0
- drowse/server/request_helpers.py +198 -0
- drowse/server/request_ledger.py +85 -0
- drowse/server/response_models.py +814 -0
- drowse/server/session_models.py +146 -0
- drowse/server/session_routes.py +150 -0
- drowse/server/sse.py +333 -0
- drowse/server/streaming.py +129 -0
- drowse/server/template_routes.py +161 -0
- drowse/server/tree_models.py +121 -0
- drowse/server/tree_routes.py +550 -0
- drowse/server/ws_events.py +65 -0
- drowse/server/ws_models.py +219 -0
- drowse/server/ws_stream.py +1205 -0
- drowse/web/__init__.py +22 -0
- drowse/web/dist/LICENSE-Fluent-Icons.txt +21 -0
- drowse/web/dist/LICENSE-Fluent-System-Icons.txt +21 -0
- drowse/web/dist/LICENSE-Martian-Mono.txt +93 -0
- drowse/web/dist/LICENSE-Torph.txt +21 -0
- drowse/web/dist/LICENSE-Wix-Madefor.txt +93 -0
- drowse/web/dist/assets/App-BewwoFwv.js +33 -0
- drowse/web/dist/assets/App.css +1 -0
- drowse/web/dist/assets/MartianMono-cyrillic-ext.woff2 +0 -0
- drowse/web/dist/assets/MartianMono-cyrillic.woff2 +0 -0
- drowse/web/dist/assets/MartianMono-latin-ext.woff2 +0 -0
- drowse/web/dist/assets/MartianMono-latin.woff2 +0 -0
- drowse/web/dist/assets/WixMadeforDisplay-cyrillic.woff2 +0 -0
- drowse/web/dist/assets/WixMadeforDisplay-latin-ext.woff2 +0 -0
- drowse/web/dist/assets/WixMadeforDisplay-latin.woff2 +0 -0
- drowse/web/dist/assets/WixMadeforDisplay-vietnamese.woff2 +0 -0
- drowse/web/dist/assets/WixMadeforText-italic-latin-ext.woff2 +0 -0
- drowse/web/dist/assets/WixMadeforText-italic-latin.woff2 +0 -0
- drowse/web/dist/assets/WixMadeforText-normal-cyrillic.woff2 +0 -0
- drowse/web/dist/assets/WixMadeforText-normal-latin-ext.woff2 +0 -0
- drowse/web/dist/assets/WixMadeforText-normal-latin.woff2 +0 -0
- drowse/web/dist/assets/WixMadeforText-normal-vietnamese.woff2 +0 -0
- drowse/web/dist/assets/ab.svelte-CbVGAYXo.js +1 -0
- drowse/web/dist/assets/artifactUpdates-Cjeu6LJc.js +1 -0
- drowse/web/dist/assets/artifactUpdates-DfAoYC9j.js +1 -0
- drowse/web/dist/assets/chat.svelte-DxKufn9g.js +1 -0
- drowse/web/dist/assets/drawers-BDWC0hIN.js +123 -0
- drowse/web/dist/assets/drawers.css +1 -0
- drowse/web/dist/assets/drowse.js +7 -0
- drowse/web/dist/assets/eleutherai.png +0 -0
- drowse/web/dist/assets/errors-Dvb10QW_.js +2 -0
- drowse/web/dist/assets/expression-4yISdAdq.js +1 -0
- drowse/web/dist/assets/files-CvRivkey.js +1 -0
- drowse/web/dist/assets/files-JhDJVgD_.js +1 -0
- drowse/web/dist/assets/fittingCancellation-D72BZWPZ.js +1 -0
- drowse/web/dist/assets/gemma-3-1b-it.json +1 -0
- drowse/web/dist/assets/gemma-3-270m-it.json +1 -0
- drowse/web/dist/assets/gemma-3-4b-it.json +1 -0
- drowse/web/dist/assets/generation-DbkBAhP_.js +1 -0
- drowse/web/dist/assets/index-client-2OdH6IQp.js +3 -0
- drowse/web/dist/assets/index-client-D4S4PooY.js +1 -0
- drowse/web/dist/assets/index.css +1 -0
- drowse/web/dist/assets/instrumentAuthoring.svelte-Csh7NOGX.js +1 -0
- drowse/web/dist/assets/instrumentAuthoring.svelte-w9YPcDsP.js +1 -0
- drowse/web/dist/assets/instruments.svelte-XnEUQA6B.js +1 -0
- drowse/web/dist/assets/localData-DIBDM_zo.js +1 -0
- drowse/web/dist/assets/loom.svelte-D_YyqHHK.js +1 -0
- drowse/web/dist/assets/manifoldJobs.svelte-9f5hs_J7.js +1 -0
- drowse/web/dist/assets/manifoldJobs.svelte-Bwo2GYOH.js +1 -0
- drowse/web/dist/assets/openai.png +0 -0
- drowse/web/dist/assets/preload-helper-BLdHbfdN.js +1 -0
- drowse/web/dist/assets/probes.svelte-COcN1Rh8.js +1 -0
- drowse/web/dist/assets/registry-B0_pJoMg.js +1 -0
- drowse/web/dist/assets/registry-CQv71XNh.js +1 -0
- drowse/web/dist/assets/sampling.svelte-BU0kED3k.js +1 -0
- drowse/web/dist/assets/samplingCapabilities-DM6eoDoc.js +1 -0
- drowse/web/dist/assets/savedConversations.svelte-BsBLc-p7.js +1 -0
- drowse/web/dist/assets/savedConversations.svelte-TuSes9Kg.js +1 -0
- drowse/web/dist/assets/selectors-BxXnPPN_.js +1 -0
- drowse/web/dist/assets/serviceTools-CG0q1Xqg.js +2 -0
- drowse/web/dist/assets/session.svelte-D2STLuP6.js +1 -0
- drowse/web/dist/assets/steering.svelte-DvFT3O-d.js +1 -0
- drowse/web/dist/assets/steeringPositions-Dr0JOFu7.js +1 -0
- drowse/web/dist/assets/templates-Bkq2x5ID.js +1 -0
- drowse/web/dist/assets/types-CuMUbvHW.js +1 -0
- drowse/web/dist/assets/validation-5wgTuS7k.js +1 -0
- drowse/web/dist/assets/webmcp-DyqJf4z6.js +2 -0
- drowse/web/dist/assets/workspaceController-C2L33e3m.js +1 -0
- drowse/web/dist/assets/workspaceController-DJhXD_BC.js +1 -0
- drowse/web/dist/assets/workspaceTools-BWdmXopx.js +2 -0
- drowse/web/dist/favicon.ico +0 -0
- drowse/web/dist/favicon.svg +1 -0
- drowse/web/dist/icons/apple-touch-icon.png +0 -0
- drowse/web/dist/icons/drowse-192.png +0 -0
- drowse/web/dist/icons/drowse-512.png +0 -0
- drowse/web/dist/icons/drowse-maskable-512.png +0 -0
- drowse/web/dist/icons/tab-analyzing-0.png +0 -0
- drowse/web/dist/icons/tab-analyzing-1.png +0 -0
- drowse/web/dist/icons/tab-analyzing-2.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-0.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-1.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-10.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-11.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-12.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-13.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-14.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-15.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-16.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-17.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-18.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-19.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-2.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-20.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-21.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-22.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-23.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-24.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-25.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-26.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-27.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-28.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-29.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-3.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-30.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-31.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-32.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-33.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-34.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-35.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-36.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-37.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-38.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-39.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-4.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-40.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-41.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-42.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-43.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-44.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-45.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-46.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-47.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-5.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-6.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-7.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-8.png +0 -0
- drowse/web/dist/icons/tab-analyzing-dark-9.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-0.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-1.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-10.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-11.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-12.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-13.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-14.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-15.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-16.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-17.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-18.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-19.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-2.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-20.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-21.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-22.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-23.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-24.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-25.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-26.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-27.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-28.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-29.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-3.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-30.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-31.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-32.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-33.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-34.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-35.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-36.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-37.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-38.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-39.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-4.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-40.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-41.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-42.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-43.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-44.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-45.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-46.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-47.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-5.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-6.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-7.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-8.png +0 -0
- drowse/web/dist/icons/tab-analyzing-light-9.png +0 -0
- drowse/web/dist/icons/tab-chat-settings-dark.png +0 -0
- drowse/web/dist/icons/tab-chat-settings-light.png +0 -0
- drowse/web/dist/icons/tab-chat-settings.png +0 -0
- drowse/web/dist/icons/tab-chats-dark.png +0 -0
- drowse/web/dist/icons/tab-chats-light.png +0 -0
- drowse/web/dist/icons/tab-chats.png +0 -0
- drowse/web/dist/icons/tab-checking-0.png +0 -0
- drowse/web/dist/icons/tab-checking-1.png +0 -0
- drowse/web/dist/icons/tab-checking-2.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-0.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-1.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-10.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-11.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-12.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-13.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-14.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-15.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-16.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-17.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-18.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-19.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-2.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-20.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-21.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-22.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-23.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-24.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-25.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-26.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-27.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-28.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-29.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-3.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-30.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-31.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-32.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-33.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-34.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-35.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-36.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-37.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-38.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-39.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-4.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-40.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-41.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-42.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-43.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-44.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-45.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-46.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-47.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-5.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-6.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-7.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-8.png +0 -0
- drowse/web/dist/icons/tab-checking-dark-9.png +0 -0
- drowse/web/dist/icons/tab-checking-light-0.png +0 -0
- drowse/web/dist/icons/tab-checking-light-1.png +0 -0
- drowse/web/dist/icons/tab-checking-light-10.png +0 -0
- drowse/web/dist/icons/tab-checking-light-11.png +0 -0
- drowse/web/dist/icons/tab-checking-light-12.png +0 -0
- drowse/web/dist/icons/tab-checking-light-13.png +0 -0
- drowse/web/dist/icons/tab-checking-light-14.png +0 -0
- drowse/web/dist/icons/tab-checking-light-15.png +0 -0
- drowse/web/dist/icons/tab-checking-light-16.png +0 -0
- drowse/web/dist/icons/tab-checking-light-17.png +0 -0
- drowse/web/dist/icons/tab-checking-light-18.png +0 -0
- drowse/web/dist/icons/tab-checking-light-19.png +0 -0
- drowse/web/dist/icons/tab-checking-light-2.png +0 -0
- drowse/web/dist/icons/tab-checking-light-20.png +0 -0
- drowse/web/dist/icons/tab-checking-light-21.png +0 -0
- drowse/web/dist/icons/tab-checking-light-22.png +0 -0
- drowse/web/dist/icons/tab-checking-light-23.png +0 -0
- drowse/web/dist/icons/tab-checking-light-24.png +0 -0
- drowse/web/dist/icons/tab-checking-light-25.png +0 -0
- drowse/web/dist/icons/tab-checking-light-26.png +0 -0
- drowse/web/dist/icons/tab-checking-light-27.png +0 -0
- drowse/web/dist/icons/tab-checking-light-28.png +0 -0
- drowse/web/dist/icons/tab-checking-light-29.png +0 -0
- drowse/web/dist/icons/tab-checking-light-3.png +0 -0
- drowse/web/dist/icons/tab-checking-light-30.png +0 -0
- drowse/web/dist/icons/tab-checking-light-31.png +0 -0
- drowse/web/dist/icons/tab-checking-light-32.png +0 -0
- drowse/web/dist/icons/tab-checking-light-33.png +0 -0
- drowse/web/dist/icons/tab-checking-light-34.png +0 -0
- drowse/web/dist/icons/tab-checking-light-35.png +0 -0
- drowse/web/dist/icons/tab-checking-light-36.png +0 -0
- drowse/web/dist/icons/tab-checking-light-37.png +0 -0
- drowse/web/dist/icons/tab-checking-light-38.png +0 -0
- drowse/web/dist/icons/tab-checking-light-39.png +0 -0
- drowse/web/dist/icons/tab-checking-light-4.png +0 -0
- drowse/web/dist/icons/tab-checking-light-40.png +0 -0
- drowse/web/dist/icons/tab-checking-light-41.png +0 -0
- drowse/web/dist/icons/tab-checking-light-42.png +0 -0
- drowse/web/dist/icons/tab-checking-light-43.png +0 -0
- drowse/web/dist/icons/tab-checking-light-44.png +0 -0
- drowse/web/dist/icons/tab-checking-light-45.png +0 -0
- drowse/web/dist/icons/tab-checking-light-46.png +0 -0
- drowse/web/dist/icons/tab-checking-light-47.png +0 -0
- drowse/web/dist/icons/tab-checking-light-5.png +0 -0
- drowse/web/dist/icons/tab-checking-light-6.png +0 -0
- drowse/web/dist/icons/tab-checking-light-7.png +0 -0
- drowse/web/dist/icons/tab-checking-light-8.png +0 -0
- drowse/web/dist/icons/tab-checking-light-9.png +0 -0
- drowse/web/dist/icons/tab-comparison-dark.png +0 -0
- drowse/web/dist/icons/tab-comparison-light.png +0 -0
- drowse/web/dist/icons/tab-comparison.png +0 -0
- drowse/web/dist/icons/tab-controls-dark.png +0 -0
- drowse/web/dist/icons/tab-controls-light.png +0 -0
- drowse/web/dist/icons/tab-controls.png +0 -0
- drowse/web/dist/icons/tab-conversation-dark.png +0 -0
- drowse/web/dist/icons/tab-conversation-light.png +0 -0
- drowse/web/dist/icons/tab-conversation.png +0 -0
- drowse/web/dist/icons/tab-credits-dark.png +0 -0
- drowse/web/dist/icons/tab-credits-light.png +0 -0
- drowse/web/dist/icons/tab-credits.png +0 -0
- drowse/web/dist/icons/tab-downloading-0.png +0 -0
- drowse/web/dist/icons/tab-downloading-1.png +0 -0
- drowse/web/dist/icons/tab-downloading-2.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-0.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-1.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-10.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-11.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-12.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-13.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-14.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-15.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-16.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-17.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-18.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-19.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-2.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-20.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-21.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-22.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-23.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-24.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-25.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-26.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-27.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-28.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-29.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-3.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-30.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-31.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-32.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-33.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-34.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-35.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-36.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-37.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-38.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-39.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-4.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-40.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-41.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-42.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-43.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-44.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-45.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-46.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-47.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-5.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-6.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-7.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-8.png +0 -0
- drowse/web/dist/icons/tab-downloading-dark-9.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-0.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-1.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-10.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-11.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-12.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-13.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-14.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-15.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-16.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-17.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-18.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-19.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-2.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-20.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-21.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-22.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-23.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-24.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-25.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-26.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-27.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-28.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-29.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-3.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-30.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-31.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-32.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-33.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-34.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-35.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-36.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-37.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-38.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-39.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-4.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-40.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-41.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-42.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-43.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-44.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-45.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-46.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-47.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-5.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-6.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-7.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-8.png +0 -0
- drowse/web/dist/icons/tab-downloading-light-9.png +0 -0
- drowse/web/dist/icons/tab-error-dark.png +0 -0
- drowse/web/dist/icons/tab-error-light.png +0 -0
- drowse/web/dist/icons/tab-error.png +0 -0
- drowse/web/dist/icons/tab-home-dark.png +0 -0
- drowse/web/dist/icons/tab-home-light.png +0 -0
- drowse/web/dist/icons/tab-home.png +0 -0
- drowse/web/dist/icons/tab-loading-0.png +0 -0
- drowse/web/dist/icons/tab-loading-1.png +0 -0
- drowse/web/dist/icons/tab-loading-2.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-0.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-1.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-10.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-11.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-12.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-13.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-14.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-15.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-16.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-17.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-18.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-19.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-2.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-20.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-21.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-22.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-23.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-24.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-25.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-26.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-27.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-28.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-29.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-3.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-30.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-31.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-32.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-33.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-34.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-35.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-36.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-37.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-38.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-39.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-4.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-40.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-41.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-42.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-43.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-44.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-45.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-46.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-47.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-5.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-6.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-7.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-8.png +0 -0
- drowse/web/dist/icons/tab-loading-dark-9.png +0 -0
- drowse/web/dist/icons/tab-loading-light-0.png +0 -0
- drowse/web/dist/icons/tab-loading-light-1.png +0 -0
- drowse/web/dist/icons/tab-loading-light-10.png +0 -0
- drowse/web/dist/icons/tab-loading-light-11.png +0 -0
- drowse/web/dist/icons/tab-loading-light-12.png +0 -0
- drowse/web/dist/icons/tab-loading-light-13.png +0 -0
- drowse/web/dist/icons/tab-loading-light-14.png +0 -0
- drowse/web/dist/icons/tab-loading-light-15.png +0 -0
- drowse/web/dist/icons/tab-loading-light-16.png +0 -0
- drowse/web/dist/icons/tab-loading-light-17.png +0 -0
- drowse/web/dist/icons/tab-loading-light-18.png +0 -0
- drowse/web/dist/icons/tab-loading-light-19.png +0 -0
- drowse/web/dist/icons/tab-loading-light-2.png +0 -0
- drowse/web/dist/icons/tab-loading-light-20.png +0 -0
- drowse/web/dist/icons/tab-loading-light-21.png +0 -0
- drowse/web/dist/icons/tab-loading-light-22.png +0 -0
- drowse/web/dist/icons/tab-loading-light-23.png +0 -0
- drowse/web/dist/icons/tab-loading-light-24.png +0 -0
- drowse/web/dist/icons/tab-loading-light-25.png +0 -0
- drowse/web/dist/icons/tab-loading-light-26.png +0 -0
- drowse/web/dist/icons/tab-loading-light-27.png +0 -0
- drowse/web/dist/icons/tab-loading-light-28.png +0 -0
- drowse/web/dist/icons/tab-loading-light-29.png +0 -0
- drowse/web/dist/icons/tab-loading-light-3.png +0 -0
- drowse/web/dist/icons/tab-loading-light-30.png +0 -0
- drowse/web/dist/icons/tab-loading-light-31.png +0 -0
- drowse/web/dist/icons/tab-loading-light-32.png +0 -0
- drowse/web/dist/icons/tab-loading-light-33.png +0 -0
- drowse/web/dist/icons/tab-loading-light-34.png +0 -0
- drowse/web/dist/icons/tab-loading-light-35.png +0 -0
- drowse/web/dist/icons/tab-loading-light-36.png +0 -0
- drowse/web/dist/icons/tab-loading-light-37.png +0 -0
- drowse/web/dist/icons/tab-loading-light-38.png +0 -0
- drowse/web/dist/icons/tab-loading-light-39.png +0 -0
- drowse/web/dist/icons/tab-loading-light-4.png +0 -0
- drowse/web/dist/icons/tab-loading-light-40.png +0 -0
- drowse/web/dist/icons/tab-loading-light-41.png +0 -0
- drowse/web/dist/icons/tab-loading-light-42.png +0 -0
- drowse/web/dist/icons/tab-loading-light-43.png +0 -0
- drowse/web/dist/icons/tab-loading-light-44.png +0 -0
- drowse/web/dist/icons/tab-loading-light-45.png +0 -0
- drowse/web/dist/icons/tab-loading-light-46.png +0 -0
- drowse/web/dist/icons/tab-loading-light-47.png +0 -0
- drowse/web/dist/icons/tab-loading-light-5.png +0 -0
- drowse/web/dist/icons/tab-loading-light-6.png +0 -0
- drowse/web/dist/icons/tab-loading-light-7.png +0 -0
- drowse/web/dist/icons/tab-loading-light-8.png +0 -0
- drowse/web/dist/icons/tab-loading-light-9.png +0 -0
- drowse/web/dist/icons/tab-loom-dark.png +0 -0
- drowse/web/dist/icons/tab-loom-light.png +0 -0
- drowse/web/dist/icons/tab-loom-working-0.png +0 -0
- drowse/web/dist/icons/tab-loom-working-1.png +0 -0
- drowse/web/dist/icons/tab-loom-working-2.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-0.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-1.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-10.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-11.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-12.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-13.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-14.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-15.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-16.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-17.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-18.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-19.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-2.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-20.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-21.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-22.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-23.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-24.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-25.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-26.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-27.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-28.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-29.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-3.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-30.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-31.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-32.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-33.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-34.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-35.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-36.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-37.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-38.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-39.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-4.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-40.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-41.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-42.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-43.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-44.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-45.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-46.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-47.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-5.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-6.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-7.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-8.png +0 -0
- drowse/web/dist/icons/tab-loom-working-dark-9.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-0.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-1.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-10.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-11.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-12.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-13.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-14.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-15.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-16.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-17.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-18.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-19.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-2.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-20.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-21.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-22.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-23.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-24.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-25.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-26.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-27.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-28.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-29.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-3.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-30.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-31.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-32.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-33.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-34.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-35.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-36.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-37.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-38.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-39.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-4.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-40.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-41.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-42.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-43.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-44.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-45.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-46.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-47.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-5.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-6.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-7.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-8.png +0 -0
- drowse/web/dist/icons/tab-loom-working-light-9.png +0 -0
- drowse/web/dist/icons/tab-loom.png +0 -0
- drowse/web/dist/icons/tab-models-dark.png +0 -0
- drowse/web/dist/icons/tab-models-light.png +0 -0
- drowse/web/dist/icons/tab-models.png +0 -0
- drowse/web/dist/icons/tab-offline-dark.png +0 -0
- drowse/web/dist/icons/tab-offline-light.png +0 -0
- drowse/web/dist/icons/tab-offline.png +0 -0
- drowse/web/dist/icons/tab-paused-dark.png +0 -0
- drowse/web/dist/icons/tab-paused-light.png +0 -0
- drowse/web/dist/icons/tab-paused.png +0 -0
- drowse/web/dist/icons/tab-ready-dark.png +0 -0
- drowse/web/dist/icons/tab-ready-light.png +0 -0
- drowse/web/dist/icons/tab-ready.png +0 -0
- drowse/web/dist/icons/tab-saving-0.png +0 -0
- drowse/web/dist/icons/tab-saving-1.png +0 -0
- drowse/web/dist/icons/tab-saving-2.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-0.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-1.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-10.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-11.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-12.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-13.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-14.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-15.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-16.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-17.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-18.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-19.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-2.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-20.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-21.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-22.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-23.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-24.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-25.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-26.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-27.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-28.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-29.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-3.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-30.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-31.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-32.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-33.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-34.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-35.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-36.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-37.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-38.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-39.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-4.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-40.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-41.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-42.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-43.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-44.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-45.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-46.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-47.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-5.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-6.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-7.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-8.png +0 -0
- drowse/web/dist/icons/tab-saving-dark-9.png +0 -0
- drowse/web/dist/icons/tab-saving-light-0.png +0 -0
- drowse/web/dist/icons/tab-saving-light-1.png +0 -0
- drowse/web/dist/icons/tab-saving-light-10.png +0 -0
- drowse/web/dist/icons/tab-saving-light-11.png +0 -0
- drowse/web/dist/icons/tab-saving-light-12.png +0 -0
- drowse/web/dist/icons/tab-saving-light-13.png +0 -0
- drowse/web/dist/icons/tab-saving-light-14.png +0 -0
- drowse/web/dist/icons/tab-saving-light-15.png +0 -0
- drowse/web/dist/icons/tab-saving-light-16.png +0 -0
- drowse/web/dist/icons/tab-saving-light-17.png +0 -0
- drowse/web/dist/icons/tab-saving-light-18.png +0 -0
- drowse/web/dist/icons/tab-saving-light-19.png +0 -0
- drowse/web/dist/icons/tab-saving-light-2.png +0 -0
- drowse/web/dist/icons/tab-saving-light-20.png +0 -0
- drowse/web/dist/icons/tab-saving-light-21.png +0 -0
- drowse/web/dist/icons/tab-saving-light-22.png +0 -0
- drowse/web/dist/icons/tab-saving-light-23.png +0 -0
- drowse/web/dist/icons/tab-saving-light-24.png +0 -0
- drowse/web/dist/icons/tab-saving-light-25.png +0 -0
- drowse/web/dist/icons/tab-saving-light-26.png +0 -0
- drowse/web/dist/icons/tab-saving-light-27.png +0 -0
- drowse/web/dist/icons/tab-saving-light-28.png +0 -0
- drowse/web/dist/icons/tab-saving-light-29.png +0 -0
- drowse/web/dist/icons/tab-saving-light-3.png +0 -0
- drowse/web/dist/icons/tab-saving-light-30.png +0 -0
- drowse/web/dist/icons/tab-saving-light-31.png +0 -0
- drowse/web/dist/icons/tab-saving-light-32.png +0 -0
- drowse/web/dist/icons/tab-saving-light-33.png +0 -0
- drowse/web/dist/icons/tab-saving-light-34.png +0 -0
- drowse/web/dist/icons/tab-saving-light-35.png +0 -0
- drowse/web/dist/icons/tab-saving-light-36.png +0 -0
- drowse/web/dist/icons/tab-saving-light-37.png +0 -0
- drowse/web/dist/icons/tab-saving-light-38.png +0 -0
- drowse/web/dist/icons/tab-saving-light-39.png +0 -0
- drowse/web/dist/icons/tab-saving-light-4.png +0 -0
- drowse/web/dist/icons/tab-saving-light-40.png +0 -0
- drowse/web/dist/icons/tab-saving-light-41.png +0 -0
- drowse/web/dist/icons/tab-saving-light-42.png +0 -0
- drowse/web/dist/icons/tab-saving-light-43.png +0 -0
- drowse/web/dist/icons/tab-saving-light-44.png +0 -0
- drowse/web/dist/icons/tab-saving-light-45.png +0 -0
- drowse/web/dist/icons/tab-saving-light-46.png +0 -0
- drowse/web/dist/icons/tab-saving-light-47.png +0 -0
- drowse/web/dist/icons/tab-saving-light-5.png +0 -0
- drowse/web/dist/icons/tab-saving-light-6.png +0 -0
- drowse/web/dist/icons/tab-saving-light-7.png +0 -0
- drowse/web/dist/icons/tab-saving-light-8.png +0 -0
- drowse/web/dist/icons/tab-saving-light-9.png +0 -0
- drowse/web/dist/icons/tab-thinking-0.png +0 -0
- drowse/web/dist/icons/tab-thinking-1.png +0 -0
- drowse/web/dist/icons/tab-thinking-2.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-0.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-1.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-10.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-11.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-12.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-13.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-14.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-15.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-16.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-17.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-18.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-19.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-2.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-20.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-21.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-22.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-23.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-24.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-25.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-26.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-27.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-28.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-29.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-3.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-30.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-31.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-32.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-33.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-34.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-35.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-36.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-37.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-38.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-39.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-4.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-40.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-41.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-42.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-43.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-44.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-45.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-46.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-47.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-5.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-6.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-7.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-8.png +0 -0
- drowse/web/dist/icons/tab-thinking-dark-9.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-0.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-1.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-10.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-11.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-12.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-13.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-14.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-15.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-16.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-17.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-18.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-19.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-2.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-20.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-21.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-22.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-23.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-24.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-25.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-26.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-27.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-28.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-29.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-3.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-30.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-31.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-32.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-33.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-34.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-35.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-36.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-37.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-38.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-39.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-4.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-40.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-41.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-42.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-43.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-44.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-45.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-46.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-47.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-5.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-6.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-7.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-8.png +0 -0
- drowse/web/dist/icons/tab-thinking-light-9.png +0 -0
- drowse/web/dist/icons/tab-tokens-dark.png +0 -0
- drowse/web/dist/icons/tab-tokens-light.png +0 -0
- drowse/web/dist/icons/tab-tokens.png +0 -0
- drowse/web/dist/icons/tab-training-0.png +0 -0
- drowse/web/dist/icons/tab-training-1.png +0 -0
- drowse/web/dist/icons/tab-training-2.png +0 -0
- drowse/web/dist/icons/tab-training-dark-0.png +0 -0
- drowse/web/dist/icons/tab-training-dark-1.png +0 -0
- drowse/web/dist/icons/tab-training-dark-10.png +0 -0
- drowse/web/dist/icons/tab-training-dark-11.png +0 -0
- drowse/web/dist/icons/tab-training-dark-12.png +0 -0
- drowse/web/dist/icons/tab-training-dark-13.png +0 -0
- drowse/web/dist/icons/tab-training-dark-14.png +0 -0
- drowse/web/dist/icons/tab-training-dark-15.png +0 -0
- drowse/web/dist/icons/tab-training-dark-16.png +0 -0
- drowse/web/dist/icons/tab-training-dark-17.png +0 -0
- drowse/web/dist/icons/tab-training-dark-18.png +0 -0
- drowse/web/dist/icons/tab-training-dark-19.png +0 -0
- drowse/web/dist/icons/tab-training-dark-2.png +0 -0
- drowse/web/dist/icons/tab-training-dark-20.png +0 -0
- drowse/web/dist/icons/tab-training-dark-21.png +0 -0
- drowse/web/dist/icons/tab-training-dark-22.png +0 -0
- drowse/web/dist/icons/tab-training-dark-23.png +0 -0
- drowse/web/dist/icons/tab-training-dark-24.png +0 -0
- drowse/web/dist/icons/tab-training-dark-25.png +0 -0
- drowse/web/dist/icons/tab-training-dark-26.png +0 -0
- drowse/web/dist/icons/tab-training-dark-27.png +0 -0
- drowse/web/dist/icons/tab-training-dark-28.png +0 -0
- drowse/web/dist/icons/tab-training-dark-29.png +0 -0
- drowse/web/dist/icons/tab-training-dark-3.png +0 -0
- drowse/web/dist/icons/tab-training-dark-30.png +0 -0
- drowse/web/dist/icons/tab-training-dark-31.png +0 -0
- drowse/web/dist/icons/tab-training-dark-32.png +0 -0
- drowse/web/dist/icons/tab-training-dark-33.png +0 -0
- drowse/web/dist/icons/tab-training-dark-34.png +0 -0
- drowse/web/dist/icons/tab-training-dark-35.png +0 -0
- drowse/web/dist/icons/tab-training-dark-36.png +0 -0
- drowse/web/dist/icons/tab-training-dark-37.png +0 -0
- drowse/web/dist/icons/tab-training-dark-38.png +0 -0
- drowse/web/dist/icons/tab-training-dark-39.png +0 -0
- drowse/web/dist/icons/tab-training-dark-4.png +0 -0
- drowse/web/dist/icons/tab-training-dark-40.png +0 -0
- drowse/web/dist/icons/tab-training-dark-41.png +0 -0
- drowse/web/dist/icons/tab-training-dark-42.png +0 -0
- drowse/web/dist/icons/tab-training-dark-43.png +0 -0
- drowse/web/dist/icons/tab-training-dark-44.png +0 -0
- drowse/web/dist/icons/tab-training-dark-45.png +0 -0
- drowse/web/dist/icons/tab-training-dark-46.png +0 -0
- drowse/web/dist/icons/tab-training-dark-47.png +0 -0
- drowse/web/dist/icons/tab-training-dark-5.png +0 -0
- drowse/web/dist/icons/tab-training-dark-6.png +0 -0
- drowse/web/dist/icons/tab-training-dark-7.png +0 -0
- drowse/web/dist/icons/tab-training-dark-8.png +0 -0
- drowse/web/dist/icons/tab-training-dark-9.png +0 -0
- drowse/web/dist/icons/tab-training-light-0.png +0 -0
- drowse/web/dist/icons/tab-training-light-1.png +0 -0
- drowse/web/dist/icons/tab-training-light-10.png +0 -0
- drowse/web/dist/icons/tab-training-light-11.png +0 -0
- drowse/web/dist/icons/tab-training-light-12.png +0 -0
- drowse/web/dist/icons/tab-training-light-13.png +0 -0
- drowse/web/dist/icons/tab-training-light-14.png +0 -0
- drowse/web/dist/icons/tab-training-light-15.png +0 -0
- drowse/web/dist/icons/tab-training-light-16.png +0 -0
- drowse/web/dist/icons/tab-training-light-17.png +0 -0
- drowse/web/dist/icons/tab-training-light-18.png +0 -0
- drowse/web/dist/icons/tab-training-light-19.png +0 -0
- drowse/web/dist/icons/tab-training-light-2.png +0 -0
- drowse/web/dist/icons/tab-training-light-20.png +0 -0
- drowse/web/dist/icons/tab-training-light-21.png +0 -0
- drowse/web/dist/icons/tab-training-light-22.png +0 -0
- drowse/web/dist/icons/tab-training-light-23.png +0 -0
- drowse/web/dist/icons/tab-training-light-24.png +0 -0
- drowse/web/dist/icons/tab-training-light-25.png +0 -0
- drowse/web/dist/icons/tab-training-light-26.png +0 -0
- drowse/web/dist/icons/tab-training-light-27.png +0 -0
- drowse/web/dist/icons/tab-training-light-28.png +0 -0
- drowse/web/dist/icons/tab-training-light-29.png +0 -0
- drowse/web/dist/icons/tab-training-light-3.png +0 -0
- drowse/web/dist/icons/tab-training-light-30.png +0 -0
- drowse/web/dist/icons/tab-training-light-31.png +0 -0
- drowse/web/dist/icons/tab-training-light-32.png +0 -0
- drowse/web/dist/icons/tab-training-light-33.png +0 -0
- drowse/web/dist/icons/tab-training-light-34.png +0 -0
- drowse/web/dist/icons/tab-training-light-35.png +0 -0
- drowse/web/dist/icons/tab-training-light-36.png +0 -0
- drowse/web/dist/icons/tab-training-light-37.png +0 -0
- drowse/web/dist/icons/tab-training-light-38.png +0 -0
- drowse/web/dist/icons/tab-training-light-39.png +0 -0
- drowse/web/dist/icons/tab-training-light-4.png +0 -0
- drowse/web/dist/icons/tab-training-light-40.png +0 -0
- drowse/web/dist/icons/tab-training-light-41.png +0 -0
- drowse/web/dist/icons/tab-training-light-42.png +0 -0
- drowse/web/dist/icons/tab-training-light-43.png +0 -0
- drowse/web/dist/icons/tab-training-light-44.png +0 -0
- drowse/web/dist/icons/tab-training-light-45.png +0 -0
- drowse/web/dist/icons/tab-training-light-46.png +0 -0
- drowse/web/dist/icons/tab-training-light-47.png +0 -0
- drowse/web/dist/icons/tab-training-light-5.png +0 -0
- drowse/web/dist/icons/tab-training-light-6.png +0 -0
- drowse/web/dist/icons/tab-training-light-7.png +0 -0
- drowse/web/dist/icons/tab-training-light-8.png +0 -0
- drowse/web/dist/icons/tab-training-light-9.png +0 -0
- drowse/web/dist/icons/tab-unsupported-dark.png +0 -0
- drowse/web/dist/icons/tab-unsupported-light.png +0 -0
- drowse/web/dist/icons/tab-unsupported.png +0 -0
- drowse/web/dist/icons/tab-working-0.png +0 -0
- drowse/web/dist/icons/tab-working-1.png +0 -0
- drowse/web/dist/icons/tab-working-2.png +0 -0
- drowse/web/dist/icons/tab-working-dark-0.png +0 -0
- drowse/web/dist/icons/tab-working-dark-1.png +0 -0
- drowse/web/dist/icons/tab-working-dark-10.png +0 -0
- drowse/web/dist/icons/tab-working-dark-11.png +0 -0
- drowse/web/dist/icons/tab-working-dark-12.png +0 -0
- drowse/web/dist/icons/tab-working-dark-13.png +0 -0
- drowse/web/dist/icons/tab-working-dark-14.png +0 -0
- drowse/web/dist/icons/tab-working-dark-15.png +0 -0
- drowse/web/dist/icons/tab-working-dark-16.png +0 -0
- drowse/web/dist/icons/tab-working-dark-17.png +0 -0
- drowse/web/dist/icons/tab-working-dark-18.png +0 -0
- drowse/web/dist/icons/tab-working-dark-19.png +0 -0
- drowse/web/dist/icons/tab-working-dark-2.png +0 -0
- drowse/web/dist/icons/tab-working-dark-20.png +0 -0
- drowse/web/dist/icons/tab-working-dark-21.png +0 -0
- drowse/web/dist/icons/tab-working-dark-22.png +0 -0
- drowse/web/dist/icons/tab-working-dark-23.png +0 -0
- drowse/web/dist/icons/tab-working-dark-24.png +0 -0
- drowse/web/dist/icons/tab-working-dark-25.png +0 -0
- drowse/web/dist/icons/tab-working-dark-26.png +0 -0
- drowse/web/dist/icons/tab-working-dark-27.png +0 -0
- drowse/web/dist/icons/tab-working-dark-28.png +0 -0
- drowse/web/dist/icons/tab-working-dark-29.png +0 -0
- drowse/web/dist/icons/tab-working-dark-3.png +0 -0
- drowse/web/dist/icons/tab-working-dark-30.png +0 -0
- drowse/web/dist/icons/tab-working-dark-31.png +0 -0
- drowse/web/dist/icons/tab-working-dark-32.png +0 -0
- drowse/web/dist/icons/tab-working-dark-33.png +0 -0
- drowse/web/dist/icons/tab-working-dark-34.png +0 -0
- drowse/web/dist/icons/tab-working-dark-35.png +0 -0
- drowse/web/dist/icons/tab-working-dark-36.png +0 -0
- drowse/web/dist/icons/tab-working-dark-37.png +0 -0
- drowse/web/dist/icons/tab-working-dark-38.png +0 -0
- drowse/web/dist/icons/tab-working-dark-39.png +0 -0
- drowse/web/dist/icons/tab-working-dark-4.png +0 -0
- drowse/web/dist/icons/tab-working-dark-40.png +0 -0
- drowse/web/dist/icons/tab-working-dark-41.png +0 -0
- drowse/web/dist/icons/tab-working-dark-42.png +0 -0
- drowse/web/dist/icons/tab-working-dark-43.png +0 -0
- drowse/web/dist/icons/tab-working-dark-44.png +0 -0
- drowse/web/dist/icons/tab-working-dark-45.png +0 -0
- drowse/web/dist/icons/tab-working-dark-46.png +0 -0
- drowse/web/dist/icons/tab-working-dark-47.png +0 -0
- drowse/web/dist/icons/tab-working-dark-5.png +0 -0
- drowse/web/dist/icons/tab-working-dark-6.png +0 -0
- drowse/web/dist/icons/tab-working-dark-7.png +0 -0
- drowse/web/dist/icons/tab-working-dark-8.png +0 -0
- drowse/web/dist/icons/tab-working-dark-9.png +0 -0
- drowse/web/dist/icons/tab-working-light-0.png +0 -0
- drowse/web/dist/icons/tab-working-light-1.png +0 -0
- drowse/web/dist/icons/tab-working-light-10.png +0 -0
- drowse/web/dist/icons/tab-working-light-11.png +0 -0
- drowse/web/dist/icons/tab-working-light-12.png +0 -0
- drowse/web/dist/icons/tab-working-light-13.png +0 -0
- drowse/web/dist/icons/tab-working-light-14.png +0 -0
- drowse/web/dist/icons/tab-working-light-15.png +0 -0
- drowse/web/dist/icons/tab-working-light-16.png +0 -0
- drowse/web/dist/icons/tab-working-light-17.png +0 -0
- drowse/web/dist/icons/tab-working-light-18.png +0 -0
- drowse/web/dist/icons/tab-working-light-19.png +0 -0
- drowse/web/dist/icons/tab-working-light-2.png +0 -0
- drowse/web/dist/icons/tab-working-light-20.png +0 -0
- drowse/web/dist/icons/tab-working-light-21.png +0 -0
- drowse/web/dist/icons/tab-working-light-22.png +0 -0
- drowse/web/dist/icons/tab-working-light-23.png +0 -0
- drowse/web/dist/icons/tab-working-light-24.png +0 -0
- drowse/web/dist/icons/tab-working-light-25.png +0 -0
- drowse/web/dist/icons/tab-working-light-26.png +0 -0
- drowse/web/dist/icons/tab-working-light-27.png +0 -0
- drowse/web/dist/icons/tab-working-light-28.png +0 -0
- drowse/web/dist/icons/tab-working-light-29.png +0 -0
- drowse/web/dist/icons/tab-working-light-3.png +0 -0
- drowse/web/dist/icons/tab-working-light-30.png +0 -0
- drowse/web/dist/icons/tab-working-light-31.png +0 -0
- drowse/web/dist/icons/tab-working-light-32.png +0 -0
- drowse/web/dist/icons/tab-working-light-33.png +0 -0
- drowse/web/dist/icons/tab-working-light-34.png +0 -0
- drowse/web/dist/icons/tab-working-light-35.png +0 -0
- drowse/web/dist/icons/tab-working-light-36.png +0 -0
- drowse/web/dist/icons/tab-working-light-37.png +0 -0
- drowse/web/dist/icons/tab-working-light-38.png +0 -0
- drowse/web/dist/icons/tab-working-light-39.png +0 -0
- drowse/web/dist/icons/tab-working-light-4.png +0 -0
- drowse/web/dist/icons/tab-working-light-40.png +0 -0
- drowse/web/dist/icons/tab-working-light-41.png +0 -0
- drowse/web/dist/icons/tab-working-light-42.png +0 -0
- drowse/web/dist/icons/tab-working-light-43.png +0 -0
- drowse/web/dist/icons/tab-working-light-44.png +0 -0
- drowse/web/dist/icons/tab-working-light-45.png +0 -0
- drowse/web/dist/icons/tab-working-light-46.png +0 -0
- drowse/web/dist/icons/tab-working-light-47.png +0 -0
- drowse/web/dist/icons/tab-working-light-5.png +0 -0
- drowse/web/dist/icons/tab-working-light-6.png +0 -0
- drowse/web/dist/icons/tab-working-light-7.png +0 -0
- drowse/web/dist/icons/tab-working-light-8.png +0 -0
- drowse/web/dist/icons/tab-working-light-9.png +0 -0
- drowse/web/dist/index.html +34 -0
- drowse/web/dist/social/drowse.png +0 -0
- drowse/web/dist/social/drowse.svg +6 -0
- drowse/web/dist/theme-init.js +25 -0
- drowse/web/routes.py +118 -0
- drowse_ai-5.3.1.dist-info/METADATA +632 -0
- drowse_ai-5.3.1.dist-info/RECORD +1341 -0
- drowse_ai-5.3.1.dist-info/WHEEL +5 -0
- drowse_ai-5.3.1.dist-info/entry_points.txt +2 -0
- drowse_ai-5.3.1.dist-info/licenses/LICENSE +661 -0
- 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
|
+
]
|