ltcai 12.2.1 → 12.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/README.md +40 -33
  2. package/docs/CHANGELOG.md +65 -0
  3. package/docs/COMMUNITY_AND_PLUGINS.md +1 -1
  4. package/docs/DEVELOPMENT.md +11 -11
  5. package/docs/ONBOARDING.md +1 -1
  6. package/docs/OPERATIONS.md +1 -1
  7. package/docs/ROADMAP.md +1 -1
  8. package/docs/TRUST_MODEL.md +1 -1
  9. package/docs/WHY_LATTICE.md +1 -1
  10. package/docs/kg-schema.md +1 -1
  11. package/lattice_brain/__init__.py +1 -1
  12. package/latticeai/__init__.py +1 -1
  13. package/latticeai/core/embedding_providers/autodetect.py +0 -1
  14. package/latticeai/core/model_compat.py +2 -2
  15. package/latticeai/models/model_providers.py +12 -11
  16. package/latticeai/services/architecture_readiness.py +1 -1
  17. package/latticeai/services/model_capability_registry.py +79 -2
  18. package/latticeai/services/model_catalog.py +38 -12
  19. package/latticeai/services/model_engines.py +29 -15
  20. package/latticeai/services/model_runtime/download.py +53 -6
  21. package/latticeai/services/product_readiness.py +1 -1
  22. package/package.json +6 -8
  23. package/requirements.txt +3 -1
  24. package/scripts/check_current_release_docs.mjs +1 -1
  25. package/scripts/release_screen_claims.json +24 -0
  26. package/src-tauri/Cargo.lock +10 -10
  27. package/src-tauri/Cargo.toml +1 -1
  28. package/src-tauri/tauri.conf.json +1 -1
  29. package/static/app/asset-manifest.json +46 -47
  30. package/static/app/assets/Act-inLiZfDE.js +2 -0
  31. package/static/app/assets/AdminConsole-iLFwSJSg.js +1 -0
  32. package/static/app/assets/Brain-Cb7noiNc.js +2 -0
  33. package/static/app/assets/BrainHome-CfiJ4tau.js +2 -0
  34. package/static/app/assets/BrainSignals-ShxKNNqr.js +1 -0
  35. package/static/app/assets/Capture-Cajj1Trf.js +1 -0
  36. package/static/app/assets/Chronicle-CPd8GP_O.js +1 -0
  37. package/static/app/assets/CommandPalette-Cb_GWoYC.js +1 -0
  38. package/static/app/assets/DigitalBrainExplorer-Df6KVrBz.js +321 -0
  39. package/static/app/assets/Library-Dk5Mefl_.js +1 -0
  40. package/static/app/assets/LivingBrain-u9X_XGC2.js +1 -0
  41. package/static/app/assets/{ProductFlow-DeBGF6qz.js → ProductFlow-CpX0BMr9.js} +1 -1
  42. package/static/app/assets/{QueryClientProvider-B3OjqSyJ.js → QueryClientProvider-CTiSBeU6.js} +1 -1
  43. package/static/app/assets/ReviewCard-C64YFHOR.js +3 -0
  44. package/static/app/assets/RunsListPanel-DKZEJcxF.js +1 -0
  45. package/static/app/assets/System-Dretrknf.js +1 -0
  46. package/static/app/assets/WorkflowGraph-CE6XgWjJ.js +1 -0
  47. package/static/app/assets/WorkflowsPanel-MKU05J7_.js +2 -0
  48. package/static/app/assets/actHelpers-BjMnKMCI.js +1 -0
  49. package/static/app/assets/arrow-left-Cbck4Ig2.js +1 -0
  50. package/static/app/assets/{bot-Dm3fmXAE.js → bot-Qgvc2PGU.js} +1 -1
  51. package/static/app/assets/{brain-C2XwdQL1.js → brain-BwGnubn8.js} +1 -1
  52. package/static/app/assets/{button-xXPeemQr.js → button-DEloiIsj.js} +1 -1
  53. package/static/app/assets/circle-check-CDygnRMn.js +1 -0
  54. package/static/app/assets/{circle-pause-B_lmNicW.js → circle-pause-CkkmXxA9.js} +1 -1
  55. package/static/app/assets/{circle-play-DSYCP0RD.js → circle-play-rnb6A1zq.js} +1 -1
  56. package/static/app/assets/{cpu-D7x-dtxi.js → cpu-CzcGFQQq.js} +1 -1
  57. package/static/app/assets/{download-BHuJr-5V.js → download-BTQigJvp.js} +1 -1
  58. package/static/app/assets/{folder-open-BiO31EwS.js → folder-open-CIXPPhhm.js} +1 -1
  59. package/static/app/assets/{hard-drive-CFEaZ-wP.js → hard-drive-CZXxdIcT.js} +1 -1
  60. package/static/app/assets/index-CHQbWj9a.js +13 -0
  61. package/static/app/assets/index-C_dThdD6.css +2 -0
  62. package/static/app/assets/{input-D3YrgxvO.js → input-CTZHuOXe.js} +1 -1
  63. package/static/app/assets/jsx-runtime-CU_pEDDh.js +1 -0
  64. package/static/app/assets/{link-2-3O-By3qc.js → link-2-BsG1NQUA.js} +1 -1
  65. package/static/app/assets/{permissionCopy-CNK2tfkz.js → permissionCopy-klyWL3ai.js} +1 -1
  66. package/static/app/assets/primitives-ZmN4jzq-.js +1 -0
  67. package/static/app/assets/search-xjKVb4Nh.js +1 -0
  68. package/static/app/assets/{share-2-BljIPAku.js → share-2-Cuv9rj7A.js} +1 -1
  69. package/static/app/assets/{shield-alert-WDP2DSTM.js → shield-alert-KKySFd03.js} +1 -1
  70. package/static/app/assets/{textarea-5v8vtDlK.js → textarea-CBwqgGSA.js} +1 -1
  71. package/static/app/assets/useFocusTrap-D93vds_Z.js +1 -0
  72. package/static/app/assets/{useMutation-Bi0PXQMC.js → useMutation-B9hHPD0p.js} +1 -1
  73. package/static/app/assets/{workspace-BsxrRYQI.js → workspace-JGzrc0D8.js} +1 -1
  74. package/static/app/index.html +4 -4
  75. package/static/sw.js +1 -1
  76. package/static/app/assets/Act-DC676bqE.js +0 -2
  77. package/static/app/assets/AdminConsole-aCxQgD2L.js +0 -1
  78. package/static/app/assets/Brain-Dbd0xvsc.js +0 -2
  79. package/static/app/assets/BrainHome-N00B-MAJ.js +0 -2
  80. package/static/app/assets/BrainSignals-CNA0d6xS.js +0 -1
  81. package/static/app/assets/Capture-BB19fo7P.js +0 -1
  82. package/static/app/assets/Chronicle-D8p3dqxZ.js +0 -1
  83. package/static/app/assets/CommandPalette-uVFYAa-6.js +0 -1
  84. package/static/app/assets/DigitalBrainExplorer-mH6ZSuvK.js +0 -321
  85. package/static/app/assets/Library-0q8Sdke7.js +0 -1
  86. package/static/app/assets/LivingBrain-wess-qJZ.js +0 -1
  87. package/static/app/assets/ReviewCard-DyTrDpy0.js +0 -3
  88. package/static/app/assets/RunsListPanel-CHJv2Qyw.js +0 -1
  89. package/static/app/assets/System-CyKGHQrW.js +0 -1
  90. package/static/app/assets/WorkflowGraph-B5nKCCGa.js +0 -1
  91. package/static/app/assets/WorkflowsPanel-C7RZNRGo.js +0 -2
  92. package/static/app/assets/actHelpers-6MYDH2kW.js +0 -1
  93. package/static/app/assets/arrow-left-DOnpwsVV.js +0 -1
  94. package/static/app/assets/circle-check-D44VI2ZE.js +0 -1
  95. package/static/app/assets/index-C8gwOf0C.css +0 -2
  96. package/static/app/assets/index-DCT79wzR.js +0 -13
  97. package/static/app/assets/jsx-runtime-bzQ4Vb5N.js +0 -1
  98. package/static/app/assets/primitives-B6DzQC3H.js +0 -1
  99. package/static/app/assets/search-BwMK0hjs.js +0 -1
  100. package/static/app/assets/sourceMeta-By2WIjlN.js +0 -1
  101. package/static/app/assets/useFocusTrap-ssiDeh6P.js +0 -1
