ltcai 9.1.0 → 9.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 +49 -41
- package/docs/CHANGELOG.md +32 -0
- package/docs/COMMUNITY_AND_PLUGINS.md +4 -3
- package/docs/DEVELOPMENT.md +8 -8
- package/docs/LEGACY_COMPATIBILITY.md +1 -1
- package/docs/ONBOARDING.md +2 -2
- package/docs/OPERATIONS.md +1 -1
- package/docs/TRUST_MODEL.md +1 -1
- package/docs/WHY_LATTICE.md +1 -1
- package/docs/kg-schema.md +1 -1
- package/docs/mcp-tools.md +1 -1
- package/lattice_brain/__init__.py +1 -1
- package/lattice_brain/runtime/multi_agent.py +1 -1
- package/latticeai/__init__.py +1 -1
- package/latticeai/api/chat_helpers.py +4 -0
- package/latticeai/api/chat_intents.py +30 -16
- package/latticeai/core/agent.py +31 -4
- package/latticeai/core/agent_prompts.py +5 -0
- package/latticeai/core/file_generation.py +451 -0
- package/latticeai/core/legacy_compatibility.py +1 -1
- package/latticeai/core/marketplace.py +1 -1
- package/latticeai/core/workspace_os.py +1 -1
- package/latticeai/services/architecture_readiness.py +1 -1
- package/latticeai/services/product_readiness.py +1 -1
- package/package.json +1 -1
- package/scripts/check_current_release_docs.mjs +1 -1
- package/src-tauri/Cargo.lock +1 -1
- package/src-tauri/Cargo.toml +1 -1
- package/src-tauri/tauri.conf.json +1 -1
- package/static/app/asset-manifest.json +10 -10
- package/static/app/assets/{Act-Bzz0bUyW.js → Act-C3dBrWE-.js} +1 -1
- package/static/app/assets/{Brain-Dj2J20YA.js → Brain-DBYgdcjt.js} +1 -1
- package/static/app/assets/{Capture-CqlEl1Ga.js → Capture-Cf3hqRtN.js} +1 -1
- package/static/app/assets/{Library-B03FP1Yx.js → Library-CFfkNn3s.js} +1 -1
- package/static/app/assets/{System-80lHW0Ux.js → System-BOurbT-v.js} +1 -1
- package/static/app/assets/{index-BiMofBTM.js → index-A3M9sElj.js} +3 -3
- package/static/app/assets/{primitives-Q1A96_7v.js → primitives-DcUUmhdC.js} +1 -1
- package/static/app/assets/{textarea-D13RtnTo.js → textarea-BklR6zN4.js} +1 -1
- package/static/app/index.html +1 -1
- package/static/sw.js +1 -1
package/README.md
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
# Lattice AI
|
|
2
2
|
|
|
3
|
-
**Lattice AI 9.
|
|
3
|
+
**Lattice AI 9.2.0 is the local-first Digital Brain platform. Model-Agnostic File Generation makes "create a file" work reliably with any loaded LLM: file requests run through a strict extension-aware prompt, robust extraction, per-type validation, one corrective retry, and a deterministic repair fallback, so even small local models (gemma/qwen class) always produce a structurally valid HTML, JSON, or code file.**
|
|
4
4
|
|
|
5
5
|
**Lattice AI는 모델이 바뀌어도 내 지식과 맥락을 보존하는 로컬 우선 AI 브레인입니다.**
|
|
6
6
|
|
|
7
|
-
> The 9.
|
|
7
|
+
> The 9.2.0 release hardens file creation end to end: chat file requests are
|
|
8
|
+
> routed to a deterministic direct-write path (including type-only requests
|
|
9
|
+
> like "html 파일 만들어줘"), model replies are treated as untrusted content
|
|
10
|
+
> and cleaned of fences, reasoning blocks, and chat framing, and the agent
|
|
11
|
+
> JSON loop tolerates small-model formatting slips instead of aborting.
|
|
12
|
+
> The 9.1.0 release added request-scoped model routing,
|
|
8
13
|
> workspace-isolated graph identities and frontend caches, fail-closed admin
|
|
9
14
|
> gates, SSRF-safe web capture, private local state permissions, and reproducible
|
|
10
|
-
> release/test isolation. The same release
|
|
15
|
+
> release/test isolation. The same release introduced a human-first UI:
|
|
11
16
|
> a visible knowledge journey from conversation or source capture into the
|
|
12
17
|
> living Brain, its real relationship graph, and memory-grounded automation;
|
|
13
18
|
> the empty Brain home now keeps that complete loop inside one viewport, with
|
|
@@ -87,10 +92,11 @@ You need Lattice AI when:
|
|
|
87
92
|
The screenshots below are the latest checked-in visual evidence captures. They
|
|
88
93
|
keep the first-run Brain flow, memory graph, source capture, model library,
|
|
89
94
|
system view, admin console, and review center visible as release gates while
|
|
90
|
-
9.
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
checked-in 9.
|
|
95
|
+
9.2.0 makes file generation model-agnostic: chat file requests always end in
|
|
96
|
+
a structurally valid file regardless of which LLM is loaded, backed by
|
|
97
|
+
extraction, validation, corrective retry, and deterministic repair. The
|
|
98
|
+
captures below are the checked-in 9.2.0 visual release evidence for that
|
|
99
|
+
product flow.
|
|
94
100
|
|
|
95
101
|
### 1. Wake Brain
|
|
96
102
|
|
|
@@ -102,21 +108,21 @@ confirm owner, check the computer, choose the Brain voice.
|
|
|
102
108
|
Choose the owner of the Brain. The profile is not a SaaS account by default; it
|
|
103
109
|
is the local identity for the knowledge you keep.
|
|
104
110
|
|
|
105
|
-

