@researai/deepscientist 1.5.2 → 1.5.4
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 +22 -0
- package/bin/ds.js +399 -175
- package/docs/en/00_QUICK_START.md +22 -0
- package/docs/en/01_SETTINGS_REFERENCE.md +13 -4
- package/docs/en/99_ACKNOWLEDGEMENTS.md +1 -0
- package/docs/images/connectors/discord-setup-overview.svg +52 -0
- package/docs/images/connectors/feishu-setup-overview.svg +53 -0
- package/docs/images/connectors/slack-setup-overview.svg +51 -0
- package/docs/images/connectors/telegram-setup-overview.svg +55 -0
- package/docs/images/connectors/whatsapp-setup-overview.svg +51 -0
- package/docs/images/lingzhu/lingzhu-openclaw-config.svg +17 -0
- package/docs/images/lingzhu/lingzhu-platform-values.svg +16 -0
- package/docs/images/lingzhu/lingzhu-settings-overview.svg +30 -0
- package/docs/images/qq/tencent-cloud-qq-chat.png +0 -0
- package/docs/images/qq/tencent-cloud-qq-register.png +0 -0
- package/docs/images/quickstart/00-home.png +0 -0
- package/docs/images/quickstart/01-start-research.png +0 -0
- package/docs/images/quickstart/02-list-quest.png +0 -0
- package/docs/zh/00_QUICK_START.md +22 -0
- package/docs/zh/01_SETTINGS_REFERENCE.md +14 -5
- package/docs/zh/99_ACKNOWLEDGEMENTS.md +1 -0
- package/install.sh +120 -4
- package/package.json +8 -4
- package/pyproject.toml +1 -1
- package/src/deepscientist/__init__.py +1 -1
- package/src/deepscientist/artifact/service.py +1 -1
- 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 +12 -20
- package/src/deepscientist/bridges/connectors.py +2 -1
- package/src/deepscientist/channels/discord_gateway.py +27 -4
- 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 +24 -5
- package/src/deepscientist/channels/relay.py +429 -90
- package/src/deepscientist/channels/slack_socket.py +31 -7
- package/src/deepscientist/channels/telegram_polling.py +27 -3
- package/src/deepscientist/channels/whatsapp_local_session.py +32 -4
- package/src/deepscientist/cli.py +31 -1
- package/src/deepscientist/config/models.py +13 -43
- package/src/deepscientist/config/service.py +216 -157
- package/src/deepscientist/connector_profiles.py +346 -0
- package/src/deepscientist/connector_runtime.py +88 -43
- package/src/deepscientist/daemon/api/handlers.py +53 -16
- package/src/deepscientist/daemon/api/router.py +2 -2
- package/src/deepscientist/daemon/app.py +747 -228
- package/src/deepscientist/mcp/server.py +60 -7
- package/src/deepscientist/migration.py +114 -0
- package/src/deepscientist/network.py +78 -0
- package/src/deepscientist/prompts/builder.py +50 -4
- package/src/deepscientist/qq_profiles.py +186 -0
- package/src/deepscientist/quest/service.py +1 -1
- package/src/deepscientist/skills/installer.py +77 -1
- package/src/prompts/connectors/qq.md +42 -2
- package/src/prompts/system.md +162 -6
- package/src/skills/analysis-campaign/SKILL.md +19 -5
- package/src/skills/baseline/SKILL.md +66 -31
- package/src/skills/decision/SKILL.md +1 -1
- package/src/skills/experiment/SKILL.md +11 -5
- package/src/skills/finalize/SKILL.md +1 -1
- package/src/skills/idea/SKILL.md +246 -4
- package/src/skills/intake-audit/SKILL.md +1 -1
- package/src/skills/rebuttal/SKILL.md +1 -1
- package/src/skills/review/SKILL.md +1 -1
- package/src/skills/scout/SKILL.md +1 -1
- package/src/skills/write/SKILL.md +152 -2
- package/src/tui/package.json +1 -1
- package/src/ui/dist/assets/{AiManusChatView-CZpg376x.js → AiManusChatView-BGLArZRn.js} +14 -37
- package/src/ui/dist/assets/{AnalysisPlugin-CtHA22g3.js → AnalysisPlugin-BgDGSigG.js} +1 -1
- package/src/ui/dist/assets/{AutoFigurePlugin-BSWmLMmF.js → AutoFigurePlugin-B65HD7L4.js} +5 -5
- package/src/ui/dist/assets/{CliPlugin-CJ7jdm_s.js → CliPlugin-CUqgsFHC.js} +17 -110
- package/src/ui/dist/assets/{CodeEditorPlugin-DhInVGFf.js → CodeEditorPlugin-CF5EdvaS.js} +8 -8
- package/src/ui/dist/assets/{CodeViewerPlugin-D1n8S9r5.js → CodeViewerPlugin-DEeU063D.js} +5 -5
- package/src/ui/dist/assets/{DocViewerPlugin-C4XM_kqk.js → DocViewerPlugin-Df-FuDlZ.js} +3 -3
- package/src/ui/dist/assets/{GitDiffViewerPlugin-W6kS9r6v.js → GitDiffViewerPlugin-RAnNaRxM.js} +1 -1
- package/src/ui/dist/assets/{ImageViewerPlugin-DPeUx_Oz.js → ImageViewerPlugin-DXJ0ZJGg.js} +5 -5
- package/src/ui/dist/assets/{LabCopilotPanel-eAelUaub.js → LabCopilotPanel-BlO-sKsj.js} +10 -10
- package/src/ui/dist/assets/{LabPlugin-BbOrBxKY.js → LabPlugin-BajPZW5v.js} +1 -1
- package/src/ui/dist/assets/{LatexPlugin-C-HhkVXY.js → LatexPlugin-F1OEol8D.js} +7 -7
- package/src/ui/dist/assets/{MarkdownViewerPlugin-BDIzIBfh.js → MarkdownViewerPlugin-MhUupqwT.js} +4 -4
- package/src/ui/dist/assets/{MarketplacePlugin-DAOJphwr.js → MarketplacePlugin-DxhIEsv0.js} +3 -3
- package/src/ui/dist/assets/{NotebookEditor-BsoMvDoU.js → NotebookEditor-q7TkhewC.js} +1 -1
- package/src/ui/dist/assets/{PdfLoader-fiC7RtHf.js → PdfLoader-B8ZOTKFc.js} +1 -1
- package/src/ui/dist/assets/{PdfMarkdownPlugin-C5OxZBFK.js → PdfMarkdownPlugin-xFPvzvWh.js} +3 -3
- package/src/ui/dist/assets/{PdfViewerPlugin-CAbxQebk.js → PdfViewerPlugin-EjEcsIB8.js} +10 -10
- package/src/ui/dist/assets/{SearchPlugin-SE33Lb9B.js → SearchPlugin-ixY-1lgW.js} +1 -1
- package/src/ui/dist/assets/{Stepper-0Av7GfV7.js → Stepper-gYFK2Pgz.js} +1 -1
- package/src/ui/dist/assets/{TextViewerPlugin-Daf2gJDI.js → TextViewerPlugin-Cym6pv_n.js} +4 -4
- package/src/ui/dist/assets/{VNCViewer-BKrMUIOX.js → VNCViewer-BPmIHcmK.js} +9 -9
- package/src/ui/dist/assets/{bibtex-JBdOEe45.js → bibtex-Btv6Wi7f.js} +1 -1
- package/src/ui/dist/assets/{code-B0TDFCZz.js → code-BlG7g85c.js} +1 -1
- package/src/ui/dist/assets/{file-content-3YtrSacz.js → file-content-DBT5OfTZ.js} +1 -1
- package/src/ui/dist/assets/{file-diff-panel-CJEg5OG1.js → file-diff-panel-BWXYzqHk.js} +1 -1
- package/src/ui/dist/assets/{file-socket-CYQYdmB1.js → file-socket-wDlx6byM.js} +1 -1
- package/src/ui/dist/assets/{file-utils-Cd1C9Ppl.js → file-utils-Ba3nJmH0.js} +1 -1
- package/src/ui/dist/assets/{image-B33ctrvC.js → image-BwtCyguk.js} +1 -1
- package/src/ui/dist/assets/{index-BNQWqmJ2.js → index-B-2scqCJ.js} +11 -11
- package/src/ui/dist/assets/{index-BVXsmS7V.js → index-Bz5AaWL7.js} +52383 -51440
- package/src/ui/dist/assets/{index-Buw_N1VQ.js → index-CfRpE209.js} +2 -2
- package/src/ui/dist/assets/{index-9CLPVeZh.js → index-DcqvKzeJ.js} +1 -1
- package/src/ui/dist/assets/{index-SwmFAld3.css → index-DpMZw8aM.css} +49 -2
- package/src/ui/dist/assets/{message-square-D0cUJ9yU.js → message-square-BnlyWVH0.js} +1 -1
- package/src/ui/dist/assets/{monaco-UZLYkp2n.js → monaco-CXe0pAVe.js} +1 -1
- package/src/ui/dist/assets/{popover-CTeiY-dK.js → popover-BCHmVhHj.js} +1 -1
- package/src/ui/dist/assets/{project-sync-Dbs01Xky.js → project-sync-Brk6kaOD.js} +1 -1
- package/src/ui/dist/assets/{sigma-CM08S-xT.js → sigma-D72eSUep.js} +1 -1
- package/src/ui/dist/assets/{tooltip-pDtzvU9p.js → tooltip-BMWd0dqX.js} +1 -1
- package/src/ui/dist/assets/{trash-YvPCP-da.js → trash-BIt_eWIS.js} +1 -1
- package/src/ui/dist/assets/{useCliAccess-Bavi74Ac.js → useCliAccess-N1hkTRrR.js} +1 -1
- package/src/ui/dist/assets/{useFileDiffOverlay-CVXY6oeg.js → useFileDiffOverlay-DPRPv6rv.js} +1 -1
- package/src/ui/dist/assets/{wrap-text-Cf4flRW7.js → wrap-text-E5-UheyP.js} +1 -1
- package/src/ui/dist/assets/{zoom-out-Hb0Z1YpT.js → zoom-out-D4TR-ZZ_.js} +1 -1
- package/src/ui/dist/index.html +2 -2
|
@@ -4,11 +4,12 @@ import json
|
|
|
4
4
|
import threading
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
from typing import Any, Callable
|
|
7
|
-
from urllib.request import Request
|
|
7
|
+
from urllib.request import Request
|
|
8
8
|
|
|
9
9
|
from websockets.exceptions import ConnectionClosed
|
|
10
|
-
from websockets.sync.client import connect as websocket_connect
|
|
11
10
|
|
|
11
|
+
from ..connector_runtime import format_conversation_id
|
|
12
|
+
from ..network import urlopen_with_proxy as urlopen, websocket_connect_with_proxy as websocket_connect
|
|
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
|
|
|
@@ -4,8 +4,10 @@ import json
|
|
|
4
4
|
import threading
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
from typing import Any, Callable
|
|
7
|
-
from urllib.request import Request
|
|
7
|
+
from urllib.request import Request
|
|
8
8
|
|
|
9
|
+
from ..connector_runtime import format_conversation_id
|
|
10
|
+
from ..network import urlopen_with_proxy as urlopen
|
|
9
11
|
from ..shared import read_json, utc_now, write_json
|
|
10
12
|
|
|
11
13
|
|
|
@@ -17,14 +19,22 @@ class TelegramPollingService:
|
|
|
17
19
|
config: dict[str, Any],
|
|
18
20
|
on_event: Callable[[dict[str, Any]], None],
|
|
19
21
|
log: Callable[[str, str], None] | None = None,
|
|
22
|
+
profile_id: str | None = None,
|
|
23
|
+
profile_label: str | None = None,
|
|
24
|
+
encode_profile_id: bool = False,
|
|
20
25
|
) -> None:
|
|
21
26
|
self.home = home
|
|
22
27
|
self.config = config
|
|
23
28
|
self.on_event = on_event
|
|
24
29
|
self.log = log or self._default_log
|
|
30
|
+
self.profile_id = str(profile_id or "").strip() or None
|
|
31
|
+
self.profile_label = str(profile_label or "").strip() or None
|
|
32
|
+
self._encode_profile_id = bool(encode_profile_id and self.profile_id)
|
|
25
33
|
self._thread: threading.Thread | None = None
|
|
26
34
|
self._stop_event = threading.Event()
|
|
27
35
|
self._root = home / "logs" / "connectors" / "telegram"
|
|
36
|
+
if self.profile_id:
|
|
37
|
+
self._root = self._root / "profiles" / self.profile_id
|
|
28
38
|
self._runtime_path = self._root / "runtime.json"
|
|
29
39
|
|
|
30
40
|
def start(self) -> bool:
|
|
@@ -59,7 +69,7 @@ class TelegramPollingService:
|
|
|
59
69
|
self._thread = threading.Thread(
|
|
60
70
|
target=self._run,
|
|
61
71
|
daemon=True,
|
|
62
|
-
name="deepscientist-telegram-polling",
|
|
72
|
+
name=f"deepscientist-telegram-polling-{self.profile_id or 'default'}",
|
|
63
73
|
)
|
|
64
74
|
self._thread.start()
|
|
65
75
|
return True
|
|
@@ -219,12 +229,22 @@ class TelegramPollingService:
|
|
|
219
229
|
"sender_id": sender_id,
|
|
220
230
|
"sender_name": sender_name,
|
|
221
231
|
"message_id": str(message.get("message_id") or "").strip(),
|
|
222
|
-
"conversation_id":
|
|
232
|
+
"conversation_id": self._conversation_id(chat_type, chat_id),
|
|
233
|
+
"profile_id": self.profile_id,
|
|
234
|
+
"profile_label": self.profile_label,
|
|
223
235
|
"text": normalized_text,
|
|
224
236
|
"mentioned": mentioned,
|
|
225
237
|
"raw_event": update,
|
|
226
238
|
}
|
|
227
239
|
|
|
240
|
+
def _conversation_id(self, chat_type: str, chat_id: str) -> str:
|
|
241
|
+
return format_conversation_id(
|
|
242
|
+
"telegram",
|
|
243
|
+
chat_type,
|
|
244
|
+
chat_id,
|
|
245
|
+
profile_id=self.profile_id if self._encode_profile_id else None,
|
|
246
|
+
)
|
|
247
|
+
|
|
228
248
|
@staticmethod
|
|
229
249
|
def _normalize_command_target(text: str, *, bot_name: str) -> str:
|
|
230
250
|
cleaned = str(text or "").strip()
|
|
@@ -272,6 +292,10 @@ class TelegramPollingService:
|
|
|
272
292
|
state = read_json(self._runtime_path, {}) or {}
|
|
273
293
|
if not isinstance(state, dict):
|
|
274
294
|
state = {}
|
|
295
|
+
if self.profile_id:
|
|
296
|
+
state["profile_id"] = self.profile_id
|
|
297
|
+
if self.profile_label:
|
|
298
|
+
state["profile_label"] = self.profile_label
|
|
275
299
|
state.update(patch)
|
|
276
300
|
write_json(self._runtime_path, state)
|
|
277
301
|
|
|
@@ -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
|
@@ -9,7 +9,7 @@ import sys
|
|
|
9
9
|
import webbrowser
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
from urllib.error import URLError
|
|
12
|
-
from urllib.request import Request
|
|
12
|
+
from urllib.request import Request
|
|
13
13
|
|
|
14
14
|
from .artifact import ArtifactService
|
|
15
15
|
from .config import ConfigManager
|
|
@@ -17,6 +17,8 @@ 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
|
|
21
|
+
from .network import configure_runtime_proxy, urlopen_with_proxy as urlopen
|
|
20
22
|
from .prompts import PromptBuilder
|
|
21
23
|
from .quest import QuestService
|
|
22
24
|
from .registries import BaselineRegistry
|
|
@@ -36,6 +38,7 @@ def _local_ui_url(host: str, port: int) -> str:
|
|
|
36
38
|
def build_parser() -> argparse.ArgumentParser:
|
|
37
39
|
parser = argparse.ArgumentParser(prog="ds", description="DeepScientist Core skeleton")
|
|
38
40
|
parser.add_argument("--home", default=None, help="Override DeepScientist home")
|
|
41
|
+
parser.add_argument("--proxy", default=None, help="Explicit outbound HTTP/WS proxy, for example `http://127.0.0.1:7890`.")
|
|
39
42
|
|
|
40
43
|
subparsers = parser.add_subparsers(dest="command", required=True)
|
|
41
44
|
|
|
@@ -109,6 +112,9 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
109
112
|
config_edit.add_argument("name", choices=("config", "runners", "connectors", "plugins", "mcp_servers"))
|
|
110
113
|
config_subparsers.add_parser("validate")
|
|
111
114
|
|
|
115
|
+
migrate_parser = subparsers.add_parser("migrate")
|
|
116
|
+
migrate_parser.add_argument("target")
|
|
117
|
+
|
|
112
118
|
return parser
|
|
113
119
|
|
|
114
120
|
|
|
@@ -445,9 +451,31 @@ def config_validate_command(home: Path) -> int:
|
|
|
445
451
|
return 0
|
|
446
452
|
|
|
447
453
|
|
|
454
|
+
def migrate_command(home: Path, target: str) -> int:
|
|
455
|
+
try:
|
|
456
|
+
payload = migrate_deepscientist_root(home, Path(target))
|
|
457
|
+
except ValueError as exc:
|
|
458
|
+
print(
|
|
459
|
+
json.dumps(
|
|
460
|
+
{
|
|
461
|
+
"ok": False,
|
|
462
|
+
"source": str(home.expanduser().resolve()),
|
|
463
|
+
"target": str(Path(target).expanduser().resolve()),
|
|
464
|
+
"message": str(exc),
|
|
465
|
+
},
|
|
466
|
+
ensure_ascii=False,
|
|
467
|
+
indent=2,
|
|
468
|
+
)
|
|
469
|
+
)
|
|
470
|
+
return 1
|
|
471
|
+
print(json.dumps(payload, ensure_ascii=False, indent=2))
|
|
472
|
+
return 0
|
|
473
|
+
|
|
474
|
+
|
|
448
475
|
def main(argv: list[str] | None = None) -> int:
|
|
449
476
|
parser = build_parser()
|
|
450
477
|
args = parser.parse_args(argv)
|
|
478
|
+
configure_runtime_proxy(args.proxy)
|
|
451
479
|
home = resolve_home(args)
|
|
452
480
|
|
|
453
481
|
if args.command == "init":
|
|
@@ -492,6 +520,8 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
492
520
|
return config_edit_command(home, args.name)
|
|
493
521
|
if args.command == "config" and args.config_command == "validate":
|
|
494
522
|
return config_validate_command(home)
|
|
523
|
+
if args.command == "migrate":
|
|
524
|
+
return migrate_command(home, args.target)
|
|
495
525
|
parser.error(f"Unknown command: {args.command}")
|
|
496
526
|
return 1
|
|
497
527
|
|
|
@@ -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")
|
|
@@ -57,6 +56,10 @@ def default_config(home: Path) -> dict:
|
|
|
57
56
|
"codex_ready": False,
|
|
58
57
|
"codex_last_checked_at": None,
|
|
59
58
|
"codex_last_result": {},
|
|
59
|
+
"locale_source": "default",
|
|
60
|
+
"locale_initialized_from_browser": False,
|
|
61
|
+
"locale_initialized_at": None,
|
|
62
|
+
"locale_initialized_browser_locale": None,
|
|
60
63
|
},
|
|
61
64
|
"connectors": {
|
|
62
65
|
"auto_ack": True,
|
|
@@ -92,9 +95,9 @@ def default_runners() -> dict:
|
|
|
92
95
|
"sandbox_mode": "workspace-write",
|
|
93
96
|
"retry_on_failure": True,
|
|
94
97
|
"retry_max_attempts": 5,
|
|
95
|
-
"retry_initial_backoff_sec":
|
|
96
|
-
"retry_backoff_multiplier":
|
|
97
|
-
"retry_max_backoff_sec":
|
|
98
|
+
"retry_initial_backoff_sec": 10.0,
|
|
99
|
+
"retry_backoff_multiplier": 6.0,
|
|
100
|
+
"retry_max_backoff_sec": 1800.0,
|
|
98
101
|
# Increase MCP tool timeout so codex can wait for long `bash_exec(mode='await', ...)`
|
|
99
102
|
# or other durable MCP calls without prematurely timing out.
|
|
100
103
|
# Mirrors DS_2027's `codex.mcp_tool_timeout_sec` default.
|
|
@@ -122,6 +125,7 @@ def default_connectors() -> dict:
|
|
|
122
125
|
"qq": {
|
|
123
126
|
"enabled": False,
|
|
124
127
|
"transport": "gateway_direct",
|
|
128
|
+
"profiles": [],
|
|
125
129
|
"app_id": None,
|
|
126
130
|
"app_secret": None,
|
|
127
131
|
"app_secret_env": "QQ_APP_SECRET",
|
|
@@ -140,17 +144,12 @@ def default_connectors() -> dict:
|
|
|
140
144
|
},
|
|
141
145
|
"telegram": {
|
|
142
146
|
"enabled": False,
|
|
147
|
+
"profiles": [],
|
|
143
148
|
"transport": "polling",
|
|
144
|
-
"mode": "relay",
|
|
145
149
|
"bot_name": "DeepScientist",
|
|
146
150
|
"command_prefix": "/",
|
|
147
151
|
"bot_token": None,
|
|
148
152
|
"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
153
|
"dm_policy": "pairing",
|
|
155
154
|
"allow_from": [],
|
|
156
155
|
"group_policy": "open",
|
|
@@ -161,18 +160,13 @@ def default_connectors() -> dict:
|
|
|
161
160
|
},
|
|
162
161
|
"discord": {
|
|
163
162
|
"enabled": False,
|
|
163
|
+
"profiles": [],
|
|
164
164
|
"transport": "gateway",
|
|
165
|
-
"mode": "relay",
|
|
166
165
|
"bot_name": "DeepScientist",
|
|
167
166
|
"command_prefix": "/",
|
|
168
167
|
"bot_token": None,
|
|
169
168
|
"bot_token_env": "DISCORD_BOT_TOKEN",
|
|
170
169
|
"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
170
|
"dm_policy": "pairing",
|
|
177
171
|
"allow_from": [],
|
|
178
172
|
"group_policy": "open",
|
|
@@ -184,8 +178,8 @@ def default_connectors() -> dict:
|
|
|
184
178
|
},
|
|
185
179
|
"slack": {
|
|
186
180
|
"enabled": False,
|
|
181
|
+
"profiles": [],
|
|
187
182
|
"transport": "socket_mode",
|
|
188
|
-
"mode": "relay",
|
|
189
183
|
"bot_name": "DeepScientist",
|
|
190
184
|
"command_prefix": "/",
|
|
191
185
|
"bot_token": None,
|
|
@@ -193,11 +187,6 @@ def default_connectors() -> dict:
|
|
|
193
187
|
"bot_user_id": None,
|
|
194
188
|
"app_token": None,
|
|
195
189
|
"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
190
|
"dm_policy": "pairing",
|
|
202
191
|
"allow_from": [],
|
|
203
192
|
"group_policy": "open",
|
|
@@ -208,21 +197,14 @@ def default_connectors() -> dict:
|
|
|
208
197
|
},
|
|
209
198
|
"feishu": {
|
|
210
199
|
"enabled": False,
|
|
200
|
+
"profiles": [],
|
|
211
201
|
"transport": "long_connection",
|
|
212
|
-
"mode": "relay",
|
|
213
202
|
"bot_name": "DeepScientist",
|
|
214
203
|
"command_prefix": "/",
|
|
215
204
|
"app_id": None,
|
|
216
205
|
"app_secret": None,
|
|
217
206
|
"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
207
|
"api_base_url": "https://open.feishu.cn",
|
|
223
|
-
"public_callback_url": None,
|
|
224
|
-
"relay_url": None,
|
|
225
|
-
"relay_auth_token": None,
|
|
226
208
|
"dm_policy": "pairing",
|
|
227
209
|
"allow_from": [],
|
|
228
210
|
"group_policy": "open",
|
|
@@ -233,24 +215,12 @@ def default_connectors() -> dict:
|
|
|
233
215
|
},
|
|
234
216
|
"whatsapp": {
|
|
235
217
|
"enabled": False,
|
|
218
|
+
"profiles": [],
|
|
236
219
|
"transport": "local_session",
|
|
237
|
-
"mode": "relay",
|
|
238
220
|
"bot_name": "DeepScientist",
|
|
239
221
|
"command_prefix": "/",
|
|
240
222
|
"auth_method": "qr_browser",
|
|
241
223
|
"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
224
|
"dm_policy": "pairing",
|
|
255
225
|
"allow_from": [],
|
|
256
226
|
"group_policy": "allowlist",
|