@researai/deepscientist 1.5.1 → 1.5.3
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 +69 -1
- package/bin/ds.js +2239 -153
- package/docs/en/00_QUICK_START.md +60 -20
- package/docs/en/01_SETTINGS_REFERENCE.md +20 -20
- package/docs/en/02_START_RESEARCH_GUIDE.md +11 -11
- package/docs/en/03_QQ_CONNECTOR_GUIDE.md +10 -10
- package/docs/en/05_TUI_GUIDE.md +1 -1
- package/docs/en/09_DOCTOR.md +48 -4
- package/docs/en/90_ARCHITECTURE.md +4 -2
- package/docs/zh/00_QUICK_START.md +60 -20
- package/docs/zh/01_SETTINGS_REFERENCE.md +21 -21
- package/docs/zh/02_START_RESEARCH_GUIDE.md +19 -19
- package/docs/zh/03_QQ_CONNECTOR_GUIDE.md +10 -10
- package/docs/zh/05_TUI_GUIDE.md +1 -1
- package/docs/zh/09_DOCTOR.md +46 -4
- package/install.sh +125 -8
- package/package.json +2 -1
- package/pyproject.toml +1 -1
- package/src/deepscientist/__init__.py +6 -1
- package/src/deepscientist/artifact/service.py +553 -26
- package/src/deepscientist/bash_exec/monitor.py +23 -4
- package/src/deepscientist/bash_exec/runtime.py +3 -0
- package/src/deepscientist/bash_exec/service.py +132 -4
- package/src/deepscientist/bridges/base.py +10 -19
- package/src/deepscientist/channels/discord_gateway.py +25 -2
- package/src/deepscientist/channels/feishu_long_connection.py +41 -3
- package/src/deepscientist/channels/qq.py +524 -64
- package/src/deepscientist/channels/qq_gateway.py +22 -3
- package/src/deepscientist/channels/relay.py +429 -90
- package/src/deepscientist/channels/slack_socket.py +29 -5
- package/src/deepscientist/channels/telegram_polling.py +25 -2
- package/src/deepscientist/channels/whatsapp_local_session.py +32 -4
- package/src/deepscientist/cli.py +27 -0
- package/src/deepscientist/config/models.py +6 -40
- package/src/deepscientist/config/service.py +165 -156
- package/src/deepscientist/connector_profiles.py +346 -0
- package/src/deepscientist/connector_runtime.py +88 -43
- package/src/deepscientist/daemon/api/handlers.py +65 -11
- package/src/deepscientist/daemon/api/router.py +4 -2
- package/src/deepscientist/daemon/app.py +772 -219
- package/src/deepscientist/doctor.py +69 -2
- package/src/deepscientist/gitops/diff.py +3 -0
- package/src/deepscientist/home.py +25 -2
- package/src/deepscientist/mcp/context.py +3 -1
- package/src/deepscientist/mcp/server.py +66 -7
- package/src/deepscientist/migration.py +114 -0
- package/src/deepscientist/prompts/builder.py +71 -3
- package/src/deepscientist/qq_profiles.py +186 -0
- package/src/deepscientist/quest/layout.py +1 -0
- package/src/deepscientist/quest/service.py +70 -12
- package/src/deepscientist/quest/stage_views.py +46 -0
- package/src/deepscientist/runners/codex.py +2 -0
- package/src/deepscientist/shared.py +44 -17
- package/src/prompts/connectors/lingzhu.md +3 -0
- package/src/prompts/connectors/qq.md +42 -2
- package/src/prompts/system.md +123 -10
- package/src/skills/analysis-campaign/SKILL.md +35 -6
- package/src/skills/baseline/SKILL.md +73 -32
- package/src/skills/decision/SKILL.md +4 -3
- package/src/skills/experiment/SKILL.md +28 -6
- package/src/skills/finalize/SKILL.md +5 -2
- package/src/skills/idea/SKILL.md +2 -2
- package/src/skills/intake-audit/SKILL.md +2 -2
- package/src/skills/rebuttal/SKILL.md +4 -2
- package/src/skills/review/SKILL.md +4 -2
- package/src/skills/scout/SKILL.md +2 -2
- package/src/skills/write/SKILL.md +2 -2
- package/src/tui/package.json +1 -1
- package/src/ui/dist/assets/{AiManusChatView-w5lF2Ttt.js → AiManusChatView-qzChi9uh.js} +67 -94
- package/src/ui/dist/assets/{AnalysisPlugin-DJOED79I.js → AnalysisPlugin-CcC_-UqN.js} +1 -1
- package/src/ui/dist/assets/{AutoFigurePlugin-DaG61Y0M.js → AutoFigurePlugin-DD8LkJLe.js} +5 -5
- package/src/ui/dist/assets/{CliPlugin-CV4LqUB_.js → CliPlugin-DJJFfVmW.js} +17 -110
- package/src/ui/dist/assets/{CodeEditorPlugin-DylfAea4.js → CodeEditorPlugin-CrjkHNLh.js} +8 -8
- package/src/ui/dist/assets/{CodeViewerPlugin-F7saY0LM.js → CodeViewerPlugin-obnD6G5R.js} +5 -5
- package/src/ui/dist/assets/{DocViewerPlugin-COP0c7jf.js → DocViewerPlugin-DB9SUQVd.js} +3 -3
- package/src/ui/dist/assets/{GitDiffViewerPlugin-CAS05pT9.js → GitDiffViewerPlugin-DZLlNlD2.js} +1 -1
- package/src/ui/dist/assets/{ImageViewerPlugin-Bco1CN_w.js → ImageViewerPlugin-BGwfDZ0Y.js} +5 -5
- package/src/ui/dist/assets/{LabCopilotPanel-CvMlCD99.js → LabCopilotPanel-dfLptQcR.js} +10 -10
- package/src/ui/dist/assets/{LabPlugin-BYankkE4.js → LabPlugin-CeGjAl3A.js} +1 -1
- package/src/ui/dist/assets/{LatexPlugin-LDSMR-t-.js → LatexPlugin-BBJ7kd1V.js} +7 -7
- package/src/ui/dist/assets/{MarkdownViewerPlugin-B7o80jgm.js → MarkdownViewerPlugin-DKZi7BcB.js} +4 -4
- package/src/ui/dist/assets/{MarketplacePlugin-CM6ZOcpC.js → MarketplacePlugin-C_k-9jD0.js} +3 -3
- package/src/ui/dist/assets/{NotebookEditor-Dc61cXmK.js → NotebookEditor-4R88_BMO.js} +1 -1
- package/src/ui/dist/assets/{PdfLoader-DWowuQwx.js → PdfLoader-DwEFQLrw.js} +1 -1
- package/src/ui/dist/assets/{PdfMarkdownPlugin-BsJM1q_a.js → PdfMarkdownPlugin-D-jdsqF8.js} +3 -3
- package/src/ui/dist/assets/{PdfViewerPlugin-DB2eEEFQ.js → PdfViewerPlugin-CmeBGDY0.js} +10 -10
- package/src/ui/dist/assets/{SearchPlugin-CraThSvt.js → SearchPlugin-Dlz2WKJ4.js} +1 -1
- package/src/ui/dist/assets/{Stepper-CgocRTPq.js → Stepper-ClOgzWM3.js} +1 -1
- package/src/ui/dist/assets/{TextViewerPlugin-B1JGhKtd.js → TextViewerPlugin-DDQWxibk.js} +4 -4
- package/src/ui/dist/assets/{VNCViewer-CclFC7FM.js → VNCViewer-CJXT0Nm8.js} +9 -9
- package/src/ui/dist/assets/{bibtex-D3IKsMl7.js → bibtex-DLr4Rtk4.js} +1 -1
- package/src/ui/dist/assets/{code-BP37Xx0p.js → code-DgKK408Y.js} +1 -1
- package/src/ui/dist/assets/{file-content-BAJSu-9r.js → file-content-6HBqQnvQ.js} +1 -1
- package/src/ui/dist/assets/{file-diff-panel-DUGeCTuy.js → file-diff-panel-Dhu0TbBM.js} +1 -1
- package/src/ui/dist/assets/{file-socket-CXc1Ojf7.js → file-socket-CP3iwVZG.js} +1 -1
- package/src/ui/dist/assets/{file-utils-2J21jt7M.js → file-utils-BsS-Aw68.js} +1 -1
- package/src/ui/dist/assets/{image-CMMmgvcn.js → image-ByeK-Zcv.js} +1 -1
- package/src/ui/dist/assets/{index-DmwmJmbW.js → index-BLjo5--a.js} +33610 -31016
- package/src/ui/dist/assets/{index-CWgMgpow.js → index-BdsE0uRz.js} +11 -11
- package/src/ui/dist/assets/{index-s7aHnNQ4.js → index-C-eX-N6A.js} +1 -1
- package/src/ui/dist/assets/{index-KGt-z-dD.css → index-CuQhlrR-.css} +2747 -2
- package/src/ui/dist/assets/{index-BaVumsQT.js → index-DyremSIv.js} +2 -2
- package/src/ui/dist/assets/{message-square-CQRfX0Am.js → message-square-DnagiLnc.js} +1 -1
- package/src/ui/dist/assets/{monaco-B4TbdsrF.js → monaco-4kBFeprs.js} +1 -1
- package/src/ui/dist/assets/{popover-B8Rokodk.js → popover-hRCXZzs2.js} +1 -1
- package/src/ui/dist/assets/{project-sync-D_i96KH4.js → project-sync-O_85YuP6.js} +1 -1
- package/src/ui/dist/assets/{sigma-D12PnzCN.js → sigma-DvKopSnL.js} +1 -1
- package/src/ui/dist/assets/{tooltip-B6YrI4aJ.js → tooltip-BmlPc6kc.js} +1 -1
- package/src/ui/dist/assets/{trash-Bc8jGp0V.js → trash-n-UvdZFR.js} +1 -1
- package/src/ui/dist/assets/{useCliAccess-mXVCYSZ-.js → useCliAccess-WDd3_wIh.js} +1 -1
- package/src/ui/dist/assets/{useFileDiffOverlay-Bg6b9H9K.js → useFileDiffOverlay-rXLIL2NF.js} +1 -1
- package/src/ui/dist/assets/{wrap-text-Drh5GEnL.js → wrap-text-qIYQ4a_W.js} +1 -1
- package/src/ui/dist/assets/{zoom-out-CJj9DZLn.js → zoom-out-fZXCEFsy.js} +1 -1
- package/src/ui/dist/index.html +2 -2
- package/uv.lock +1155 -0
- package/src/ui/dist/assets/LabPlugin-D9jVIo0A.css +0 -2698
|
@@ -9,6 +9,7 @@ from urllib.request import Request, urlopen
|
|
|
9
9
|
from websockets.exceptions import ConnectionClosed
|
|
10
10
|
from websockets.sync.client import connect as websocket_connect
|
|
11
11
|
|
|
12
|
+
from ..connector_runtime import format_conversation_id
|
|
12
13
|
from ..shared import read_json, utc_now, write_json
|
|
13
14
|
|
|
14
15
|
|
|
@@ -20,15 +21,23 @@ class SlackSocketModeService:
|
|
|
20
21
|
config: dict[str, Any],
|
|
21
22
|
on_event: Callable[[dict[str, Any]], None],
|
|
22
23
|
log: Callable[[str, str], None] | None = None,
|
|
24
|
+
profile_id: str | None = None,
|
|
25
|
+
profile_label: str | None = None,
|
|
26
|
+
encode_profile_id: bool = False,
|
|
23
27
|
) -> None:
|
|
24
28
|
self.home = home
|
|
25
29
|
self.config = config
|
|
26
30
|
self.on_event = on_event
|
|
27
31
|
self.log = log or self._default_log
|
|
32
|
+
self.profile_id = str(profile_id or "").strip() or None
|
|
33
|
+
self.profile_label = str(profile_label or "").strip() or None
|
|
34
|
+
self._encode_profile_id = bool(encode_profile_id and self.profile_id)
|
|
28
35
|
self._thread: threading.Thread | None = None
|
|
29
36
|
self._stop_event = threading.Event()
|
|
30
37
|
self._connection = None
|
|
31
38
|
self._root = home / "logs" / "connectors" / "slack"
|
|
39
|
+
if self.profile_id:
|
|
40
|
+
self._root = self._root / "profiles" / self.profile_id
|
|
32
41
|
self._runtime_path = self._root / "runtime.json"
|
|
33
42
|
|
|
34
43
|
def start(self) -> bool:
|
|
@@ -64,7 +73,7 @@ class SlackSocketModeService:
|
|
|
64
73
|
self._thread = threading.Thread(
|
|
65
74
|
target=self._run,
|
|
66
75
|
daemon=True,
|
|
67
|
-
name="deepscientist-slack-socket-mode",
|
|
76
|
+
name=f"deepscientist-slack-socket-mode-{self.profile_id or 'default'}",
|
|
68
77
|
)
|
|
69
78
|
self._thread.start()
|
|
70
79
|
return True
|
|
@@ -208,14 +217,15 @@ class SlackSocketModeService:
|
|
|
208
217
|
"sender_id": sender_id,
|
|
209
218
|
"sender_name": str(event.get("username") or sender_id).strip(),
|
|
210
219
|
"message_id": str(event.get("ts") or event.get("event_ts") or "").strip(),
|
|
211
|
-
"conversation_id":
|
|
220
|
+
"conversation_id": self._conversation_id(chat_type, channel_id),
|
|
221
|
+
"profile_id": self.profile_id,
|
|
222
|
+
"profile_label": self.profile_label,
|
|
212
223
|
"text": normalized_text,
|
|
213
224
|
"mentioned": mentioned,
|
|
214
225
|
"raw_event": payload,
|
|
215
226
|
}
|
|
216
227
|
|
|
217
|
-
|
|
218
|
-
def _normalize_slash_command(payload: dict[str, Any]) -> dict[str, Any] | None:
|
|
228
|
+
def _normalize_slash_command(self, payload: dict[str, Any]) -> dict[str, Any] | None:
|
|
219
229
|
channel_id = str(payload.get("channel_id") or "").strip()
|
|
220
230
|
if not channel_id:
|
|
221
231
|
return None
|
|
@@ -232,12 +242,22 @@ class SlackSocketModeService:
|
|
|
232
242
|
"sender_id": sender_id,
|
|
233
243
|
"sender_name": str(payload.get("user_name") or sender_id).strip(),
|
|
234
244
|
"message_id": str(payload.get("trigger_id") or "").strip(),
|
|
235
|
-
"conversation_id":
|
|
245
|
+
"conversation_id": self._conversation_id(chat_type, channel_id),
|
|
246
|
+
"profile_id": self.profile_id,
|
|
247
|
+
"profile_label": self.profile_label,
|
|
236
248
|
"text": combined,
|
|
237
249
|
"mentioned": True,
|
|
238
250
|
"raw_event": payload,
|
|
239
251
|
}
|
|
240
252
|
|
|
253
|
+
def _conversation_id(self, chat_type: str, chat_id: str) -> str:
|
|
254
|
+
return format_conversation_id(
|
|
255
|
+
"slack",
|
|
256
|
+
chat_type,
|
|
257
|
+
chat_id,
|
|
258
|
+
profile_id=self.profile_id if self._encode_profile_id else None,
|
|
259
|
+
)
|
|
260
|
+
|
|
241
261
|
@staticmethod
|
|
242
262
|
def _infer_channel_type(channel_id: str) -> str:
|
|
243
263
|
if str(channel_id).startswith("D"):
|
|
@@ -321,6 +341,10 @@ class SlackSocketModeService:
|
|
|
321
341
|
state = read_json(self._runtime_path, {}) or {}
|
|
322
342
|
if not isinstance(state, dict):
|
|
323
343
|
state = {}
|
|
344
|
+
if self.profile_id:
|
|
345
|
+
state["profile_id"] = self.profile_id
|
|
346
|
+
if self.profile_label:
|
|
347
|
+
state["profile_label"] = self.profile_label
|
|
324
348
|
state.update(patch)
|
|
325
349
|
write_json(self._runtime_path, state)
|
|
326
350
|
|
|
@@ -6,6 +6,7 @@ from pathlib import Path
|
|
|
6
6
|
from typing import Any, Callable
|
|
7
7
|
from urllib.request import Request, urlopen
|
|
8
8
|
|
|
9
|
+
from ..connector_runtime import format_conversation_id
|
|
9
10
|
from ..shared import read_json, utc_now, write_json
|
|
10
11
|
|
|
11
12
|
|
|
@@ -17,14 +18,22 @@ class TelegramPollingService:
|
|
|
17
18
|
config: dict[str, Any],
|
|
18
19
|
on_event: Callable[[dict[str, Any]], None],
|
|
19
20
|
log: Callable[[str, str], None] | None = None,
|
|
21
|
+
profile_id: str | None = None,
|
|
22
|
+
profile_label: str | None = None,
|
|
23
|
+
encode_profile_id: bool = False,
|
|
20
24
|
) -> None:
|
|
21
25
|
self.home = home
|
|
22
26
|
self.config = config
|
|
23
27
|
self.on_event = on_event
|
|
24
28
|
self.log = log or self._default_log
|
|
29
|
+
self.profile_id = str(profile_id or "").strip() or None
|
|
30
|
+
self.profile_label = str(profile_label or "").strip() or None
|
|
31
|
+
self._encode_profile_id = bool(encode_profile_id and self.profile_id)
|
|
25
32
|
self._thread: threading.Thread | None = None
|
|
26
33
|
self._stop_event = threading.Event()
|
|
27
34
|
self._root = home / "logs" / "connectors" / "telegram"
|
|
35
|
+
if self.profile_id:
|
|
36
|
+
self._root = self._root / "profiles" / self.profile_id
|
|
28
37
|
self._runtime_path = self._root / "runtime.json"
|
|
29
38
|
|
|
30
39
|
def start(self) -> bool:
|
|
@@ -59,7 +68,7 @@ class TelegramPollingService:
|
|
|
59
68
|
self._thread = threading.Thread(
|
|
60
69
|
target=self._run,
|
|
61
70
|
daemon=True,
|
|
62
|
-
name="deepscientist-telegram-polling",
|
|
71
|
+
name=f"deepscientist-telegram-polling-{self.profile_id or 'default'}",
|
|
63
72
|
)
|
|
64
73
|
self._thread.start()
|
|
65
74
|
return True
|
|
@@ -219,12 +228,22 @@ class TelegramPollingService:
|
|
|
219
228
|
"sender_id": sender_id,
|
|
220
229
|
"sender_name": sender_name,
|
|
221
230
|
"message_id": str(message.get("message_id") or "").strip(),
|
|
222
|
-
"conversation_id":
|
|
231
|
+
"conversation_id": self._conversation_id(chat_type, chat_id),
|
|
232
|
+
"profile_id": self.profile_id,
|
|
233
|
+
"profile_label": self.profile_label,
|
|
223
234
|
"text": normalized_text,
|
|
224
235
|
"mentioned": mentioned,
|
|
225
236
|
"raw_event": update,
|
|
226
237
|
}
|
|
227
238
|
|
|
239
|
+
def _conversation_id(self, chat_type: str, chat_id: str) -> str:
|
|
240
|
+
return format_conversation_id(
|
|
241
|
+
"telegram",
|
|
242
|
+
chat_type,
|
|
243
|
+
chat_id,
|
|
244
|
+
profile_id=self.profile_id if self._encode_profile_id else None,
|
|
245
|
+
)
|
|
246
|
+
|
|
228
247
|
@staticmethod
|
|
229
248
|
def _normalize_command_target(text: str, *, bot_name: str) -> str:
|
|
230
249
|
cleaned = str(text or "").strip()
|
|
@@ -272,6 +291,10 @@ class TelegramPollingService:
|
|
|
272
291
|
state = read_json(self._runtime_path, {}) or {}
|
|
273
292
|
if not isinstance(state, dict):
|
|
274
293
|
state = {}
|
|
294
|
+
if self.profile_id:
|
|
295
|
+
state["profile_id"] = self.profile_id
|
|
296
|
+
if self.profile_label:
|
|
297
|
+
state["profile_label"] = self.profile_label
|
|
275
298
|
state.update(patch)
|
|
276
299
|
write_json(self._runtime_path, state)
|
|
277
300
|
|
|
@@ -5,6 +5,7 @@ import threading
|
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
from typing import Any, Callable
|
|
7
7
|
|
|
8
|
+
from ..connector_runtime import format_conversation_id, parse_conversation_id
|
|
8
9
|
from ..shared import append_jsonl, ensure_dir, read_json, utc_now, write_json
|
|
9
10
|
|
|
10
11
|
|
|
@@ -16,14 +17,22 @@ class WhatsAppLocalSessionService:
|
|
|
16
17
|
config: dict[str, Any],
|
|
17
18
|
on_event: Callable[[dict[str, Any]], None],
|
|
18
19
|
log: Callable[[str, str], None] | None = None,
|
|
20
|
+
profile_id: str | None = None,
|
|
21
|
+
profile_label: str | None = None,
|
|
22
|
+
encode_profile_id: bool = False,
|
|
19
23
|
) -> None:
|
|
20
24
|
self.home = home
|
|
21
25
|
self.config = config
|
|
22
26
|
self.on_event = on_event
|
|
23
27
|
self.log = log or self._default_log
|
|
28
|
+
self.profile_id = str(profile_id or "").strip() or None
|
|
29
|
+
self.profile_label = str(profile_label or "").strip() or None
|
|
30
|
+
self._encode_profile_id = bool(encode_profile_id and self.profile_id)
|
|
24
31
|
self._thread: threading.Thread | None = None
|
|
25
32
|
self._stop_event = threading.Event()
|
|
26
33
|
self._root = home / "logs" / "connectors" / "whatsapp"
|
|
34
|
+
if self.profile_id:
|
|
35
|
+
self._root = self._root / "profiles" / self.profile_id
|
|
27
36
|
self._runtime_path = self._root / "runtime.json"
|
|
28
37
|
self._cursor_path = self._root / "local_session.cursor.json"
|
|
29
38
|
|
|
@@ -60,7 +69,7 @@ class WhatsAppLocalSessionService:
|
|
|
60
69
|
self._thread = threading.Thread(
|
|
61
70
|
target=self._run,
|
|
62
71
|
daemon=True,
|
|
63
|
-
name="deepscientist-whatsapp-local-session",
|
|
72
|
+
name=f"deepscientist-whatsapp-local-session-{self.profile_id or 'default'}",
|
|
64
73
|
)
|
|
65
74
|
self._thread.start()
|
|
66
75
|
return True
|
|
@@ -165,11 +174,16 @@ class WhatsAppLocalSessionService:
|
|
|
165
174
|
)
|
|
166
175
|
write_json(self._cursor_path, {"offset": offset})
|
|
167
176
|
|
|
168
|
-
|
|
169
|
-
def _normalize_entry(payload: dict[str, Any]) -> dict[str, Any] | None:
|
|
177
|
+
def _normalize_entry(self, payload: dict[str, Any]) -> dict[str, Any] | None:
|
|
170
178
|
if isinstance(payload.get("normalized"), dict):
|
|
171
179
|
normalized = dict(payload["normalized"])
|
|
172
180
|
normalized.setdefault("raw_event", payload)
|
|
181
|
+
parsed = parse_conversation_id(normalized.get("conversation_id"))
|
|
182
|
+
chat_type = str((parsed or {}).get("chat_type") or normalized.get("chat_type") or "direct").strip().lower() or "direct"
|
|
183
|
+
chat_id = str((parsed or {}).get("chat_id") or normalized.get("group_id") or normalized.get("direct_id") or "").strip() or "unknown"
|
|
184
|
+
normalized["conversation_id"] = self._conversation_id(chat_type, chat_id)
|
|
185
|
+
normalized["profile_id"] = self.profile_id
|
|
186
|
+
normalized["profile_label"] = self.profile_label
|
|
173
187
|
return normalized
|
|
174
188
|
conversation_id = str(payload.get("conversation_id") or "").strip()
|
|
175
189
|
chat_type = str(payload.get("chat_type") or "").strip().lower()
|
|
@@ -201,12 +215,22 @@ class WhatsAppLocalSessionService:
|
|
|
201
215
|
"sender_id": sender_id or chat_id,
|
|
202
216
|
"sender_name": sender_name or sender_id or chat_id,
|
|
203
217
|
"message_id": message_id,
|
|
204
|
-
"conversation_id":
|
|
218
|
+
"conversation_id": self._conversation_id(chat_type, chat_id),
|
|
219
|
+
"profile_id": self.profile_id,
|
|
220
|
+
"profile_label": self.profile_label,
|
|
205
221
|
"text": text,
|
|
206
222
|
"mentioned": False,
|
|
207
223
|
"raw_event": payload,
|
|
208
224
|
}
|
|
209
225
|
|
|
226
|
+
def _conversation_id(self, chat_type: str, chat_id: str) -> str:
|
|
227
|
+
return format_conversation_id(
|
|
228
|
+
"whatsapp",
|
|
229
|
+
chat_type,
|
|
230
|
+
chat_id,
|
|
231
|
+
profile_id=self.profile_id if self._encode_profile_id else None,
|
|
232
|
+
)
|
|
233
|
+
|
|
210
234
|
def _session_dir(self) -> Path | None:
|
|
211
235
|
raw = str(self.config.get("session_dir") or "").strip()
|
|
212
236
|
if not raw:
|
|
@@ -217,6 +241,10 @@ class WhatsAppLocalSessionService:
|
|
|
217
241
|
state = read_json(self._runtime_path, {}) or {}
|
|
218
242
|
if not isinstance(state, dict):
|
|
219
243
|
state = {}
|
|
244
|
+
if self.profile_id:
|
|
245
|
+
state["profile_id"] = self.profile_id
|
|
246
|
+
if self.profile_label:
|
|
247
|
+
state["profile_label"] = self.profile_label
|
|
220
248
|
state.update(patch)
|
|
221
249
|
write_json(self._runtime_path, state)
|
|
222
250
|
|
package/src/deepscientist/cli.py
CHANGED
|
@@ -17,6 +17,7 @@ from .daemon import DaemonApp
|
|
|
17
17
|
from .doctor import render_doctor_report, run_doctor
|
|
18
18
|
from .home import default_home, ensure_home_layout, repo_root
|
|
19
19
|
from .memory import MemoryService
|
|
20
|
+
from .migration import migrate_deepscientist_root
|
|
20
21
|
from .prompts import PromptBuilder
|
|
21
22
|
from .quest import QuestService
|
|
22
23
|
from .registries import BaselineRegistry
|
|
@@ -109,6 +110,9 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
109
110
|
config_edit.add_argument("name", choices=("config", "runners", "connectors", "plugins", "mcp_servers"))
|
|
110
111
|
config_subparsers.add_parser("validate")
|
|
111
112
|
|
|
113
|
+
migrate_parser = subparsers.add_parser("migrate")
|
|
114
|
+
migrate_parser.add_argument("target")
|
|
115
|
+
|
|
112
116
|
return parser
|
|
113
117
|
|
|
114
118
|
|
|
@@ -445,6 +449,27 @@ def config_validate_command(home: Path) -> int:
|
|
|
445
449
|
return 0
|
|
446
450
|
|
|
447
451
|
|
|
452
|
+
def migrate_command(home: Path, target: str) -> int:
|
|
453
|
+
try:
|
|
454
|
+
payload = migrate_deepscientist_root(home, Path(target))
|
|
455
|
+
except ValueError as exc:
|
|
456
|
+
print(
|
|
457
|
+
json.dumps(
|
|
458
|
+
{
|
|
459
|
+
"ok": False,
|
|
460
|
+
"source": str(home.expanduser().resolve()),
|
|
461
|
+
"target": str(Path(target).expanduser().resolve()),
|
|
462
|
+
"message": str(exc),
|
|
463
|
+
},
|
|
464
|
+
ensure_ascii=False,
|
|
465
|
+
indent=2,
|
|
466
|
+
)
|
|
467
|
+
)
|
|
468
|
+
return 1
|
|
469
|
+
print(json.dumps(payload, ensure_ascii=False, indent=2))
|
|
470
|
+
return 0
|
|
471
|
+
|
|
472
|
+
|
|
448
473
|
def main(argv: list[str] | None = None) -> int:
|
|
449
474
|
parser = build_parser()
|
|
450
475
|
args = parser.parse_args(argv)
|
|
@@ -492,6 +517,8 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
492
517
|
return config_edit_command(home, args.name)
|
|
493
518
|
if args.command == "config" and args.config_command == "validate":
|
|
494
519
|
return config_validate_command(home)
|
|
520
|
+
if args.command == "migrate":
|
|
521
|
+
return migrate_command(home, args.target)
|
|
495
522
|
parser.error(f"Unknown command: {args.command}")
|
|
496
523
|
return 1
|
|
497
524
|
|
|
@@ -3,7 +3,6 @@ from __future__ import annotations
|
|
|
3
3
|
from dataclasses import dataclass
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
|
|
6
|
-
|
|
7
6
|
CONFIG_NAMES = ("config", "runners", "connectors", "plugins", "mcp_servers")
|
|
8
7
|
REQUIRED_CONFIG_NAMES = ("config", "runners", "connectors")
|
|
9
8
|
OPTIONAL_CONFIG_NAMES = ("plugins", "mcp_servers")
|
|
@@ -122,6 +121,7 @@ def default_connectors() -> dict:
|
|
|
122
121
|
"qq": {
|
|
123
122
|
"enabled": False,
|
|
124
123
|
"transport": "gateway_direct",
|
|
124
|
+
"profiles": [],
|
|
125
125
|
"app_id": None,
|
|
126
126
|
"app_secret": None,
|
|
127
127
|
"app_secret_env": "QQ_APP_SECRET",
|
|
@@ -140,17 +140,12 @@ def default_connectors() -> dict:
|
|
|
140
140
|
},
|
|
141
141
|
"telegram": {
|
|
142
142
|
"enabled": False,
|
|
143
|
+
"profiles": [],
|
|
143
144
|
"transport": "polling",
|
|
144
|
-
"mode": "relay",
|
|
145
145
|
"bot_name": "DeepScientist",
|
|
146
146
|
"command_prefix": "/",
|
|
147
147
|
"bot_token": None,
|
|
148
148
|
"bot_token_env": "TELEGRAM_BOT_TOKEN",
|
|
149
|
-
"webhook_secret": None,
|
|
150
|
-
"webhook_secret_env": "TELEGRAM_WEBHOOK_SECRET",
|
|
151
|
-
"public_callback_url": None,
|
|
152
|
-
"relay_url": None,
|
|
153
|
-
"relay_auth_token": None,
|
|
154
149
|
"dm_policy": "pairing",
|
|
155
150
|
"allow_from": [],
|
|
156
151
|
"group_policy": "open",
|
|
@@ -161,18 +156,13 @@ def default_connectors() -> dict:
|
|
|
161
156
|
},
|
|
162
157
|
"discord": {
|
|
163
158
|
"enabled": False,
|
|
159
|
+
"profiles": [],
|
|
164
160
|
"transport": "gateway",
|
|
165
|
-
"mode": "relay",
|
|
166
161
|
"bot_name": "DeepScientist",
|
|
167
162
|
"command_prefix": "/",
|
|
168
163
|
"bot_token": None,
|
|
169
164
|
"bot_token_env": "DISCORD_BOT_TOKEN",
|
|
170
165
|
"application_id": None,
|
|
171
|
-
"public_key": None,
|
|
172
|
-
"public_key_env": "DISCORD_PUBLIC_KEY",
|
|
173
|
-
"public_interactions_url": None,
|
|
174
|
-
"relay_url": None,
|
|
175
|
-
"relay_auth_token": None,
|
|
176
166
|
"dm_policy": "pairing",
|
|
177
167
|
"allow_from": [],
|
|
178
168
|
"group_policy": "open",
|
|
@@ -184,8 +174,8 @@ def default_connectors() -> dict:
|
|
|
184
174
|
},
|
|
185
175
|
"slack": {
|
|
186
176
|
"enabled": False,
|
|
177
|
+
"profiles": [],
|
|
187
178
|
"transport": "socket_mode",
|
|
188
|
-
"mode": "relay",
|
|
189
179
|
"bot_name": "DeepScientist",
|
|
190
180
|
"command_prefix": "/",
|
|
191
181
|
"bot_token": None,
|
|
@@ -193,11 +183,6 @@ def default_connectors() -> dict:
|
|
|
193
183
|
"bot_user_id": None,
|
|
194
184
|
"app_token": None,
|
|
195
185
|
"app_token_env": "SLACK_APP_TOKEN",
|
|
196
|
-
"signing_secret": None,
|
|
197
|
-
"signing_secret_env": "SLACK_SIGNING_SECRET",
|
|
198
|
-
"public_callback_url": None,
|
|
199
|
-
"relay_url": None,
|
|
200
|
-
"relay_auth_token": None,
|
|
201
186
|
"dm_policy": "pairing",
|
|
202
187
|
"allow_from": [],
|
|
203
188
|
"group_policy": "open",
|
|
@@ -208,21 +193,14 @@ def default_connectors() -> dict:
|
|
|
208
193
|
},
|
|
209
194
|
"feishu": {
|
|
210
195
|
"enabled": False,
|
|
196
|
+
"profiles": [],
|
|
211
197
|
"transport": "long_connection",
|
|
212
|
-
"mode": "relay",
|
|
213
198
|
"bot_name": "DeepScientist",
|
|
214
199
|
"command_prefix": "/",
|
|
215
200
|
"app_id": None,
|
|
216
201
|
"app_secret": None,
|
|
217
202
|
"app_secret_env": "FEISHU_APP_SECRET",
|
|
218
|
-
"verification_token": None,
|
|
219
|
-
"verification_token_env": "FEISHU_VERIFICATION_TOKEN",
|
|
220
|
-
"encrypt_key": None,
|
|
221
|
-
"encrypt_key_env": "FEISHU_ENCRYPT_KEY",
|
|
222
203
|
"api_base_url": "https://open.feishu.cn",
|
|
223
|
-
"public_callback_url": None,
|
|
224
|
-
"relay_url": None,
|
|
225
|
-
"relay_auth_token": None,
|
|
226
204
|
"dm_policy": "pairing",
|
|
227
205
|
"allow_from": [],
|
|
228
206
|
"group_policy": "open",
|
|
@@ -233,24 +211,12 @@ def default_connectors() -> dict:
|
|
|
233
211
|
},
|
|
234
212
|
"whatsapp": {
|
|
235
213
|
"enabled": False,
|
|
214
|
+
"profiles": [],
|
|
236
215
|
"transport": "local_session",
|
|
237
|
-
"mode": "relay",
|
|
238
216
|
"bot_name": "DeepScientist",
|
|
239
217
|
"command_prefix": "/",
|
|
240
218
|
"auth_method": "qr_browser",
|
|
241
219
|
"session_dir": "~/.deepscientist/connectors/whatsapp",
|
|
242
|
-
"provider": "relay",
|
|
243
|
-
"access_token": None,
|
|
244
|
-
"access_token_env": "WHATSAPP_ACCESS_TOKEN",
|
|
245
|
-
"phone_number_id": None,
|
|
246
|
-
"business_account_id": None,
|
|
247
|
-
"verify_token": None,
|
|
248
|
-
"verify_token_env": "WHATSAPP_VERIFY_TOKEN",
|
|
249
|
-
"api_base_url": "https://graph.facebook.com",
|
|
250
|
-
"api_version": "v21.0",
|
|
251
|
-
"public_callback_url": None,
|
|
252
|
-
"relay_url": None,
|
|
253
|
-
"relay_auth_token": None,
|
|
254
220
|
"dm_policy": "pairing",
|
|
255
221
|
"allow_from": [],
|
|
256
222
|
"group_policy": "allowlist",
|