|
|
106
112
|
|
|
107
113
|
### 3. Recommended Models
|
|
108
114
|
|
|
109
115
|
Start with a short list: safest recommendation, faster model, stronger model.
|
|
110
116
|
Advanced details stay available without overwhelming first-time users.
|
|
111
117
|
|
|
112
|
-

|
|
113
119
|
|
|
114
120
|
### 4. Install And Load
|
|
115
121
|
|
|
116
122
|
Download and load only after consent. Lattice explains model size, local
|
|
117
123
|
execution, and network use before work starts.
|
|
118
124
|
|
|
119
|
-

|
|
120
126
|
|
|
121
127
|
### 5. Brain Chat
|
|
122
128
|
|
|
@@ -128,14 +134,14 @@ and its visible life signal follow real listening, recall, synthesis, and action
|
|
|
128
134
|
state. Detailed memory rings, provenance, conversation history, and
|
|
129
135
|
model/runtime proof open as overlays only when requested.
|
|
130
136
|
|
|
131
|
-

|
|
132
138
|
|
|
133
139
|
### 6. Review Center
|
|
134
140
|
|
|
135
141
|
Automation results are staged for review before they become durable decisions.
|
|
136
142
|
Snooze, unsnooze, run now, approve, and dismiss actions stay explicit.
|
|
137
143
|
|
|
138
|
-

|
|
139
145
|
|
|
140
146
|
## Brain Depths
|
|
141
147
|
|
|
@@ -151,10 +157,10 @@ The user travels inward from everyday memory to deeper structure:
|
|
|
151
157
|
|
|
152
158
|
Walkthrough:
|
|
153
159
|
|
|
154
|
-