@@ -102,11 +102,17 @@ ENGINE_MODEL_CATALOG: Dict[str, List[Dict[str, Any]]] = {}
102
102
  # gated — the download could never succeed without Hub credentials.
103
103
 
104
104
 
105
- def _gguf_routes(mlx_repo: str, gguf_repo: str, hf_repo: str) -> Dict[str, str]:
105
+ def _gguf_routes(
106
+ mlx_repo: str,
107
+ gguf_repo: str,
108
+ hf_repo: str,
109
+ *,
110
+ ollama_tag: str = "Q4_K_M",
111
+ ) -> Dict[str, str]:
106
112
  """One model's engine map: MLX weights, a GGUF repo, and the upstream HF repo."""
107
113
  return {
108
114
  "local_mlx": mlx_repo,
109
- "ollama": f"hf.co/{gguf_repo}:Q4_K_M",
115
+ "ollama": f"hf.co/{gguf_repo}:{ollama_tag}",
110
116
  "vllm": hf_repo,
111
117
  "lmstudio": gguf_repo,
112
118
  "llamacpp": gguf_repo,
@@ -119,36 +125,51 @@ _ENGINE_ROUTES: Dict[str, Dict[str, str]] = {
119
125
  ),
120
126
  "mlx-community/gemma-4-e2b-it-4bit": _gguf_routes(
121
127
  "mlx-community/gemma-4-e2b-it-4bit", "ggml-org/gemma-4-E2B-it-GGUF", "google/gemma-4-E2B-it",
128
+ ollama_tag="Q4_0",
122
129
  ),
123
130
  "mlx-community/gemma-4-e4b-it-4bit": _gguf_routes(
124
131
  "mlx-community/gemma-4-e4b-it-4bit", "ggml-org/gemma-4-E4B-it-GGUF", "google/gemma-4-E4B-it",
132
+ ollama_tag="Q4_0",
125
133
  ),
126
134
  "mlx-community/gemma-4-12B-it-4bit": _gguf_routes(
127
135
  "mlx-community/gemma-4-12B-it-4bit", "ggml-org/gemma-4-12B-it-GGUF", "google/gemma-4-12B-it",
136
+ ollama_tag="Q4_0",
137
+ ),
138
+ "mlx-community/gemma-4-26B-A4B-it-qat-4bit": _gguf_routes(
139
+ "mlx-community/gemma-4-26B-A4B-it-qat-4bit", "google/gemma-4-26B-A4B-it-qat-q4_0-gguf",
140
+ "google/gemma-4-26B-A4B-it-qat-q4_0-unquantized",
141
+ ollama_tag="Q4_0",
128
142
  ),
129
143
  "mlx-community/gemma-4-26b-a4b-it-4bit": _gguf_routes(
130
144
  "mlx-community/gemma-4-26b-a4b-it-4bit", "ggml-org/gemma-4-26B-A4B-it-GGUF",
131
145
  "google/gemma-4-26B-A4B-it",
146
+ ollama_tag="Q4_0",
147
+ ),
148
+ "mlx-community/gemma-4-26B-A4B-it-qat-OptiQ-4bit": _gguf_routes(
149
+ "mlx-community/gemma-4-26B-A4B-it-qat-OptiQ-4bit", "unsloth/gemma-4-26B-A4B-it-GGUF",
150
+ "google/gemma-4-26B-A4B-it-qat-q4_0-unquantized",
151
+ ollama_tag="Q4_0",
132
152
  ),
133
153
  "mlx-community/gemma-4-31b-it-4bit": _gguf_routes(
134
154
  "mlx-community/gemma-4-31b-it-4bit", "ggml-org/gemma-4-31B-it-GGUF", "google/gemma-4-31B-it",
155
+ ollama_tag="Q4_0",
156
+ ),
157
+ "mlx-community/Qwen3.8-27B-4bit": _gguf_routes(
158
+ "mlx-community/Qwen3.8-27B-4bit", "ggml-org/Qwen3.8-27B-GGUF", "Qwen/Qwen3.8-27B",
135
159
  ),
136
160
  "mlx-community/Qwen3.6-27B-4bit": _gguf_routes(
137
161
  "mlx-community/Qwen3.6-27B-4bit", "ggml-org/Qwen3.6-27B-GGUF", "Qwen/Qwen3.6-27B",
138
162
  ),
139
163
  "mlx-community/gpt-oss-20b-MXFP4-Q8": _gguf_routes(
140
164
  "mlx-community/gpt-oss-20b-MXFP4-Q8", "ggml-org/gpt-oss-20b-GGUF", "openai/gpt-oss-20b",
165
+ ollama_tag="MXFP4",
166
+ ),
167
+ "mlx-community/Qwen3.5-9B-MLX-4bit": _gguf_routes(
168
+ "mlx-community/Qwen3.5-9B-MLX-4bit", "unsloth/Qwen3.5-9B-GGUF", "Qwen/Qwen3.5-9B",
169
+ ),
170
+ "mlx-community/Qwen3.6-35B-A3B-4bit": _gguf_routes(
171
+ "mlx-community/Qwen3.6-35B-A3B-4bit", "ggml-org/Qwen3.6-35B-A3B-GGUF", "Qwen/Qwen3.6-35B-A3B",
141
172
  ),
142
- # No community GGUF build verified for these two, so they offer the MLX
143
- # weights and the upstream repo only rather than a route that would 404.
144
- "mlx-community/Qwen3.5-9B-MLX-4bit": {
145
- "local_mlx": "mlx-community/Qwen3.5-9B-MLX-4bit",
146
- "vllm": "Qwen/Qwen3.5-9B",
147
- },
148
- "mlx-community/Qwen3.6-35B-A3B-4bit": {
149
- "local_mlx": "mlx-community/Qwen3.6-35B-A3B-4bit",
150
- "vllm": "Qwen/Qwen3.6-35B-A3B",
151
- },
152
173
  }
153
174
 
154
175
  # Names people actually type that are not the repo's own short name. Kept
