ltcai 2.2.1 → 2.2.7
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 +183 -140
- package/codex_telegram_bot.py +6 -2
- package/docs/CHANGELOG.md +100 -23
- package/docs/EDITION_STRATEGY.md +8 -8
- package/docs/ENTERPRISE.md +5 -5
- package/docs/PLUGIN_SDK.md +4 -4
- package/docs/V2_ARCHITECTURE.md +9 -9
- package/docs/architecture.md +18 -17
- package/docs/images/admin-dashboard.png +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/mobile-responsive.png +0 -0
- package/docs/images/pipeline.png +0 -0
- package/docs/images/workspace-dark.png +0 -0
- package/docs/images/workspace-light.png +0 -0
- package/latticeai/__init__.py +1 -1
- package/latticeai/api/static_routes.py +10 -0
- package/latticeai/core/logging_safety.py +62 -0
- package/latticeai/core/workspace_os.py +1 -1
- package/package.json +10 -5
- package/static/account.html +9 -4
- package/static/activity.html +4 -4
- package/static/admin.html +8 -3
- package/static/agents.html +4 -4
- package/static/chat.html +15 -10
- package/static/css/reference/account.css +303 -0
- package/static/css/reference/admin.css +610 -0
- package/static/css/reference/base.css +1658 -0
- package/static/{lattice-reference.css → css/reference/chat.css} +243 -3599
- package/static/css/reference/graph.css +1016 -0
- package/static/css/responsive.css +226 -4
- package/static/css/tokens.css +16 -5
- package/static/favicon.ico +0 -0
- package/static/graph.html +9 -4
- package/static/platform.css +1 -1
- package/static/plugins.html +4 -4
- package/static/scripts/chat.js +187 -69
- package/static/scripts/ux.js +1 -1
- package/static/sw.js +5 -3
- package/static/workflows.html +4 -4
- package/static/workspace.css +75 -14
- package/static/workspace.html +5 -5
- package/telegram_bot.py +18 -14
package/static/workspace.html
CHANGED
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
<meta charset="utf-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover, interactive-widget=resizes-content">
|
|
6
6
|
<title>Lattice AI Workspace OS</title>
|
|
7
|
-
<script src="/static/scripts/ux.js?v=2.2.
|
|
7
|
+
<script src="/static/scripts/ux.js?v=2.2.7"></script>
|
|
8
8
|
<link rel="manifest" href="/manifest.json">
|
|
9
9
|
<link rel="icon" type="image/png" sizes="32x32" href="/icons/favicon-32.png">
|
|
10
10
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap">
|
|
11
11
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@latest/tabler-icons.min.css">
|
|
12
|
-
<link rel="stylesheet" href="/static/css/tokens.css?v=2.2.
|
|
13
|
-
<link rel="stylesheet" href="/static/workspace.css?v=2.2.
|
|
14
|
-
<link rel="stylesheet" href="/static/css/responsive.css?v=2.2.
|
|
12
|
+
<link rel="stylesheet" href="/static/css/tokens.css?v=2.2.7">
|
|
13
|
+
<link rel="stylesheet" href="/static/workspace.css?v=2.2.7">
|
|
14
|
+
<link rel="stylesheet" href="/static/css/responsive.css?v=2.2.7">
|
|
15
15
|
</head>
|
|
16
16
|
<body>
|
|
17
17
|
<div class="workspace-shell">
|
|
@@ -333,6 +333,6 @@
|
|
|
333
333
|
</div>
|
|
334
334
|
|
|
335
335
|
<div class="toast" id="toast"></div>
|
|
336
|
-
<script src="/static/scripts/workspace.js?v=
|
|
336
|
+
<script src="/static/scripts/workspace.js?v=2.2.7"></script>
|
|
337
337
|
</body>
|
|
338
338
|
</html>
|
package/telegram_bot.py
CHANGED
|
@@ -11,6 +11,10 @@ import zipfile
|
|
|
11
11
|
import json
|
|
12
12
|
from pathlib import Path
|
|
13
13
|
|
|
14
|
+
from latticeai.core.logging_safety import install_sensitive_log_filter, safe_log_text
|
|
15
|
+
|
|
16
|
+
install_sensitive_log_filter()
|
|
17
|
+
|
|
14
18
|
def load_env_file(path=".env"):
|
|
15
19
|
env_path = Path(path)
|
|
16
20
|
if not env_path.exists():
|
|
@@ -98,7 +102,7 @@ def load_chat_ids():
|
|
|
98
102
|
data = json.loads(CHAT_IDS_FILE.read_text(encoding="utf-8"))
|
|
99
103
|
return {int(cid) for cid in data.get("chat_ids", [])}
|
|
100
104
|
except Exception as e:
|
|
101
|
-
logger.error("텔레그램 채팅 목록 로드 실패: %s", e)
|
|
105
|
+
logger.error("텔레그램 채팅 목록 로드 실패: %s", safe_log_text(e))
|
|
102
106
|
return set()
|
|
103
107
|
|
|
104
108
|
def save_chat_ids(chat_ids):
|
|
@@ -108,7 +112,7 @@ def save_chat_ids(chat_ids):
|
|
|
108
112
|
encoding="utf-8",
|
|
109
113
|
)
|
|
110
114
|
except Exception as e:
|
|
111
|
-
logger.error("텔레그램 채팅 목록 저장 실패: %s", e)
|
|
115
|
+
logger.error("텔레그램 채팅 목록 저장 실패: %s", safe_log_text(e))
|
|
112
116
|
|
|
113
117
|
def register_chat_id(chat_id):
|
|
114
118
|
chat_ids = load_chat_ids()
|
|
@@ -129,7 +133,7 @@ async def send_message(client, chat_id, text, reply_markup=None):
|
|
|
129
133
|
payload["reply_markup"] = reply_markup
|
|
130
134
|
await client.post(url, json=payload)
|
|
131
135
|
except Exception as e:
|
|
132
|
-
logger.error("메시지 전송 실패: %s", e)
|
|
136
|
+
logger.error("메시지 전송 실패: %s", safe_log_text(e))
|
|
133
137
|
|
|
134
138
|
async def send_photo(client, chat_id, file_path: Path, caption: str = ""):
|
|
135
139
|
url = f"{API_URL}/sendPhoto"
|
|
@@ -140,8 +144,8 @@ async def send_photo(client, chat_id, file_path: Path, caption: str = ""):
|
|
|
140
144
|
if res.status_code != 200:
|
|
141
145
|
await send_message(client, chat_id, f"사진 전송 실패 ({res.status_code})")
|
|
142
146
|
except Exception as e:
|
|
143
|
-
logger.error("사진 전송 실패: %s", e)
|
|
144
|
-
await send_message(client, chat_id, f"사진 전송 오류: {e}")
|
|
147
|
+
logger.error("사진 전송 실패: %s", safe_log_text(e))
|
|
148
|
+
await send_message(client, chat_id, f"사진 전송 오류: {safe_log_text(e)}")
|
|
145
149
|
|
|
146
150
|
async def send_document(client, chat_id, file_path, caption=None, filename=None):
|
|
147
151
|
url = f"{API_URL}/sendDocument"
|
|
@@ -154,9 +158,9 @@ async def send_document(client, chat_id, file_path, caption=None, filename=None)
|
|
|
154
158
|
timeout=300.0,
|
|
155
159
|
)
|
|
156
160
|
if res.status_code != 200:
|
|
157
|
-
logger.error("파일 전송 실패 (%s): %s", res.status_code, res.text)
|
|
161
|
+
logger.error("파일 전송 실패 (%s): %s", res.status_code, safe_log_text(res.text))
|
|
158
162
|
except Exception as e:
|
|
159
|
-
logger.error("파일 전송 실패: %s", e)
|
|
163
|
+
logger.error("파일 전송 실패: %s", safe_log_text(e))
|
|
160
164
|
|
|
161
165
|
async def send_chat_action(client, chat_id, action="typing"):
|
|
162
166
|
try:
|
|
@@ -247,7 +251,7 @@ async def download_telegram_file(client, file_id) -> bytes | None:
|
|
|
247
251
|
dl = await client.get(f"https://api.telegram.org/file/bot{TOKEN}/{file_path}")
|
|
248
252
|
return dl.content if dl.status_code == 200 else None
|
|
249
253
|
except Exception as e:
|
|
250
|
-
logger.error("파일 다운로드 실패: %s", e)
|
|
254
|
+
logger.error("파일 다운로드 실패: %s", safe_log_text(e))
|
|
251
255
|
return None
|
|
252
256
|
|
|
253
257
|
async def download_as_base64(client, file_id) -> str | None:
|
|
@@ -509,7 +513,7 @@ async def send_web_link(client, chat_id):
|
|
|
509
513
|
async with _server_client() as lc:
|
|
510
514
|
await lc.post(f"{API_URL}/sendMessage", json=payload)
|
|
511
515
|
except Exception as e:
|
|
512
|
-
logger.error("웹 링크 전송 실패: %s", e)
|
|
516
|
+
logger.error("웹 링크 전송 실패: %s", safe_log_text(e))
|
|
513
517
|
|
|
514
518
|
# ── MCP tools ─────────────────────────────────────────────────────────────────
|
|
515
519
|
|
|
@@ -760,7 +764,7 @@ async def handle_plan_callback(client, chat_id, data: str) -> None:
|
|
|
760
764
|
async def process_ai_request(client, chat_id, user_text, image_data=None):
|
|
761
765
|
try:
|
|
762
766
|
await send_chat_action(client, chat_id, "upload_photo" if image_data else "typing")
|
|
763
|
-
logger.info("ask_ai 호출 시작: chat_id=%s text=%r", chat_id, user_text[:30])
|
|
767
|
+
logger.info("ask_ai 호출 시작: chat_id=%s text=%r", chat_id, safe_log_text(user_text[:30]))
|
|
764
768
|
data = await ask_ai(client, user_text, image_data, agent_mode=not image_data)
|
|
765
769
|
logger.info("ask_ai 완료: chat_id=%s result_keys=%s", chat_id, list(data.keys()) if isinstance(data, dict) else type(data))
|
|
766
770
|
|
|
@@ -777,7 +781,7 @@ async def process_ai_request(client, chat_id, user_text, image_data=None):
|
|
|
777
781
|
await send_generated_files(client, chat_id, collect_generated_files(data))
|
|
778
782
|
await send_preview_links(client, chat_id, collect_preview_urls(data))
|
|
779
783
|
except Exception as e:
|
|
780
|
-
logger.error("process_ai_request 실패 (chat_id=%s): %s", chat_id, e, exc_info=True)
|
|
784
|
+
logger.error("process_ai_request 실패 (chat_id=%s): %s", chat_id, safe_log_text(e), exc_info=True)
|
|
781
785
|
try:
|
|
782
786
|
await send_message(client, chat_id, "⚠️ 처리 중 오류가 발생했습니다. 잠시 후 다시 시도해 주세요.")
|
|
783
787
|
except Exception:
|
|
@@ -916,7 +920,7 @@ async def run_bot():
|
|
|
916
920
|
updates = await get_updates(client, last_update_id)
|
|
917
921
|
retry_delay = 1
|
|
918
922
|
except Exception as e:
|
|
919
|
-
logger.error("get_updates 실패: %s", e)
|
|
923
|
+
logger.error("get_updates 실패: %s", safe_log_text(e))
|
|
920
924
|
await asyncio.sleep(min(retry_delay, 30))
|
|
921
925
|
retry_delay = min(retry_delay * 2, 30)
|
|
922
926
|
continue
|
|
@@ -997,13 +1001,13 @@ async def run_bot():
|
|
|
997
1001
|
task.add_done_callback(_log_task_exception)
|
|
998
1002
|
|
|
999
1003
|
except Exception as e:
|
|
1000
|
-
logger.error("업데이트 처리 중 예외: %s", e)
|
|
1004
|
+
logger.error("업데이트 처리 중 예외: %s", safe_log_text(e))
|
|
1001
1005
|
|
|
1002
1006
|
await asyncio.sleep(0.5)
|
|
1003
1007
|
|
|
1004
1008
|
def _log_task_exception(task):
|
|
1005
1009
|
if not task.cancelled() and task.exception():
|
|
1006
|
-
logger.error("백그라운드 태스크 예외: %s", task.exception())
|
|
1010
|
+
logger.error("백그라운드 태스크 예외: %s", safe_log_text(task.exception()))
|
|
1007
1011
|
|
|
1008
1012
|
if __name__ == "__main__":
|
|
1009
1013
|
try:
|