ltcai 3.6.0 → 4.0.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 +11 -7
- package/docs/V4_BRAIN_ARCHITECTURE.md +322 -0
- package/docs/V4_DIGITAL_BRAIN_RECOVERY.md +509 -0
- package/docs/V4_IMPLEMENTATION_PLAN.md +470 -0
- package/docs/kg-schema.md +47 -53
- package/kg_schema.py +93 -10
- package/knowledge_graph.py +362 -33
- package/knowledge_graph_api.py +11 -127
- package/latticeai/__init__.py +1 -1
- package/latticeai/api/admin.py +1 -1
- package/latticeai/api/agents.py +7 -1
- package/latticeai/api/auth.py +27 -4
- package/latticeai/api/chat.py +112 -76
- package/latticeai/api/health.py +1 -1
- package/latticeai/api/hooks.py +1 -1
- package/latticeai/api/knowledge_graph.py +146 -0
- package/latticeai/api/local_files.py +1 -1
- package/latticeai/api/mcp.py +23 -11
- package/latticeai/api/memory.py +1 -1
- package/latticeai/api/models.py +1 -1
- package/latticeai/api/network.py +81 -0
- package/latticeai/api/realtime.py +1 -1
- package/latticeai/api/search.py +26 -2
- package/latticeai/api/security_dashboard.py +2 -3
- package/latticeai/api/setup.py +2 -2
- package/latticeai/api/static_routes.py +2 -4
- package/latticeai/api/tools.py +3 -0
- package/latticeai/api/workflow_designer.py +46 -0
- package/latticeai/api/workspace.py +71 -49
- package/latticeai/app_factory.py +1710 -0
- package/latticeai/brain/__init__.py +18 -0
- package/latticeai/brain/context.py +213 -0
- package/latticeai/brain/conversations.py +236 -0
- package/latticeai/brain/identity.py +175 -0
- package/latticeai/brain/memory.py +102 -0
- package/latticeai/brain/network.py +205 -0
- package/latticeai/core/agent.py +31 -7
- package/latticeai/core/audit.py +0 -7
- package/latticeai/core/config.py +1 -1
- package/latticeai/core/context_builder.py +1 -2
- package/latticeai/core/enterprise.py +1 -1
- package/latticeai/core/graph_curator.py +2 -2
- package/latticeai/core/marketplace.py +1 -1
- package/latticeai/core/mcp_registry.py +791 -0
- package/latticeai/core/model_compat.py +1 -1
- package/latticeai/core/model_resolution.py +0 -1
- package/latticeai/core/multi_agent.py +238 -4
- package/latticeai/core/security.py +1 -1
- package/latticeai/core/sessions.py +37 -7
- package/latticeai/core/workflow_engine.py +114 -2
- package/latticeai/core/workspace_os.py +58 -10
- package/latticeai/models/__init__.py +7 -0
- package/latticeai/models/router.py +779 -0
- package/latticeai/server_app.py +29 -1536
- package/latticeai/services/agent_runtime.py +1 -0
- package/latticeai/services/app_context.py +75 -14
- package/latticeai/services/ingestion.py +47 -0
- package/latticeai/services/kg_portability.py +33 -3
- package/latticeai/services/memory_service.py +39 -11
- package/latticeai/services/model_runtime.py +2 -5
- package/latticeai/services/platform_runtime.py +100 -23
- package/latticeai/services/search_service.py +17 -8
- package/latticeai/services/tool_dispatch.py +12 -2
- package/latticeai/services/triggers.py +241 -0
- package/latticeai/services/upload_service.py +37 -12
- package/latticeai/services/workspace_service.py +31 -0
- package/llm_router.py +29 -772
- package/ltcai_cli.py +1 -2
- package/mcp_registry.py +25 -788
- package/p_reinforce.py +124 -14
- package/package.json +9 -7
- package/scripts/bump_version.py +99 -0
- package/scripts/generate_diagrams.py +0 -1
- package/scripts/lint_v3.mjs +82 -18
- package/scripts/validate_release_artifacts.py +0 -1
- package/scripts/wheel_smoke.py +142 -0
- package/server.py +11 -7
- package/setup_wizard.py +1142 -0
- package/static/account.html +2 -4
- package/static/admin.html +3 -5
- package/static/chat.html +3 -6
- package/static/graph.html +2 -4
- package/static/sw.js +81 -52
- package/static/v3/asset-manifest.json +20 -19
- package/static/v3/css/{lattice.base.e4cdd05d.css → lattice.base.49deefb5.css} +1 -1
- package/static/v3/css/lattice.base.css +1 -1
- package/static/v3/css/{lattice.components.9b49d614.css → lattice.components.cde18231.css} +1 -1
- package/static/v3/css/lattice.components.css +1 -1
- package/static/v3/css/{lattice.shell.8fcc9d33.css → lattice.shell.29d36d85.css} +1 -1
- package/static/v3/css/lattice.shell.css +1 -1
- package/static/v3/css/{lattice.tokens.e7018963.css → lattice.tokens.304cbc40.css} +3 -0
- package/static/v3/css/lattice.tokens.css +3 -0
- package/static/v3/css/{lattice.views.22f69117.css → lattice.views.0a18b6c5.css} +2 -2
- package/static/v3/css/lattice.views.css +2 -2
- package/static/v3/index.html +3 -4
- package/static/v3/js/{app.c541f955.js → app.356e6452.js} +1 -1
- package/static/v3/js/core/{api.33d6320e.js → api.7a308b89.js} +1 -1
- package/static/v3/js/core/{routes.2ce3815a.js → routes.7222343d.js} +22 -22
- package/static/v3/js/core/routes.js +22 -22
- package/static/v3/js/core/{shell.8c163e0e.js → shell.a1657f20.js} +4 -4
- package/static/v3/js/core/shell.js +1 -1
- package/static/v3/js/core/{store.34ebd5e6.js → store.204a08b2.js} +1 -1
- package/static/v3/js/core/store.js +1 -1
- package/static/v3/js/views/graph-canvas.17c15d65.js +509 -0
- package/static/v3/js/views/graph-canvas.js +509 -0
- package/static/v3/js/views/{hybrid-search.b22b97e0.js → hybrid-search.2fb63ed9.js} +1 -2
- package/static/v3/js/views/hybrid-search.js +1 -2
- package/static/v3/js/views/{knowledge-graph.a96040a5.js → knowledge-graph.5e40cbeb.js} +33 -37
- package/static/v3/js/views/knowledge-graph.js +33 -37
- package/static/vendor/chart.umd.min.js +20 -0
- package/static/vendor/fonts/inter-latin-300-normal.woff2 +0 -0
- package/static/vendor/fonts/inter-latin-400-normal.woff2 +0 -0
- package/static/vendor/fonts/inter-latin-500-normal.woff2 +0 -0
- package/static/vendor/fonts/inter-latin-600-normal.woff2 +0 -0
- package/static/vendor/fonts/inter-latin-700-normal.woff2 +0 -0
- package/static/vendor/fonts/inter-latin-800-normal.woff2 +0 -0
- package/static/vendor/fonts/inter.css +44 -0
- package/static/vendor/icons/tabler-icons.min.css +4 -0
- package/static/vendor/icons/tabler-icons.woff2 +0 -0
- package/static/vendor/marked.min.js +69 -0
- package/static/workspace.html +2 -2
- package/telegram_bot.py +1 -2
- package/tools/commands.py +4 -2
- package/tools/computer.py +1 -1
- package/tools/documents.py +1 -3
- package/tools/filesystem.py +0 -4
- package/tools/knowledge.py +1 -3
- package/tools/network.py +1 -3
- package/codex_telegram_bot.py +0 -195
- package/docs/assets/v3.4.0/agent-run.png +0 -0
- package/docs/assets/v3.4.0/agents.png +0 -0
- package/docs/assets/v3.4.0/before/chat-before.png +0 -0
- package/docs/assets/v3.4.0/before/files-before.png +0 -0
- package/docs/assets/v3.4.0/chat.png +0 -0
- package/docs/assets/v3.4.0/connect-folder.png +0 -0
- package/docs/assets/v3.4.0/files.png +0 -0
- package/docs/assets/v3.4.0/home.png +0 -0
- package/docs/assets/v3.4.0/hooks-dispatch.png +0 -0
- package/docs/assets/v3.4.0/knowledge-graph.png +0 -0
- package/docs/assets/v3.4.0/local-agent.png +0 -0
- package/docs/assets/v3.4.0/memory.png +0 -0
- package/docs/assets/v3.4.0/settings.png +0 -0
- package/docs/assets/v3.4.0/vision-input.png +0 -0
- package/docs/assets/v3.4.0/workflows.png +0 -0
- package/docs/assets/v3.4.1/e2e_runtime_log.txt +0 -42
- package/docs/assets/v3.4.1/hooks-dispatch.png +0 -0
- package/docs/assets/v3.4.1/local-agent.png +0 -0
- package/docs/images/admin-dashboard.png +0 -0
- package/docs/images/architecture.png +0 -0
- package/docs/images/enterprise.png +0 -0
- package/docs/images/graph.png +0 -0
- package/docs/images/hero.gif +0 -0
- package/docs/images/knowledge-graph.png +0 -0
- package/docs/images/lattice-ai-demo.gif +0 -0
- package/docs/images/lattice-ai-hero.png +0 -0
- package/docs/images/logo.svg +0 -33
- package/docs/images/mobile-responsive.png +0 -0
- package/docs/images/model-recommendation.png +0 -0
- package/docs/images/onboarding.png +0 -0
- package/docs/images/organization.png +0 -0
- package/docs/images/pipeline.png +0 -0
- package/docs/images/screenshot-admin.png +0 -0
- package/docs/images/screenshot-chat.png +0 -0
- package/docs/images/screenshot-graph.png +0 -0
- package/docs/images/skills.png +0 -0
- package/docs/images/workspace-dark.png +0 -0
- package/docs/images/workspace-light.png +0 -0
- package/docs/images/workspace.png +0 -0
- package/requirements.txt +0 -16
package/kg_schema.py
CHANGED
|
@@ -116,8 +116,14 @@ class NodeType(str, Enum):
|
|
|
116
116
|
매핑이 없는(동적 이벤트 등) 타입은 ``CONCEPT`` 로 폴백하지만, 호출부는
|
|
117
117
|
원본 문자열을 ``legacy_type`` 칼럼에 별도 보존하므로 정보 손실은 없다.
|
|
118
118
|
"""
|
|
119
|
-
m = (label or "").strip()
|
|
120
|
-
|
|
119
|
+
m = (label or "").strip()
|
|
120
|
+
# Canonical values round-trip exactly (v4 native writes use them);
|
|
121
|
+
# without this, CODE_FILE/AI_RESPONSE etc. would degrade to CONCEPT.
|
|
122
|
+
try:
|
|
123
|
+
return cls(m.upper())
|
|
124
|
+
except ValueError:
|
|
125
|
+
pass
|
|
126
|
+
return _LEGACY_NODE_MAP.get(m.lower(), cls.CONCEPT)
|
|
121
127
|
|
|
122
128
|
|
|
123
129
|
class EdgeType(str, Enum):
|
|
@@ -170,8 +176,13 @@ class EdgeType(str, Enum):
|
|
|
170
176
|
매핑이 없는 동적 타입은 ``MENTIONS`` 로 폴백하지만, 호출부는 원본 문자열을
|
|
171
177
|
``edges_v2.legacy_type`` 에 보존하므로 정보 손실은 없다.
|
|
172
178
|
"""
|
|
173
|
-
m = (label or "").strip()
|
|
174
|
-
|
|
179
|
+
m = (label or "").strip()
|
|
180
|
+
# Canonical values round-trip exactly (v4 native writes use them).
|
|
181
|
+
try:
|
|
182
|
+
return cls(m.upper())
|
|
183
|
+
except ValueError:
|
|
184
|
+
pass
|
|
185
|
+
return _LEGACY_EDGE_MAP.get(m.lower(), cls.MENTIONS)
|
|
175
186
|
|
|
176
187
|
|
|
177
188
|
# legacy(자유 문자열 / 한글 동사) → enum 매핑 표.
|
|
@@ -318,7 +329,13 @@ CREATE TABLE IF NOT EXISTS nodes_v2 (
|
|
|
318
329
|
attrs TEXT NOT NULL DEFAULT '{}',
|
|
319
330
|
embedding BLOB,
|
|
320
331
|
owner_id TEXT,
|
|
332
|
+
-- NULL workspace_id = legacy-global (pre-scoping rows, readable machine-wide).
|
|
333
|
+
workspace_id TEXT,
|
|
334
|
+
-- 'legacy' marks rows that predate scoping — the 'private' default must not
|
|
335
|
+
-- silently privatize previously machine-shared data (design-review ruling).
|
|
321
336
|
visibility TEXT NOT NULL DEFAULT 'private',
|
|
337
|
+
-- Revision chain: a node replaced by a newer one points at its successor.
|
|
338
|
+
superseded_by TEXT,
|
|
322
339
|
created_at TEXT NOT NULL,
|
|
323
340
|
updated_at TEXT NOT NULL,
|
|
324
341
|
style TEXT,
|
|
@@ -339,14 +356,33 @@ CREATE TABLE IF NOT EXISTS edges_v2 (
|
|
|
339
356
|
metadata TEXT NOT NULL DEFAULT '{}',
|
|
340
357
|
created_by TEXT NOT NULL DEFAULT 'user',
|
|
341
358
|
created_at TEXT NOT NULL,
|
|
342
|
-
-- Edge identity
|
|
343
|
-
--
|
|
344
|
-
--
|
|
345
|
-
|
|
359
|
+
-- Edge identity (v4): the normalized type AND the raw legacy type.
|
|
360
|
+
-- Migrated rows keep their legacy_type discriminator, so two distinct
|
|
361
|
+
-- legacy strings between one pair (e.g. "mentions" / "관련됨") stay
|
|
362
|
+
-- distinct even though both normalize to MENTIONS. Native canonical
|
|
363
|
+
-- writes carry legacy_type='' so their identity is effectively
|
|
364
|
+
-- (source, target, type) — two canonical types between the same pair
|
|
365
|
+
-- (e.g. MENTIONS + CONTAINS) never collide. The pre-v4
|
|
366
|
+
-- UNIQUE(source, target, legacy_type) would have silently merged them.
|
|
367
|
+
UNIQUE(source, target, type, legacy_type),
|
|
346
368
|
FOREIGN KEY(source) REFERENCES nodes_v2(id) ON DELETE CASCADE,
|
|
347
369
|
FOREIGN KEY(target) REFERENCES nodes_v2(id) ON DELETE CASCADE
|
|
348
370
|
);
|
|
349
371
|
|
|
372
|
+
-- Temporal dimension (v4): every repeated observation of a relationship is
|
|
373
|
+
-- recorded — edges_v2's UNIQUE identity + weight=max would otherwise erase
|
|
374
|
+
-- when something was learned, how often, and whether it still holds.
|
|
375
|
+
CREATE TABLE IF NOT EXISTS edge_occurrences (
|
|
376
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
377
|
+
edge_id TEXT NOT NULL,
|
|
378
|
+
observed_at TEXT NOT NULL,
|
|
379
|
+
weight REAL NOT NULL DEFAULT 1.0,
|
|
380
|
+
source TEXT,
|
|
381
|
+
FOREIGN KEY(edge_id) REFERENCES edges_v2(id) ON DELETE CASCADE
|
|
382
|
+
);
|
|
383
|
+
CREATE INDEX IF NOT EXISTS idx_edge_occurrences_edge ON edge_occurrences(edge_id);
|
|
384
|
+
CREATE INDEX IF NOT EXISTS idx_edge_occurrences_time ON edge_occurrences(observed_at);
|
|
385
|
+
|
|
350
386
|
CREATE INDEX IF NOT EXISTS idx_nodes_v2_type ON nodes_v2(type);
|
|
351
387
|
CREATE INDEX IF NOT EXISTS idx_nodes_v2_legacy ON nodes_v2(legacy_type);
|
|
352
388
|
CREATE INDEX IF NOT EXISTS idx_nodes_v2_owner ON nodes_v2(owner_id);
|
|
@@ -398,8 +434,16 @@ class KGStoreV2:
|
|
|
398
434
|
"edges_v2": {"id", "source", "target", "type", "legacy_type", "weight",
|
|
399
435
|
"confidence", "evidence", "metadata", "created_by", "created_at"},
|
|
400
436
|
"nodes_v2": {"id", "type", "legacy_type", "label", "summary", "attrs",
|
|
401
|
-
"embedding", "owner_id", "
|
|
402
|
-
"
|
|
437
|
+
"embedding", "owner_id", "workspace_id", "visibility",
|
|
438
|
+
"superseded_by", "created_at", "updated_at", "style",
|
|
439
|
+
"tone", "importance_score", "last_used"},
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
# Columns added after a table's first release that can be healed in place
|
|
443
|
+
# with ALTER TABLE ADD COLUMN (nullable / defaulted only).
|
|
444
|
+
_V2_ADDABLE_COLUMNS = {
|
|
445
|
+
"nodes_v2": {"workspace_id": "TEXT", "superseded_by": "TEXT"},
|
|
446
|
+
"edges_v2": {},
|
|
403
447
|
}
|
|
404
448
|
|
|
405
449
|
def _drop_stale_empty_v2_tables(self, conn: sqlite3.Connection) -> None:
|
|
@@ -420,6 +464,13 @@ class KGStoreV2:
|
|
|
420
464
|
continue
|
|
421
465
|
cols = {r[1] for r in conn.execute(f"PRAGMA table_info({table})").fetchall()}
|
|
422
466
|
missing = self._V2_EXPECTED_COLUMNS[table] - cols
|
|
467
|
+
if not missing:
|
|
468
|
+
continue
|
|
469
|
+
# Additive columns heal in place without touching data.
|
|
470
|
+
addable = self._V2_ADDABLE_COLUMNS.get(table, {})
|
|
471
|
+
for col in sorted(missing & set(addable)):
|
|
472
|
+
conn.execute(f"ALTER TABLE {table} ADD COLUMN {col} {addable[col]}")
|
|
473
|
+
missing -= set(addable)
|
|
423
474
|
if not missing:
|
|
424
475
|
continue
|
|
425
476
|
count = conn.execute(f"SELECT COUNT(*) FROM {table}").fetchone()[0]
|
|
@@ -446,8 +497,40 @@ class KGStoreV2:
|
|
|
446
497
|
with self._conn() as own:
|
|
447
498
|
self._init_schema_on(own)
|
|
448
499
|
|
|
500
|
+
def _rebuild_edges_identity(self, conn: sqlite3.Connection) -> None:
|
|
501
|
+
"""Migrate edges_v2 from the pre-v4 UNIQUE(source, target, legacy_type)
|
|
502
|
+
identity to UNIQUE(source, target, type, legacy_type).
|
|
503
|
+
|
|
504
|
+
SQLite cannot alter constraints, so this is a create→copy→swap inside
|
|
505
|
+
the caller's transaction. Data-preserving: every existing row keeps its
|
|
506
|
+
legacy_type discriminator. Re-entrant: keyed on the actual constraint
|
|
507
|
+
in sqlite_master, not a one-time stamp.
|
|
508
|
+
"""
|
|
509
|
+
row = conn.execute(
|
|
510
|
+
"SELECT sql FROM sqlite_master WHERE type='table' AND name='edges_v2'"
|
|
511
|
+
).fetchone()
|
|
512
|
+
if not row or "UNIQUE(source, target, type, legacy_type)" in (row["sql"] or ""):
|
|
513
|
+
return
|
|
514
|
+
conn.execute("ALTER TABLE edges_v2 RENAME TO edges_v2_old")
|
|
515
|
+
# Recreate from the canonical DDL (edges_v2 portion of SCHEMA_SQL).
|
|
516
|
+
start = SCHEMA_SQL.index("CREATE TABLE IF NOT EXISTS edges_v2")
|
|
517
|
+
end = SCHEMA_SQL.index(");", start) + 2
|
|
518
|
+
conn.execute(SCHEMA_SQL[start:end].rstrip(";"))
|
|
519
|
+
conn.execute(
|
|
520
|
+
"""
|
|
521
|
+
INSERT INTO edges_v2 (id, source, target, type, legacy_type, weight,
|
|
522
|
+
confidence, evidence, metadata, created_by, created_at)
|
|
523
|
+
SELECT id, source, target, type, legacy_type, weight,
|
|
524
|
+
confidence, evidence, metadata, created_by, created_at
|
|
525
|
+
FROM edges_v2_old
|
|
526
|
+
"""
|
|
527
|
+
)
|
|
528
|
+
conn.execute("DROP TABLE edges_v2_old")
|
|
529
|
+
logging.info("kg_schema: rebuilt edges_v2 with (source, target, type, legacy_type) identity")
|
|
530
|
+
|
|
449
531
|
def _init_schema_on(self, conn: sqlite3.Connection) -> None:
|
|
450
532
|
self._drop_stale_empty_v2_tables(conn)
|
|
533
|
+
self._rebuild_edges_identity(conn)
|
|
451
534
|
_exec_script(conn, SCHEMA_SQL)
|
|
452
535
|
conn.execute(
|
|
453
536
|
"INSERT OR REPLACE INTO kg_meta(key, value) VALUES (?, ?)",
|