ltcai 3.0.1 → 3.1.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 (96) hide show
  1. package/README.md +27 -20
  2. package/docs/CHANGELOG.md +37 -0
  3. package/docs/V3_FRONTEND.md +20 -17
  4. package/latticeai/__init__.py +1 -1
  5. package/latticeai/api/auth.py +4 -1
  6. package/latticeai/api/search.py +4 -0
  7. package/latticeai/core/config.py +2 -0
  8. package/latticeai/core/embedding_providers.py +123 -0
  9. package/latticeai/core/workspace_os.py +1 -1
  10. package/latticeai/server_app.py +22 -6
  11. package/package.json +9 -4
  12. package/scripts/build_v3_assets.mjs +164 -0
  13. package/scripts/capture/README.md +28 -0
  14. package/scripts/capture/capture_enterprise.js +8 -0
  15. package/scripts/capture/capture_graph.js +8 -0
  16. package/scripts/capture/capture_onboarding.js +8 -0
  17. package/scripts/capture/capture_page.js +43 -0
  18. package/scripts/capture/capture_release_media.js +125 -0
  19. package/scripts/capture/capture_skills.js +8 -0
  20. package/scripts/capture/capture_workspace.js +8 -0
  21. package/scripts/generate_diagrams.py +513 -0
  22. package/scripts/lint_v3.mjs +33 -0
  23. package/scripts/release-0.3.1.sh +105 -0
  24. package/scripts/take_screenshots.js +69 -0
  25. package/scripts/validate_release_artifacts.py +167 -0
  26. package/static/account.html +9 -9
  27. package/static/activity.html +4 -4
  28. package/static/admin.html +8 -8
  29. package/static/agents.html +4 -4
  30. package/static/chat.html +9 -9
  31. package/static/css/tokens.5a595671.css +260 -0
  32. package/static/css/tokens.css +1 -1
  33. package/static/graph.html +9 -9
  34. package/static/plugins.html +4 -4
  35. package/static/sw.js +3 -1
  36. package/static/v3/asset-manifest.json +47 -0
  37. package/static/v3/css/lattice.base.e4cdd05d.css +128 -0
  38. package/static/v3/css/lattice.components.011e988b.css +447 -0
  39. package/static/v3/css/lattice.components.css +2 -2
  40. package/static/v3/css/lattice.shell.4920f42d.css +407 -0
  41. package/static/v3/css/lattice.tokens.c597ff81.css +132 -0
  42. package/static/v3/css/lattice.views.3ee19d4e.css +277 -0
  43. package/static/v3/index.html +38 -9
  44. package/static/v3/js/app.46fb61d9.js +26 -0
  45. package/static/v3/js/core/api.22a41d42.js +344 -0
  46. package/static/v3/js/core/api.js +68 -51
  47. package/static/v3/js/core/components.4c83e0a9.js +222 -0
  48. package/static/v3/js/core/components.js +9 -2
  49. package/static/v3/js/core/dom.a2773eb0.js +148 -0
  50. package/static/v3/js/core/router.584570f2.js +37 -0
  51. package/static/v3/js/core/routes.f935dd50.js +78 -0
  52. package/static/v3/js/core/routes.js +6 -1
  53. package/static/v3/js/core/shell.1b6199d6.js +363 -0
  54. package/static/v3/js/core/store.34ebd5e6.js +113 -0
  55. package/static/v3/js/views/admin-audit.660a1fb1.js +185 -0
  56. package/static/v3/js/views/admin-audit.js +1 -1
  57. package/static/v3/js/views/admin-permissions.a7ae5f09.js +177 -0
  58. package/static/v3/js/views/admin-permissions.js +4 -5
  59. package/static/v3/js/views/admin-policies.3658fd86.js +102 -0
  60. package/static/v3/js/views/admin-policies.js +4 -5
  61. package/static/v3/js/views/admin-private-vpc.7d342d36.js +135 -0
  62. package/static/v3/js/views/admin-private-vpc.js +2 -5
  63. package/static/v3/js/views/admin-security.07c66b72.js +180 -0
  64. package/static/v3/js/views/admin-security.js +4 -5
  65. package/static/v3/js/views/admin-users.03bac88c.js +168 -0
  66. package/static/v3/js/views/admin-users.js +6 -6
  67. package/static/v3/js/views/agents.14e48bdd.js +193 -0
  68. package/static/v3/js/views/agents.js +1 -2
  69. package/static/v3/js/views/chat.718144ce.js +449 -0
  70. package/static/v3/js/views/chat.js +2 -3
  71. package/static/v3/js/views/files.4935197e.js +186 -0
  72. package/static/v3/js/views/files.js +27 -21
  73. package/static/v3/js/views/home.cdde3b32.js +119 -0
  74. package/static/v3/js/views/hybrid-search.b22b97e0.js +195 -0
  75. package/static/v3/js/views/hybrid-search.js +1 -1
  76. package/static/v3/js/views/knowledge-graph.a14ea7e7.js +237 -0
  77. package/static/v3/js/views/knowledge-graph.js +2 -3
  78. package/static/v3/js/views/models.a1ffa147.js +256 -0
  79. package/static/v3/js/views/models.js +17 -8
  80. package/static/v3/js/views/my-computer.1b2ff621.js +237 -0
  81. package/static/v3/js/views/my-computer.js +5 -5
  82. package/static/v3/js/views/pipeline.c522f1ce.js +157 -0
  83. package/static/v3/js/views/pipeline.js +3 -7
  84. package/static/v3/js/views/settings.4f777210.js +250 -0
  85. package/static/v3/js/views/settings.js +6 -14
  86. package/static/workflows.html +4 -4
  87. package/static/workspace.html +5 -5
  88. package/docs/images/tmp_frames/frame_00.png +0 -0
  89. package/docs/images/tmp_frames/frame_01.png +0 -0
  90. package/docs/images/tmp_frames/frame_02.png +0 -0
  91. package/docs/images/tmp_frames/frame_03.png +0 -0
  92. package/docs/images/tmp_frames/hero_00.png +0 -0
  93. package/docs/images/tmp_frames/hero_01.png +0 -0
  94. package/docs/images/tmp_frames/hero_02.png +0 -0
  95. package/docs/images/tmp_frames/hero_03.png +0 -0
  96. package/static/v3/js/core/fixtures.js +0 -171
