entari-plugin-hyw 3.2.104__tar.gz → 3.2.106__tar.gz

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.

Potentially problematic release.


This version of entari-plugin-hyw might be problematic. Click here for more details.

Files changed (54) hide show
  1. {entari_plugin_hyw-3.2.104/src/entari_plugin_hyw.egg-info → entari_plugin_hyw-3.2.106}/PKG-INFO +2 -1
  2. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/pyproject.toml +2 -1
  3. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/__init__.py +126 -7
  4. entari_plugin_hyw-3.2.106/src/entari_plugin_hyw/assets/libs/tailwind.css +1 -0
  5. entari_plugin_hyw-3.2.106/src/entari_plugin_hyw/assets/package-lock.json +953 -0
  6. entari_plugin_hyw-3.2.106/src/entari_plugin_hyw/assets/package.json +16 -0
  7. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/assets/tailwind.config.js +1 -1
  8. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/assets/tailwind.input.css +8 -8
  9. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/assets/template.html +39 -43
  10. entari_plugin_hyw-3.2.106/src/entari_plugin_hyw/assets/template.html.bak +157 -0
  11. entari_plugin_hyw-3.2.106/src/entari_plugin_hyw/assets/template.j2 +259 -0
  12. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/core/config.py +2 -4
  13. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/core/pipeline.py +192 -23
  14. entari_plugin_hyw-3.2.106/src/entari_plugin_hyw/core/render.py +477 -0
  15. entari_plugin_hyw-3.2.104/src/entari_plugin_hyw/core/render.py → entari_plugin_hyw-3.2.106/src/entari_plugin_hyw/core/render.py.bak +302 -189
  16. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/utils/prompts.py +6 -6
  17. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106/src/entari_plugin_hyw.egg-info}/PKG-INFO +2 -1
  18. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw.egg-info/SOURCES.txt +5 -0
  19. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw.egg-info/requires.txt +1 -0
  20. entari_plugin_hyw-3.2.104/src/entari_plugin_hyw/assets/libs/tailwind.css +0 -1
  21. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/MANIFEST.in +0 -0
  22. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/README.md +0 -0
  23. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/setup.cfg +0 -0
  24. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/assets/icon/anthropic.svg +0 -0
  25. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/assets/icon/deepseek.png +0 -0
  26. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/assets/icon/gemini.svg +0 -0
  27. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/assets/icon/google.svg +0 -0
  28. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/assets/icon/grok.png +0 -0
  29. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/assets/icon/microsoft.svg +0 -0
  30. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/assets/icon/minimax.png +0 -0
  31. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/assets/icon/mistral.png +0 -0
  32. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/assets/icon/nvida.png +0 -0
  33. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/assets/icon/openai.svg +0 -0
  34. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/assets/icon/openrouter.png +0 -0
  35. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/assets/icon/perplexity.svg +0 -0
  36. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/assets/icon/qwen.png +0 -0
  37. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/assets/icon/xai.png +0 -0
  38. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/assets/icon/zai.png +0 -0
  39. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/assets/libs/highlight.css +0 -0
  40. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/assets/libs/highlight.js +0 -0
  41. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/assets/libs/katex-auto-render.js +0 -0
  42. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/assets/libs/katex.css +0 -0
  43. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/assets/libs/katex.js +0 -0
  44. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/core/__init__.py +0 -0
  45. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/core/history.py +0 -0
  46. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/core/hyw.py +0 -0
  47. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/utils/__init__.py +0 -0
  48. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/utils/browser.py +0 -0
  49. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/utils/mcp_playwright.py +0 -0
  50. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/utils/misc.py +0 -0
  51. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/utils/playwright_tool.py +0 -0
  52. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw/utils/search.py +0 -0
  53. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw.egg-info/dependency_links.txt +0 -0
  54. {entari_plugin_hyw-3.2.104 → entari_plugin_hyw-3.2.106}/src/entari_plugin_hyw.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: entari_plugin_hyw
3
- Version: 3.2.104
3
+ Version: 3.2.106
4
4
  Summary: Use large language models to interpret chat messages
5
5
  Author-email: kumoSleeping <zjr2992@outlook.com>
6
6
  License: MIT
@@ -23,6 +23,7 @@ Requires-Dist: httpx
23
23
  Requires-Dist: markdown>=3.10
