ltcai 7.1.0 → 7.3.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 +26 -19
- package/docs/CHANGELOG.md +41 -0
- package/docs/ROADMAP_RECOMMENDATIONS.md +55 -0
- package/frontend/src/api/client.ts +3 -0
- package/frontend/src/features/admin/AdminConsole.tsx +41 -1
- package/frontend/src/i18n.ts +24 -0
- package/frontend/src/styles.css +45 -0
- package/lattice_brain/__init__.py +1 -1
- package/lattice_brain/runtime/agent_runtime.py +62 -1
- package/lattice_brain/runtime/contracts.py +107 -0
- package/lattice_brain/runtime/multi_agent.py +6 -2
- package/latticeai/__init__.py +1 -1
- package/latticeai/api/agents.py +12 -0
- package/latticeai/api/tools.py +14 -0
- package/latticeai/core/agent.py +5 -0
- package/latticeai/core/marketplace.py +1 -1
- package/latticeai/core/tool_registry.py +47 -0
- package/latticeai/core/workspace_os.py +1 -1
- package/latticeai/services/tool_dispatch.py +14 -0
- package/package.json +1 -1
- package/scripts/brain_quality_eval.py +24 -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 +28 -28
- package/static/app/assets/{Act-BHEb8bAM.js → Act-Di4tRFWY.js} +2 -2
- package/static/app/assets/{Act-BHEb8bAM.js.map → Act-Di4tRFWY.js.map} +1 -1
- package/static/app/assets/{Brain-yvR7xkrV.js → Brain-BZB3Gy9w.js} +2 -2
- package/static/app/assets/{Brain-yvR7xkrV.js.map → Brain-BZB3Gy9w.js.map} +1 -1
- package/static/app/assets/{Capture-BrAmsSEH.js → Capture-tNyYWxnh.js} +2 -2
- package/static/app/assets/{Capture-BrAmsSEH.js.map → Capture-tNyYWxnh.js.map} +1 -1
- package/static/app/assets/{Library-BOVzYfxI.js → Library-DAtDDLdg.js} +2 -2
- package/static/app/assets/{Library-BOVzYfxI.js.map → Library-DAtDDLdg.js.map} +1 -1
- package/static/app/assets/{System-D4WaN4kj.js → System-DEu0xNUc.js} +2 -2
- package/static/app/assets/{System-D4WaN4kj.js.map → System-DEu0xNUc.js.map} +1 -1
- package/static/app/assets/{index-DvLsGy-z.css → index-Bi_bpigM.css} +1 -1
- package/static/app/assets/{index-BOB-W1FZ.js → index-COuGp7_5.js} +3 -3
- package/static/app/assets/index-COuGp7_5.js.map +1 -0
- package/static/app/assets/{primitives-C3_BfUb8.js → primitives-CdwcE--L.js} +2 -2
- package/static/app/assets/{primitives-C3_BfUb8.js.map → primitives-CdwcE--L.js.map} +1 -1
- package/static/app/assets/{textarea-CbvhHvzg.js → textarea-CqOdBPL1.js} +2 -2
- package/static/app/assets/{textarea-CbvhHvzg.js.map → textarea-CqOdBPL1.js.map} +1 -1
- package/static/app/index.html +2 -2
- package/static/app/assets/index-BOB-W1FZ.js.map +0 -1
package/README.md
CHANGED
|
@@ -200,28 +200,33 @@ See [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md) for developer workflow details.
|
|
|
200
200
|
|
|
201
201
|
## Current Release
|
|
202
202
|
|
|
203
|
-
The current release is **7.
|
|
204
|
-
|
|
205
|
-
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
- `ltcai-7.
|
|
220
|
-
- `dist/ltcai-7.
|
|
221
|
-
- `
|
|
203
|
+
The current release is **7.3.0 Runtime Contract & Retrieval Quality**:
|
|
204
|
+
|
|
205
|
+
- Single-agent and multi-agent execution now share a serializable
|
|
206
|
+
`agent-run-contract/v1` payload for run identity, mode, status, roles,
|
|
207
|
+
timeline, retries, artifacts, and terminal state.
|
|
208
|
+
- Agent runtime API responses include the shared contract, keeping real and
|
|
209
|
+
simulated run history distinguishable as runtime extraction continues.
|
|
210
|
+
- Brain quality evaluation now includes deterministic hybrid recall/ranking
|
|
211
|
+
regression thresholds, not only "some recall exists" checks.
|
|
212
|
+
- The 7.2.0 preview/diagnostics work remains the admin trust surface while
|
|
213
|
+
7.3.0 tightens the underlying run and retrieval contracts.
|
|
214
|
+
- The roadmap focus is durability over model choice: knowledge, run evidence,
|
|
215
|
+
and retrieval quality become measurable product assets.
|
|
216
|
+
|
|
217
|
+
Expected artifacts for 7.3.0 release must use exact filenames:
|
|
218
|
+
|
|
219
|
+
- `dist/ltcai-7.3.0-py3-none-any.whl`
|
|
220
|
+
- `dist/ltcai-7.3.0.tar.gz`
|
|
221
|
+
- `ltcai-7.3.0.tgz`
|
|
222
|
+
- `dist/ltcai-7.3.0.vsix`
|
|
223
|
+
- `src-tauri/target/release/bundle/dmg/Lattice AI_7.3.0_aarch64.dmg`
|
|
222
224
|
|
|
223
225
|
Do not upload `dist/*`. Package registry publishing remains owner-run.
|
|
224
226
|
|
|
227
|
+
See [docs/ROADMAP_RECOMMENDATIONS.md](docs/ROADMAP_RECOMMENDATIONS.md) for the
|
|
228
|
+
strategic roadmap slice applied in 7.3.0 and the follow-up tracks.
|
|
229
|
+
|
|
225
230
|
## Known Limitations
|
|
226
231
|
|
|
227
232
|
- External package registries are owner-published and can lag behind GitHub.
|
|
@@ -237,6 +242,8 @@ Do not upload `dist/*`. Package registry publishing remains owner-run.
|
|
|
237
242
|
|
|
238
243
|
| Version | Theme |
|
|
239
244
|
| --- | --- |
|
|
245
|
+
| 7.3.0 | Runtime Contract & Retrieval Quality: shared agent-run contract across runtimes plus deterministic hybrid recall/ranking regression gates |
|
|
246
|
+
| 7.2.0 | Runtime Trust Baseline: agent run preview/readiness, simulation-mode guardrails, live ToolRegistry manifest/diagnostics, and tests for dispatch/governance/catalog drift |
|
|
240
247
|
| 7.1.0 | Brain Usability Completion: clearer first-run onboarding, ingestion progress/emergence, richer graph controls, inline answer proof, workspace/profile/admin discovery, empty/error/consent feedback, and VS Code sync status |
|
|
241
248
|
| 7.0.0 | Brain Productization Loop: first-screen ingestion for files/folders/notes/web, answer-level memory proof and source citations, model-continuity demo flow, five-minute first-run loop, and recall/KG quality eval in CI |
|
|
242
249
|
| 6.7.0 | Brain IA Cleanup: reachable rich pages, separated product routes vs compatibility aliases, shared Brain shell navigation, and lazy-loaded rich pages |
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,47 @@ 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
|
+
## [7.3.0] - 2026-06-20
|
|
8
|
+
|
|
9
|
+
> Runtime Contract & Retrieval Quality. Turns the next AgentRuntime extraction
|
|
10
|
+
> step and the uploaded roadmap's hybrid-search quality goals into a small,
|
|
11
|
+
> tested release: shared run contracts and deterministic recall regression.
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
- `lattice_brain.runtime.contracts.AgentRunContract`, a serializable
|
|
15
|
+
`agent-run-contract/v1` payload shared by single-agent and multi-agent
|
|
16
|
+
execution paths.
|
|
17
|
+
- Multi-agent API result/run patches now include the shared contract with
|
|
18
|
+
runtime, mode, status, roles, retries, timeline, and terminal-state data.
|
|
19
|
+
- Single-agent runtime exposes the same contract helper for UI/API/storage
|
|
20
|
+
convergence in the next extraction pass.
|
|
21
|
+
- `scripts/brain_quality_eval.py` now runs deterministic hybrid recall/ranking
|
|
22
|
+
regression checks with recall and precision thresholds.
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
- Package/runtime/static metadata is synchronized to 7.3.0; package publish and
|
|
26
|
+
deployment remain owner-run only.
|
|
27
|
+
|
|
28
|
+
## [7.2.0] - 2026-06-20
|
|
29
|
+
|
|
30
|
+
> Runtime Trust Baseline. Adds execution preview and registry diagnostics so
|
|
31
|
+
> agent runs and tool permissions become inspectable contracts before action.
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
- `POST /agents/api/run/preview` for AgentRuntime readiness, role selection,
|
|
35
|
+
input keys, retry clamping, and blocking reasons without starting a run.
|
|
36
|
+
- `GET /tools/registry` for the live ToolRegistry manifest across dispatch
|
|
37
|
+
handlers, governance policy, catalog descriptions, and permissions.
|
|
38
|
+
- `GET /tools/registry/diagnostics` for a compact drift check suitable for CI,
|
|
39
|
+
admin views, and runtime health panels.
|
|
40
|
+
- Unit coverage for AgentRuntime preview and ToolRegistry manifest diagnostics.
|
|
41
|
+
|
|
42
|
+
### Changed
|
|
43
|
+
- Tool governance now covers `read_document`, and the catalog describes
|
|
44
|
+
`create_web_project`, closing the current dispatch/governance/catalog drift.
|
|
45
|
+
- Package/runtime/static metadata is synchronized to 7.2.0; package publish and
|
|
46
|
+
deployment remain owner-run only.
|
|
47
|
+
|
|
7
48
|
## [7.1.0] - 2026-06-20
|
|
8
49
|
|
|
9
50
|
> Brain Usability Completion. Completes the 7.1.0 first-run through editor-sync
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Strategic Roadmap Recommendations
|
|
2
|
+
|
|
3
|
+
This roadmap captures the 2026-06-20 product direction input and maps it to
|
|
4
|
+
small release-sized work. The operating principle stays unchanged:
|
|
5
|
+
|
|
6
|
+
> Models are temporary. Knowledge is durable. The Brain is the product.
|
|
7
|
+
|
|
8
|
+
## 7.3.0 Applied Slice
|
|
9
|
+
|
|
10
|
+
7.3.0 implements the first narrow slice of the roadmap:
|
|
11
|
+
|
|
12
|
+
- Runtime evolution: single-agent and multi-agent execution share
|
|
13
|
+
`agent-run-contract/v1`, making mode/status/timeline evidence inspectable.
|
|
14
|
+
- Hybrid search optimization: the Brain quality gate now includes deterministic
|
|
15
|
+
recall and ranking regression thresholds.
|
|
16
|
+
- Security and trust: run contracts distinguish runtime type and execution mode
|
|
17
|
+
so simulated output is not presented as real execution.
|
|
18
|
+
|
|
19
|
+
## Near-Term Tracks
|
|
20
|
+
|
|
21
|
+
1. Retrieval quality and scale
|
|
22
|
+
- Expand fixture datasets for hybrid search.
|
|
23
|
+
- Add latency budgets for large corpora.
|
|
24
|
+
- Track recall, precision, and ranking regressions in CI.
|
|
25
|
+
- Tune semantic/graph/keyword fusion by query class.
|
|
26
|
+
|
|
27
|
+
2. Incremental ingestion
|
|
28
|
+
- Add background indexing jobs.
|
|
29
|
+
- Detect duplicates and merge memory candidates.
|
|
30
|
+
- Surface conflict resolution for contradictory memories.
|
|
31
|
+
|
|
32
|
+
3. Runtime convergence
|
|
33
|
+
- Use `agent-run-contract/v1` across single-agent, multi-agent, workflows,
|
|
34
|
+
audit logs, and UI event streams.
|
|
35
|
+
- Keep simulation mode explicit and never record it as product success.
|
|
36
|
+
- Route tools through explicit registry/governance contracts.
|
|
37
|
+
|
|
38
|
+
4. Brain SDK boundary
|
|
39
|
+
- Continue extracting `lattice_brain` as a reusable Brain Core package.
|
|
40
|
+
- Keep compatibility shims until downstream imports are migrated.
|
|
41
|
+
- Preserve migration rollback paths for graph and memory storage.
|
|
42
|
+
|
|
43
|
+
5. Trust and operations
|
|
44
|
+
- Extend audit logging around tool execution and retrieval injection.
|
|
45
|
+
- Add dependency vulnerability monitoring.
|
|
46
|
+
- Add Tauri update/rollback planning before enabling auto-update.
|
|
47
|
+
|
|
48
|
+
## Longer-Term Tracks
|
|
49
|
+
|
|
50
|
+
- Multi-modal ingestion and retrieval for images, audio, and video.
|
|
51
|
+
- Proactive Brain synthesis, contradiction detection, and recommendations.
|
|
52
|
+
- Temporal reasoning over historical graph states.
|
|
53
|
+
- Interoperability with Obsidian, Notion, Email, Calendar, Git, Slack, and Teams.
|
|
54
|
+
- Encrypted Brain Network sharing.
|
|
55
|
+
- Plugin marketplace and public benchmarks.
|
|
@@ -481,7 +481,10 @@ export const latticeApi = {
|
|
|
481
481
|
unloadModel: (model_id: string) => del(`/models/unload/${encodeURIComponent(model_id)}`, {}),
|
|
482
482
|
embeddingsStatus: () => get("/api/embeddings/status", {}),
|
|
483
483
|
agentRuntime: () => get("/agents/api/runtime/status", { runtime: {}, agents: [], runs: [] }),
|
|
484
|
+
agentRunPreview: (goal: string, roles: string[] = []) => post("/agents/api/run/preview", { goal, roles }, { ready: false, blocking_reasons: [] }),
|
|
484
485
|
runAgent: (goal: string, roles: string[]) => post("/agents/api/run", { goal, roles }, {}),
|
|
486
|
+
toolRegistryDiagnostics: () => get("/tools/registry/diagnostics", { diagnostics: { ready: false } }),
|
|
487
|
+
toolRegistry: () => get("/tools/registry", { status: "unavailable", diagnostics: {}, tools: [] }),
|
|
485
488
|
agentRun: (id: string) => get(`/agents/api/runs/${encodeURIComponent(id)}`, {}),
|
|
486
489
|
stopAgentRun: (id: string) => post(`/agents/api/runs/${encodeURIComponent(id)}/stop`, {}, {}),
|
|
487
490
|
agentRegistry: () => get("/agents/api/registry", { agents: [] }),
|
|
@@ -15,7 +15,7 @@ export function AdminConsole({ onBack }: { onBack: () => void }) {
|
|
|
15
15
|
const qc = useQueryClient();
|
|
16
16
|
const language = useAppStore((state) => state.language);
|
|
17
17
|
const [filters, setFilters] = React.useState<AdminFilterState>({ q: "", actor: "", action: "", severity: "", limit: 50 });
|
|
18
|
-
const { summaryQ, statsQ, usersQ, auditQ, securityQ, securityEventsQ, policiesQ, rolesQ, retentionQ, indexQ } = useAdminConsoleData(filters);
|
|
18
|
+
const { summaryQ, statsQ, usersQ, auditQ, securityQ, securityEventsQ, policiesQ, rolesQ, retentionQ, indexQ, agentRuntimeQ, toolRegistryQ } = useAdminConsoleData(filters);
|
|
19
19
|
const rebuildIndex = useMutation({
|
|
20
20
|
mutationFn: latticeApi.rebuildIndex,
|
|
21
21
|
onSuccess: () => void qc.invalidateQueries({ queryKey: ["indexStatus"] }),
|
|
@@ -139,6 +139,10 @@ export function AdminConsole({ onBack }: { onBack: () => void }) {
|
|
|
139
139
|
</div>
|
|
140
140
|
</AdminPanel>
|
|
141
141
|
|
|
142
|
+
<AdminPanel title={t(language, "admin.panel.runtimeTrust")} eyebrow={t(language, "admin.panel.contracts")}>
|
|
143
|
+
<RuntimeTrustPanel runtime={agentRuntimeQ.data?.data as ApiRecord | undefined} registry={toolRegistryQ.data?.data as ApiRecord | undefined} language={language} />
|
|
144
|
+
</AdminPanel>
|
|
145
|
+
|
|
142
146
|
</section>
|
|
143
147
|
</main>
|
|
144
148
|
);
|
|
@@ -164,9 +168,45 @@ function useAdminConsoleData(filters: AdminFilterState) {
|
|
|
164
168
|
rolesQ: useQuery({ queryKey: ["adminRoles"], queryFn: latticeApi.adminRoles }),
|
|
165
169
|
retentionQ: useQuery({ queryKey: ["adminLogRetention"], queryFn: latticeApi.adminLogRetention }),
|
|
166
170
|
indexQ: useQuery({ queryKey: ["indexStatus"], queryFn: latticeApi.indexStatus }),
|
|
171
|
+
agentRuntimeQ: useQuery({ queryKey: ["agentRuntime"], queryFn: latticeApi.agentRuntime }),
|
|
172
|
+
toolRegistryQ: useQuery({ queryKey: ["toolRegistryDiagnostics"], queryFn: latticeApi.toolRegistryDiagnostics }),
|
|
167
173
|
};
|
|
168
174
|
}
|
|
169
175
|
|
|
176
|
+
function RuntimeTrustPanel({ runtime, registry, language }: { runtime?: ApiRecord; registry?: ApiRecord; language: "ko" | "en" }) {
|
|
177
|
+
const runtimeInfo = (runtime?.runtime || {}) as ApiRecord;
|
|
178
|
+
const health = (runtime?.health || {}) as ApiRecord;
|
|
179
|
+
const diagnostics = (registry?.diagnostics || {}) as ApiRecord;
|
|
180
|
+
const ready = Boolean(runtimeInfo.ready);
|
|
181
|
+
const registryReady = Boolean(diagnostics.ready);
|
|
182
|
+
const blocking = stringValue(runtimeInfo.unavailable_reason, ready ? t(language, "admin.runtime.readyDetail") : t(language, "admin.runtime.blockedFallback"));
|
|
183
|
+
return (
|
|
184
|
+
<div className="admin-runtime-trust">
|
|
185
|
+
<div className="admin-runtime-row">
|
|
186
|
+
<strong>{t(language, "admin.runtime.agent")}</strong>
|
|
187
|
+
<span className={ready ? "is-ok" : "is-warn"}>{ready ? t(language, "admin.status.ready") : t(language, "admin.status.unavailable")}</span>
|
|
188
|
+
<small>{blocking}</small>
|
|
189
|
+
</div>
|
|
190
|
+
<div className="admin-runtime-row">
|
|
191
|
+
<strong>{t(language, "admin.runtime.tools")}</strong>
|
|
192
|
+
<span className={registryReady ? "is-ok" : "is-warn"}>{registryReady ? t(language, "admin.runtime.aligned") : t(language, "admin.runtime.drift")}</span>
|
|
193
|
+
<small>
|
|
194
|
+
{t(language, "admin.runtime.toolCounts", {
|
|
195
|
+
registered: stringValue(diagnostics.registered_tools, "0"),
|
|
196
|
+
governed: stringValue(diagnostics.governed_tools, "0"),
|
|
197
|
+
described: stringValue(diagnostics.described_tools, "0"),
|
|
198
|
+
})}
|
|
199
|
+
</small>
|
|
200
|
+
</div>
|
|
201
|
+
<div className="admin-policy-strip">
|
|
202
|
+
<span>{t(language, "admin.runtime.mode", { mode: stringValue(runtimeInfo.mode, "unknown") })}</span>
|
|
203
|
+
<span>{t(language, "admin.runtime.execution", { mode: stringValue(runtimeInfo.execution_mode, "unknown") })}</span>
|
|
204
|
+
<span>{t(language, "admin.runtime.health", { status: stringValue(health.status, "unknown") })}</span>
|
|
205
|
+
</div>
|
|
206
|
+
</div>
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
170
210
|
function AdminLogFilters({
|
|
171
211
|
filters,
|
|
172
212
|
matched,
|
package/frontend/src/i18n.ts
CHANGED
|
@@ -348,6 +348,8 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
348
348
|
"admin.panel.protection": "보호",
|
|
349
349
|
"admin.panel.brainOps": "Brain 운영",
|
|
350
350
|
"admin.panel.maintenance": "유지보수",
|
|
351
|
+
"admin.panel.runtimeTrust": "런타임 신뢰도",
|
|
352
|
+
"admin.panel.contracts": "계약",
|
|
351
353
|
"admin.empty.users": "관리 API가 보고한 사용자가 없습니다.",
|
|
352
354
|
"admin.empty.roles": "보고된 역할 매트릭스가 없습니다.",
|
|
353
355
|
"admin.empty.audit": "최근 감사 이벤트가 없습니다.",
|
|
@@ -369,6 +371,16 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
369
371
|
"admin.brain.summaryFallback": "로컬 Brain 서비스는 사용자 대화와 분리되어 있습니다.",
|
|
370
372
|
"admin.brain.rebuilding": "재구성 중",
|
|
371
373
|
"admin.brain.rebuild": "인덱스 재구성",
|
|
374
|
+
"admin.runtime.agent": "AgentRuntime",
|
|
375
|
+
"admin.runtime.tools": "ToolRegistry",
|
|
376
|
+
"admin.runtime.readyDetail": "실행 preview와 실제 실행이 준비되었습니다.",
|
|
377
|
+
"admin.runtime.blockedFallback": "실행 전 preview가 차단 사유를 반환합니다.",
|
|
378
|
+
"admin.runtime.aligned": "정렬됨",
|
|
379
|
+
"admin.runtime.drift": "점검 필요",
|
|
380
|
+
"admin.runtime.toolCounts": "등록 {registered} · 정책 {governed} · 설명 {described}",
|
|
381
|
+
"admin.runtime.mode": "mode {mode}",
|
|
382
|
+
"admin.runtime.execution": "exec {mode}",
|
|
383
|
+
"admin.runtime.health": "health {status}",
|
|
372
384
|
"admin.policy.fallback": "정책",
|
|
373
385
|
"admin.policy.quiet": "정책 API 대기 중",
|
|
374
386
|
"admin.retention.days": "{days}일 보관",
|
|
@@ -894,6 +906,8 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
894
906
|
"admin.panel.protection": "Protection",
|
|
895
907
|
"admin.panel.brainOps": "Brain Operations",
|
|
896
908
|
"admin.panel.maintenance": "Maintenance",
|
|
909
|
+
"admin.panel.runtimeTrust": "Runtime Trust",
|
|
910
|
+
"admin.panel.contracts": "Contracts",
|
|
897
911
|
"admin.empty.users": "No users reported by the admin API.",
|
|
898
912
|
"admin.empty.roles": "No role matrix reported.",
|
|
899
913
|
"admin.empty.audit": "No recent audit events.",
|
|
@@ -915,6 +929,16 @@ export const COPY: Record<Language, TextMap> = {
|
|
|
915
929
|
"admin.brain.summaryFallback": "Local Brain services are separated from user chat.",
|
|
916
930
|
"admin.brain.rebuilding": "Rebuilding",
|
|
917
931
|
"admin.brain.rebuild": "Rebuild index",
|
|
932
|
+
"admin.runtime.agent": "AgentRuntime",
|
|
933
|
+
"admin.runtime.tools": "ToolRegistry",
|
|
934
|
+
"admin.runtime.readyDetail": "Run preview and execution are ready.",
|
|
935
|
+
"admin.runtime.blockedFallback": "Run preview returns the blocking reason before execution.",
|
|
936
|
+
"admin.runtime.aligned": "Aligned",
|
|
937
|
+
"admin.runtime.drift": "Needs review",
|
|
938
|
+
"admin.runtime.toolCounts": "Registered {registered} · governed {governed} · described {described}",
|
|
939
|
+
"admin.runtime.mode": "mode {mode}",
|
|
940
|
+
"admin.runtime.execution": "exec {mode}",
|
|
941
|
+
"admin.runtime.health": "health {status}",
|
|
918
942
|
"admin.policy.fallback": "Policy",
|
|
919
943
|
"admin.policy.quiet": "Policy API quiet",
|
|
920
944
|
"admin.retention.days": "{days} day retention",
|
package/frontend/src/styles.css
CHANGED
|
@@ -3472,6 +3472,51 @@ body {
|
|
|
3472
3472
|
font-size: 0.88rem;
|
|
3473
3473
|
}
|
|
3474
3474
|
|
|
3475
|
+
.admin-runtime-trust {
|
|
3476
|
+
display: grid;
|
|
3477
|
+
gap: 0.72rem;
|
|
3478
|
+
}
|
|
3479
|
+
|
|
3480
|
+
.admin-runtime-row {
|
|
3481
|
+
display: grid;
|
|
3482
|
+
grid-template-columns: minmax(8rem, 1fr) auto;
|
|
3483
|
+
gap: 0.2rem 0.75rem;
|
|
3484
|
+
border: 1px solid hsl(var(--border) / 0.48);
|
|
3485
|
+
border-radius: 8px;
|
|
3486
|
+
background: hsl(var(--bg) / 0.35);
|
|
3487
|
+
padding: 0.72rem;
|
|
3488
|
+
}
|
|
3489
|
+
|
|
3490
|
+
.admin-runtime-row strong {
|
|
3491
|
+
color: hsl(var(--fg));
|
|
3492
|
+
font-size: 0.88rem;
|
|
3493
|
+
}
|
|
3494
|
+
|
|
3495
|
+
.admin-runtime-row > span {
|
|
3496
|
+
align-self: start;
|
|
3497
|
+
border-radius: 999px;
|
|
3498
|
+
padding: 0.18rem 0.48rem;
|
|
3499
|
+
font-size: 0.72rem;
|
|
3500
|
+
font-weight: 700;
|
|
3501
|
+
}
|
|
3502
|
+
|
|
3503
|
+
.admin-runtime-row > small {
|
|
3504
|
+
grid-column: 1 / -1;
|
|
3505
|
+
color: hsl(var(--fg-muted));
|
|
3506
|
+
font-size: 0.78rem;
|
|
3507
|
+
line-height: 1.35;
|
|
3508
|
+
}
|
|
3509
|
+
|
|
3510
|
+
.admin-runtime-row .is-ok {
|
|
3511
|
+
background: hsl(151 65% 36% / 0.13);
|
|
3512
|
+
color: hsl(151 48% 32%);
|
|
3513
|
+
}
|
|
3514
|
+
|
|
3515
|
+
.admin-runtime-row .is-warn {
|
|
3516
|
+
background: hsl(36 88% 52% / 0.14);
|
|
3517
|
+
color: hsl(30 82% 35%);
|
|
3518
|
+
}
|
|
3519
|
+
|
|
3475
3520
|
.brain-document-input,
|
|
3476
3521
|
.brain-image-input {
|
|
3477
3522
|
display: inline-flex;
|
|
@@ -37,6 +37,7 @@ from .multi_agent import (
|
|
|
37
37
|
MULTI_AGENT_VERSION,
|
|
38
38
|
ROLE_AGENT_IDS,
|
|
39
39
|
)
|
|
40
|
+
from .contracts import multi_agent_contract
|
|
40
41
|
|
|
41
42
|
ROLE_DESCRIPTIONS = {
|
|
42
43
|
"researcher": "Gathers workspace context and memory for the goal.",
|
|
@@ -228,6 +229,57 @@ class AgentRuntime:
|
|
|
228
229
|
"runs": runs[:25],
|
|
229
230
|
}
|
|
230
231
|
|
|
232
|
+
def preview(
|
|
233
|
+
self,
|
|
234
|
+
goal: str,
|
|
235
|
+
*,
|
|
236
|
+
roles: Optional[List[str]] = None,
|
|
237
|
+
inputs: Optional[Dict[str, Any]] = None,
|
|
238
|
+
max_retries: int = 2,
|
|
239
|
+
scope: Optional[str] = None,
|
|
240
|
+
) -> Dict[str, Any]:
|
|
241
|
+
"""Return the execution contract without reserving or starting a run.
|
|
242
|
+
|
|
243
|
+
The preview is the product-facing readiness gate for agent execution:
|
|
244
|
+
clients can show whether a real LLM-backed run can start, which roles
|
|
245
|
+
will execute, how retry limits are clamped, and why the run is blocked.
|
|
246
|
+
"""
|
|
247
|
+
|
|
248
|
+
requested_roles = list(roles or CORE_PIPELINE)
|
|
249
|
+
unknown_roles = [role for role in requested_roles if role not in AGENT_ROLES]
|
|
250
|
+
health = self.health()
|
|
251
|
+
goal_ready = bool(str(goal or "").strip())
|
|
252
|
+
retry_budget = max(0, min(int(max_retries or 0), self._max_retries_cap))
|
|
253
|
+
blocking_reasons: List[str] = []
|
|
254
|
+
if not goal_ready:
|
|
255
|
+
blocking_reasons.append("goal is required")
|
|
256
|
+
if unknown_roles:
|
|
257
|
+
blocking_reasons.append(f"unknown roles: {', '.join(unknown_roles)}")
|
|
258
|
+
if not health.get("ready"):
|
|
259
|
+
orchestrator = (health.get("checks") or {}).get("orchestrator") or {}
|
|
260
|
+
blocking_reasons.append(str(orchestrator.get("detail") or "agent runtime is unavailable"))
|
|
261
|
+
can_start = not blocking_reasons
|
|
262
|
+
return {
|
|
263
|
+
"ready": can_start,
|
|
264
|
+
"can_start": can_start,
|
|
265
|
+
"blocking_reasons": blocking_reasons,
|
|
266
|
+
"goal": str(goal or "").strip(),
|
|
267
|
+
"roles": requested_roles,
|
|
268
|
+
"unknown_roles": unknown_roles,
|
|
269
|
+
"inputs_keys": sorted((inputs or {}).keys()),
|
|
270
|
+
"max_retries": retry_budget,
|
|
271
|
+
"max_retries_requested": max_retries,
|
|
272
|
+
"scope": scope,
|
|
273
|
+
"execution_mode": self._execution_mode(),
|
|
274
|
+
"runtime": {
|
|
275
|
+
"version": MULTI_AGENT_VERSION,
|
|
276
|
+
"default_pipeline": list(CORE_PIPELINE),
|
|
277
|
+
"max_retries_cap": self._max_retries_cap,
|
|
278
|
+
"simulation_runs_allowed": self._allow_simulation_runs,
|
|
279
|
+
},
|
|
280
|
+
"health": health,
|
|
281
|
+
}
|
|
282
|
+
|
|
231
283
|
# ── events / state ────────────────────────────────────────────────────
|
|
232
284
|
def list_runs(self, *, scope: Optional[str] = None) -> Dict[str, Any]:
|
|
233
285
|
return self._store.list_agents(workspace_id=scope)
|
|
@@ -293,6 +345,7 @@ class AgentRuntime:
|
|
|
293
345
|
"retry_history": result.retry_history,
|
|
294
346
|
"memory_snapshots": result.memory_snapshots,
|
|
295
347
|
"mode": getattr(result, "mode", "simulation"),
|
|
348
|
+
"contract": multi_agent_contract(result=result, goal=goal),
|
|
296
349
|
"current_role": None,
|
|
297
350
|
}
|
|
298
351
|
|
|
@@ -458,6 +511,12 @@ class AgentRuntime:
|
|
|
458
511
|
status=updated.get("status") or result.status,
|
|
459
512
|
)
|
|
460
513
|
result_payload = result.as_dict()
|
|
514
|
+
result_payload["contract"] = multi_agent_contract(
|
|
515
|
+
result=result,
|
|
516
|
+
goal=goal,
|
|
517
|
+
run_id=run_id,
|
|
518
|
+
current_role=updated.get("current_role") if isinstance(updated, dict) else None,
|
|
519
|
+
)
|
|
461
520
|
if updated.get("status") == "cancelled":
|
|
462
521
|
result_payload = {"status": "cancelled", "reason": updated.get("cancel_reason"), "completed_result": result_payload}
|
|
463
522
|
payload = {"run": updated, "result": result_payload}
|
|
@@ -550,7 +609,9 @@ class AgentRuntime:
|
|
|
550
609
|
user_email=user_email, workspace_id=scope,
|
|
551
610
|
)
|
|
552
611
|
|
|
553
|
-
|
|
612
|
+
result_payload = result.as_dict()
|
|
613
|
+
result_payload["contract"] = multi_agent_contract(result=result, goal=goal, run_id=run.get("id") if isinstance(run, dict) else None)
|
|
614
|
+
payload = {"run": run, "result": result_payload}
|
|
554
615
|
if pre_dispatch is not None:
|
|
555
616
|
payload["pre_run_hooks"] = pre_dispatch
|
|
556
617
|
if post_dispatch is not None:
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"""Shared runtime contracts for agent execution surfaces.
|
|
2
|
+
|
|
3
|
+
These contracts are deliberately small and serializable. The single-agent
|
|
4
|
+
state machine and the multi-agent facade can evolve independently, but callers
|
|
5
|
+
should see the same run identity, mode, status, role, timeline and artifact
|
|
6
|
+
shape across both paths.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from dataclasses import dataclass, field
|
|
12
|
+
from datetime import datetime
|
|
13
|
+
from typing import Any, Dict, List, Optional
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def runtime_timestamp() -> str:
|
|
17
|
+
return datetime.now().isoformat(timespec="seconds")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass(frozen=True)
|
|
21
|
+
class AgentRunContract:
|
|
22
|
+
run_id: Optional[str]
|
|
23
|
+
agent_id: str
|
|
24
|
+
runtime: str
|
|
25
|
+
mode: str
|
|
26
|
+
status: str
|
|
27
|
+
goal: str
|
|
28
|
+
roles: List[str] = field(default_factory=list)
|
|
29
|
+
current_role: Optional[str] = None
|
|
30
|
+
retries: int = 0
|
|
31
|
+
timeline: List[Dict[str, Any]] = field(default_factory=list)
|
|
32
|
+
artifacts: List[Dict[str, Any]] = field(default_factory=list)
|
|
33
|
+
blocking_reasons: List[str] = field(default_factory=list)
|
|
34
|
+
schema_version: str = "agent-run-contract/v1"
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def is_terminal(self) -> bool:
|
|
38
|
+
return self.status in {"ok", "retried_ok", "failed", "rejected", "cancelled", "interrupted", "partial", "done"}
|
|
39
|
+
|
|
40
|
+
def as_dict(self) -> Dict[str, Any]:
|
|
41
|
+
return {
|
|
42
|
+
"schema_version": self.schema_version,
|
|
43
|
+
"run_id": self.run_id,
|
|
44
|
+
"agent_id": self.agent_id,
|
|
45
|
+
"runtime": self.runtime,
|
|
46
|
+
"mode": self.mode,
|
|
47
|
+
"status": self.status,
|
|
48
|
+
"goal": self.goal,
|
|
49
|
+
"roles": list(self.roles),
|
|
50
|
+
"current_role": self.current_role,
|
|
51
|
+
"retries": self.retries,
|
|
52
|
+
"timeline": list(self.timeline),
|
|
53
|
+
"artifacts": list(self.artifacts),
|
|
54
|
+
"blocking_reasons": list(self.blocking_reasons),
|
|
55
|
+
"is_terminal": self.is_terminal,
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def multi_agent_contract(
|
|
60
|
+
*,
|
|
61
|
+
result: Any,
|
|
62
|
+
goal: str,
|
|
63
|
+
run_id: Optional[str] = None,
|
|
64
|
+
current_role: Optional[str] = None,
|
|
65
|
+
blocking_reasons: Optional[List[str]] = None,
|
|
66
|
+
) -> Dict[str, Any]:
|
|
67
|
+
return AgentRunContract(
|
|
68
|
+
run_id=run_id,
|
|
69
|
+
agent_id=getattr(result, "agent_id", "agent:executor"),
|
|
70
|
+
runtime="multi_agent",
|
|
71
|
+
mode=getattr(result, "mode", "simulation"),
|
|
72
|
+
status=getattr(result, "status", "unknown"),
|
|
73
|
+
goal=goal,
|
|
74
|
+
roles=list(getattr(result, "roles_run", []) or []),
|
|
75
|
+
current_role=current_role,
|
|
76
|
+
retries=int(getattr(result, "retries", 0) or 0),
|
|
77
|
+
timeline=list(getattr(result, "timeline", []) or []),
|
|
78
|
+
artifacts=[],
|
|
79
|
+
blocking_reasons=list(blocking_reasons or []),
|
|
80
|
+
).as_dict()
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def single_agent_contract(
|
|
84
|
+
*,
|
|
85
|
+
ctx: Any,
|
|
86
|
+
goal: str,
|
|
87
|
+
run_id: Optional[str] = None,
|
|
88
|
+
agent_id: str = "agent:single",
|
|
89
|
+
mode: str = "llm",
|
|
90
|
+
blocking_reasons: Optional[List[str]] = None,
|
|
91
|
+
) -> Dict[str, Any]:
|
|
92
|
+
state = getattr(getattr(ctx, "state", None), "value", getattr(ctx, "state", "unknown"))
|
|
93
|
+
status = "done" if state == "DONE" else "failed" if state == "FAILED" else str(state or "unknown").lower()
|
|
94
|
+
return AgentRunContract(
|
|
95
|
+
run_id=run_id,
|
|
96
|
+
agent_id=agent_id,
|
|
97
|
+
runtime="single_agent",
|
|
98
|
+
mode=mode,
|
|
99
|
+
status=status,
|
|
100
|
+
goal=goal,
|
|
101
|
+
roles=["planner", "executor", "critic"],
|
|
102
|
+
current_role=str(state or ""),
|
|
103
|
+
retries=int(getattr(ctx, "retry_count", 0) or 0),
|
|
104
|
+
timeline=list(getattr(ctx, "transcript", []) or []),
|
|
105
|
+
artifacts=[],
|
|
106
|
+
blocking_reasons=list(blocking_reasons or []),
|
|
107
|
+
).as_dict()
|
|
@@ -18,8 +18,10 @@ from dataclasses import dataclass, field
|
|
|
18
18
|
from datetime import datetime
|
|
19
19
|
from typing import Any, Callable, Dict, List, Optional
|
|
20
20
|
|
|
21
|
+
from .contracts import multi_agent_contract
|
|
21
22
|
|
|
22
|
-
|
|
23
|
+
|
|
24
|
+
MULTI_AGENT_VERSION = "7.3.0"
|
|
23
25
|
|
|
24
26
|
AGENT_ROLES = ("researcher", "planner", "executor", "reviewer", "release")
|
|
25
27
|
CORE_PIPELINE = ("planner", "executor", "reviewer")
|
|
@@ -288,7 +290,7 @@ class AgentRunResult:
|
|
|
288
290
|
mode: str = "simulation"
|
|
289
291
|
|
|
290
292
|
def as_dict(self) -> Dict[str, Any]:
|
|
291
|
-
|
|
293
|
+
payload = {
|
|
292
294
|
"agent_id": self.agent_id,
|
|
293
295
|
"mode": self.mode,
|
|
294
296
|
"status": self.status,
|
|
@@ -305,6 +307,8 @@ class AgentRunResult:
|
|
|
305
307
|
"plan_review": self.plan_review,
|
|
306
308
|
"memory_snapshots": self.memory_snapshots,
|
|
307
309
|
}
|
|
310
|
+
payload["contract"] = multi_agent_contract(result=self, goal=self.output)
|
|
311
|
+
return payload
|
|
308
312
|
|
|
309
313
|
|
|
310
314
|
def default_role_runner(
|
package/latticeai/__init__.py
CHANGED
package/latticeai/api/agents.py
CHANGED
|
@@ -192,4 +192,16 @@ def create_agents_router(
|
|
|
192
192
|
# A pre_run hook gated this run (e.g. a policy/permission hook).
|
|
193
193
|
raise HTTPException(status_code=403, detail=str(exc)) from exc
|
|
194
194
|
|
|
195
|
+
@router.post("/agents/api/run/preview")
|
|
196
|
+
async def agent_run_preview(req: AgentRunRequest, request: Request):
|
|
197
|
+
require_user(request)
|
|
198
|
+
scope = gate_read(request)
|
|
199
|
+
return runtime.preview(
|
|
200
|
+
req.goal,
|
|
201
|
+
scope=scope,
|
|
202
|
+
roles=req.roles or None,
|
|
203
|
+
inputs=req.inputs,
|
|
204
|
+
max_retries=req.max_retries,
|
|
205
|
+
)
|
|
206
|
+
|
|
195
207
|
return router
|
package/latticeai/api/tools.py
CHANGED
|
@@ -25,6 +25,8 @@ from latticeai.services.tool_dispatch import (
|
|
|
25
25
|
check_tool_role as _check_tool_role,
|
|
26
26
|
get_tool_permission,
|
|
27
27
|
list_tool_permissions,
|
|
28
|
+
tool_registry_diagnostics,
|
|
29
|
+
tool_registry_manifest,
|
|
28
30
|
)
|
|
29
31
|
from latticeai.services.router_context import ToolRouterContext
|
|
30
32
|
from latticeai.services.p_reinforce import BRAIN_DIR
|
|
@@ -602,6 +604,18 @@ def create_tools_router(
|
|
|
602
604
|
"""
|
|
603
605
|
require_user(request)
|
|
604
606
|
return {"status": "ok", "permissions": list_tool_permissions()}
|
|
607
|
+
|
|
608
|
+
@api_router.get("/tools/registry")
|
|
609
|
+
async def tools_registry(request: Request):
|
|
610
|
+
"""Full ToolRegistry contract: handlers, governance, catalog, diagnostics."""
|
|
611
|
+
require_user(request)
|
|
612
|
+
return tool_registry_manifest()
|
|
613
|
+
|
|
614
|
+
@api_router.get("/tools/registry/diagnostics")
|
|
615
|
+
async def tools_registry_diagnostics(request: Request):
|
|
616
|
+
"""Small drift check for CI/admin runtime readiness views."""
|
|
617
|
+
require_user(request)
|
|
618
|
+
return {"status": "ok", "diagnostics": tool_registry_diagnostics()}
|
|
605
619
|
|
|
606
620
|
|
|
607
621
|
# ── MCP / skills / plugins router (latticeai.api.mcp, v1.3.0) ────────────────
|