ltcai 7.8.0 → 7.9.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
@@ -1,6 +1,6 @@
1
1
  # Lattice AI
2
2
 
3
- **Lattice AI 7.8 is the glanceable local-first Digital Brain product. It keeps your knowledge durable across any AI model, with Brain Chat Home rebuilt around immediate use instead of dashboard clutter.**
3
+ **Lattice AI 7.9 is the local-first Digital Brain product with cleaner runtime boundaries. It keeps your knowledge durable across any AI model, with Brain Chat Home ready for immediate use and agent execution hardened behind explicit runtime ports.**
4
4
 
5
5
  **Lattice AI는 모델이 바뀌어도 내 지식과 맥락을 보존하는 로컬 우선 AI 브레인입니다.**
6
6
 
@@ -11,7 +11,7 @@ downloads, update checks, and other external communication happen only after
11
11
  explicit consent.
12
12
 
13
13
  It is not a ChatGPT clone, a model launcher, a graph database, or a note app.
14
- It is the finished private AI memory layer wrapped in a Living Brain experience — now with a cleaner 7.8 Brain Chat Home.
14
+ It is the finished private AI memory layer wrapped in a Living Brain experience — now with a clearer 7.9 agent-runtime boundary.
15
15
 
16
16
  [![PyPI Version](https://img.shields.io/pypi/v/ltcai?label=PyPI)](https://pypi.org/project/ltcai/)
17
17
  [![npm Version](https://img.shields.io/npm/v/ltcai?label=npm)](https://www.npmjs.com/package/ltcai)
@@ -64,7 +64,7 @@ You need Lattice AI when:
64
64
 
65
65
  ## Living Brain Flow
66
66
 
67
- The screenshots below are release evidence captures. The 7.8 line keeps the
67
+ The screenshots below are release evidence captures. The 7.9 line keeps the
68
68
  same first-run flow and rebuilds the Brain Chat Home layout so chat and the
69
69
  composer are the first visible action.
70
70
 
@@ -78,28 +78,28 @@ confirm owner, check the computer, choose the Brain voice.
78
78
  Choose the owner of the Brain. The profile is not a SaaS account by default; it
79
79
  is the local identity for the knowledge you keep.
80
80
 
81
- ![Login](output/release/v7.7.0/screenshots/01-login.png)
81
+ ![Login](output/release/v7.8.0/screenshots/01-login.png)
82
82
 
83
83
  ### 3. Environment Analysis
84
84
 
85
85
  See what kind of local AI experience this computer can support before choosing a
86
86
  model.
87
87
 
88
- ![Environment Analysis](output/release/v7.7.0/screenshots/02-environment-analysis.png)
88
+ ![Environment Analysis](output/release/v7.8.0/screenshots/02-environment-analysis.png)
89
89
 
90
90
  ### 4. Recommended Models
91
91
 
92
92
  Start with a short list: safest recommendation, faster model, stronger model.
93
93
  Advanced details stay available without overwhelming first-time users.
94
94
 
95
- ![Recommended Models](output/release/v7.7.0/screenshots/03-recommended-models.png)
95
+ ![Recommended Models](output/release/v7.8.0/screenshots/03-recommended-models.png)
96
96
 
97
97
  ### 5. Install And Load
98
98
 
99
99
  Download and load only after consent. Lattice explains model size, local
100
100
  execution, and network use before work starts.
101
101
 
102
- ![Install and Load](output/release/v7.7.0/screenshots/04-install-load-progress.png)
102
+ ![Install and Load](output/release/v7.8.0/screenshots/04-install-load-progress.png)
103
103
 
104
104
  ### 6. Brain Chat
105
105
 
@@ -107,14 +107,14 @@ Talk normally. Useful decisions and context become memory, then appear later as
107
107
  topics, relationships, graph structure, and the concentric memory rings around
108
108
  the Brain.
109
109
 
110
- ![Brain Chat Home](output/release/v7.7.0/screenshots/05-brain-chat-home.png)
110
+ ![Brain Chat Home](output/release/v7.8.0/screenshots/05-brain-chat-home.png)
111
111
 
112
112
  ### 7. Review Center
113
113
 
114
114
  Automation results are staged for review before they become durable decisions.
115
115
  Snooze, unsnooze, run now, approve, and dismiss actions stay explicit.
116
116
 
117
- ![Review Center](output/release/v7.7.0/screenshots/13-review-center.png)
117
+ ![Review Center](output/release/v7.8.0/screenshots/13-review-center.png)
118
118
 
119
119
  ## Brain Depths
120
120
 
@@ -130,10 +130,10 @@ The user travels inward from everyday memory to deeper structure:
130
130
 
131
131
  Walkthrough:
132
132
 
133
- ![v7.7.0 Living Brain walkthrough](output/release/v7.7.0/gifs/v7.7.0-living-brain-walkthrough.gif)
133
+ ![v7.8.0 Living Brain walkthrough](output/release/v7.8.0/gifs/v7.8.0-living-brain-walkthrough.gif)
134
134
 
135
135
  Screenshot index and capture notes:
136
- [output/release/v7.7.0/SCREENSHOT_INDEX.md](output/release/v7.7.0/SCREENSHOT_INDEX.md)
136
+ [output/release/v7.8.0/SCREENSHOT_INDEX.md](output/release/v7.8.0/SCREENSHOT_INDEX.md)
137
137
 
138
138
  ## Install
139
139
 
@@ -210,33 +210,36 @@ See [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md) for developer workflow details.
210
210
 
211
211
  ## Current Release
212
212
 
213
- The current release is **7.8.0 — Brain Chat Home UX Simplification**:
214
-
215
- - Brain Chat Home now opens with chat, starter prompts, and the composer as the
216
- first action. Source ingestion, readiness, proof, timeline, and care controls
217
- move behind a single utility drawer instead of occupying the first viewport.
218
- - The default Brain surface now keeps workspace navigation visible, removes
219
- permanent marketing intro copy, and only reveals deep memory controls after
220
- the user chooses to travel deeper.
221
- - Obsolete Brain conversation and first-run guide components were removed so the
222
- canonical Brain/onboarding implementation is the only path.
213
+ The current release is **7.9.0 — Agent Runtime Boundary Hardening**:
214
+
215
+ - The single-agent state machine is now named `SingleAgentRuntime`, while the
216
+ historical `AgentRuntime` import remains as a compatibility alias.
217
+ - The product AgentRuntime facade in `lattice_brain.runtime.agent_runtime`
218
+ remains the unambiguous `/agents` execution and observability boundary.
219
+ - Agent rollback is now an injected runtime port wired through
220
+ `ToolDispatchService`, so the core state machine no longer shells out directly.
221
+ - Both runtime surfaces expose a `runtime-boundary/v1` descriptor so tests and
222
+ API clients can identify the owning execution boundary without relying on
223
+ ambiguous class names.
224
+ - A shared `RuntimeBoundaryProtocol` now fixes the common inspection surface
225
+ while letting each runtime keep its own execution methods.
223
226
  - Product readiness is machine-checkable through `product_readiness()`, which
224
227
  composes the architecture contract with exact artifact/docs/workflow evidence.
225
228
  - CI and release workflows now run frontend lint/typecheck/build gates plus the
226
- 7.8 product readiness score before a tag can be treated as release-safe.
229
+ 7.9 product readiness score before a tag can be treated as release-safe.
227
230
 
228
- Expected artifacts for 7.8.0 release must use exact filenames:
231
+ Expected artifacts for 7.9.0 release must use exact filenames:
229
232
 
230
- - `dist/ltcai-7.8.0-py3-none-any.whl`
231
- - `dist/ltcai-7.8.0.tar.gz`
232
- - `ltcai-7.8.0.tgz`
233
- - `dist/ltcai-7.8.0.vsix`
234
- - `src-tauri/target/release/bundle/dmg/Lattice AI_7.8.0_aarch64.dmg`
233
+ - `dist/ltcai-7.9.0-py3-none-any.whl`
234
+ - `dist/ltcai-7.9.0.tar.gz`
235
+ - `ltcai-7.9.0.tgz`
236
+ - `dist/ltcai-7.9.0.vsix`
237
+ - `src-tauri/target/release/bundle/dmg/Lattice AI_7.9.0_aarch64.dmg`
235
238
 
236
- Do not upload `dist/*`. Package registry publishing remains owner-run.
239
+ Do not use wildcard artifact uploads. Package registry publishing remains owner-run.
237
240
 
238
241
  See [docs/ROADMAP_RECOMMENDATIONS.md](docs/ROADMAP_RECOMMENDATIONS.md) for the
239
- strategic roadmap slices applied through 7.8.0 and the follow-up tracks.
242
+ strategic roadmap slices applied through 7.9.0 and the follow-up tracks.
240
243
 
241
244
  ## Known Limitations
242
245
 
@@ -253,6 +256,7 @@ strategic roadmap slices applied through 7.8.0 and the follow-up tracks.
253
256
 
254
257
  | Version | Theme |
255
258
  | --- | --- |
259
+ | 7.9.0 | Agent Runtime Boundary Hardening: explicit `SingleAgentRuntime`, compatibility alias preservation, injected rollback port, and release/readiness docs aligned to the product AgentRuntime facade |
256
260
  | 7.8.0 | Brain Chat Home UX Simplification: chat-first first viewport, visible workspace navigation, collapsed source/status utilities, hidden default depth controls, and removal of obsolete Brain UX components |
257
261
  | 7.7.0 | Complete Product Polish: command-center Brain Home, repaired Review Center evidence, exact 7.7 docs/artifacts, product readiness gate, and stronger CI/release checks |
258
262
  | 7.6.0 | Brain-Centered UX & Architecture Closure: Wake Brain first-run surface, concentric memory rings with direct depth controls, and machine-checkable closure of the two architecture/UX review files |
package/docs/CHANGELOG.md CHANGED
@@ -6,6 +6,21 @@ existed at that release.
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [7.9.0] - 2026-06-23
10
+
11
+ ### Changed
12
+ - Added `SingleAgentRuntime` as the explicit name for the legacy single-agent
13
+ state machine while preserving `AgentRuntime` as a compatibility alias.
14
+ - Updated tool dispatch to build `SingleAgentRuntime` directly.
15
+ - Moved single-agent git rollback behind an injected `rollback_file` port owned
16
+ by `ToolDispatchService`, keeping shell execution out of the core state
17
+ machine.
18
+ - Added a shared `runtime-boundary/v1` descriptor so product and single-agent
19
+ runtime boundaries are machine-readable in config/tests.
20
+ - Added `RuntimeBoundaryProtocol` as the minimal shared inspection surface for
21
+ runtime-boundary-aware dependency injection.
22
+ - Updated architecture and product readiness targets to 7.9.0.
23
+
9
24
  ## [7.8.0] - 2026-06-22
10
25
 
11
26
  ### Changed
@@ -23,6 +38,8 @@ existed at that release.
23
38
  - Moved draft onboarding polish out of inline styles and into the shared design
24
39
  stylesheet with responsive behavior and bilingual copy.
25
40
  - Updated architecture and product readiness targets to 7.8.0.
41
+ - Refreshed 7.8.0 release screenshots, walkthrough video/GIF, and capture
42
+ notes under `output/release/v7.8.0/`.
26
43
 
27
44
  ## [7.7.0] - 2026-06-22
28
45
 
@@ -95,5 +95,4 @@ For user-facing, API, runtime, release, or packaging changes, check:
95
95
  - `docs/LEGACY_COMPATIBILITY.md` when root compatibility files change
96
96
 
97
97
  Release/publish examples must use exact target-version filenames. Do not
98
- document wildcard upload commands such as `dist/*`.
99
-
98
+ document wildcard artifact upload commands.
@@ -2,7 +2,7 @@
2
2
 
3
3
  The Multi-Agent Runtime is the **orchestration layer** introduced in v2.0.0 and
4
4
  operationalized in v2.2.0. It sits
5
- *above* the v1.x single-agent state machine ([`AgentRuntime`](../latticeai/core/agent.py))
5
+ *above* the v1.x single-agent state machine ([`SingleAgentRuntime`](../latticeai/core/agent.py))
6
6
  and coordinates a pipeline of named **roles** that hand off work to one another,
7
7
  retry on a failing review, and emit a fully observable, replayable timeline.
8
8
 
@@ -34,20 +34,21 @@ objects durable and inspectable:
34
34
 
35
35
  ## How it relates to the v1 single-agent runtime
36
36
 
37
- v1.x shipped a single-agent state machine — `AgentRuntime` driving
37
+ v1.x shipped a single-agent state machine — `SingleAgentRuntime` driving
38
38
  `PLAN → EXECUTE → VERIFY → DONE` (with `ROLLBACK` / `FAILED` recovery paths) over an
39
- injected `AgentDeps` port. That runtime is unchanged.
39
+ injected `AgentDeps` port. The historical `AgentRuntime` import remains as a
40
+ compatibility alias.
40
41
 
41
42
  v2.0 adds the *orchestration* layer on top: instead of one agent looping through
42
43
  internal phases, the `MultiAgentOrchestrator` drives a **pipeline of distinct roles**
43
44
  (researcher, planner, executor, reviewer, release) that hand off to one another and
44
45
  can rewind on a failing review. The two layers are complementary — the v2
45
46
  orchestrator coordinates roles; an individual role's runner could itself be backed by
46
- the v1 `AgentRuntime` loop or an LLM, but that is an implementation choice behind the
47
+ the v1 `SingleAgentRuntime` loop or an LLM, but that is an implementation choice behind the
47
48
  injected runner port.
48
49
 
49
50
  > **Compatibility.** The Multi-Agent Runtime is purely additive. The v1
50
- > `AgentRuntime` state machine and its `/agent` endpoints are untouched, and the v2
51
+ > `SingleAgentRuntime` state machine and its `/agent` endpoints are untouched, and the v2
51
52
  > API is namespaced under `/agents` (plural) so it never collides with the existing
52
53
  > single-agent `/agent` routes. Existing v1.x data is preserved; new runs are appended
53
54
  > to workspace state and the Knowledge Graph alongside it.
@@ -141,8 +141,9 @@ portable JSON representation (definition only — no run history or scope).
141
141
 
142
142
  ### 1.3 Multi-Agent Runtime 2.0 (`latticeai.core.multi_agent`)
143
143
 
144
- v1.x shipped a single-agent state machine (`latticeai.core.agent.AgentRuntime`:
145
- PLAN → EXECUTE → VERIFY → DONE). v2.0 adds the **orchestration** layer above it:
144
+ v1.x shipped a single-agent state machine (`latticeai.core.agent.SingleAgentRuntime`;
145
+ `latticeai.core.agent.AgentRuntime` remains a compatibility alias) that drives
146
+ PLAN → EXECUTE → VERIFY → DONE. v2.0 adds the **orchestration** layer above it:
146
147
  a pipeline of named roles that hand off to one another, retry on a failing
147
148
  review, and emit a structured timeline that drops straight into the Workspace
148
149
  timeline / Knowledge Graph.
@@ -26,7 +26,7 @@ from .storage import (
26
26
  storage_from_env,
27
27
  )
28
28
 
29
- __version__ = "7.8.0"
29
+ __version__ = "7.9.0"
30
30
 
31
31
  __all__ = [
32
32
  "AgentRuntime",
@@ -44,9 +44,9 @@ orchestrator, and the agent runtime service. Lazy-loaded so importing
44
44
  /agents/api/runtime/* , POST /agents (start via runtime.start or executor)
45
45
  api/chat.py
46
46
  from latticeai.services.tool_dispatch import build_agent_runtime
47
- -> latticeai/core/agent.py:AgentRuntime (별도 state/plan/transcript 머신, single-agent /agent 경로. dispatch_tool 만 공유)
47
+ -> latticeai/core/agent.py:SingleAgentRuntime (별도 state/plan/transcript 머신, single-agent /agent 경로. dispatch_tool 만 공유)
48
48
  latticeai/services/tool_dispatch.py:14
49
- from latticeai.core.agent import AgentRuntime as CoreAgentRuntime
49
+ from latticeai.core.agent import SingleAgentRuntime
50
50
  (tool governance + core single-agent용)
51
51
  latticeai/services/platform_runtime.py
52
52
  from lattice_brain.runtime.{hooks, multi_agent}
@@ -54,6 +54,7 @@ orchestrator, and the agent runtime service. Lazy-loaded so importing
54
54
 
55
55
  core/tool_registry.py (신규) + services/tool_dispatch.py 가 tool build 주도.
56
56
  lattice_brain/runtime 는 multi-agent + hooks + facade 에 집중. core/agent 는 chat/agent 단일 루프.
57
+ 기존 latticeai.core.agent.AgentRuntime import 는 SingleAgentRuntime 호환 alias 로 유지.
57
58
 
58
59
  이 매핑으로 중복 제거 및 wiring 명확화 완료 (feat(Act, automation) 방향).
59
60
  """
@@ -64,6 +65,7 @@ __all__ = [
64
65
  "AgentRuntime",
65
66
  "AgentRuntimeUnavailable",
66
67
  "MultiAgentOrchestrator",
68
+ "RuntimeBoundaryProtocol",
67
69
  "HooksRegistry",
68
70
  "dispatch_tool",
69
71
  ]
@@ -78,6 +80,10 @@ def __getattr__(name: str):
78
80
  from .multi_agent import MultiAgentOrchestrator
79
81
 
80
82
  return MultiAgentOrchestrator
83
+ if name == "RuntimeBoundaryProtocol":
84
+ from .contracts import RuntimeBoundaryProtocol
85
+
86
+ return RuntimeBoundaryProtocol
81
87
  if name in {"HooksRegistry", "dispatch_tool"}:
82
88
  from . import hooks
83
89
 
@@ -37,7 +37,13 @@ from .multi_agent import (
37
37
  MULTI_AGENT_VERSION,
38
38
  ROLE_AGENT_IDS,
39
39
  )
40
- from .contracts import contract_view, contract_views, extract_contract, multi_agent_contract
40
+ from .contracts import (
41
+ contract_view,
42
+ contract_views,
43
+ extract_contract,
44
+ multi_agent_contract,
45
+ runtime_boundary_contract,
46
+ )
41
47
 
42
48
  ROLE_DESCRIPTIONS = {
43
49
  "researcher": "Gathers workspace context and memory for the goal.",
@@ -91,10 +97,20 @@ class AgentRuntime:
91
97
  def _execution_mode(self) -> str:
92
98
  return "async" if self._run_executor is not None else "synchronous"
93
99
 
100
+ def boundary(self) -> Dict[str, Any]:
101
+ return runtime_boundary_contract(
102
+ name="AgentRuntime",
103
+ runtime="multi_agent",
104
+ entrypoint="lattice_brain.runtime.agent_runtime.AgentRuntime",
105
+ surface="/agents",
106
+ owns="product agent execution, observability, status, health, events, replay, and stop",
107
+ )
108
+
94
109
  # ── configuration ─────────────────────────────────────────────────────
95
110
  def config(self) -> Dict[str, Any]:
96
111
  return {
97
112
  "version": MULTI_AGENT_VERSION,
113
+ "boundary": self.boundary(),
98
114
  "roles": list(AGENT_ROLES),
99
115
  "default_pipeline": list(CORE_PIPELINE),
100
116
  "max_retries_cap": self._max_retries_cap,
@@ -30,7 +30,7 @@ from __future__ import annotations
30
30
 
31
31
  from dataclasses import dataclass, field
32
32
  from datetime import datetime
33
- from typing import Any, Dict, Iterable, List, Optional
33
+ from typing import Any, Dict, Iterable, List, Optional, Protocol, runtime_checkable
34
34
 
35
35
 
36
36
  def runtime_timestamp() -> str:
@@ -69,6 +69,8 @@ CONTRACT_VIEW_KEYS = (
69
69
  "blocking_reasons",
70
70
  )
71
71
 
72
+ RUNTIME_BOUNDARY_SCHEMA = "runtime-boundary/v1"
73
+
72
74
  _SCHEMA_FOR_KIND = {
73
75
  "agent_run": AGENT_RUN_SCHEMA,
74
76
  "workflow_run": WORKFLOW_RUN_SCHEMA,
@@ -223,6 +225,67 @@ def multi_agent_contract(
223
225
  ).as_dict()
224
226
 
225
227
 
228
+ @dataclass(frozen=True)
229
+ class RuntimeBoundaryContract:
230
+ """Machine-readable descriptor for an execution runtime boundary.
231
+
232
+ This is intentionally separate from run records: it lets tests, routers, and
233
+ docs assert which class owns which execution surface without importing the
234
+ wrong runtime by name.
235
+ """
236
+
237
+ name: str
238
+ runtime: str
239
+ entrypoint: str
240
+ surface: str
241
+ owns: str
242
+ compatibility_aliases: List[str] = field(default_factory=list)
243
+
244
+ def as_dict(self) -> Dict[str, Any]:
245
+ return {
246
+ "schema_version": RUNTIME_BOUNDARY_SCHEMA,
247
+ "name": self.name,
248
+ "runtime": self.runtime,
249
+ "entrypoint": self.entrypoint,
250
+ "surface": self.surface,
251
+ "owns": self.owns,
252
+ "compatibility_aliases": list(self.compatibility_aliases),
253
+ }
254
+
255
+
256
+ def runtime_boundary_contract(
257
+ *,
258
+ name: str,
259
+ runtime: str,
260
+ entrypoint: str,
261
+ surface: str,
262
+ owns: str,
263
+ compatibility_aliases: Optional[List[str]] = None,
264
+ ) -> Dict[str, Any]:
265
+ return RuntimeBoundaryContract(
266
+ name=name,
267
+ runtime=runtime,
268
+ entrypoint=entrypoint,
269
+ surface=surface,
270
+ owns=owns,
271
+ compatibility_aliases=list(compatibility_aliases or []),
272
+ ).as_dict()
273
+
274
+
275
+ @runtime_checkable
276
+ class RuntimeBoundaryProtocol(Protocol):
277
+ """Minimal shared surface for runtime boundary discovery.
278
+
279
+ Product ``AgentRuntime`` and core ``SingleAgentRuntime`` intentionally keep
280
+ different execution methods. This protocol only fixes the common inspection
281
+ surface that DI, readiness gates, and tests can depend on safely.
282
+ """
283
+
284
+ def boundary(self) -> Dict[str, Any]: ...
285
+
286
+ def config(self) -> Dict[str, Any]: ...
287
+
288
+
226
289
  def run_record_contract(run: Dict[str, Any], *, runtime: str = "multi_agent") -> Dict[str, Any]:
227
290
  """Build the family contract from a persisted agent run row."""
228
291
  run = dict(run or {})
@@ -21,7 +21,7 @@ from typing import Any, Callable, Dict, List, Optional
21
21
  from .contracts import multi_agent_contract
22
22
 
23
23
 
24
- MULTI_AGENT_VERSION = "7.8.0"
24
+ MULTI_AGENT_VERSION = "7.9.0"
25
25
 
26
26
  AGENT_ROLES = ("researcher", "planner", "executor", "reviewer", "release")
27
27
  CORE_PIPELINE = ("planner", "executor", "reviewer")
@@ -1,3 +1,3 @@
1
1
  """Lattice AI - modular server package."""
2
2
 
3
- __version__ = "7.8.0"
3
+ __version__ = "7.9.0"
@@ -1,7 +1,7 @@
1
- """Agent Runtime — the Discover→Plan→Implement→Verify state machine.
1
+ """Single-agent runtime — the Discover→Plan→Implement→Verify state machine.
2
2
 
3
- This module is the deep one: a small interface (``AgentDeps`` ports +
4
- ``AgentRuntime.run_to_completion``) over the whole multi-role agent loop
3
+ This module is the deep single-agent loop: a small interface (``AgentDeps`` ports +
4
+ ``SingleAgentRuntime.run_to_completion``) over the whole role-phased state machine
5
5
  (planner → executor → critic → rollback → memory). It carries no FastAPI,
6
6
  no globals, and no I/O of its own — every collaborator is injected through
7
7
  ``AgentDeps``.
@@ -23,14 +23,13 @@ from __future__ import annotations
23
23
  import json
24
24
  import logging
25
25
  import re
26
- import subprocess
27
26
  from dataclasses import dataclass
28
27
  from enum import Enum
29
28
  from pathlib import Path
30
29
  from typing import Any, Awaitable, Callable, Dict, FrozenSet, List, Optional
31
30
 
32
31
  from lattice_brain.runtime.hooks import dispatch_tool
33
- from lattice_brain.runtime.contracts import single_agent_contract
32
+ from lattice_brain.runtime.contracts import runtime_boundary_contract, single_agent_contract
34
33
  from tools import ToolError
35
34
 
36
35
 
@@ -92,7 +91,7 @@ def extract_action(raw: str) -> Dict:
92
91
 
93
92
  @dataclass
94
93
  class AgentDeps:
95
- """The ports an :class:`AgentRuntime` needs from the outside world.
94
+ """The ports a :class:`SingleAgentRuntime` needs from the outside world.
96
95
 
97
96
  Everything the state machine touches is here, so the loop can be exercised
98
97
  against fakes. See module docstring for the two-adapter rationale.
@@ -125,6 +124,11 @@ class AgentDeps:
125
124
  memory_updater_prompt: str
126
125
  agent_root: Path
127
126
 
127
+ # ── rollback port (optional) ─────────────────────────────────────
128
+ # Production injects this from the tool dispatch service so this pure
129
+ # state machine does not shell out directly. Tests can pass a recorder.
130
+ rollback_file: Optional[Callable[[str], Dict[str, Any]]] = None
131
+
128
132
  # ── lifecycle hooks port (optional) ──────────────────────────────
129
133
  # When present, every tool execution fires the shared pre_tool/post_tool
130
134
  # lifecycle, so the agent tool path no longer bypasses hooks.
@@ -137,12 +141,30 @@ class AgentDeps:
137
141
  brain_memory: Any = None
138
142
 
139
143
 
140
- class AgentRuntime:
144
+ class SingleAgentRuntime:
141
145
  """Drives the agent state machine over injected :class:`AgentDeps`."""
142
146
 
143
147
  def __init__(self, deps: AgentDeps) -> None:
144
148
  self.deps = deps
145
149
 
150
+ def boundary(self) -> Dict[str, Any]:
151
+ return runtime_boundary_contract(
152
+ name="SingleAgentRuntime",
153
+ runtime="single_agent",
154
+ entrypoint="latticeai.core.agent.SingleAgentRuntime",
155
+ surface="/agent",
156
+ owns="single-agent PLAN / EXECUTE / VERIFY state machine over injected ports",
157
+ compatibility_aliases=["latticeai.core.agent.AgentRuntime"],
158
+ )
159
+
160
+ def config(self) -> Dict[str, Any]:
161
+ return {
162
+ "boundary": self.boundary(),
163
+ "states": [state.value for state in AgentState],
164
+ "terminal_states": sorted(state.value for state in AGENT_TERMINAL_STATES),
165
+ "execution_mode": "injected_ports",
166
+ }
167
+
146
168
  def contract(self, ctx: AgentRunContext, req: Any, *, run_id: Optional[str] = None) -> Dict[str, Any]:
147
169
  """Expose the shared agent-run contract for the single-agent loop."""
148
170
  return single_agent_contract(ctx=ctx, goal=getattr(req, "message", ""), run_id=run_id)
@@ -405,12 +427,11 @@ class AgentRuntime:
405
427
  path = result.get("path") or (step.get("args") or {}).get("path", "")
406
428
  if not path:
407
429
  continue
430
+ if d.rollback_file is None:
431
+ rolled.append({"path": path, "ok": False, "error": "rollback_file port is not configured"})
432
+ continue
408
433
  try:
409
- r = subprocess.run(
410
- ["git", "checkout", "--", path], cwd=str(d.agent_root),
411
- capture_output=True, text=True, timeout=10,
412
- )
413
- rolled.append({"path": path, "ok": r.returncode == 0, "stderr": r.stderr[:200]})
434
+ rolled.append(d.rollback_file(str(path)))
414
435
  except Exception as exc:
415
436
  rolled.append({"path": path, "ok": False, "error": str(exc)})
416
437
 
@@ -491,3 +512,9 @@ class AgentRuntime:
491
512
  ctx.state = AgentState.FAILED
492
513
 
493
514
  ctx.state_history.append(ctx.state.value)
515
+
516
+
517
+ # Backward compatibility: external callers historically imported
518
+ # ``latticeai.core.agent.AgentRuntime`` for the single-agent state machine.
519
+ # The product/runtime facade lives at ``lattice_brain.runtime.agent_runtime``.
520
+ AgentRuntime = SingleAgentRuntime
@@ -11,7 +11,7 @@ from copy import deepcopy
11
11
  from typing import Any, Dict, List, Optional
12
12
 
13
13
 
14
- MARKETPLACE_VERSION = "7.8.0"
14
+ MARKETPLACE_VERSION = "7.9.0"
15
15
  TEMPLATE_KINDS = ("plugin", "workflow", "agent")
16
16
 
17
17
 
@@ -21,7 +21,7 @@ from typing import Any, Callable, Dict, Iterable, List, Optional
21
21
  from lattice_brain.runtime.contracts import realtime_event_contract, run_record_contract, workflow_run_contract
22
22
 
23
23
 
24
- WORKSPACE_OS_VERSION = "7.8.0"
24
+ WORKSPACE_OS_VERSION = "7.9.0"
25
25
 
26
26
  # Workspace types separate single-user Personal workspaces from shared
27
27
  # Organization workspaces. Both keep the same local-first JSON store; the type
@@ -110,7 +110,7 @@ def architecture_readiness(root: Path | None = None) -> Dict[str, Any]:
110
110
  runtime_module_count = len(list((root / "latticeai" / "runtime").glob("*.py")))
111
111
  return {
112
112
  "status": "complete" if all(gate.status == "complete" for gate in gates) else "incomplete",
113
- "version_target": "7.8.0",
113
+ "version_target": "7.9.0",
114
114
  "gates": [gate.__dict__ for gate in gates],
115
115
  "metrics": {
116
116
  "api_router_modules": api_router_count,
@@ -1,8 +1,8 @@
1
- """Machine-checkable *product* readiness gates for the 7.8 line.
1
+ """Machine-checkable *product* readiness gates for the 7.9 line.
2
2
 
3
3
  Where ``architecture_readiness`` proves the internal structure is sound, this
4
- module answers the product question the 7.8 release exists to settle: *can
5
- someone understand and use the Brain at a glance?* It does so honestly — every
4
+ module answers the product question the 7.9 release exists to settle: *are the
5
+ runtime boundaries still clear and release-ready after hardening?* It does so honestly — every
6
6
  gate is backed by evidence that is probed on disk, so a gate only reports
7
7
  ``complete`` when its evidence actually resolves. The same report can be printed
8
8
  by ``scripts/product_readiness.py`` and re-run after every change, which is the
@@ -17,7 +17,7 @@ from typing import Any, Dict, List
17
17
 
18
18
  from latticeai.services.architecture_readiness import architecture_readiness
19
19
 
20
- PRODUCT_VERSION_TARGET = "7.8.0"
20
+ PRODUCT_VERSION_TARGET = "7.9.0"
21
21
 
22
22
 
23
23
  @dataclass(frozen=True)
@@ -64,10 +64,10 @@ PRODUCT_GATES: List[ProductGate] = [
64
64
  evidence=[
65
65
  "package.json::release:artifacts",
66
66
  "package.json::release:validate",
67
- "README.md::dist/ltcai-7.8.0-py3-none-any.whl",
68
- "README.md::dist/ltcai-7.8.0.tar.gz",
69
- "README.md::dist/ltcai-7.8.0.vsix",
70
- "README.md::ltcai-7.8.0.tgz",
67
+ "README.md::dist/ltcai-7.9.0-py3-none-any.whl",
68
+ "README.md::dist/ltcai-7.9.0.tar.gz",
69
+ "README.md::dist/ltcai-7.9.0.vsix",
70
+ "README.md::ltcai-7.9.0.tgz",
71
71
  "scripts/validate_release_artifacts.py",
72
72
  "scripts/release_smoke.py",
73
73
  "Dockerfile",
@@ -83,12 +83,19 @@ PRODUCT_GATES: List[ProductGate] = [
83
83
  title="Release story is documented and honest",
84
84
  evidence=[
85
85
  "README.md",
86
- "README.md::The current release is **7.8.0",
87
- "SECURITY.md::7.8.x (latest)",
88
- "vscode-extension/README.md::**7.8.0",
89
- "docs/CHANGELOG.md::## [7.8.0]",
86
+ "README.md::The current release is **7.9.0",
87
+ "SECURITY.md::7.9.x (latest)",
88
+ "vscode-extension/README.md::**7.9.0",
89
+ "docs/CHANGELOG.md::## [7.9.0]",
90
90
  "FEATURE_STATUS.md",
91
- "RELEASE_NOTES_v7.8.0.md",
91
+ "RELEASE_NOTES_v7.9.0.md",
92
+ "latticeai/core/agent.py::SingleAgentRuntime",
93
+ "latticeai/core/agent.py::AgentRuntime = SingleAgentRuntime",
94
+ "lattice_brain/runtime/contracts.py::runtime-boundary/v1",
95
+ "lattice_brain/runtime/contracts.py::RuntimeBoundaryProtocol",
96
+ "lattice_brain/runtime/agent_runtime.py::def boundary",
97
+ "latticeai/core/agent.py::def boundary",
98
+ "latticeai/services/tool_dispatch.py::rollback_file",
92
99
  ],
93
100
  ),
94
101
  ProductGate(
@@ -8,11 +8,12 @@ from __future__ import annotations
8
8
 
9
9
  from dataclasses import dataclass, field
10
10
  from pathlib import Path
11
+ import subprocess
11
12
  from typing import Any, Callable, Dict, Mapping, Optional
12
13
 
13
14
  from fastapi import HTTPException
14
15
 
15
- from latticeai.core.agent import AgentDeps, AgentRuntime
16
+ from latticeai.core.agent import AgentDeps, SingleAgentRuntime
16
17
  from latticeai.core.agent_prompts import (
17
18
  CRITIC_PROMPT,
18
19
  EXECUTOR_PROMPT,
@@ -106,6 +107,16 @@ class ToolDispatchService:
106
107
  detail=f"'{tool_name}' 툴은 관리자 전용입니다.",
107
108
  )
108
109
 
110
+ def rollback_file(self, path: str) -> Dict[str, Any]:
111
+ r = subprocess.run(
112
+ ["git", "checkout", "--", path],
113
+ cwd=str(AGENT_ROOT),
114
+ capture_output=True,
115
+ text=True,
116
+ timeout=10,
117
+ )
118
+ return {"path": path, "ok": r.returncode == 0, "stderr": r.stderr[:200]}
119
+
109
120
 
110
121
  DEFAULT_TOOL_DISPATCH_SERVICE = ToolDispatchService()
111
122
 
@@ -185,7 +196,7 @@ def build_agent_runtime(
185
196
  hooks: Any = None,
186
197
  brain_memory: Any = None,
187
198
  dispatch_service: ToolDispatchService = DEFAULT_TOOL_DISPATCH_SERVICE,
188
- ) -> AgentRuntime:
199
+ ) -> SingleAgentRuntime:
189
200
  ensure_agent_root()
190
201
  deps = AgentDeps(
191
202
  generate_as=model_router.generate_as,
@@ -205,10 +216,11 @@ def build_agent_runtime(
205
216
  critic_prompt=CRITIC_PROMPT,
206
217
  memory_updater_prompt=MEMORY_UPDATER_PROMPT,
207
218
  agent_root=AGENT_ROOT,
219
+ rollback_file=dispatch_service.rollback_file,
208
220
  hooks=hooks,
209
221
  brain_memory=brain_memory,
210
222
  )
211
- return AgentRuntime(deps)
223
+ return SingleAgentRuntime(deps)
212
224
 
213
225
 
214
226
  def tool_response(fn, *args):
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ltcai",
3
- "version": "7.8.0",
3
+ "version": "7.9.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": {
@@ -1584,7 +1584,7 @@ dependencies = [
1584
1584
 
1585
1585
  [[package]]
1586
1586
  name = "lattice-ai-desktop"
1587
- version = "7.7.0"
1587
+ version = "7.9.0"
1588
1588
  dependencies = [
1589
1589
  "plist",
1590
1590
  "serde",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "lattice-ai-desktop"
3
- version = "7.8.0"
3
+ version = "7.9.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": "7.8.0",
4
+ "version": "7.9.0",
5
5
  "identifier": "ai.lattice.desktop",
6
6
  "build": {
7
7
  "beforeDevCommand": "npm run frontend:dev",
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "7.8.0",
2
+ "version": "7.9.0",
3
3
  "generated_at": "vite",
4
4
  "entrypoints": {
5
5
  "app": "/static/app/index.html"