24
24
  Requires-Dist: trafilatura>=2.0.0
25
25
  Requires-Dist: playwright>=1.56.0
26
+ Requires-Dist: jinja2>=3.0
26
27
  Provides-Extra: playwright
27
28
  Requires-Dist: playwright>=1.56.0; extra == "playwright"
28
29
  Requires-Dist: trafilatura>=2.0.0; extra == "playwright"
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "entari_plugin_hyw"
7
- version = "3.2.104"
7
+ version = "3.2.106"
8
8
  description = "Use large language models to interpret chat messages"
9
9
  authors = [{name = "kumoSleeping", email = "zjr2992@outlook.com"}]
10
10
  dependencies = [
@@ -15,6 +15,7 @@ dependencies = [
15
15
  "markdown>=3.10",
16
16
  "trafilatura>=2.0.0",
17
17
  "playwright>=1.56.0",
18
+ "jinja2>=3.0",
18
19
  ]
19
20
  requires-python = ">=3.10"
20
21
  readme = "README.md"
@@ -1,5 +1,5 @@
1
1
  from dataclasses import dataclass, field
2
- from typing import List, Dict, Any, Optional
2
+ from typing import List, Dict, Any, Optional, Union
3
3
  import time
4
4
 
5
5
  from arclet.alconna import Alconna, Args, AllParam, CommandMeta, Option, Arparma, MultiVar, store_true
@@ -87,6 +87,15 @@ class HywConfig(BasicConfModel):
87
87
  # Instruct model pricing overrides (defaults to main model pricing if not set)
88
88
  intruct_input_price: Optional[float] = None
89
89
  intruct_output_price: Optional[float] = None
90
+
91
+ # Provider Names
92
+ search_name: str = "SearXNG"
93
+ search_provider: str = "SearXNG"
94
+ model_provider: Optional[str] = None
95
+ vision_model_provider: Optional[str] = None
96
+ intruct_model_provider: Optional[str] = None
97
+
98
+ start_test: Optional[Union[str, bool]] = None
90
99
 
91
100
  conf = plugin_config(HywConfig)
92
101
  history_manager = HistoryManager()
@@ -100,6 +109,93 @@ async def _hyw_warmup_mcp():
100
109
  except Exception as e:
101
110
  logger.warning(f"MCP Playwright warmup error: {e}")
102
111
 
112
+ @listen(Ready, once=True)
113
+ async def _run_ui_test():
114
+ """Run UI rendering test on startup if configured."""
115
+ # Debug log to confirm listener is active
116
+ logger.info(f"UI TEST Listener Active. start_test config: {conf.start_test} (type: {type(conf.start_test)})")
117
+
118
+ if not conf.start_test:
119
+ return
120
+
121
+ test_file = ""
122
+ if isinstance(conf.start_test, str):
123
+ test_file = conf.start_test
124
+ elif conf.start_test is True:
125
+ # User enabled boolean toggle, assume default path
126
+ # Try a few locations
127
+ candidates = ["data/conversations/ui-test.md", "ui-test.md", "README.md"]
128
+ for c in candidates:
129
+ if os.path.exists(c):
130
+ test_file = c
131
+ break
132
+ if not test_file:
133
+ logger.warning("UI TEST: start_test=True but no default test file found (tried: data/conversations/ui-test.md, ui-test.md, README.md)")
134
+ return
135
+
136
+ logger.info(f"UI TEST: Starting render test with file {test_file}")
137
+
138
+ if not os.path.exists(test_file):
139
+ logger.error(f"UI TEST: File not found: {test_file}")
140
+ return
141
+
142
+ try:
143
+ with open(test_file, "r", encoding="utf-8") as f:
144
+ content = f.read()
145
+
146
+ # Mock Data for Full UI Test
147
+ stats = {
148
+ "time": 12.5,
149
+ "vision_duration": 3.2,
150
+ "cost": 0.0015
151
+ }
152
+
153
+ stages = [
154
+ {"name": "Vision", "model": "google/gemini-pro-vision", "time": 3.2, "cost": 0.0005, "provider": "Google"},
155
+ {"name": "Search", "model": "duckduckgo", "time": 1.5, "cost": 0.0, "provider": "DDG"},
156
+ {"name": "Agent", "model": "anthropic/claude-3-5-sonnet", "time": 7.8, "cost": 0.0010, "provider": "Anthropic"}
157
+ ]
158
+
159
+ mcp_steps = [
160
+ {"name": "search_google", "description": "searching for 'latest entari news'", "icon": "search"},
161
+ {"name": "visit_page", "description": "visiting python.org", "icon": "navigate"},
162
+ {"name": "click_element", "description": "clicking 'Downloads'", "icon": "click"}
163
+ ]
164
+
165
+ references = [
166
+ {"title": "Entari Docs", "url": "https://entari.onebot.dev", "domain": "entari.onebot.dev"},
167
+ {"title": "Python Language", "url": "https://python.org", "domain": "python.org"}
168
+ ]
169
+
170
+ output_dir = "data/cache"
171
+ os.makedirs(output_dir, exist_ok=True)
172
+ output_path = f"{output_dir}/ui_test_result.png"
173
+
174
+ logger.info(f"UI TEST: Rendering to {output_path}...")
175
+
176
+ start = time.time()
177
+ success = await renderer.render(
178
+ markdown_content=content,
179
+ output_path=output_path,
180
+ stats=stats,
181
+ stages_used=stages,
182
+ mcp_steps=mcp_steps,
183
+ references=references,
184
+ model_name="CLAUDE-3-5-SONNET",
185
+ provider_name="Anthropic",
186
+ behavior_summary="Automated Test",
187
+ icon_config="anthropic",
188
+ render_timeout_ms=10000
189
+ )
190
+
191
+ if success:
192
+ logger.success(f"UI TEST: Render completed in {time.time() - start:.2f}s. Saved to {output_path}")
193
+ else:
194
+ logger.error("UI TEST: Render FAILED.")
195
+
196
+ except Exception as e:
197
+ logger.error(f"UI TEST: Exception during test: {e}")
198
+
103
199
 
104
200
  @listen(Cleanup, once=True)
105
201
  async def _hyw_cleanup():
@@ -338,10 +434,29 @@ async def process_request(session: Session[MessageCreatedEvent], all_param: Opti
338
434
  model_used = final_resp.get("model_used")
339
435
  vision_model_used = final_resp.get("vision_model_used")
340
436
 
437
+ # Helper to infer icon from model name
438
+ def infer_icon_from_model(model_name: str) -> str:
439
+ """Infer icon name from model name (e.g. 'google/gemini-3-flash' -> 'google' or 'gemini')"""
440
+ if not model_name:
441
+ return conf.icon
442
+ name_lower = model_name.lower()
443
+ # Check for known providers/models in the name
444
+ known_icons = ["google", "gemini", "openai", "anthropic", "deepseek", "mistral",
445
+ "qwen", "grok", "xai", "perplexity", "microsoft", "minimax", "nvidia"]
446
+ for icon_name in known_icons:
447
+ if icon_name in name_lower:
448
+ return icon_name
449
+ return conf.icon
450
+
341
451
  icon = conf.icon
452
+ m_conf = None
342
453
  if model_used:
343
- if m_conf := next((m for m in conf.models if m.get("name") == model_used), None):
344
- icon = m_conf.get("icon", icon)
454
+ m_conf = next((m for m in conf.models if m.get("name") == model_used), None)
455
+ if m_conf:
456
+ icon = m_conf.get("icon", infer_icon_from_model(model_used))
457
+ else:
458
+ # Model not in config list, infer from name
459
+ icon = infer_icon_from_model(model_used)
345
460
 
346
461
  # Determine session short code
347
462
  if hist_key:
@@ -358,14 +473,17 @@ async def process_request(session: Session[MessageCreatedEvent], all_param: Opti
358
473
  vision_icon = None
359
474
 
360
475
  if vision_model_used:
361
- if v_conf := next((m for m in conf.models if m.get("name") == vision_model_used), None):
476
+ v_conf = next((m for m in conf.models if m.get("name") == vision_model_used), None)
477
+ if v_conf:
362
478
  vision_base_url = v_conf.get("base_url")
363
- vision_icon = v_conf.get("icon")
479
+ vision_icon = v_conf.get("icon", infer_icon_from_model(vision_model_used))
480
+ else:
481
+ vision_icon = infer_icon_from_model(vision_model_used)
364
482
 
365
483
  # Handle Vision Only Mode (suppress text model display)
366
484
  render_model_name = model_used or conf.model_name or "unknown"
367
485
  render_icon = icon
368
- render_base_url = m_conf.get("base_url", conf.base_url) if model_used and (m_conf := next((m for m in conf.models if m.get("name") == model_used), None)) else conf.base_url
486
+ render_base_url = m_conf.get("base_url", conf.base_url) if m_conf else conf.base_url
369
487
 
370
488
  if not model_used and vision_model_used:
371
489
  render_model_name = ""
@@ -406,6 +524,7 @@ async def process_request(session: Session[MessageCreatedEvent], all_param: Opti
406
524
  stats=stats_to_render,
407
525
  references=structured.get("references", []),
408
526
  mcp_steps=structured.get("mcp_steps", []),
527
+ stages_used=final_resp.get("stages_used", []),
409
528
  model_name=render_model_name,
410
529
  provider_name=provider_name,
411
530
  behavior_summary=behavior_summary,
@@ -686,7 +805,7 @@ async def handle_question_command(session: Session[MessageCreatedEvent], result:
686
805
  await process_request(session, args.get("all_param"), selected_model=selected_text_model, selected_vision_model=selected_vision_model, conversation_key_override=target_key, local_mode=local_mode_val,
687
806
  next_prompt=next_prompt, next_text_model=next_text_model, next_vision_model=next_vision_model)
688
807
 
689
- metadata("hyw", author=[{"name": "kumoSleeping", "email": "zjr2992@outlook.com"}], version="3.2.104", config=HywConfig)
808
+ metadata("hyw", author=[{"name": "kumoSleeping", "email": "zjr2992@outlook.com"}], version="3.2.105", config=HywConfig)
690
809
 
691
810
  @leto.on(CommandReceive)
692
811
  async def remove_at(content: MessageChain):
@@ -0,0 +1 @@
1
+ *,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/*! tailwindcss v3.4.17 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.relative{position:relative}.-top-0\.5{top:-.125rem}.m-0{margin:0}.mx-0\.5{margin-left:.125rem;margin-right:.125rem}.mx-auto{margin-left:auto;margin-right:auto}.mb-1{margin-bottom:.25rem}.mb-3{margin-bottom:.75rem}.ml-2{margin-left:.5rem}.ml-4{margin-left:1rem}.ml-auto{margin-left:auto}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.box-border{box-sizing:border-box}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.h-10{height:2.5rem}.h-2{height:.5rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-8{height:2rem}.h-fit{height:-moz-fit-content;height:fit-content}.w-10{width:2.5rem}.w-2{width:.5rem}.w-3\.5{width:.875rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-8{width:2rem}.w-full{width:100%}.min-w-0{min-width:0}.min-w-\[14px\]{min-width:14px}.min-w-\[16px\]{min-width:16px}.max-w-\[450px\]{max-width:450px}.max-w-\[80px\]{max-width:80px}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.cursor-default{cursor:default}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.items-start{align-items:flex-start}.items-center{align-items:center}.items-baseline{align-items:baseline}.justify-center{justify-content:center}.gap-0\.5{gap:.125rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-2\.5{gap:.625rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.overflow-hidden,.truncate{overflow:hidden}.truncate{white-space:nowrap}.text-ellipsis,.truncate{text-overflow:ellipsis}.whitespace-nowrap{white-space:nowrap}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-sm{border-radius:.125rem}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-l-2{border-left-width:2px}.border-blue-200{--tw-border-opacity:1;border-color:rgb(191 219 254/var(--tw-border-opacity,1))}.border-gray-100{--tw-border-opacity:1;border-color:rgb(243 244 246/var(--tw-border-opacity,1))}.border-gray-200{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity,1))}.border-orange-200{--tw-border-opacity:1;border-color:rgb(254 215 170/var(--tw-border-opacity,1))}.bg-\[\#f2f2f2\]{--tw-bg-opacity:1;background-color:rgb(242 242 242/var(--tw-bg-opacity,1))}.bg-blue-50{--tw-bg-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity,1))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity,1))}.bg-green-400{--tw-bg-opacity:1;background-color:rgb(74 222 128/var(--tw-bg-opacity,1))}.bg-orange-50{--tw-bg-opacity:1;background-color:rgb(255 247 237/var(--tw-bg-opacity,1))}.bg-pink-500{--tw-bg-opacity:1;background-color:rgb(236 72 153/var(--tw-bg-opacity,1))}.bg-purple-400{--tw-bg-opacity:1;background-color:rgb(192 132 252/var(--tw-bg-opacity,1))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.bg-white\/60{background-color:hsla(0,0%,100%,.6)}.bg-white\/80{background-color:hsla(0,0%,100%,.8)}.object-contain{-o-object-fit:contain;object-fit:contain}.p-0{padding:0}.p-2\.5{padding:.625rem}.p-5{padding:1.25rem}.px-0\.5{padding-left:.125rem;padding-right:.125rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3\.5{padding-left:.875rem;padding-right:.875rem}.px-4{padding-left:1rem;padding-right:1rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3\.5{padding-top:.875rem;padding-bottom:.875rem}.pb-3{padding-bottom:.75rem}.pl-4{padding-left:1rem}.align-top{vertical-align:top}.font-mono{font-family:SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace}.font-sans{font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[13px\]{font-size:13px}.text-\[15px\]{font-size:15px}.text-\[16px\]{font-size:16px}.text-\[9px\]{font-size:9px}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.uppercase{text-transform:uppercase}.leading-relaxed{line-height:1.625}.leading-tight{line-height:1.25}.tracking-wide{letter-spacing:.025em}.tracking-wider{letter-spacing:.05em}.text-blue-600{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity,1))}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity,1))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity,1))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity,1))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity,1))}.text-gray-800{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity,1))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1))}.text-inherit{color:inherit}.text-orange-600{--tw-text-opacity:1;color:rgb(234 88 12/var(--tw-text-opacity,1))}.text-pink-600{--tw-text-opacity:1;color:rgb(219 39 119/var(--tw-text-opacity,1))}.underline{text-decoration-line:underline}.no-underline{text-decoration-line:none}.decoration-gray-300{text-decoration-color:#d1d5db}.decoration-0{text-decoration-thickness:0}.decoration-1{text-decoration-thickness:1px}.underline-offset-2{text-underline-offset:2px}.opacity-80{opacity:.8}.shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-inset{--tw-ring-inset:inset}.ring-black\/5{--tw-ring-color:rgba(0,0,0,.05)}.backdrop-blur-sm{--tw-backdrop-blur:blur(4px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-shadow{transition-property:box-shadow;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}pre::-webkit-scrollbar{height:8px;background-color:transparent}pre::-webkit-scrollbar-thumb{background-color:hsla(0,0%,100%,.2);border-radius:4px}.markdown-body h1{margin-top:1.5rem;margin-bottom:1rem;border-bottom-width:1px;--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity,1));padding-bottom:.5rem;font-size:1.5rem;line-height:2rem;font-weight:700;--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity,1))}.markdown-body h2{margin-top:1.25rem;margin-bottom:.75rem;font-size:1.25rem}.markdown-body h2,.markdown-body h3{line-height:1.75rem;font-weight:700;--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity,1))}.markdown-body h3{margin-top:1rem;margin-bottom:.5rem;font-size:1.125rem}.markdown-body h4{margin-top:.75rem;margin-bottom:.5rem;font-size:1rem;line-height:1.5rem;font-weight:700;--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity,1))}.markdown-body p{margin-bottom:1rem;line-height:1.75rem;--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity,1))}.markdown-body ul{margin-bottom:1rem;list-style-type:disc}.markdown-body ul>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem*var(--tw-space-y-reverse))}.markdown-body ul{padding-left:1.25rem;--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity,1))}.markdown-body ol{margin-bottom:1rem;list-style-type:decimal}.markdown-body ol>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem*var(--tw-space-y-reverse))}.markdown-body ol{padding-left:1.25rem;--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity,1))}.markdown-body li{padding-left:.25rem}.markdown-body li>p{margin-bottom:.25rem}.markdown-body a{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity,1));text-decoration-line:underline;text-decoration-color:#93c5fd;text-underline-offset:2px;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.markdown-body a:hover{--tw-text-opacity:1;color:rgb(29 78 216/var(--tw-text-opacity,1));text-decoration-color:#1d4ed8}.markdown-body blockquote{margin-top:1rem;margin-bottom:1rem;border-top-right-radius:.25rem;border-bottom-right-radius:.25rem;border-left-width:4px;--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity,1));--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity,1));padding:.5rem .5rem .5rem 1rem;font-style:italic;--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity,1))}.hljs-built_in,.hljs-keyword,.hljs-name,.hljs-selector-tag,.hljs-tag{color:#db2777!important}.hljs-addition,.hljs-attribute,.hljs-literal,.hljs-section,.hljs-string,.hljs-template-tag,.hljs-template-variable,.hljs-title,.hljs-type{color:#d97706!important}.hljs-comment,.hljs-deletion,.hljs-meta,.hljs-quote{color:#9ca3af!important}.hljs-bullet,.hljs-number,.hljs-symbol{color:#ea580c!important}.hljs-doctag,.hljs-keyword,.hljs-literal,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-strong,.hljs-title,.hljs-type{font-weight:700}.markdown-body code{border-radius:.25rem;--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1));padding:.125rem .375rem;font-family:SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;font-size:.875rem;line-height:1.25rem;--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity,1))}.markdown-body pre{margin-bottom:1rem;overflow-x:auto;border-radius:.5rem;border-width:1px;--tw-border-opacity:1;border-color:rgb(243 244 246/var(--tw-border-opacity,1));--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity,1));padding:1rem;font-size:.875rem;line-height:1.25rem;line-height:1.5;--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.markdown-body pre code{border-style:none;background-color:transparent;padding:0;--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity,1))}.markdown-body img{margin-top:1rem;margin-bottom:1rem;height:auto;max-width:60%;border-radius:.5rem;border-width:1px;--tw-border-opacity:1;border-color:rgb(243 244 246/var(--tw-border-opacity,1));--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.markdown-body table{margin-bottom:1rem;width:100%;border-collapse:collapse;font-size:.875rem;line-height:1.25rem}.markdown-body th{--tw-border-opacity:1;--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity,1));text-align:left;font-weight:600;--tw-text-opacity:1}.markdown-body td,.markdown-body th{border-width:1px;border-color:rgb(209 213 219/var(--tw-border-opacity,1));padding:.5rem 1rem;color:rgb(55 65 81/var(--tw-text-opacity,1))}.markdown-body td{--tw-border-opacity:1;--tw-text-opacity:1}.markdown-body hr{margin-top:1.5rem;margin-bottom:1.5rem;--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity,1))}.markdown-body>:last-child{margin-bottom:0}.katex-display{overflow-x:auto;overflow-y:hidden;padding-top:.5rem;padding-bottom:.5rem}.mermaid{margin-top:1rem;margin-bottom:1rem;display:flex;justify-content:center;border-radius:.5rem;border-width:1px;--tw-border-opacity:1;border-color:rgb(243 244 246/var(--tw-border-opacity,1));--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity,1));padding:1rem}.citation-ref{display:inline-flex;align-items:center;justify-content:center;vertical-align:baseline;font-size:.75em;font-weight:700;color:#4b5563;background-color:#f3f4f6;border:1px solid #e5e7eb;border-radius:9999px;width:1.4em;height:1.4em;margin-left:2px;cursor:pointer;text-decoration:none!important;transition:all .2s;position:relative;line-height:1;box-shadow:none!important}.citation-ref:hover{background-color:#4b5563;color:#fff;text-decoration:none!important}.citation-tooltip{position:absolute;bottom:100%;left:50%;transform:translateX(-50%);margin-bottom:8px;background:#fff;border:1px solid #e5e7eb;box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06);border-radius:8px;padding:8px 12px;width:-moz-max-content;width:max-content;max-width:300px;z-index:50;opacity:0;visibility:hidden;transition:all .2s;pointer-events:none;font-size:12px;line-height:1.4;color:#374151;text-align:left;font-weight:400}.citation-ref:hover .citation-tooltip{opacity:1;visibility:visible;transform:translateX(-50%) translateY(-4px)}.citation-tooltip-title{font-weight:600;color:#111827;margin-bottom:2px;display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:280px}.citation-tooltip-url{color:#6b7280;font-size:10px;display:flex;align-items:center;gap:4px}.hover\:bg-gray-50:hover{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity,1))}.hover\:text-black:hover{--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity,1))}.hover\:decoration-gray-500:hover{text-decoration-color:#6b7280}.hover\:shadow:hover{--tw-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px -1px rgba(0,0,0,.1);--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}