package/README.md CHANGED
@@ -16,7 +16,7 @@
16
16
  [![npm version](https://img.shields.io/npm/v/ltcai?label=npm)](https://www.npmjs.com/package/ltcai)
17
17
  [![VS Code Marketplace](https://vsmarketplacebadges.dev/version-short/parktaesoo.ltcai.svg)](https://marketplace.visualstudio.com/items?itemName=parktaesoo.ltcai)
18
18
  [![Open VSX](https://img.shields.io/open-vsx/v/parktaesoo/ltcai?label=Open%20VSX)](https://open-vsx.org/extension/parktaesoo/ltcai)
19
- [![GitHub release](https://img.shields.io/github/v/release/TaeSooPark-PTS/LatticeAI?label=GitHub%20release)](https://github.com/TaeSooPark-PTS/LatticeAI/releases/tag/v3.0.0)
19
+ [![GitHub release](https://img.shields.io/github/v/release/TaeSooPark-PTS/LatticeAI?label=GitHub%20release)](https://github.com/TaeSooPark-PTS/LatticeAI/releases/tag/v3.1.0)
20
20
  [![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE)
21
21
  [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue)](https://www.python.org/)
22
22
  [![VS Code extension](https://img.shields.io/badge/VS%20Code-extension-blue?logo=visualstudiocode)](https://marketplace.visualstudio.com/items?itemName=parktaesoo.ltcai)
@@ -49,7 +49,7 @@ Install the coding extension:
49
49
 
50
50
  - [VS Code Marketplace: parktaesoo.ltcai](https://marketplace.visualstudio.com/items?itemName=parktaesoo.ltcai)
51
51
  - [Open VSX: parktaesoo.ltcai](https://open-vsx.org/extension/parktaesoo/ltcai)
52
- - [GitHub Release v3.0.0](https://github.com/TaeSooPark-PTS/LatticeAI/releases/tag/v3.0.0)
52
+ - [GitHub Release v3.1.0](https://github.com/TaeSooPark-PTS/LatticeAI/releases/tag/v3.1.0)
53
53
 
54
54
  ## Quick Start
55
55
 
@@ -88,8 +88,8 @@ place.
88
88
 
89
89
  - **Primary app shell**: `/app` is the default product experience with Native
90
90
  Chat, Knowledge Graph, Hybrid Search, Files, Pipeline, Agents, Models, My
91
- Computer, Settings, and Admin areas. Legacy `/chat` remains available as a
92
- rollback/debug path.
91
+ Computer, Settings, and Admin areas. Classic pages remain compatibility
92
+ routes only; normal workflows stay in `/app`.
93
93
  - **Local-first AI Workspace**: work starts on your machine, with local data and
94
94
  workspace state by default.
95
95
  - **AI Pipeline Platform**: plan, execute, review, retry, and replay work across
@@ -105,8 +105,8 @@ place.
105
105
  Knowledge Graph and fused with keyword and graph signals.
106
106
  - **Local Model Management**: choose current multimodal local models with source
107
107
  disclosure, hardware-aware recommendations, and cloud fallback options.
108
- - **SSO for teams**: organization workspaces can be paired with Okta or
109
- Microsoft Entra ID patterns for team access.
108
+ - **Community-first workspaces**: Personal and Organization workspaces ship in
109
+ the local product; enterprise SSO/SCIM/governance remain future extensions.
110
110
 
111
111
  ## Why Lattice AI?
112
112
 
@@ -122,10 +122,11 @@ and disconnected automations. Lattice AI keeps those parts together:
122
122
  - multi-agent workflows leave behind replayable plans, reviews, retries, and
123
123
  outcomes.
124
124
 
125
- ## v3.0.0 Highlights
125
+ ## v3.1.0 Highlights
126
126
 
127
- Lattice AI v3.0.0 makes `/app` the primary workspace shell and ships the v3
128
- backend retrieval stack together with the native frontend.
127
+ Lattice AI v3.1.0 completes the non-enterprise local-first workspace platform
128
+ around `/app`: Classic is retired from normal workflows, retrieval is wired
129
+ through a shared service layer, and browser assets are hash-manifested.
129
130
 
130
131
  - Native v3 Chat lives inside `/app#/chat` and streams through the real
131
132
  `POST /chat` backend while showing friendly setup guidance when no model is
@@ -134,11 +135,17 @@ backend retrieval stack together with the native frontend.
134
135
  surfaces. Hybrid results show keyword, local vector, and graph scores.
135
136
  - Personal and Organization workspaces, plus Basic / Advanced / Admin modes,
136
137
  are built into the shell.
137
- - Legacy `/chat` remains reachable for rollback and debugging.
138
- - The default embedding signal is `lattice-local-hash-v1`, a deterministic
139
- local fallback. It is not described as a production semantic embedding model;
140
- future providers may include Ollama, MLX, OpenAI-compatible endpoints, and
141
- other local embedding runtimes.
138
+ - Models can load/unload from the native Models view; Agents read the
139
+ AgentRuntime boundary with run health, history, events, replay, and stop
140
+ affordances.
141
+ - Production embedding profiles cover local `bge-m3`, `nomic-embed-text`,
142
+ `e5-large`, `gte-large`, Ollama `nomic-embed-text`, `mxbai-embed-large`,
143
+ BGE-M3-compatible providers, MLX, and OpenAI-compatible
144
+ `text-embedding-3-small` / `text-embedding-3-large`. Hash embeddings remain
145
+ fallback only.
146
+ - `/app` loads `static/v3/asset-manifest.json` and build-generated hashed
147
+ assets such as `app.<hash>.js` and `lattice.base.<hash>.css`; manual `?v=`
148
+ cache-busting is no longer used by runtime HTML.
142
149
 
143
150
  ## Screenshots
144
151
 
@@ -184,11 +191,10 @@ The v3 backend adds a local-first retrieval stack that combines the Knowledge
184
191
  Graph, a SQLite vector index, and hybrid result fusion. It preserves existing
185
192
  graph data while adding derived vector rows that can be rebuilt at any time.
186
193
 
187
- Embedding status: the current default is `lattice-local-hash-v1`, a
188
- deterministic local fallback embedder for indexing and tests. It provides a
189
- stable vector signal without downloads or cloud calls; it is not a production
190
- semantic embedding model. Future provider support may include Ollama, MLX,
191
- OpenAI-compatible providers, and other local embedding runtimes.
194
+ Embedding status: production profiles are exposed through
195
+ `GET /api/embeddings/providers`, while `lattice-local-hash-v1` remains a
196
+ deterministic fallback for offline indexing and tests. It is never presented as
197
+ a production semantic embedding model.
192
198
 
193
199
  Core API contracts:
194
200
 
@@ -259,7 +265,8 @@ Core areas:
259
265
 
260
266
  | Version | Theme |
261
267
  | --- | --- |
262
- | **3.0.1** | Release-blocker remediationprovider-backed embeddings (Hash/MLX/Ollama/OpenAI/Custom), unified AgentRuntime boundary, every v3 surface connected or clearly unavailable |
268
+ | **3.1.0** | Mainline platform completion native `/app` workflows, Classic retired from normal paths, production embedding profiles, AgentRuntime/registries, hashed v3 assets |
269
+ | 3.0.1 | Release-blocker remediation — provider-backed embeddings (Hash/MLX/Ollama/OpenAI/Custom), unified AgentRuntime boundary, every v3 surface connected or clearly unavailable |
263
270
  | 3.0.0 | v3 local-first AI workspace platform — `/app`, Native Chat, Knowledge Graph, Vector Index, Hybrid Search, workspace modes |
264
271
  | 2.2.7 | Visual system stabilization — cohesive dark/light screens, crisp chat composer, dark graph canvas, Workspace OS polish |
265
272
  | 2.2.6 | Token-native CSS foundation |
package/docs/CHANGELOG.md CHANGED
@@ -1,5 +1,42 @@
1
1
  # Changelog
2
2
 
3
+ ## [3.1.0] - 2026-06-07
4
+
5
+ > v3.1 — Mainline Product Platform Completion. `/app` is now the full
6
+ > non-enterprise local-first workspace: Classic pages are compatibility routes,
7
+ > production embedding profiles are explicit, AgentRuntime and registries are
8
+ > the integration boundaries, and v3 runtime assets are hash-manifested.
9
+
10
+ ### Added
11
+
12
+ - **Hashed asset pipeline** — `npm run build:assets` writes
13
+ `static/v3/asset-manifest.json`, hashed CSS/JS siblings, and import-rewritten
14
+ ES modules. `/app` reads the manifest and loads hashed assets automatically.
15
+ - **Production embedding profiles** — local `bge-m3`, `nomic-embed-text`,
16
+ `e5-large`, `gte-large`; Ollama `nomic-embed-text`, `mxbai-embed-large`,
17
+ BGE-M3-compatible providers; MLX Apple Silicon profiles; and
18
+ OpenAI-compatible `text-embedding-3-small` / `text-embedding-3-large`.
19
+ - **Native model lifecycle controls** — `/app#/models` now calls the real
20
+ `/models/load` and `/models/unload/{model_id}` endpoints.
21
+
22
+ ### Changed
23
+
24
+ - **Classic retirement** — normal user workflows no longer link to Classic
25
+ Chat, Classic Runtime, or Classic Admin. Compatibility routes remain available
26
+ for rollback/debug.
27
+ - **Truthful unavailable states** — v3 fallback adapters return empty
28
+ unavailable payloads instead of sample data, fake counters, or fabricated
29
+ health.
30
+ - **Release metadata** — package, npm, VS Code extension, Workspace OS, docs,
31
+ and expected artifacts are aligned at `3.1.0`.
32
+
33
+ ### Validation
34
+
35
+ - Release target: `npm run lint`, `npm run typecheck`, `npm run check:python`,
36
+ backend/integration tests, Playwright visual tests, `python -m build`,
37
+ `npm run build`, `npm pack`, VSIX package, and exact-version artifact
38
+ validation.
39
+
3
40
  ## [3.0.0] - 2026-06-07
4
41
 
5
42
  > v3 — Local-first AI Workspace Platform. The hybrid-search
@@ -2,13 +2,13 @@
2
2
 
3
3
  > A token-native single-page workspace shell for Lattice AI v3. It ships as the
4
4
  > primary product experience and calls the real v3 retrieval/chat APIs while
5
- > keeping graceful, clearly-badged sample states for unavailable local services.
5
+ > rendering clear unavailable states for local services that are not running.
6
6
 
7
7
  Entry point: **`/app`** (served by `latticeai/api/static_routes.py` →
8
8
  `static/v3/index.html`). Login, auto-login after registration, SSO callback, and
9
9
  the PWA manifest land on `/app`. The legacy multi-page screens (`/workspace`,
10
- `/chat`, `/graph`, `/admin`, …) remain reachable; `/chat` is the rollback/debug
11
- path for the native v3 Chat view.
10
+ `/chat`, `/graph`, `/admin`, …) remain reachable only as compatibility/debug
11
+ routes; normal user workflows stay in `/app`.
12
12
 
13
13
  ---
14
14
 
@@ -49,6 +49,9 @@ Administration Users · Permissions · Audit Logs · Security · Policies · Pri
49
49
  Token-native, layered on the existing **single color source**
50
50
  (`static/css/tokens.css`, `data-lt-theme` light/dark). No legacy override layers
51
51
  (`responsive.css` / `workspace.css` / `platform.css`) are loaded by v3.
52
+ Runtime assets are loaded through `static/v3/asset-manifest.json`; the build
53
+ step writes hashed CSS/JS siblings and `/app` reads the manifest instead of
54
+ using manual `?v=` query strings.
52
55
 
53
56
  | File | Responsibility |
54
57
  | --- | --- |
@@ -91,28 +94,27 @@ export async function render(ctx) { /* … */ return singleDomNode; }
91
94
  ## Integration contract
92
95
 
93
96
  `core/api.js` is the only transport layer. Every call hits the **real** endpoint
94
- first and degrades to a clearly-badged sample payload (`core/fixtures.js`) when
95
- the endpoint is absent returning `{ ok, status, data, source }` where `source`
96
- is `"live"` or `"placeholder"`. The UI always renders a **Sample data** badge for
97
- placeholder responses, so nothing fake is presented as backend output.
97
+ first and returns `{ ok, status, data, source }` where `source` is `"live"` or
98
+ `"unavailable"`. Unavailable responses carry empty data so primary surfaces do
99
+ not invent counters, sample graphs, fake health, or fake run history.
98
100
 
99
- Live surfaces wired in v3.0.0:
101
+ Live surfaces wired in v3.1.0:
100
102
 
101
- | Adapter | Endpoint | Fallback |
103
+ | Adapter | Endpoint | Unavailable state |
102
104
  | --- | --- | --- |
103
- | `api.indexStatus()` | `GET /api/index/status` | sample KG/vector/hybrid pipeline state |
104
- | `api.graph(params)` | `GET /api/graph` → `GET /knowledge-graph/graph` | sample mesh |
105
- | `api.hybridSearch(q, opts)` | `POST /api/search/hybrid` | sample fused results |
106
- | `api.streamChat(body)` | `POST /chat` SSE | sample stream only when endpoint is unavailable |
105
+ | `api.indexStatus()` | `GET /api/index/status` | empty retrieval status |
106
+ | `api.graph(params)` | `GET /api/graph` → `GET /knowledge-graph/graph` | empty graph |
107
+ | `api.hybridSearch(q, opts)` | `POST /api/search/hybrid` | empty results |
108
+ | `api.streamChat(body)` | `POST /chat` SSE | unavailable chat message |
107
109
 
108
110
  No backend retrieval logic is implemented in the frontend — only transport,
109
111
  normalization, clear provenance badges, and graceful fallback. When the live
110
112
  chat backend reports `no_model_loaded`, v3 Chat shows a setup message instead of
111
- falling back to sample generation.
113
+ falling back to generated text.
112
114
 
113
- Embedding disclosure: the current default vector signal is
114
- `lattice-local-hash-v1`, a deterministic local fallback. The UI avoids calling
115
- it a production semantic embedding model.
115
+ Embedding disclosure: production profiles are exposed for local/Ollama/MLX and
116
+ OpenAI-compatible providers. `lattice-local-hash-v1` remains a deterministic
117
+ fallback and is not presented as a production semantic embedding model.
116
118
 
117
119
  ---
118
120
 
@@ -131,6 +133,7 @@ focus rings, skip link, keyboard command palette (⌘K / Ctrl-K).
131
133
  ## Validation
132
134
 
133
135
  - `npm run lint` (extended to cover `static/v3/**` via `scripts/lint_v3.mjs`).
136
+ - `npm run build:assets` (writes hashed v3 assets and `asset-manifest.json`).
134
137
  - `npm run test:visual` (`tests/visual/v3.spec.js` against the mock server, which
135
138
  serves `/app` and mocks the future API surfaces).
136
139
  - Browser-rendered smoke checks of every route in light and dark themes.
@@ -1,3 +1,3 @@
1
1
  """Lattice AI - modular server package."""
2
2
 
3
- __version__ = "3.0.1"
3
+ __version__ = "3.1.0"
@@ -57,6 +57,7 @@ def create_auth_router(
57
57
  public_sso_config: Callable[..., Dict],
58
58
  open_registration: bool,
59
59
  session_ttl: int,
60
+ require_auth: bool = True,
60
61
  ) -> APIRouter:
61
62
  router = APIRouter()
62
63
 
@@ -221,7 +222,9 @@ def create_auth_router(
221
222
  async def get_profile(request: Request):
222
223
  email = require_user(request)
223
224
  if not email:
224
- raise HTTPException(status_code=401, detail="인증이 필요합니다.")
225
+ if require_auth:
226
+ raise HTTPException(status_code=401, detail="인증이 필요합니다.")
227
+ return {"email": "", "name": "Local User", "nickname": "You", "role": "admin", "is_admin": True}
225
228
  users = load_users()
226
229
  user = users.get(email)
227
230
  if not user:
@@ -7,6 +7,7 @@ from typing import Any, Callable, Dict, Optional
7
7
  from fastapi import APIRouter, HTTPException, Request
8
8
  from pydantic import BaseModel, Field
9
9
 
10
+ from latticeai.core.embedding_providers import embedding_provider_profiles
10
11
  from latticeai.services.search_service import DEFAULT_HYBRID_WEIGHTS, SearchService
11
12
 
12
13
 
@@ -213,9 +214,12 @@ def create_search_router(
213
214
  async def embeddings_providers(request: Request) -> Dict[str, Any]:
214
215
  require_user(request)
215
216
  resolved = embedding_info() if embedding_info else {}
217
+ profiles = resolved.get("profiles") or embedding_provider_profiles()
216
218
  return {
217
219
  "active": resolved.get("active_provider"),
218
220
  "requested": resolved.get("requested_provider"),
221
+ "profile": resolved.get("profile") or "",
222
+ "profiles": profiles,
219
223
  "providers": [
220
224
  {"id": "hash", "label": "Local hash (fallback)", "grade": "fallback",
221
225
  "requires": [], "detail": "Deterministic offline vectors — always available."},
@@ -95,6 +95,7 @@ class Config:
95
95
 
96
96
  # ── embeddings (retrieval vector signal) ────────────────────────
97
97
  embedding_provider: str
98
+ embedding_profile: str
98
99
  embedding_model: str
99
100
  embedding_base_url: str
100
101
  embedding_api_key: str
@@ -174,6 +175,7 @@ class Config:
174
175
  local_draft_model=_value(env, "LATTICEAI_LOCAL_DRAFT_MODEL", ""),
175
176
  auto_read_chat_paths=_bool(env, "LATTICEAI_AUTO_READ_CHAT_PATHS", default=False),
176
177
  embedding_provider=_value(env, "LATTICEAI_EMBEDDING_PROVIDER", "hash").strip().lower(),
178
+ embedding_profile=_value(env, "LATTICEAI_EMBEDDING_PROFILE", "").strip().lower(),
177
179
  embedding_model=_value(env, "LATTICEAI_EMBEDDING_MODEL", ""),
178
180
  embedding_base_url=_value(env, "LATTICEAI_EMBEDDING_BASE_URL", ""),
179
181
  embedding_api_key=_value(env, "LATTICEAI_EMBEDDING_API_KEY", ""),
@@ -51,6 +51,7 @@ class EmbeddingUnavailable(RuntimeError):
51
51
  # identity is stable before the first (possibly remote) call. A configured
52
52
  # ``dim`` always wins; an unknown model falls back to a one-time live probe.
53
53
  _KNOWN_DIMS = {
54
+ "bge-m3": 1024,
54
55
  "nomic-embed-text": 768,
55
56
  "mxbai-embed-large": 1024,
56
57
  "all-minilm": 384,
@@ -61,12 +62,131 @@ _KNOWN_DIMS = {
61
62
  "gte-small": 384,
62
63
  "gte-base": 768,
63
64
  "gte-large": 1024,
65
+ "e5-large": 1024,
66
+ "multilingual-e5-large": 1024,
64
67
  "text-embedding-3-small": 1536,
65
68
  "text-embedding-3-large": 3072,
66
69
  "text-embedding-ada-002": 1536,
67
70
  }
68
71
 
69
72
 
73
+ PRODUCTION_PROVIDER_PROFILES: Dict[str, Dict[str, Any]] = {
74
+ "local:bge-m3": {
75
+ "id": "local:bge-m3",
76
+ "provider": "mlx",
77
+ "model": "bge-m3",
78
+ "dimensions": 1024,
79
+ "grade": "production",
80
+ "family": "local",
81
+ "label": "BGE-M3 local",
82
+ "detail": "Multilingual semantic embeddings for local retrieval.",
83
+ },
84
+ "local:nomic-embed-text": {
85
+ "id": "local:nomic-embed-text",
86
+ "provider": "ollama",
87
+ "model": "nomic-embed-text",
88
+ "dimensions": 768,
89
+ "grade": "production",
90
+ "family": "local",
91
+ "label": "Nomic Embed Text local",
92
+ "detail": "General-purpose local semantic embeddings.",
93
+ },
94
+ "local:e5-large": {
95
+ "id": "local:e5-large",
96
+ "provider": "mlx",
97
+ "model": "e5-large",
98
+ "dimensions": 1024,
99
+ "grade": "production",
100
+ "family": "local",
101
+ "label": "E5 Large local",
102
+ "detail": "High-recall local retrieval profile.",
103
+ },
104
+ "local:gte-large": {
105
+ "id": "local:gte-large",
106
+ "provider": "mlx",
107
+ "model": "gte-large",
108
+ "dimensions": 1024,
109
+ "grade": "production",
110
+ "family": "local",
111
+ "label": "GTE Large local",
112
+ "detail": "Large local semantic embedding profile.",
113
+ },
114
+ "ollama:nomic-embed-text": {
115
+ "id": "ollama:nomic-embed-text",
116
+ "provider": "ollama",
117
+ "model": "nomic-embed-text",
118
+ "dimensions": 768,
119
+ "grade": "production",
120
+ "family": "ollama",
121
+ "label": "Ollama Nomic Embed Text",
122
+ "detail": "Production semantic embeddings through Ollama.",
123
+ },
124
+ "ollama:mxbai-embed-large": {
125
+ "id": "ollama:mxbai-embed-large",
126
+ "provider": "ollama",
127
+ "model": "mxbai-embed-large",
128
+ "dimensions": 1024,
129
+ "grade": "production",
130
+ "family": "ollama",
131
+ "label": "Ollama MXBAI Embed Large",
132
+ "detail": "High-quality local semantic embeddings through Ollama.",
133
+ },
134
+ "ollama:bge-m3": {
135
+ "id": "ollama:bge-m3",
136
+ "provider": "ollama",
137
+ "model": "bge-m3",
138
+ "dimensions": 1024,
139
+ "grade": "production",
140
+ "family": "ollama",
141
+ "label": "Ollama BGE-M3-compatible",
142
+ "detail": "BGE-M3-compatible providers exposed through Ollama.",
143
+ },
144
+ "mlx:bge-m3": {
145
+ "id": "mlx:bge-m3",
146
+ "provider": "mlx",
147
+ "model": "bge-m3",
148
+ "dimensions": 1024,
149
+ "grade": "production",
150
+ "family": "mlx",
151
+ "label": "MLX BGE-M3",
152
+ "detail": "Apple Silicon optimized local embeddings.",
153
+ },
154
+ "openai:text-embedding-3-small": {
155
+ "id": "openai:text-embedding-3-small",
156
+ "provider": "openai",
157
+ "model": "text-embedding-3-small",
158
+ "dimensions": 1536,
159
+ "grade": "production",
160
+ "family": "openai-compatible",
161
+ "label": "OpenAI-compatible small",
162
+ "detail": "OpenAI-compatible /v1/embeddings endpoint.",
163
+ },
164
+ "openai:text-embedding-3-large": {
165
+ "id": "openai:text-embedding-3-large",
166
+ "provider": "openai",
167
+ "model": "text-embedding-3-large",
168
+ "dimensions": 3072,
169
+ "grade": "production",
170
+ "family": "openai-compatible",
171
+ "label": "OpenAI-compatible large",
172
+ "detail": "Highest-dimensional OpenAI-compatible embedding profile.",
173
+ },
174
+ }
175
+
176
+
177
+ def embedding_provider_profiles() -> List[Dict[str, Any]]:
178
+ return [dict(PRODUCTION_PROVIDER_PROFILES[key]) for key in sorted(PRODUCTION_PROVIDER_PROFILES)]
179
+
180
+
181
+ def resolve_embedding_profile(profile: str) -> Dict[str, Any]:
182
+ if not profile:
183
+ return {}
184
+ key = str(profile).strip().lower()
185
+ if key in PRODUCTION_PROVIDER_PROFILES:
186
+ return dict(PRODUCTION_PROVIDER_PROFILES[key])
187
+ raise ValueError(f"unknown embedding profile: {profile!r}")
188
+
189
+
70
190
  def _guess_dim(model: str, default: int) -> int:
71
191
  key = str(model or "").split("/")[-1].strip().lower()
72
192
  key = key.split(":")[0]
@@ -498,5 +618,8 @@ __all__ = [
498
618
  "ResolvedEmbedder",
499
619
  "build_embedding_provider",
500
620
  "resolve_embedder",
621
+ "resolve_embedding_profile",
622
+ "embedding_provider_profiles",
623
+ "PRODUCTION_PROVIDER_PROFILES",
501
624
  "PROVIDER_TYPES",
502
625
  ]
@@ -18,7 +18,7 @@ from pathlib import Path
18
18
  from typing import Any, Callable, Dict, Iterable, List, Optional
19
19
 
20
20
 
21
- WORKSPACE_OS_VERSION = "3.0.1"
21
+ WORKSPACE_OS_VERSION = "3.1.0"
22
22
 
23
23
  # Workspace types separate single-user Personal workspaces from shared
24
24
  # Organization workspaces. Both keep the same local-first JSON store; the type
@@ -73,7 +73,7 @@ from latticeai.services.workspace_service import WorkspaceService
73
73
  from latticeai.services.model_service import ModelService
74
74
  from latticeai.services.chat_service import ChatService
75
75
  from latticeai.services.search_service import SearchService
76
- from latticeai.core.embedding_providers import resolve_embedder
76
+ from latticeai.core.embedding_providers import resolve_embedder, resolve_embedding_profile
77
77
  from latticeai.services.agent_runtime import AgentRuntime
78
78
  from latticeai.services.model_runtime import (
79
79
  CLOUD_VERIFY_TTL_SECONDS,
@@ -251,15 +251,26 @@ SSO_FILE = DATA_DIR / "sso_config.json"
251
251
  # Resolve the configured embedding provider once at startup. Degrades to the
252
252
  # offline hash fallback when the requested provider is unavailable, while
253
253
  # recording the requested-vs-active provider for the Embeddings status surface.
254
+ try:
255
+ EMBEDDING_PROFILE = resolve_embedding_profile(CONFIG.embedding_profile)
256
+ except ValueError as exc:
257
+ logging.warning("Embedding profile ignored: %s", exc)
258
+ EMBEDDING_PROFILE = {}
259
+ _embedding_provider = CONFIG.embedding_provider
260
+ _embedding_model = CONFIG.embedding_model or str(EMBEDDING_PROFILE.get("model") or "")
261
+ _embedding_dim = CONFIG.embedding_dim or int(EMBEDDING_PROFILE.get("dimensions") or 0)
262
+ if CONFIG.embedding_profile and CONFIG.embedding_provider in {"", "hash", "local", "fallback"}:
263
+ _embedding_provider = str(EMBEDDING_PROFILE.get("provider") or CONFIG.embedding_provider)
264
+
254
265
  EMBEDDER = resolve_embedder(
255
- CONFIG.embedding_provider,
256
- model=CONFIG.embedding_model,
266
+ _embedding_provider,
267
+ model=_embedding_model,
257
268
  base_url=CONFIG.embedding_base_url,
258
269
  api_key=CONFIG.embedding_api_key,
259
- dim=CONFIG.embedding_dim,
270
+ dim=_embedding_dim,
260
271
  timeout=CONFIG.embedding_timeout,
261
272
  extra={"target": CONFIG.embedding_custom_target},
262
- probe=CONFIG.embedding_provider not in {"", "hash", "local", "fallback"},
273
+ probe=_embedding_provider not in {"", "hash", "local", "fallback"},
263
274
  )
264
275
  if EMBEDDER.fell_back:
265
276
  logging.warning("Embedding provider %s unavailable: %s", EMBEDDER.requested, EMBEDDER.detail)
@@ -805,6 +816,8 @@ def _require_local_approval(
805
816
 
806
817
  def require_admin(request: Request) -> tuple[str, Dict]:
807
818
  users = load_users()
819
+ if not REQUIRE_AUTH:
820
+ return "", users
808
821
  token = _extract_bearer_token(request)
809
822
  if token:
810
823
  email = get_session_email(token)
@@ -1100,6 +1113,7 @@ app.include_router(create_auth_router(
1100
1113
  get_sso_settings=get_sso_settings, get_sso_discovery=_get_sso_discovery,
1101
1114
  public_sso_config=public_sso_config,
1102
1115
  open_registration=OPEN_REGISTRATION, session_ttl=_SESSION_TTL,
1116
+ require_auth=REQUIRE_AUTH,
1103
1117
  ))
1104
1118
 
1105
1119
  def _graph_stats_safe():
@@ -1387,9 +1401,11 @@ app.include_router(create_chat_router(
1387
1401
  ))
1388
1402
 
1389
1403
  def _embedding_info() -> dict:
1390
- from latticeai.core.embedding_providers import PROVIDER_TYPES
1404
+ from latticeai.core.embedding_providers import PROVIDER_TYPES, embedding_provider_profiles
1391
1405
  info = EMBEDDER.as_dict()
1392
1406
  info["available_providers"] = list(PROVIDER_TYPES)
1407
+ info["profile"] = CONFIG.embedding_profile or ""
1408
+ info["profiles"] = embedding_provider_profiles()
1393
1409
  return info
1394
1410
 
1395
1411
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ltcai",
3
- "version": "3.0.1",
3
+ "version": "3.1.0",
4
4
  "description": "Lattice AI v3 local-first AI workspace platform with knowledge graph, vector index, hybrid search, agents, and workspace modes.",
5
5
  "homepage": "https://github.com/TaeSooPark-PTS/LatticeAI#readme",
6
6
  "repository": {
@@ -17,9 +17,10 @@
17
17
  "scripts": {
18
18
  "start": "LTCAI",
19
19
  "dev": "python3 ltcai_cli.py --reload",
20
- "build": "npm run build:python",
20
+ "build": "npm run build:assets && npm run build:python",
21
+ "build:assets": "node scripts/build_v3_assets.mjs",
21
22
  "build:python": "python3 -m build",
22
- "check:python": "python3 -m py_compile ltcai_cli.py server.py latticeai/server_app.py latticeai/api/chat.py latticeai/api/computer_use.py latticeai/api/deps.py latticeai/api/garden.py latticeai/api/local_files.py latticeai/api/permissions.py latticeai/api/setup.py latticeai/api/static_routes.py latticeai/api/tools.py latticeai/api/plugins.py latticeai/api/workflow_designer.py latticeai/api/agents.py latticeai/api/realtime.py latticeai/api/marketplace.py latticeai/api/search.py latticeai/services/search_service.py latticeai/core/local_embeddings.py latticeai/core/embedding_providers.py latticeai/services/agent_runtime.py latticeai/core/config.py latticeai/api/admin.py latticeai/services/app_context.py latticeai/services/model_runtime.py latticeai/services/model_catalog.py latticeai/services/model_recommendation.py latticeai/services/tool_dispatch.py latticeai/services/upload_service.py latticeai/core/tool_registry.py latticeai/core/enterprise.py latticeai/core/enterprise_admin.py latticeai/core/agent_prompts.py latticeai/core/workspace_os.py latticeai/core/plugins.py latticeai/core/marketplace.py latticeai/core/workflow_engine.py latticeai/core/multi_agent.py latticeai/core/realtime.py knowledge_graph.py knowledge_graph_api.py local_knowledge_api.py llm_router.py p_reinforce.py telegram_bot.py tools.py codex_telegram_bot.py",
23
+ "check:python": "python3 -m py_compile ltcai_cli.py server.py latticeai/server_app.py latticeai/api/auth.py latticeai/api/chat.py latticeai/api/computer_use.py latticeai/api/deps.py latticeai/api/garden.py latticeai/api/local_files.py latticeai/api/permissions.py latticeai/api/setup.py latticeai/api/static_routes.py latticeai/api/tools.py latticeai/api/plugins.py latticeai/api/workflow_designer.py latticeai/api/agents.py latticeai/api/realtime.py latticeai/api/marketplace.py latticeai/api/search.py latticeai/services/search_service.py latticeai/core/local_embeddings.py latticeai/core/embedding_providers.py latticeai/services/agent_runtime.py latticeai/core/config.py latticeai/api/admin.py latticeai/services/app_context.py latticeai/services/model_runtime.py latticeai/services/model_catalog.py latticeai/services/model_recommendation.py latticeai/services/tool_dispatch.py latticeai/services/upload_service.py latticeai/core/tool_registry.py latticeai/core/enterprise.py latticeai/core/enterprise_admin.py latticeai/core/agent_prompts.py latticeai/core/workspace_os.py latticeai/core/plugins.py latticeai/core/marketplace.py latticeai/core/workflow_engine.py latticeai/core/multi_agent.py latticeai/core/realtime.py knowledge_graph.py knowledge_graph_api.py local_knowledge_api.py llm_router.py p_reinforce.py telegram_bot.py tools.py codex_telegram_bot.py",
23
24
  "lint": "node --check static/scripts/account.js && node --check static/scripts/admin.js && node --check static/scripts/chat.js && node --check static/scripts/graph.js && node --check static/scripts/platform.js && node --check static/scripts/ux.js && node --check static/scripts/workspace.js && node --check tests/visual/mock_server.cjs && node --check tests/visual/v3.spec.js && npm run lint:v3",
24
25
  "lint:v3": "node scripts/lint_v3.mjs",
25
26
  "typecheck": "cd vscode-extension && npm run build",
@@ -32,7 +33,7 @@
32
33
  "capture:skills": "node scripts/capture/capture_skills.js",
33
34
  "capture:enterprise": "node scripts/capture/capture_enterprise.js",
34
35
  "capture:onboarding": "node scripts/capture/capture_onboarding.js",
35
- "release:artifacts": "npm run build:python && npm pack && cd vscode-extension && npm run package:vsix",
36
+ "release:artifacts": "npm run build:assets && npm run build:python && npm pack && cd vscode-extension && npm run package:vsix",
36
37
  "release:validate": "python3 scripts/validate_release_artifacts.py $npm_package_version --require-vsix --require-tgz",
37
38
  "publish:npm": "npm pack && npm publish ltcai-$npm_package_version.tgz --access public",
38
39
  "publish:pypi": "npm run build:python && python3 -m twine upload --skip-existing dist/ltcai-$npm_package_version.tar.gz dist/ltcai-$npm_package_version-py3-none-any.whl",
@@ -93,7 +94,11 @@
93
94
  "static/v3/",
94
95
  "static/icons/",
95
96
  "plugins/",
97
+ "scripts/",
96
98
  "docs/",
99
+ "!docs/images/tmp_frames/",
100
+ "!**/__pycache__/",
101
+ "!**/*.pyc",
97
102
  "requirements.txt",
98
103
  "README.md"
99
104
  ],