@@ -156,6 +177,11 @@ _ENGINE_ROUTES: Dict[str, Dict[str, str]] = {
156
177
  # is no other Gemma 4 26B — and resolving that to nothing would be pedantry.
157
178
  _COMMON_MISNAMES: Dict[str, str] = {
158
179
  "gemma-4-26b-it-4bit": "mlx-community/gemma-4-26b-a4b-it-4bit",
180
+ "gemma-4-26b-qat-4bit": "mlx-community/gemma-4-26B-A4B-it-qat-4bit",
181
+ "gemma-4-26b-a4b-qat-4bit": "mlx-community/gemma-4-26B-A4B-it-qat-4bit",
182
+ "gemma-4-26b-optiq-4bit": "mlx-community/gemma-4-26B-A4B-it-qat-OptiQ-4bit",
183
+ "qwen-3.8-27b-4bit": "mlx-community/Qwen3.8-27B-4bit",
184
+ "qwen3.8-27b": "mlx-community/Qwen3.8-27B-4bit",
159
185
  }
160
186
 
161
187
  # Keyed by both the lowercase short name ("gemma-4-12b-it-4bit") and the
@@ -112,6 +112,8 @@ def _json_request(
112
112
  payload: Optional[Dict[str, Any]] = None,
113
113
  timeout: float = 10.0,
114
114
  ) -> Dict[str, Any]:
115
+ if not str(url).startswith(("http://", "https://")):
116
+ raise ValueError(f"Unsupported URL scheme in {url!r}")
115
117
  data = None
116
118
  req_headers = dict(headers or {})
117
119
  if payload is not None:
@@ -225,7 +227,7 @@ def get_openai_compatible_server_models(provider: str) -> List[str]:
225
227
  config = OPENAI_COMPATIBLE_PROVIDERS.get(provider) or {}
226
228
  base_url = os.getenv(config.get("base_url_env", "")) if config.get("base_url_env") else None
227
229
  base_url = (base_url or config.get("base_url") or "").rstrip("/")
228
- if not base_url:
230
+ if not base_url or not base_url.startswith(("http://", "https://")):
229
231
  return []
230
232
 
231
233
  api_key = os.getenv(config.get("env_key", "")) or config.get("api_key_fallback") or provider
@@ -332,6 +334,10 @@ def ensure_llamacpp_server(model_name: str) -> None:
332
334
  hf_model_dir,
333
335
  hf_model_ready,
334
336
  )
337
+ from latticeai.services.model_runtime.download import (
338
+ GGUF_QUANT_PREFERENCE,
339
+ is_auxiliary_gguf,
340
+ )
335
341
 
336
342
  served_models = get_openai_compatible_server_models("llamacpp")
337
343
  if model_name in served_models:
@@ -347,23 +353,31 @@ def ensure_llamacpp_server(model_name: str) -> None:
347
353
  download_hf_model(model_name, "llamacpp")
348
354
 
349
355
  gguf_files = sorted(hf_model_dir(model_name).rglob("*.gguf"))
350
- if not gguf_files:
356
+ primary_ggufs = [p for p in gguf_files if not is_auxiliary_gguf(p.name)]
357
+ if not primary_ggufs:
351
358
  raise ModelRuntimeError(status_code=500, detail="다운로드된 GGUF 파일을 찾지 못했습니다.")
352
359
 