|
|
155
161
|
|
|
156
162
|
Screenshot index and capture notes:
|
|
157
|
-
[output/release/v9.
|
|
163
|
+
[output/release/v9.2.0/SCREENSHOT_INDEX.md](output/release/v9.2.0/SCREENSHOT_INDEX.md)
|
|
158
164
|
|
|
159
165
|
## Install
|
|
160
166
|
|
|
@@ -239,42 +245,43 @@ See [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md) for developer workflow details.
|
|
|
239
245
|
|
|
240
246
|
## Current Release
|
|
241
247
|
|
|
242
|
-
The current release is **9.
|
|
243
|
-
|
|
244
|
-
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
- The
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
- `dist/ltcai-9.
|
|
264
|
-
- `ltcai-9.
|
|
265
|
-
- `
|
|
266
|
-
- `
|
|
248
|
+
The current release is **9.2.0 — Model-Agnostic File Generation**:
|
|
249
|
+
|
|
250
|
+
- A new `latticeai.core.file_generation` pipeline treats every model reply as
|
|
251
|
+
untrusted content: extension-aware strict prompting, extraction of the real
|
|
252
|
+
payload from fences/`<think>` blocks/chat framing, per-type structural
|
|
253
|
+
validation (complete HTML documents, parseable JSON, CSS rule blocks), one
|
|
254
|
+
corrective retry that tells the model what was wrong, and a deterministic
|
|
255
|
+
repair fallback that guarantees a valid file.
|
|
256
|
+
- Type-only requests without an explicit filename ("html 파일 만들어줘",
|
|
257
|
+
"웹페이지 만들어줘") now resolve to an inferred target and use the
|
|
258
|
+
deterministic direct-write path instead of the model-driven agent loop.
|
|
259
|
+
- The agent executor tolerates small-model formatting slips: `<think>` blocks
|
|
260
|
+
and trailing commas are stripped from action JSON, and parse failures feed a
|
|
261
|
+
corrective format reminder back to the model instead of aborting the run.
|
|
262
|
+
- The executor prompt pins exact file-content rules for `write_file` so
|
|
263
|
+
agent-created files are complete and fence-free.
|
|
264
|
+
- File writes report whether content was generated cleanly, retried, or
|
|
265
|
+
auto-repaired in the response payload (`generation` metadata).
|
|
266
|
+
|
|
267
|
+
Expected artifacts for 9.2.0 release must use exact filenames:
|
|
268
|
+
|
|
269
|
+
- `dist/ltcai-9.2.0-py3-none-any.whl`
|
|
270
|
+
- `dist/ltcai-9.2.0.tar.gz`
|
|
271
|
+
- `ltcai-9.2.0.tgz`
|
|
272
|
+
- `dist/ltcai-9.2.0.vsix`
|
|
273
|
+
- `src-tauri/target/release/bundle/dmg/Lattice AI_9.2.0_aarch64.dmg`
|
|
267
274
|
|
|
268
275
|
Do not use wildcard artifact uploads. Package registry publishing remains owner-run.
|
|
269
276
|
|
|
270
277
|
See [docs/ROADMAP_RECOMMENDATIONS.md](docs/ROADMAP_RECOMMENDATIONS.md) for the
|
|
271
|
-
strategic roadmap slices applied through 9.
|
|
278
|
+
strategic roadmap slices applied through 9.2.0 and the follow-up tracks.
|
|
272
279
|
|
|
273
280
|
## Known Limitations
|
|
274
281
|
|
|
275
282
|
- External package registries are owner-published and can lag behind GitHub.
|
|
276
283
|
- PostgreSQL/pgvector is optional scale/migration tooling. SQLite remains the
|
|
277
|
-
live local Brain store in 9.
|
|
284
|
+
live local Brain store in 9.2.0.
|
|
278
285
|
- Docker, model downloads, cloud model calls, Telegram, Brain Network, and update
|
|
279
286
|
checks require explicit user action.
|
|
280
287
|
- Conversation does not fabricate answers when no model is loaded.
|
|
@@ -286,6 +293,7 @@ strategic roadmap slices applied through 9.1.0 and the follow-up tracks.
|
|
|
286
293
|
|
|
287
294
|
| Version | Theme |
|
|
288
295
|
| --- | --- |
|
|
296
|
+
| 9.2.0 | Model-Agnostic File Generation: chat file requests always produce structurally valid files with any LLM via extraction, per-type validation, corrective retry, deterministic repair, inferred file targets, and a fault-tolerant agent JSON loop |
|
|
289
297
|
| 9.1.0 | Code Review Completion & Fail-Closed Runtime: all July 11 review findings closed across fail-closed security, typed runtime/model/chat boundaries, honest frontend failures and tests, and repository hygiene |
|
|
290
298
|
| 9.0.0 | Code Review Closure & Runtime Cleanup: July 8 code-review follow-ups fixed, chat/runtime reliability improved, duplicated utility surfaces consolidated, runtime audit append paths moved to JSONL, and release metadata/artifacts synchronized |
|
|
291
299
|
| 8.9.0 | Scoped Memory & Tool Policy Hardening: authenticated history/KG reads are workspace-scoped, direct Tool API paths enforce registry policy, local approvals hash tokens at rest, AgentRuntime approval semantics are explicit, and frontend/runtime seams are split |
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,38 @@ The top entry is either the current unreleased main-branch work or the current
|
|
|
4
4
|
release line. Older entries are historical and may describe behavior as it
|
|
5
5
|
existed at that release.
|
|
6
6
|
|
|
7
|
+
## [9.2.0] - 2026-07-20
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- Added `latticeai/core/file_generation.py`, a model-agnostic file content
|
|
11
|
+
pipeline: extension-aware strict prompting with pinned first lines, payload
|
|
12
|
+
extraction from fences/`<think>` blocks/chat framing, per-type structural
|
|
13
|
+
validation, one corrective retry, and a deterministic repair fallback that
|
|
14
|
+
guarantees a structurally valid file from any loaded LLM.
|
|
15
|
+
- Added filename inference for chat file requests that name a type but no path
|
|
16
|
+
("html 파일 만들어줘" → `generated_page.html`), keeping such requests on the
|
|
17
|
+
deterministic direct-write path instead of the model-driven agent loop.
|
|
18
|
+
- Added `generation` metadata (attempts, validation reasons, auto-repair flag)
|
|
19
|
+
to `/chat` direct file-action responses, and a user-facing notice when the
|
|
20
|
+
saved file was produced by auto-repair.
|
|
21
|
+
- Added `tests/unit/test_file_generation.py` covering extraction, validation,
|
|
22
|
+
repair, inference, prompting, and retry/repair orchestration (22 tests).
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
- Chat file-action routing counts explicit artifact types (html, 웹페이지,
|
|
26
|
+
webpage) as file words, so "html 페이지 만들어줘" creates a real file.
|
|
27
|
+
- Direct file generation clamps temperature to ≤0.3 and raises the token
|
|
28
|
+
budget to ≥4096 so generated documents complete.
|
|
29
|
+
- The agent executor prompt pins `write_file` content rules: complete raw
|
|
30
|
+
content, no Markdown fences, extension-valid documents.
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
- Small local models (gemma/qwen class) no longer save chat wrappers, fenced
|
|
34
|
+
code blocks, reasoning traces, or truncated documents as file bytes.
|
|
35
|
+
- The agent JSON loop no longer aborts on the first malformed action reply:
|
|
36
|
+
`extract_action` strips `<think>` blocks and tolerates trailing commas, and
|
|
37
|
+
up to two corrective format reminders are fed back before halting.
|
|
38
|
+
|
|
7
39
|
## [9.1.0] - 2026-07-11
|
|
8
40
|
|
|
9
41
|
### Added
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
# Community And Plugins
|
|
2
2
|
|
|
3
|
-
Current release: **9.
|
|
3
|
+
Current release: **9.2.0 — Model-Agnostic File Generation**.
|
|
4
4
|
|
|
5
5
|
LatticeAI defines the path from a strong local-first framework (8.4.0
|
|
6
6
|
action-aware baseline, 8.5.0 registry+DI hardening, 8.6.0 capture/navigation
|
|
7
7
|
reliability, 8.7.0 runtime-state hygiene, 8.8.0 Brain Core extraction
|
|
8
|
-
readiness, 8.9.0 scoped Tool API hardening, 9.0.0 cleanup closure,
|
|
9
|
-
fail-closed review completion) to a
|
|
8
|
+
readiness, 8.9.0 scoped Tool API hardening, 9.0.0 cleanup closure, 9.1.0
|
|
9
|
+
fail-closed review completion, and 9.2.0 model-agnostic file generation) to a
|
|
10
|
+
product ecosystem. The
|
|
10
11
|
immediate goal is small and practical: make it clear how
|
|
11
12
|
contributors can extend the Brain without weakening local-first trust,
|
|
12
13
|
workspace scoping, or release quality.
|
package/docs/DEVELOPMENT.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Lattice AI Development
|
|
2
2
|
|
|
3
|
-
Current release: **9.
|
|
3
|
+
Current release: **9.2.0 — Model-Agnostic File Generation**.
|
|
4
4
|
|
|
5
5
|
This document is for contributors working on the local-first Digital Brain
|
|
6
6
|
codebase. Product positioning and quick start stay in `README.md`; release
|
|
7
|
-
history is intentionally limited to 8.0.0-9.
|
|
7
|
+
history is intentionally limited to 8.0.0-9.2.0 in `docs/CHANGELOG.md` and
|
|
8
8
|
`RELEASE.md`.
|
|
9
9
|
|
|
10
10
|
## Product Contract
|
|
@@ -153,10 +153,10 @@ For user-facing, API, runtime, release, or packaging changes, check:
|
|
|
153
153
|
Release/publish examples must use exact target-version filenames. Do not
|
|
154
154
|
document wildcard artifact upload commands.
|
|
155
155
|
|
|
156
|
-
For 9.
|
|
156
|
+
For 9.2.0 release work, exact artifacts are:
|
|
157
157
|
|
|
158
|
-
- `dist/ltcai-9.
|
|
159
|
-
- `dist/ltcai-9.
|
|
160
|
-
- `ltcai-9.
|
|
161
|
-
- `dist/ltcai-9.
|
|
162
|
-
- `src-tauri/target/release/bundle/dmg/Lattice AI_9.
|
|
158
|
+
- `dist/ltcai-9.2.0-py3-none-any.whl`
|
|
159
|
+
- `dist/ltcai-9.2.0.tar.gz`
|
|
160
|
+
- `ltcai-9.2.0.tgz`
|
|
161
|
+
- `dist/ltcai-9.2.0.vsix`
|
|
162
|
+
- `src-tauri/target/release/bundle/dmg/Lattice AI_9.2.0_aarch64.dmg`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Legacy Compatibility Map
|
|
2
2
|
|
|
3
|
-
Current target: **9.
|
|
3
|
+
Current target: **9.2.0 — Model-Agnostic File Generation**.
|
|
4
4
|
|
|
5
5
|
Lattice AI is moving toward a smaller, modular architecture centered on
|
|
6
6
|
`lattice_brain`, `latticeai.services`, `latticeai.api`, and `latticeai.runtime`.
|
package/docs/ONBOARDING.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Lattice AI Onboarding
|
|
2
2
|
|
|
3
|
-
Current release: **9.
|
|
3
|
+
Current release: **9.2.0 — Model-Agnostic File Generation**.
|
|
4
4
|
|
|
5
5
|
The first-run goal is a five-minute path from "I opened the app" to "my Brain
|
|
6
6
|
has a source, a question, and proof." This page is the product contract behind
|
|
@@ -40,7 +40,7 @@ read the docs first.
|
|
|
40
40
|
|
|
41
41
|
## Release Gate
|
|
42
42
|
|
|
43
|
-
9.
|
|
43
|
+
9.2.0 treats onboarding as a release gate, not marketing copy. The current
|
|
44
44
|
machine-checkable product readiness report requires this five-minute contract,
|
|
45
45
|
the Brain Home surface, setup helpers, graph ingestion tests, and exact release
|
|
46
46
|
artifact documentation before the release can be called complete.
|
package/docs/OPERATIONS.md
CHANGED
package/docs/TRUST_MODEL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Lattice AI Trust Model
|
|
2
2
|
|
|
3
|
-
Current release: **9.
|
|
3
|
+
Current release: **9.2.0 — Model-Agnostic File Generation**.
|
|
4
4
|
|
|
5
5
|
Lattice AI is local-first, explicit about external communication, and honest
|
|
6
6
|
when a capability is unavailable.
|
package/docs/WHY_LATTICE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Why Lattice AI Exists
|
|
2
2
|
|
|
3
|
-
Current release: **9.
|
|
3
|
+
Current release: **9.2.0 — Model-Agnostic File Generation**.
|
|
4
4
|
|
|
5
5
|
**Lattice AI is a local-first Digital Brain that keeps your knowledge durable
|
|
6
6
|
across any AI model.**
|
package/docs/kg-schema.md
CHANGED
package/docs/mcp-tools.md
CHANGED
|
@@ -21,7 +21,7 @@ from .contracts import multi_agent_contract
|
|
|
21
21
|
from ..utils import now_iso as _now
|
|
22
22
|
|
|
23
23
|
|
|
24
|
-
MULTI_AGENT_VERSION = "9.
|
|
24
|
+
MULTI_AGENT_VERSION = "9.2.0"
|
|
25
25
|
|
|
26
26
|
AGENT_ROLES = ("researcher", "planner", "executor", "reviewer", "release")
|
|
27
27
|
CORE_PIPELINE = ("planner", "executor", "reviewer")
|
package/latticeai/__init__.py
CHANGED
|
@@ -128,6 +128,10 @@ def is_file_action_request(text: str) -> bool:
|
|
|
128
128
|
has_target = bool(_FILE_TARGET_RE.search(raw))
|
|
129
129
|
has_file_word = any(word in lower for word in (
|
|
130
130
|
"file", "파일", "문서", "artifact", "아티팩트", "save as", "저장",
|
|
131
|
+
# Explicit artifact types: users asking for "an html page" expect a
|
|
132
|
+
# real file, not a code block in chat — route them to the file path
|
|
133
|
+
# where the model-agnostic generation pipeline guarantees validity.
|
|
134
|
+
"html", "웹페이지", "웹 페이지", "홈페이지", "webpage", "web page",
|
|
131
135
|
))
|
|
132
136
|
has_action = any(word in lower for word in (
|
|
133
137
|
"create", "make", "write", "save", "generate", "edit", "update",
|
|
@@ -14,10 +14,10 @@ from latticeai.api.chat_helpers import (
|
|
|
14
14
|
file_action_target,
|
|
15
15
|
format_network_status,
|
|
16
16
|
inline_file_action_content,
|
|
17
|
-
strip_generated_file_content,
|
|
18
17
|
)
|
|
19
18
|
from latticeai.api.chat_stream import agent_payload_stream, single_answer_response
|
|
20
19
|
from latticeai.core.agent import AgentState
|
|
20
|
+
from latticeai.core.file_generation import generate_file_content, infer_file_target
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
class ChatIntentController:
|
|
@@ -185,28 +185,36 @@ class ChatIntentController:
|
|
|
185
185
|
return single_answer_response(req, answer, model="client_url")
|
|
186
186
|
|
|
187
187
|
async def direct_file_action(self, req: Any, *, model_id: Optional[str]):
|
|
188
|
-
|
|
188
|
+
# An explicit path ("report.txt") wins; otherwise infer one from an
|
|
189
|
+
# explicit type keyword ("html 파일 만들어줘") so weak models never
|
|
190
|
+
# have to drive the JSON tool loop just to create a file.
|
|
191
|
+
target_path = file_action_target(req.message) or infer_file_target(req.message)
|
|
189
192
|
if not target_path:
|
|
190
193
|
return None
|
|
191
194
|
content = inline_file_action_content(req.message)
|
|
195
|
+
generation_meta: Optional[Dict[str, Any]] = None
|
|
192
196
|
if content is None and not model_id:
|
|
193
197
|
return self.no_model_response()
|
|
194
198
|
if content is None and model_id:
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
199
|
+
# Model-agnostic pipeline: strict extension-aware prompt →
|
|
200
|
+
# extraction → validation → one corrective retry → deterministic
|
|
201
|
+
# repair. Guarantees a structurally valid file from any LLM.
|
|
202
|
+
async def _generate(context: str) -> str:
|
|
203
|
+
return str(
|
|
204
|
+
await self.router.generate_as(
|
|
205
|
+
model_id,
|
|
206
|
+
message="Return only the requested file content.",
|
|
207
|
+
context=context,
|
|
208
|
+
max_tokens=max(int(req.max_tokens or 0), 4096),
|
|
209
|
+
temperature=min(req.temperature, 0.3),
|
|
210
|
+
)
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
content, generation_meta = await generate_file_content(
|
|
214
|
+
_generate,
|
|
215
|
+
target_path=target_path,
|
|
216
|
+
user_request=req.message,
|
|
208
217
|
)
|
|
209
|
-
content = strip_generated_file_content(str(raw_content))
|
|
210
218
|
if content is None:
|
|
211
219
|
raise HTTPException(
|
|
212
220
|
status_code=400,
|
|
@@ -220,6 +228,10 @@ class ChatIntentController:
|
|
|
220
228
|
except self.tool_error as exc:
|
|
221
229
|
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
222
230
|
answer = f"{result.get('path') or target_path} 파일을 만들었습니다."
|
|
231
|
+
if generation_meta and generation_meta.get("repaired"):
|
|
232
|
+
answer += (
|
|
233
|
+
" (모델 출력이 불완전해 자동 보정을 거쳐 유효한 파일로 저장했습니다.)"
|
|
234
|
+
)
|
|
223
235
|
created_files = [
|
|
224
236
|
{
|
|
225
237
|
"path": result.get("path") or target_path,
|
|
@@ -248,6 +260,8 @@ class ChatIntentController:
|
|
|
248
260
|
"routed_to_agent": True,
|
|
249
261
|
"action_route": "direct_write_file",
|
|
250
262
|
}
|
|
263
|
+
if generation_meta is not None:
|
|
264
|
+
payload["generation"] = generation_meta
|
|
251
265
|
if req.stream:
|
|
252
266
|
return StreamingResponse(
|
|
253
267
|
agent_payload_stream(
|
package/latticeai/core/agent.py
CHANGED
|
@@ -69,9 +69,16 @@ class AgentRunContext:
|
|
|
69
69
|
self.approved_by_human: bool = False
|
|
70
70
|
|
|
71
71
|
|
|
72
|
+
_THINK_BLOCK_RE = re.compile(
|
|
73
|
+
r"<(think|thinking|reasoning)>.*?</\1>", flags=re.DOTALL | re.IGNORECASE
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
|
|
72
77
|
def extract_action(raw: str) -> Dict:
|
|
73
78
|
"""Parse one JSON action object out of an LLM response (tolerant of fences/prose)."""
|
|
74
|
-
|
|
79
|
+
# Small local models often prepend <think>...</think> reasoning that can
|
|
80
|
+
# itself contain braces — drop it before locating the action object.
|
|
81
|
+
text = _THINK_BLOCK_RE.sub("", raw).strip()
|
|
75
82
|
fenced = re.search(r"```(?:json)?\s*(\{.*?\})\s*```", text, flags=re.DOTALL)
|
|
76
83
|
if fenced:
|
|
77
84
|
text = fenced.group(1).strip()
|
|
@@ -83,8 +90,14 @@ def extract_action(raw: str) -> Dict:
|
|
|
83
90
|
|
|
84
91
|
try:
|
|
85
92
|
action = json.loads(text)
|
|
86
|
-
except json.JSONDecodeError
|
|
87
|
-
|
|
93
|
+
except json.JSONDecodeError:
|
|
94
|
+
# Second chance for the most common small-model JSON slips: trailing
|
|
95
|
+
# commas before a closing brace/bracket.
|
|
96
|
+
repaired = re.sub(r",\s*([}\]])", r"\1", text)
|
|
97
|
+
try:
|
|
98
|
+
action = json.loads(repaired)
|
|
99
|
+
except json.JSONDecodeError as exc:
|
|
100
|
+
raise ValueError(f"Agent did not return valid JSON: {exc}") from exc
|
|
88
101
|
|
|
89
102
|
if not isinstance(action, dict) or "action" not in action:
|
|
90
103
|
raise ValueError("Agent JSON must include an action field.")
|
|
@@ -248,6 +261,7 @@ class SingleAgentRuntime:
|
|
|
248
261
|
d = self.deps
|
|
249
262
|
exec_count = sum(1 for s in ctx.transcript if s.get("state") == AgentState.EXECUTING.value)
|
|
250
263
|
budget = max(1, max_steps - exec_count)
|
|
264
|
+
parse_failures = 0
|
|
251
265
|
|
|
252
266
|
for _ in range(budget):
|
|
253
267
|
corrections_hint = (
|
|
@@ -280,11 +294,24 @@ class SingleAgentRuntime:
|
|
|
280
294
|
try:
|
|
281
295
|
action = extract_action(str(raw))
|
|
282
296
|
except ValueError as exc:
|
|
297
|
+
parse_failures += 1
|
|
283
298
|
ctx.transcript.append({
|
|
284
299
|
"state": AgentState.EXECUTING.value, "action": "parse_error",
|
|
285
300
|
"raw": str(raw)[:400], "error": str(exc),
|
|
286
301
|
})
|
|
287
|
-
|
|
302
|
+
if parse_failures >= 3:
|
|
303
|
+
break
|
|
304
|
+
# Weak models often need one concrete reminder of the wire
|
|
305
|
+
# format; feed it through the corrections channel and retry
|
|
306
|
+
# instead of aborting the whole run on the first slip.
|
|
307
|
+
hint = (
|
|
308
|
+
'Your last reply was not a single JSON action object. Reply with '
|
|
309
|
+
'EXACTLY one JSON object like {"thoughts": "...", "action": '
|
|
310
|
+
'"tool_name", "args": {...}} and nothing else.'
|
|
311
|
+
)
|
|
312
|
+
if hint not in ctx.corrections:
|
|
313
|
+
ctx.corrections.append(hint)
|
|
314
|
+
continue
|
|
288
315
|
|
|
289
316
|
name = action.get("action")
|
|
290
317
|
thoughts = str(action.get("thoughts") or "")[:600]
|
|
@@ -43,6 +43,11 @@ You think and act like a senior software engineer:
|
|
|
43
43
|
Respond with exactly ONE JSON object per step:
|
|
44
44
|
{"thoughts": "what you learned / why this next action", "action": "tool_name", "args": {...}}
|
|
45
45
|
|
|
46
|
+
When writing a file (write_file), args.content must be the COMPLETE raw file
|
|
47
|
+
content: no Markdown fences, no commentary, valid for the file's extension
|
|
48
|
+
(an .html file starts with <!DOCTYPE html> and ends with </html>; a .json
|
|
49
|
+
file must parse as strict JSON).
|
|
50
|
+
|
|
46
51
|
When the task is fully done AND a tool result in this run confirms it:
|
|
47
52
|
{"thoughts": "verified", "action": "final", "message": "한국어로 무엇을 했고 어디서 검증했는지 요약"}
|
|
48
53
|
|