ltcai 1.1.0 → 1.2.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.
package/README.md CHANGED
@@ -36,6 +36,25 @@ Automatic knowledge graph
36
36
  Graph-aware chat, snapshots, memory, agents, workflows, skills, and timeline
37
37
  ```
38
38
 
39
+ ### New in 1.2.0: Server App Modularization
40
+
41
+ - **server_app.py modularized** — Workspace/Organization and health/engine
42
+ endpoints extracted into dedicated routers (`latticeai/api/*`) backed by a
43
+ service layer (`latticeai/services/*`); `server_app` is now app assembly +
44
+ router include (~6,585 → ~5,948 lines)
45
+ - **Routers / services split** — `create_workspace_router`,
46
+ `create_health_router`, `WorkspaceService`, `ModelService`, `ChatService`
47
+ - **Workspace API service layer** — scope resolution and role/permission checks
48
+ centralized in `WorkspaceService`
49
+ - **Workspace / org guardrails** — non-members can't read/write org data,
50
+ viewers can't write, owners/admins manage members; no-auth local owner
51
+ fallback preserved
52
+ - **Health / model / chat modularization** — `/health`, `/mode`,
53
+ `/runtime_features`, `/engines` via the health router; chat trace recording
54
+ via the chat service (streaming behavior unchanged)
55
+ - **Compatibility preserved** — `server:app` import path, all API routes, CLI,
56
+ Knowledge Graph / Admin / Security routers, and VS Code integration unchanged
57
+
39
58
  ### New in 1.1.0: Organization Workspace Foundation
40
59
 
41
60
  - **Organization Workspace** alongside Personal Workspace — create shared org
package/docs/CHANGELOG.md CHANGED
@@ -1,5 +1,54 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.2.0] - 2026-05-31
4
+
5
+ > Server app modularization (routers + service layer) and workspace/org guardrail hardening.
6
+
7
+ ### Changed
8
+
9
+ - **server_app.py modularization (phase 2)** — reduced
10
+ `latticeai/server_app.py` from ~6,585 to ~5,948 lines by extracting the
11
+ Workspace OS / Organization API and the health/engine-summary endpoints into
12
+ dedicated routers backed by a new service layer. `server_app` now focuses on
13
+ app assembly, lifespan, middleware, and router include. The historical
14
+ `server:app` import path, all API paths, and request/response shapes are
15
+ unchanged.
16
+ - **Workspace/Organization guardrails strengthened** — workspace-scoped reads
17
+ and writes now go through `WorkspaceService`, which gates explicitly-named
18
+ workspaces: non-members cannot read or write organization data, viewers
19
+ cannot write, members can write, and only owners/admins manage members. The
20
+ no-auth local-owner fallback for ownerless org workspaces is preserved, but a
21
+ *named* stranger never bypasses membership. `set_active_workspace` continues
22
+ to enforce membership.
23
+
24
+ ### Added
25
+
26
+ - **New API routers** — `latticeai/api/workspace.py`
27
+ (`create_workspace_router`) and `latticeai/api/health.py`
28
+ (`create_health_router`), mirroring the existing auth/admin router-factory
29
+ convention (no import cycle: routers receive dependencies, never import the
30
+ app).
31
+ - **New service layer** — `latticeai/services/workspace_service.py`
32
+ (`WorkspaceService`: scope resolution + permission guardrails),
33
+ `latticeai/services/model_service.py` (`ModelService`: health/engine summary
34
+ payloads), and `latticeai/services/chat_service.py` (`ChatService`: history +
35
+ answer-trace seam; the streaming chat path is unchanged and now records traces
36
+ through this façade).
37
+ - **Shared-global areas made explicit** — the local knowledge graph and
38
+ installed skills remain machine-global shared state (not partitioned per
39
+ workspace); this is now surfaced in `WorkspaceService.SHARED_GLOBAL_AREAS`,
40
+ the `/workspace/os` summary (`shared_global_areas`), and code comments.
41
+ - **Startup/modularization tests** — `tests/unit/test_server_app_modularization.py`
42
+ (import path, router registration, key route presence, no import cycle) and
43
+ `tests/unit/test_workspace_service.py` (read/write/member guardrails).
44
+
45
+ ### Notes
46
+
47
+ - Release metadata aligned to `1.2.0`; `APP_VERSION` continues to derive from
48
+ `WORKSPACE_OS_VERSION` and `/health` reports `1.2.0`.
49
+ - CI release hardening from 1.0.1/1.1.0 is retained (VSIX compile guard, Node.js
50
+ 24, version-scoped artifact validation — no `dist/*` glob).
51
+
3
52
  ## [1.1.0] - 2026-05-31
4
53
 
5
54
  > Organization Workspace foundation, open-core Enterprise seam, and CI/release hardening.
@@ -1,3 +1,3 @@
1
1
  """Lattice AI - modular server package."""
2
2
 
3
- __version__ = "1.1.0"
3
+ __version__ = "1.2.0"
@@ -0,0 +1,45 @@
1
+ """Health / status / engine-summary router.
2
+
3
+ Extracted from ``server_app.py`` in v1.2.0. Paths unchanged: ``/health``,
4
+ ``/mode``, ``/runtime_features``, ``/engines`` (GET). Heavier engine *mutation*
5
+ endpoints (install / verify-cloud / pull-model) stay in server_app for now.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import asyncio
11
+ from typing import Any, Callable, List, Optional
12
+
13
+ from fastapi import APIRouter, Request
14
+
15
+
16
+ def create_health_router(
17
+ *,
18
+ model_service,
19
+ engine_status: Callable[[], List[dict]],
20
+ get_current_user: Callable[[Request], Optional[str]],
21
+ require_auth: bool,
22
+ app_version: str,
23
+ app_mode: str,
24
+ ) -> APIRouter:
25
+ router = APIRouter()
26
+ svc = model_service
27
+
28
+ @router.get("/health")
29
+ async def health(request: Request):
30
+ base = svc.health_base(version=app_version, mode=app_mode)
31
+ if not get_current_user(request) and require_auth:
32
+ return base
33
+ engines = await asyncio.to_thread(engine_status)
34
+ return svc.health_full(base, engines)
35
+
36
+ @router.get("/mode")
37
+ @router.get("/runtime_features")
38
+ async def mode():
39
+ return svc.runtime()
40
+
41
+ @router.get("/engines")
42
+ async def engines():
43
+ return svc.engines_payload(await asyncio.to_thread(engine_status))
44
+
45
+ return router