353
- preferred = next((p for p in gguf_files if "q4_k_m" in p.name.lower()), None)
354
- model_file = preferred or gguf_files[0]
360
+ preferred = next(
361
+ (p for pref in GGUF_QUANT_PREFERENCE for p in primary_ggufs if pref in p.name.lower()),
362
+ None,
363
+ )
364
+ model_file = preferred or primary_ggufs[0]
365
+ command = [
366
+ "llama-server",
367
+ "-m",
368
+ str(model_file),
369
+ "--alias",
370
+ model_name,
371
+ "--host",
372
+ "127.0.0.1",
373
+ "--port",
374
+ "8080",
375
+ ]
376
+ mmprojs = [p for p in gguf_files if p.name.lower().startswith("mmproj-")]
377
+ if mmprojs:
378
+ command.extend(["--mmproj", str(mmprojs[0])])
355
379
  LOCAL_SERVER_PROCESSES["llamacpp"] = subprocess.Popen(
356
- [
357
- "llama-server",
358
- "-m",
359
- str(model_file),
360
- "--alias",
361
- model_name,
362
- "--host",
363
- "127.0.0.1",
364
- "--port",
365
- "8080",
366
- ],
380
+ command,
367
381
  stdout=subprocess.DEVNULL,
368
382
  stderr=subprocess.DEVNULL,
369
383
  start_new_session=True,
@@ -10,6 +10,7 @@ differently.
10
10
  from __future__ import annotations
11
11
 
12
12
  import importlib.util
13
+ import json
13
14
  import logging
14
15
  import time
15
16
  from pathlib import Path
@@ -19,6 +20,29 @@ from latticeai.core.quiet import quiet
19
20
  from latticeai.models.router import hf_cache_model_dir, hf_model_dir
20
21
  from latticeai.services.model_errors import ModelRuntimeError
21
22
 
23
+ _AUXILIARY_GGUF_PREFIXES = ("mmproj-", "mtp-", "dflash-", "eagle3-")
24
+ GGUF_QUANT_PREFERENCE = ("q4_k_m", "q4_0", "mxfp4", "q4_k_s", "q3_k_m", "q2_k", "q8_0")
25
+
26
+
27
+ def is_auxiliary_gguf(filename: str) -> bool:
28
+ base = Path(str(filename)).name.lower()
29
+ return base.startswith(_AUXILIARY_GGUF_PREFIXES) or "imatrix" in base
30
+
31
+
32
+ def _shards_complete(model_dir: Path) -> bool:
33
+ index_file = model_dir / "model.safetensors.index.json"
34
+ if not index_file.exists():
35
+ return True
36
+ try:
37
+ payload = json.loads(index_file.read_text(encoding="utf-8"))
38
+ weight_map = payload.get("weight_map") if isinstance(payload, dict) else None
39
+ if isinstance(weight_map, dict) and weight_map:
40
+ shards = {str(shard) for shard in weight_map.values() if shard}
41
+ return all((model_dir / shard).exists() for shard in shards)
42
+ except Exception:
43
+ quiet()
44
+ return True
45
+
22
46
 
23
47
  def hf_model_ready(repo_id: str, provider: str = "local_mlx") -> bool:
24
48
  model_dir = hf_model_dir(repo_id)
@@ -32,9 +56,11 @@ def hf_model_ready(repo_id: str, provider: str = "local_mlx") -> bool:
32
56
  if not model_dir.exists() or not model_dir.is_dir():
33
57
  return False
34
58
  if provider == "llamacpp":
35
- return any(model_dir.rglob("*.gguf"))
59
+ return any(not is_auxiliary_gguf(p.name) for p in model_dir.rglob("*.gguf"))
36
60
  has_config = (model_dir / "config.json").exists()
37
- has_weights = any(model_dir.glob("*.safetensors")) or any(model_dir.glob("*.bin"))
61
+ has_weights = (
62
+ any(model_dir.glob("*.safetensors")) or any(model_dir.glob("*.bin"))
63
+ ) and _shards_complete(model_dir)
38
64
  has_tokenizer = (
39
65
  (model_dir / "tokenizer.json").exists()
40
66
  or (model_dir / "tokenizer.model").exists()
@@ -139,15 +165,36 @@ def download_hf_model(
139
165
  [item for item in all_files if str(item["name"]).lower().endswith(".gguf")],
140
166
  key=lambda item: str(item["name"]),
141
167
  )
142
- if not ggufs:
168
+ primary_ggufs = [item for item in ggufs if not is_auxiliary_gguf(str(item["name"]))]
169
+ if not primary_ggufs:
143
170
  raise RuntimeError("GGUF 파일을 찾지 못했습니다.")
144
- preference = ("q4_k_m", "q4_0", "q4_k_s", "q3_k_m", "q2_k")
145
171
  selected_files = [
146
172
  next(
147
- (item for pref in preference for item in ggufs if pref in str(item["name"]).lower()),
148
- ggufs[0],
173
+ (
174
+ item
175
+ for pref in GGUF_QUANT_PREFERENCE
176
+ for item in primary_ggufs
177
+ if pref in str(item["name"]).lower()
178
+ ),
179
+ primary_ggufs[0],
149
180
  )
150
181
  ]
182
+ mmprojs = [
183
+ item
184
+ for item in ggufs
185
+ if Path(str(item["name"])).name.lower().startswith("mmproj-")
186
+ ]
187
+ if mmprojs:
188
+ preferred_mmproj = next(
189
+ (
190
+ item
191
+ for pref in ("bf16", "f16", "f32")
192
+ for item in mmprojs
193
+ if pref in str(item["name"]).lower()
194
+ ),
195
+ mmprojs[0],
196
+ )
197
+ selected_files.append(preferred_mmproj)
151
198
  else:
152
199
  selected_files = all_files
153
200
 
@@ -28,7 +28,7 @@ from typing import Any, Dict, List
28
28
 
29
29
  from latticeai.services.architecture_readiness import architecture_readiness
30
30
 
31
- PRODUCT_VERSION_TARGET = "12.2.1"
31
+ PRODUCT_VERSION_TARGET = "12.4.0"
32
32
 
33
33
 
34
34
  @dataclass(frozen=True)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ltcai",
3
- "version": "12.2.1",
3
+ "version": "12.4.0",
4
4
  "description": "Lattice AI — local-first Digital Brain that keeps your knowledge durable across any AI model.",
5
5
  "homepage": "https://github.com/TaeSooPark-PTS/LatticeAI#readme",
6
6
  "repository": {
@@ -111,16 +111,14 @@
111
111
  "!TOOLS.md",
112
112
  "!USER.md",
113
113
  "!docs/images/tmp_frames/",
114
- "!**/__pycache__/",
115
- "!**/*.pyc",
116
- "!**/*.map",
114
+ "!{latticeai,lattice_brain,skills,plugins,scripts}/**/__pycache__/",
115
+ "!{latticeai,lattice_brain,skills,plugins,scripts}/**/*.pyc",
116
+ "!static/**/*.map",
117
117
  "README.md",
118
118
  "static/vendor/",
119
119
  "src-tauri/",
120
120
  "!src-tauri/gen/",
121
- "!src-tauri/gen/**",
122
121
  "!src-tauri/target/",
123
- "!src-tauri/target/**",
124
122
  "docs/*.md",
125
123
  "!docs/assets/",
126
124
  "!docs/images/"
@@ -142,7 +140,7 @@
142
140
  "@types/react": "^19.2.17",
143
141
  "@types/react-dom": "^19.2.3",
144
142
  "@vitejs/plugin-react": "^6.0.2",
145
- "@vitest/coverage-v8": "^4.1.10",
143
+ "@vitest/coverage-v8": "^4.1.12",
146
144
  "autoprefixer": "^10.5.0",
147
145
  "class-variance-authority": "^0.7.1",
148
146
  "clsx": "^2.1.1",
@@ -159,7 +157,7 @@
159
157
  "tailwindcss": "^4.3.0",
160
158
  "typescript": "^5.9.3",
161
159
  "vite": "^8.0.16",
162
- "vitest": "^4.1.10",
160
+ "vitest": "^4.1.12",
163
161
  "zustand": "^5.0.14"
164
162
  },
165
163
  "overrides": {
package/requirements.txt CHANGED
@@ -2,10 +2,12 @@ fastapi>=0.110,<1
2
2
  uvicorn>=0.29,<1
3
3
  pydantic>=2.7,<3
4
4
  httpx>=0.27,<1
5
- pillow>=10,<13
5
+ pillow>=13,<14
6
6
  openai>=1.30,<3
7
7
  python-docx>=1.1,<2
8
8
  openpyxl>=3.1,<4
9
9
  python-pptx>=0.6.23,<2
10
10
  keyring>=24,<26
11
11
  pdfplumber>=0.11,<0.12
12
+ reportlab>=4,<5
13
+ huggingface_hub>=1.0,<2
@@ -6,7 +6,7 @@ const root = process.cwd();
6
6
  const pkg = JSON.parse(readFileSync(path.join(root, "package.json"), "utf8"));
7
7
  const version = pkg.version;
8
8
  const releaseDir = `output/release/v${version}`;
9
- const releaseTheme = "True Count";
9
+ const releaseTheme = "Sharp Weight";
10
10
  const title = `${version} — ${releaseTheme}`;
11
11
  const escapedVersion = version.replaceAll(".", "\\.");
12
12
 
@@ -20,6 +20,30 @@
20
20
  "whole-image delta: naming where the change is makes the claim more",
21
21
  "specific, not less."
22
22
  ],
23
+ "12.4.0": {
24
+ "_why": [
25
+ "Sharp Weight is a model catalog and security audit release: Qwen 3.8 27B",
26
+ "4-bit and Gemma 4 26B A4B QAT / QAT-OptiQ 4-bit catalog expansion,",
27
+ "Pillow 13.0.0 and npm lockfile vulnerability closure, model_engines",
28
+ "URL scheme validation, and scoped Tailwind CSS v4 source scanning.",
29
+ "",
30
+ "No screen was redesigned. Empty claim set on purpose. Unclaimed screens",
31
+ "are still measured and printed; they are not gated."
32
+ ]
33
+ },
34
+ "12.3.0": {
35
+ "_why": [
36
+ "Live Wire is a backend and runtime release: verified Hugging Face GGUF",
37
+ "quantization tags (Q4_0 for gemma-4, MXFP4 for gpt-oss-20b), Qwen3.5-9B",
38
+ "and Qwen3.6-35B-A3B GGUF routing, auxiliary GGUF filtering + companion",
39
+ "mmproj- download for llama-server, shard-index verification, small-model",
40
+ "tool/MCP argument recovery and fenced HTML salvage, full HTML structure",
41
+ "inspection in /tools/inspect_html, and UTF-8 / RFC 5987 download headers.",
42
+ "",
43
+ "No screen was redesigned. Empty claim set on purpose. Unclaimed screens",
44
+ "are still measured and printed; they are not gated."
45
+ ]
46
+ },
23
47
  "12.2.1": {
24
48
  "_why": [
25
49
  "True Count is a backend honesty release: HNSW COUNT+delta, SkipByHash",
@@ -1863,7 +1863,7 @@ dependencies = [
1863
1863
 
1864
1864
  [[package]]
1865
1865
  name = "lattice-agent"
1866
- version = "12.2.1"
1866
+ version = "12.4.0"
1867
1867
  dependencies = [
1868
1868
  "axum",
1869
1869
  "base64 0.22.1",
@@ -1880,7 +1880,7 @@ dependencies = [
1880
1880
 
1881
1881
  [[package]]
1882
1882
  name = "lattice-ai-desktop"
1883
- version = "12.2.1"
1883
+ version = "12.4.0"
1884
1884
  dependencies = [
1885
1885
  "lattice-host",
1886
1886
  "lattice-jobs",
@@ -1895,7 +1895,7 @@ dependencies = [
1895
1895
 
1896
1896
  [[package]]
1897
1897
  name = "lattice-auth"
1898
- version = "12.2.1"
1898
+ version = "12.4.0"
1899
1899
  dependencies = [
1900
1900
  "axum",
1901
1901
  "base64 0.22.1",
@@ -1912,7 +1912,7 @@ dependencies = [
1912
1912
 
1913
1913
  [[package]]
1914
1914
  name = "lattice-chat"
1915
- version = "12.2.1"
1915
+ version = "12.4.0"
1916
1916
  dependencies = [
1917
1917
  "axum",
1918
1918
  "bytes",
@@ -1934,7 +1934,7 @@ dependencies = [
1934
1934
 
1935
1935
  [[package]]
1936
1936
  name = "lattice-core"
1937
- version = "12.2.1"
1937
+ version = "12.4.0"
1938
1938
  dependencies = [
1939
1939
  "blake2",
1940
1940
  "bytes",
@@ -1950,7 +1950,7 @@ dependencies = [
1950
1950
 
1951
1951
  [[package]]
1952
1952
  name = "lattice-host"
1953
- version = "12.2.1"
1953
+ version = "12.4.0"
1954
1954
  dependencies = [
1955
1955
  "axum",
1956
1956
  "lattice-agent",
@@ -1971,7 +1971,7 @@ dependencies = [
1971
1971
 
1972
1972
  [[package]]
1973
1973
  name = "lattice-ingest"
1974
- version = "12.2.1"
1974
+ version = "12.4.0"
1975
1975
  dependencies = [
1976
1976
  "axum",
1977
1977
  "lattice-auth",
@@ -1986,7 +1986,7 @@ dependencies = [
1986
1986
 
1987
1987
  [[package]]
1988
1988
  name = "lattice-jobs"
1989
- version = "12.2.1"
1989
+ version = "12.4.0"
1990
1990
  dependencies = [
1991
1991
  "axum",
1992
1992
  "lattice-auth",
@@ -2001,7 +2001,7 @@ dependencies = [
2001
2001
 
2002
2002
  [[package]]
2003
2003
  name = "lattice-platform"
2004
- version = "12.2.1"
2004
+ version = "12.4.0"
2005
2005
  dependencies = [
2006
2006
  "axum",
2007
2007
  "base64 0.22.1",
@@ -2024,7 +2024,7 @@ dependencies = [
2024
2024
 
2025
2025
  [[package]]
2026
2026
  name = "lattice-retrieval"
2027
- version = "12.2.1"
2027
+ version = "12.4.0"
2028
2028
  dependencies = [
2029
2029
  "axum",
2030
2030
  "fancy-regex",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "lattice-ai-desktop"
3
- version = "12.2.1"
3
+ version = "12.4.0"
4
4
  description = "Lattice AI Digital Brain desktop shell"
5
5
  authors = ["TaeSoo Park"]
6
6
  edition = "2021"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://schema.tauri.app/config/2",
3
3
  "productName": "Lattice AI",
4
- "version": "12.2.1",
4
+ "version": "12.4.0",
5
5
  "identifier": "ai.lattice.desktop",
6
6
  "build": {
7
7
  "beforeDevCommand": "npm run frontend:dev",
@@ -1,55 +1,54 @@
1
1
  {
2
- "version": "12.2.1",
2
+ "version": "12.4.0",
3
3
  "generated_at": "vite",
4
4
  "entrypoints": {
5
- "app": "/static/app/assets/index-DCT79wzR.js"
5
+ "app": "/static/app/assets/index-CHQbWj9a.js"
6
6
  },
7
7
  "assets": {
8
8
  "../node_modules/@tauri-apps/api/core.js": "/static/app/assets/core-CwxXejkd.js",
9
- "_BrainSignals-CNA0d6xS.js": "/static/app/assets/BrainSignals-CNA0d6xS.js",
10
- "_LivingBrain-wess-qJZ.js": "/static/app/assets/LivingBrain-wess-qJZ.js",
11
- "_QueryClientProvider-B3OjqSyJ.js": "/static/app/assets/QueryClientProvider-B3OjqSyJ.js",
12
- "_ReviewCard-DyTrDpy0.js": "/static/app/assets/ReviewCard-DyTrDpy0.js",
13
- "_actHelpers-6MYDH2kW.js": "/static/app/assets/actHelpers-6MYDH2kW.js",
14
- "_arrow-left-DOnpwsVV.js": "/static/app/assets/arrow-left-DOnpwsVV.js",
15
- "_bot-Dm3fmXAE.js": "/static/app/assets/bot-Dm3fmXAE.js",
16
- "_brain-C2XwdQL1.js": "/static/app/assets/brain-C2XwdQL1.js",
17
- "_button-xXPeemQr.js": "/static/app/assets/button-xXPeemQr.js",
18
- "_circle-check-D44VI2ZE.js": "/static/app/assets/circle-check-D44VI2ZE.js",
19
- "_circle-pause-B_lmNicW.js": "/static/app/assets/circle-pause-B_lmNicW.js",
20
- "_circle-play-DSYCP0RD.js": "/static/app/assets/circle-play-DSYCP0RD.js",
21
- "_cpu-D7x-dtxi.js": "/static/app/assets/cpu-D7x-dtxi.js",
22
- "_download-BHuJr-5V.js": "/static/app/assets/download-BHuJr-5V.js",
23
- "_folder-open-BiO31EwS.js": "/static/app/assets/folder-open-BiO31EwS.js",
24
- "_hard-drive-CFEaZ-wP.js": "/static/app/assets/hard-drive-CFEaZ-wP.js",
25
- "_input-D3YrgxvO.js": "/static/app/assets/input-D3YrgxvO.js",
26
- "_jsx-runtime-bzQ4Vb5N.js": "/static/app/assets/jsx-runtime-bzQ4Vb5N.js",
27
- "_link-2-3O-By3qc.js": "/static/app/assets/link-2-3O-By3qc.js",
28
- "_permissionCopy-CNK2tfkz.js": "/static/app/assets/permissionCopy-CNK2tfkz.js",
29
- "_primitives-B6DzQC3H.js": "/static/app/assets/primitives-B6DzQC3H.js",
30
- "_search-BwMK0hjs.js": "/static/app/assets/search-BwMK0hjs.js",
31
- "_share-2-BljIPAku.js": "/static/app/assets/share-2-BljIPAku.js",
32
- "_shield-alert-WDP2DSTM.js": "/static/app/assets/shield-alert-WDP2DSTM.js",
33
- "_sourceMeta-By2WIjlN.js": "/static/app/assets/sourceMeta-By2WIjlN.js",
34
- "_textarea-5v8vtDlK.js": "/static/app/assets/textarea-5v8vtDlK.js",
35
- "_useFocusTrap-ssiDeh6P.js": "/static/app/assets/useFocusTrap-ssiDeh6P.js",
36
- "_useMutation-Bi0PXQMC.js": "/static/app/assets/useMutation-Bi0PXQMC.js",
37
- "_workspace-BsxrRYQI.js": "/static/app/assets/workspace-BsxrRYQI.js",
38
- "index.html": "/static/app/assets/index-DCT79wzR.js",
39
- "assets/index-C8gwOf0C.css": "/static/app/assets/index-C8gwOf0C.css",
40
- "src/components/ProductFlow.tsx": "/static/app/assets/ProductFlow-DeBGF6qz.js",
41
- "src/features/act/RunsListPanel.tsx": "/static/app/assets/RunsListPanel-CHJv2Qyw.js",
42
- "src/features/act/WorkflowGraph.tsx": "/static/app/assets/WorkflowGraph-B5nKCCGa.js",
43
- "src/features/act/WorkflowsPanel.tsx": "/static/app/assets/WorkflowsPanel-C7RZNRGo.js",
44
- "src/features/admin/AdminConsole.tsx": "/static/app/assets/AdminConsole-aCxQgD2L.js",
45
- "src/features/brain/BrainHome.tsx": "/static/app/assets/BrainHome-N00B-MAJ.js",
46
- "src/features/command/CommandPalette.tsx": "/static/app/assets/CommandPalette-uVFYAa-6.js",
47
- "src/pages/Act.tsx": "/static/app/assets/Act-DC676bqE.js",
48
- "src/pages/Brain.tsx": "/static/app/assets/Brain-Dbd0xvsc.js",
49
- "src/pages/Capture.tsx": "/static/app/assets/Capture-BB19fo7P.js",
50
- "src/pages/Chronicle.tsx": "/static/app/assets/Chronicle-D8p3dqxZ.js",
51
- "src/pages/Library.tsx": "/static/app/assets/Library-0q8Sdke7.js",
52
- "src/pages/System.tsx": "/static/app/assets/System-CyKGHQrW.js",
53
- "src/pages/brain/DigitalBrainExplorer.tsx": "/static/app/assets/DigitalBrainExplorer-mH6ZSuvK.js"
9
+ "_BrainSignals-ShxKNNqr.js": "/static/app/assets/BrainSignals-ShxKNNqr.js",
10
+ "_LivingBrain-u9X_XGC2.js": "/static/app/assets/LivingBrain-u9X_XGC2.js",
11
+ "_QueryClientProvider-CTiSBeU6.js": "/static/app/assets/QueryClientProvider-CTiSBeU6.js",
12
+ "_ReviewCard-C64YFHOR.js": "/static/app/assets/ReviewCard-C64YFHOR.js",
13
+ "_actHelpers-BjMnKMCI.js": "/static/app/assets/actHelpers-BjMnKMCI.js",
14
+ "_arrow-left-Cbck4Ig2.js": "/static/app/assets/arrow-left-Cbck4Ig2.js",
15
+ "_bot-Qgvc2PGU.js": "/static/app/assets/bot-Qgvc2PGU.js",
16
+ "_brain-BwGnubn8.js": "/static/app/assets/brain-BwGnubn8.js",
17
+ "_button-DEloiIsj.js": "/static/app/assets/button-DEloiIsj.js",
18
+ "_circle-check-CDygnRMn.js": "/static/app/assets/circle-check-CDygnRMn.js",
19
+ "_circle-pause-CkkmXxA9.js": "/static/app/assets/circle-pause-CkkmXxA9.js",
20
+ "_circle-play-rnb6A1zq.js": "/static/app/assets/circle-play-rnb6A1zq.js",
21
+ "_cpu-CzcGFQQq.js": "/static/app/assets/cpu-CzcGFQQq.js",
22
+ "_download-BTQigJvp.js": "/static/app/assets/download-BTQigJvp.js",
23
+ "_folder-open-CIXPPhhm.js": "/static/app/assets/folder-open-CIXPPhhm.js",
24
+ "_hard-drive-CZXxdIcT.js": "/static/app/assets/hard-drive-CZXxdIcT.js",
25
+ "_input-CTZHuOXe.js": "/static/app/assets/input-CTZHuOXe.js",
26
+ "_jsx-runtime-CU_pEDDh.js": "/static/app/assets/jsx-runtime-CU_pEDDh.js",
27
+ "_link-2-BsG1NQUA.js": "/static/app/assets/link-2-BsG1NQUA.js",
28
+ "_permissionCopy-klyWL3ai.js": "/static/app/assets/permissionCopy-klyWL3ai.js",
29
+ "_primitives-ZmN4jzq-.js": "/static/app/assets/primitives-ZmN4jzq-.js",
30
+ "_search-xjKVb4Nh.js": "/static/app/assets/search-xjKVb4Nh.js",
31
+ "_share-2-Cuv9rj7A.js": "/static/app/assets/share-2-Cuv9rj7A.js",
32
+ "_shield-alert-KKySFd03.js": "/static/app/assets/shield-alert-KKySFd03.js",
33
+ "_textarea-CBwqgGSA.js": "/static/app/assets/textarea-CBwqgGSA.js",
34
+ "_useFocusTrap-D93vds_Z.js": "/static/app/assets/useFocusTrap-D93vds_Z.js",
35
+ "_useMutation-B9hHPD0p.js": "/static/app/assets/useMutation-B9hHPD0p.js",
36
+ "_workspace-JGzrc0D8.js": "/static/app/assets/workspace-JGzrc0D8.js",
37
+ "index.html": "/static/app/assets/index-CHQbWj9a.js",
38
+ "assets/index-C_dThdD6.css": "/static/app/assets/index-C_dThdD6.css",
39
+ "src/components/ProductFlow.tsx": "/static/app/assets/ProductFlow-CpX0BMr9.js",
40
+ "src/features/act/RunsListPanel.tsx": "/static/app/assets/RunsListPanel-DKZEJcxF.js",
41
+ "src/features/act/WorkflowGraph.tsx": "/static/app/assets/WorkflowGraph-CE6XgWjJ.js",
42
+ "src/features/act/WorkflowsPanel.tsx": "/static/app/assets/WorkflowsPanel-MKU05J7_.js",
43
+ "src/features/admin/AdminConsole.tsx": "/static/app/assets/AdminConsole-iLFwSJSg.js",
44
+ "src/features/brain/BrainHome.tsx": "/static/app/assets/BrainHome-CfiJ4tau.js",
45
+ "src/features/command/CommandPalette.tsx": "/static/app/assets/CommandPalette-Cb_GWoYC.js",
46
+ "src/pages/Act.tsx": "/static/app/assets/Act-inLiZfDE.js",
47
+ "src/pages/Brain.tsx": "/static/app/assets/Brain-Cb7noiNc.js",
48
+ "src/pages/Capture.tsx": "/static/app/assets/Capture-Cajj1Trf.js",
49
+ "src/pages/Chronicle.tsx": "/static/app/assets/Chronicle-CPd8GP_O.js",
50
+ "src/pages/Library.tsx": "/static/app/assets/Library-Dk5Mefl_.js",
51
+ "src/pages/System.tsx": "/static/app/assets/System-Dretrknf.js",
52
+ "src/pages/brain/DigitalBrainExplorer.tsx": "/static/app/assets/DigitalBrainExplorer-Df6KVrBz.js"
54
53
  }
55
54
  }
@@ -0,0 +1,2 @@
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/RunsListPanel-DKZEJcxF.js","assets/jsx-runtime-CU_pEDDh.js","assets/workspace-JGzrc0D8.js","assets/index-CHQbWj9a.js","assets/QueryClientProvider-CTiSBeU6.js","assets/index-C_dThdD6.css","assets/primitives-ZmN4jzq-.js","assets/useMutation-B9hHPD0p.js","assets/circle-check-CDygnRMn.js","assets/button-DEloiIsj.js","assets/actHelpers-BjMnKMCI.js","assets/circle-play-rnb6A1zq.js","assets/WorkflowsPanel-MKU05J7_.js","assets/input-CTZHuOXe.js","assets/textarea-CBwqgGSA.js","assets/folder-open-CIXPPhhm.js"])))=>i.map(i=>d[i]);
2
+ import{i as e,n as t,t as n}from"./jsx-runtime-CU_pEDDh.js";import"./workspace-JGzrc0D8.js";import{t as r}from"./useMutation-B9hHPD0p.js";import{D as i,H as a,R as o,S as s,b as c,i as l,k as u,o as d,v as f,z as p}from"./index-CHQbWj9a.js";import{n as m}from"./QueryClientProvider-CTiSBeU6.js";import{t as h}from"./bot-Qgvc2PGU.js";import{t as g}from"./circle-pause-CkkmXxA9.js";import{_,c as v,d as y,g as b,h as x,i as S,m as C,n as w,o as T,p as E,r as D,s as O,t as k,u as A,v as j}from"./primitives-ZmN4jzq-.js";import{t as M}from"./button-DEloiIsj.js";import{t as N}from"./input-CTZHuOXe.js";import{t as P}from"./textarea-CBwqgGSA.js";import{a as F,i as I,n as L,r as R}from"./ReviewCard-C64YFHOR.js";var z=o(`play`,[[`path`,{d:`M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z`,key:`10ikf1`}]]),B=e(t()),V=n();function H(){let e=p(e=>e.language),t=m(),[n,r]=B.useState(`pending`),[i,o]=B.useState(`all`),[c,l]=B.useState({}),u=a({queryKey:[`automationReviews`,n,i],queryFn:()=>f.automationReviews({...n===`all`?{}:{status:n},...i===`all`?{}:{source:i}})}),d=u.data?.data.items||[],h=a({queryKey:[`proposalCounts`],queryFn:f.proposalCounts}),g=Number(h.data?.data?.pending||0),_=async(n,r,i=!1,a)=>{let o=await(r===`approve`?()=>f.approveReviewItem(n.id):r===`dismiss`?n.source===`change_proposal`?()=>f.rejectProposal(n.id,a||``):()=>f.dismissReviewItem(n.id):r===`snooze`?()=>f.snoozeReviewItem(n.id,R()):r===`unsnooze`?()=>f.unsnoozeReviewItem(n.id):()=>f.runNowReviewItem(n.id))();if(!o.ok){let t=r===`approve`&&n.source===`change_proposal`&&o.status===409;return l(r=>({...r,[n.id]:t?{tone:`error`,message:s(e,`proposals.conflict.title`),conflict:!0}:{tone:`error`,message:s(e,`review.feedback.error`),...o.error?{detail:o.error}:{}}})),o}if(r===`run_now`){let t=o.data.payload||{},r=o.data.provenance||{},a=String(t.last_run_id||r.run_id||``),c=i?s(e,`review.regenerated`):s(e,`review.executed`);l(e=>({...e,[n.id]:{tone:`success`,message:a?`${c} · ${a}`:c}}))}else l(e=>{let t={...e};return delete t[n.id],t});return await Promise.all([t.invalidateQueries({queryKey:[`automationReviews`]}),t.invalidateQueries({queryKey:[`proposalCounts`]}),t.invalidateQueries({queryKey:[`pendingProposals`]})]),o};return u.isLoading?(0,V.jsx)(T,{title:s(e,`review.inbox.title`)}):(0,V.jsxs)(`div`,{className:`review-inbox`,children:[(0,V.jsxs)(`div`,{className:`review-inbox-head`,children:[(0,V.jsxs)(`div`,{children:[(0,V.jsx)(`h2`,{className:`text-xl font-bold`,children:s(e,`review.inbox.title`)}),(0,V.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:s(e,`review.inbox.description`)})]}),(0,V.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[g>0?(0,V.jsx)(j,{variant:`warning`,"data-testid":`proposal-count-badge`,children:s(e,`review.proposal.badge`,{count:g})}):null,u.data?(0,V.jsx)(j,{variant:u.data.ok?`success`:`warning`,children:u.data.ok?s(e,`review.status.connected`):s(e,`review.status.unavailable`)}):null]})]}),(0,V.jsxs)(`div`,{className:`flex flex-wrap items-center gap-x-6 gap-y-2 py-1`,children:[(0,V.jsxs)(`div`,{className:`flex min-w-0 flex-wrap items-center gap-2`,children:[(0,V.jsx)(`span`,{id:`review-status-filter-label`,className:`text-xs font-semibold tracking-wide text-muted-foreground`,children:s(e,`review.status.title`)}),(0,V.jsx)(y,{tabs:F.map(t=>({id:t.id,label:s(e,t.labelKey)})),value:n,onChange:e=>r(e),ariaLabelledBy:`review-status-filter-label`})]}),(0,V.jsxs)(`div`,{className:`flex min-w-0 flex-wrap items-center gap-2`,children:[(0,V.jsx)(`span`,{id:`review-source-filter-label`,className:`text-xs font-semibold tracking-wide text-muted-foreground`,children:s(e,`review.source.title`)}),(0,V.jsx)(y,{tabs:I.map(t=>({id:t.id,label:s(e,t.labelKey)})),value:i,onChange:e=>o(e),ariaLabelledBy:`review-source-filter-label`})]})]}),(0,V.jsx)(`div`,{className:`pt-2`,children:u.isError||u.data&&!u.data.ok?(0,V.jsx)(D,{title:s(e,`review.inbox.loadError`),detail:(0,V.jsxs)(V.Fragment,{children:[s(e,`review.inbox.unavailable`),u.data?.error?(0,V.jsx)(`span`,{className:`mt-1 block text-xs opacity-75`,children:u.data.error}):null]})}):d.length?(0,V.jsx)(`div`,{className:`flex flex-col gap-3`,children:d.map(e=>(0,V.jsx)(L,{item:e,feedback:c[e.id],onAction:_},e.id))}):(0,V.jsx)(D,{title:s(e,`review.inbox.empty`),detail:n===`snoozed`?s(e,`review.inbox.emptySnoozed`):s(e,`review.inbox.emptyPending`)})})]})}var U=[{id:`review`,labelKey:`act.tab.review`},{id:`runs`,labelKey:`act.tab.runsHistory`}],W={runs:{titleKey:`act.title.runs`,copyKey:`act.copy.runs`},agents:{titleKey:`act.title.goals`,copyKey:`act.copy.goals`},workflows:{titleKey:`act.title.workflows`,copyKey:`act.copy.workflows`},hooks:{titleKey:`act.title.safeguards`,copyKey:`act.copy.safeguards`},tools:{titleKey:`act.title.permissions`,copyKey:`act.copy.permissions`}},G=[{id:`runs`,labelKey:`act.tab.runs`},{id:`agents`,labelKey:`act.tab.goals`},{id:`workflows`,labelKey:`act.tab.recipes`},{id:`hooks`,labelKey:`act.tab.safeguards`,advancedLabelKey:`act.tab.hooks`},{id:`tools`,labelKey:`act.tab.permissions`,advancedLabelKey:`act.tab.tools`}],K=B.lazy(()=>c(()=>import(`./RunsListPanel-DKZEJcxF.js`).then(e=>({default:e.RunsListPanel})),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11]))),q=B.lazy(()=>c(()=>import(`./WorkflowsPanel-MKU05J7_.js`).then(e=>({default:e.WorkflowsPanel})),__vite__mapDeps([12,1,2,3,4,5,7,6,8,9,13,14,15,10,11])));function J({initialTab:e}){let t=p(e=>e.mode),n=p(e=>e.language),[r,a]=B.useState(()=>e===`agents`||e===`workflows`||e===`hooks`||e===`tools`?e:`runs`),[o,c]=B.useState(e===`runs`?`runs`:`review`);B.useEffect(()=>{e===`review`?(a(`runs`),c(`review`)):e===`runs`?(a(`runs`),c(`runs`)):G.some(t=>t.id===e)&&a(e)},[e]);let u=e=>{a(e),d(`/`+e)},f=e=>{c(e),d(e===`review`?`/review`:`/runs`)},{titleKey:m,copyKey:h}=W[r];return(0,V.jsxs)(`div`,{className:`product-page act-page space-y-5`,children:[(0,V.jsxs)(`header`,{className:`page-hero`,children:[(0,V.jsxs)(`div`,{className:`page-kicker`,children:[(0,V.jsx)(i,{className:`h-4 w-4`}),` `,s(n,`act.kicker`)]}),(0,V.jsx)(`h1`,{className:`page-title`,children:s(n,m)}),(0,V.jsx)(`p`,{className:`page-copy`,children:s(n,h)})]}),(0,V.jsx)(y,{tabs:(t===`basic`?G.filter(e=>e.id===`runs`||e.id===`agents`||e.id===`workflows`):G).map(e=>({id:e.id,label:s(n,t===`basic`||!e.advancedLabelKey?e.labelKey:e.advancedLabelKey)})),value:r,onChange:e=>u(e)}),r===`runs`?(0,V.jsx)(X,{subTab:o,onSubTabChange:f}):null,r===`agents`?(0,V.jsx)(Y,{}):null,r===`workflows`?(0,V.jsx)(l,{language:n,resetKey:`act-workflows`,children:(0,V.jsx)(q,{})}):null,r===`hooks`?(0,V.jsx)(Z,{}):null,r===`tools`?(0,V.jsx)(Q,{}):null]})}function Y(){let e=m(),t=p(e=>e.mode),n=p(e=>e.language),[i,o]=B.useState(``),c=a({queryKey:[`agentRuntime`],queryFn:f.agentRuntime}),l=a({queryKey:[`agentRegistry`],queryFn:f.agentRegistry,enabled:t!==`basic`}),d=a({queryKey:[`agentCapabilities`],queryFn:f.agentCapabilities,enabled:t!==`basic`}),g=r({mutationFn:()=>f.runAgent(i,[`planner`,`executor`,`reviewer`]),onSuccess:()=>e.invalidateQueries({queryKey:[`agentRuntime`]})}),[y,T]=B.useState(``),D=r({mutationFn:()=>f.registerAgent({name:y,type:`custom`,capabilities:[]}),onSuccess:()=>e.invalidateQueries({queryKey:[`agentRegistry`]})}),O=(c.data?.data||{}).runtime||{},k=!!O.ready,F=t===`basic`?s(n,`act.goal.modelRequired`):String(O.unavailable_reason||s(n,`act.runtime.modelUnavailable`)),I=!!i.trim()&&k&&!g.isPending;return(0,V.jsxs)(`div`,{className:`work-start-flow flex flex-col gap-4`,children:[(0,V.jsxs)(E,{className:`work-goal-card`,children:[(0,V.jsxs)(b,{children:[(0,V.jsxs)(_,{className:`flex items-center gap-2`,children:[(0,V.jsx)(h,{className:`h-4 w-4`}),` `,s(n,`act.goal.title`)]}),(0,V.jsx)(x,{children:s(n,`act.goal.description`)})]}),(0,V.jsxs)(C,{className:`space-y-3`,children:[(0,V.jsx)(P,{value:i,onChange:e=>o(e.target.value),placeholder:s(n,`act.goal.placeholder`)}),k?null:(0,V.jsx)(j,{variant:`warning`,children:F}),(0,V.jsxs)(M,{className:`w-full`,variant:k?`default`:`outline`,disabled:!I,onClick:()=>g.mutate(),children:[(0,V.jsx)(z,{className:`h-4 w-4`}),` `,k?s(n,`act.goal.start`):s(n,`act.goal.needsModel`)]}),g.data?(0,V.jsx)(v,{result:g.data,successLabel:s(n,`act.goal.completed`)}):null,g.data&&g.data?.data?(0,V.jsx)(`div`,{className:`text-xs text-emerald-600`,children:s(n,`act.goal.brainSaved`)}):null]})]}),t===`basic`?(0,V.jsxs)(`div`,{className:`work-safety-note`,children:[(0,V.jsx)(u,{className:`h-4 w-4`,"aria-hidden":`true`}),(0,V.jsx)(`span`,{children:s(n,`act.goal.safety`)})]}):(0,V.jsxs)(V.Fragment,{children:[(0,V.jsx)(w,{title:s(n,`act.panel.readiness`),result:c.data,children:e=>(0,V.jsx)(A,{value:e})}),(0,V.jsx)(w,{title:s(n,`act.panel.agentTeam`),result:l.data,children:e=>(0,V.jsxs)(`div`,{className:`space-y-3`,children:[(0,V.jsx)(S,{items:e.agents,titleKey:`name`,metaKey:`type`,labelPrefix:`act.agentRole`}),(0,V.jsxs)(`div`,{className:`flex gap-2`,children:[(0,V.jsx)(N,{value:y,onChange:e=>T(e.target.value),placeholder:s(n,`act.agent.namePlaceholder`)}),(0,V.jsx)(M,{disabled:!y.trim()||D.isPending,onClick:()=>D.mutate(),children:s(n,`act.agent.register`)})]})]})}),(0,V.jsx)(w,{title:s(n,`act.panel.capabilities`),result:d.data,children:e=>(0,V.jsx)(A,{value:e})})]})]})}function X({subTab:e,onSubTabChange:t}){let n=p(e=>e.language);return(0,V.jsxs)(`div`,{className:`space-y-4`,children:[(0,V.jsx)(y,{tabs:U.map(e=>({id:e.id,label:s(n,e.labelKey)})),value:e,onChange:e=>t(e)}),e===`runs`?(0,V.jsx)(l,{language:n,resetKey:`act-runs`,children:(0,V.jsx)(K,{})}):(0,V.jsx)(H,{})]})}function Z(){let e=p(e=>e.mode),t=p(e=>e.language),n=a({queryKey:[`hooks`],queryFn:f.hooks}),r=a({queryKey:[`hookRuns`],queryFn:f.hookRuns});return e===`basic`?(0,V.jsxs)(`div`,{className:`flex flex-col gap-4`,children:[(0,V.jsx)(w,{title:s(t,`act.panel.safeguards`),result:n.data,children:e=>(0,V.jsx)(S,{items:e.hooks,titleKey:`name`,metaKey:`kind`})}),(0,V.jsx)(O,{title:s(t,`act.hooks.detailed`),detail:s(t,`act.hooks.detailedHint`)})]}):(0,V.jsxs)(`div`,{className:`flex flex-col gap-4`,children:[(0,V.jsx)(w,{title:s(t,`act.panel.hooks`),result:n.data,children:e=>(0,V.jsx)(S,{items:e.hooks,titleKey:`name`,metaKey:`kind`})}),(0,V.jsx)(w,{title:s(t,`act.panel.hookRuns`),result:r.data,children:e=>(0,V.jsx)(S,{items:e.runs,titleKey:`hook_id`,metaKey:`status`})}),(0,V.jsxs)(E,{children:[(0,V.jsxs)(b,{children:[(0,V.jsxs)(_,{className:`flex items-center gap-2`,children:[(0,V.jsx)(g,{className:`h-4 w-4`}),` `,s(t,`act.hooks.runManual`)]}),(0,V.jsx)(x,{children:s(t,`act.hooks.runManualHint`)})]}),(0,V.jsx)(C,{children:(0,V.jsx)(k,{label:s(t,`act.hooks.runAll`),action:()=>f.hookRun({event:`manual`}),invalidate:[`hookRuns`]})})]})]})}function Q(){let e=p(e=>e.language),t=a({queryKey:[`toolPermissions`],queryFn:f.toolPermissions});return(0,V.jsx)(w,{title:s(e,`act.panel.permissions`),result:t.data,children:e=>(0,V.jsx)(S,{items:e.permissions||e,titleKey:`tool`,metaKey:`risk`})})}export{J as ActPage};