myagent-ai 1.4.3 → 1.5.2

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.
@@ -220,10 +220,11 @@ class UpdateManager:
220
220
  current = get_version()
221
221
 
222
222
  try:
223
- # 尝试多种方式检查更新
224
- latest = await self._check_github_tags()
225
- if not latest:
223
+ # 尝试多种方式检查更新(npm 安装优先用 npm registry)
224
+ if (PROJECT_ROOT / "package.json").exists():
226
225
  latest = await self._check_npm_registry()
226
+ if not latest:
227
+ latest = await self._check_github_tags()
227
228
  if not latest:
228
229
  latest = await self._check_pypi()
229
230
  if not latest:
@@ -320,25 +321,46 @@ class UpdateManager:
320
321
  pkg_name = pkg_data.get("name", "")
321
322
  if not pkg_name:
322
323
  return ""
324
+ except Exception as e:
325
+ logger.debug(f"读取 package.json 失败: {e}")
326
+ return ""
323
327
 
324
- # 使用 curl 检查 npm registry
328
+ # 直接请求 npm registry HTTP API(不依赖 npm 命令行)
329
+ try:
330
+ import urllib.request
331
+ url = f"https://registry.npmjs.org/{pkg_name}/latest"
332
+ logger.debug(f"检查 npm registry: {url}")
325
333
  loop = asyncio.get_running_loop()
326
- result = await loop.run_in_executor(
334
+ data = await loop.run_in_executor(
327
335
  None,
328
- lambda: subprocess.run(
329
- ["npm", "view", pkg_name, "version", "--json"],
330
- capture_output=True, text=True, timeout=10,
331
- cwd=PROJECT_ROOT,
332
- )
336
+ lambda: urllib.request.urlopen(url, timeout=10).read(),
333
337
  )
334
- version = result.stdout.strip().strip('"').strip("'")
338
+ info = json.loads(data)
339
+ version = info.get("version", "")
335
340
  if version and version[0].isdigit():
341
+ logger.debug(f"npm registry 最新版本: {version}")
336
342
  return version
337
343
 
338
- except (subprocess.TimeoutExpired, FileNotFoundError):
339
- pass
340
344
  except Exception as e:
341
- logger.debug(f"npm registry 检查失败: {e}")
345
+ logger.debug(f"npm registry HTTP 检查失败: {e}")
346
+
347
+ # 回退: 尝试用 npm 命令行检查 (可能 urllib 失败但 npm 命令可用)
348
+ try:
349
+ loop = asyncio.get_running_loop()
350
+ result = await loop.run_in_executor(
351
+ None,
352
+ lambda: subprocess.run(
353
+ ["npm", "view", pkg_name, "version", "--registry",
354
+ "https://registry.npmjs.org/"],
355
+ capture_output=True, text=True, timeout=15,
356
+ )
357
+ )
358
+ ver = result.stdout.strip()
359
+ if ver and ver[0].isdigit():
360
+ logger.debug(f"npm view 最新版本: {ver}")
361
+ return ver
362
+ except Exception as e2:
363
+ logger.debug(f"npm view 回退检查也失败: {e2}")
342
364
 
343
365
  return ""
344
366
 
@@ -562,45 +584,70 @@ class UpdateManager:
562
584
 
563
585
  async def _do_full_update(self, record: UpdateRecord):
564
586
  """
565
- 全量更新: git pull + 依赖更新 + 优雅重启。
587
+ 全量更新: npm update -g (npm 安装) 或 git pull + pip install (源码安装) + 优雅重启。
566
588
  使用 os.execv 替换当前进程,保持 PID 不变。
567
589
  """
568
590
  self._status = UpdateStatus.UPDATING
569
591
  logger.info("开始全量更新...")
570
592
 
571
- # Step 1: git pull
572
- result = subprocess.run(
573
- ["git", "pull"],
574
- capture_output=True, text=True, timeout=30,
575
- cwd=PROJECT_ROOT,
576
- )
577
- pull_output = result.stdout + result.stderr
578
- logger.info(f"git pull: {pull_output[:500]}")
593
+ is_npm_install = (PROJECT_ROOT / "package.json").exists()
579
594
 
580
- # Step 2: pip install
581
- self._status = UpdateStatus.DOWNLOADING
582
- loop = asyncio.get_running_loop()
583
- result = await loop.run_in_executor(
584
- None,
585
- lambda: subprocess.run(
586
- [sys.executable, "-m", "pip", "install", "-e", ".",
587
- "--quiet"],
588
- capture_output=True, text=True, timeout=120,
595
+ if is_npm_install:
596
+ # npm 安装: npm install -g myagent-ai
597
+ self._status = UpdateStatus.DOWNLOADING
598
+ loop = asyncio.get_running_loop()
599
+ result = await loop.run_in_executor(
600
+ None,
601
+ lambda: subprocess.run(
602
+ ["npm", "install", "-g", "myagent-ai"],
603
+ capture_output=True, text=True, timeout=180,
604
+ )
605
+ )
606
+ npm_output = result.stdout + result.stderr
607
+ record.details["update_output"] = npm_output[:2000]
608
+ logger.info(f"npm update: {npm_output[:500]}")
609
+
610
+ if result.returncode != 0:
611
+ # npm 返回非零码可能是权限问题或网络问题
612
+ error_msg = npm_output[-500:] if npm_output else "未知错误"
613
+ # 尝试判断是否真的失败了(npm 有时返回非零但实际安装成功)
614
+ if "ERR!" in error_msg or "error" in error_msg.lower():
615
+ logger.warning(f"npm install 可能失败: {error_msg}")
616
+ # 不直接抛异常,让重启后 start.js 的依赖检查来兜底
617
+ else:
618
+ logger.warning(f"npm install 有警告但不影响: {error_msg}")
619
+ else:
620
+ # 源码安装: git pull + pip install
621
+ result = subprocess.run(
622
+ ["git", "pull"],
623
+ capture_output=True, text=True, timeout=30,
589
624
  cwd=PROJECT_ROOT,
590
625
  )
591
- )
592
- pip_output = result.stdout + result.stderr
593
- record.details.update(pull_output=pull_output[:500], pip_output=pip_output[:1000])
626
+ pull_output = result.stdout + result.stderr
627
+ logger.info(f"git pull: {pull_output[:500]}")
594
628
 
595
- if result.returncode != 0:
596
- logger.warning(f"pip install 有警告: {pip_output[-300:]}")
629
+ self._status = UpdateStatus.DOWNLOADING
630
+ loop = asyncio.get_running_loop()
631
+ result = await loop.run_in_executor(
632
+ None,
633
+ lambda: subprocess.run(
634
+ [sys.executable, "-m", "pip", "install", "-e", ".",
635
+ "--quiet"],
636
+ capture_output=True, text=True, timeout=120,
637
+ cwd=PROJECT_ROOT,
638
+ )
639
+ )
640
+ pip_output = result.stdout + result.stderr
641
+ record.details["update_output"] = pip_output[:1000]
642
+ if result.returncode != 0:
643
+ logger.warning(f"pip install 有警告: {pip_output[-300:]}")
597
644
 
598
645
  # Step 3: 保存更新完成标记(用于重启后验证)
599
646
  record.status = "restarting"
600
647
  self._save_record(record)
601
648
  logger.info("全量更新完成,准备优雅重启...")
602
649
 
603
- # Step 4: 优雅重启 - os.execv 替换当前进程
650
+ # Step 4: 优雅重启
604
651
  self._status = UpdateStatus.RESTARTING
605
652
  await asyncio.sleep(0.5) # 给日志一点时间写入
606
653
 
@@ -610,8 +657,45 @@ class UpdateManager:
610
657
  env["MYAGENT_UPDATED_FROM"] = record.from_version
611
658
  env["MYAGENT_UPDATED_TO"] = record.to_version
612
659
 
613
- # 使用 os.execv 替换当前进程(PID 不变,systemd 友好)
614
- os.execv(sys.executable, [sys.executable] + sys.argv)
660
+ if is_npm_install:
661
+ # npm 安装: 通过 start.js (Node.js) 重启,确保 venv 和依赖正确处理
662
+ # start.js 会自动创建/更新 venv 并安装依赖
663
+ start_js = PROJECT_ROOT / "start.js"
664
+ if start_js.exists():
665
+ import shutil
666
+ node_cmd = shutil.which("node")
667
+ if node_cmd:
668
+ # 提取原始参数 (去掉 main.py,还原 start.js 的参数格式)
669
+ original_args = []
670
+ skip_next = False
671
+ for arg in sys.argv[1:]:
672
+ if skip_next:
673
+ skip_next = False
674
+ continue
675
+ if arg == "--web":
676
+ original_args.append("web")
677
+ elif arg == "--tray":
678
+ original_args.append("tray")
679
+ elif arg == "--cli":
680
+ original_args.append("cli")
681
+ elif arg == "--server":
682
+ original_args.append("server")
683
+ elif arg == "--setup":
684
+ original_args.append("setup")
685
+ elif arg.startswith("--port="):
686
+ original_args.append(arg.replace("--port=", ""))
687
+ elif arg.startswith("--"):
688
+ skip_next = True # 跳过 --arg value 形式的参数
689
+ logger.info(f"通过 start.js 重启: node {start_js} {' '.join(original_args)}")
690
+ os.execv(node_cmd, [node_cmd, str(start_js)] + original_args)
691
+ else:
692
+ logger.warning("未找到 node 命令,回退到直接 Python 重启")
693
+
694
+ # 回退: 直接用 Python 重启(源码安装或 node 不可用)
695
+ # 使用绝对路径避免 cwd 变化导致找不到 main.py
696
+ abs_main = str((PROJECT_ROOT / "main.py").resolve())
697
+ logger.info(f"通过 Python 直接重启: {sys.executable} {abs_main}")
698
+ os.execv(sys.executable, [sys.executable, abs_main] + sys.argv[1:])
615
699
 
616
700
  async def _do_config_update(self, record: UpdateRecord):
617
701
  """仅配置热重载(利用现有 ConfigManager.reload())"""
package/core/version.py CHANGED
@@ -11,7 +11,7 @@ import subprocess
11
11
  from pathlib import Path
12
12
 
13
13
  # ── 基线版本(与 setup.py / package.json 保持一致) ──
14
- BASE_VERSION = "1.4.3"
14
+ BASE_VERSION = "1.5.0"
15
15
 
16
16
 
17
17
  def _version_from_git() -> str:
@@ -9,7 +9,7 @@ param(
9
9
 
10
10
  $ErrorActionPreference = "Stop"
11
11
  $PKG_NAME = "myagent-ai"
12
- $PKG_VERSION = "1.4.3"
12
+ $PKG_VERSION = "1.5.2"
13
13
 
14
14
  # Allow running scripts for the current process
15
15
  if ($PSVersionTable.PSVersion.Major -ge 5) {
@@ -248,21 +248,59 @@ function Install-PythonDeps {
248
248
  Write-Host "[i] venv will be used automatically on startup" -ForegroundColor Gray
249
249
  }
250
250
 
251
- # ── Post-install guide ──────────────────────────────
251
+ # ── Post-install: 直接启动 ──────────────────────────
252
252
  function Show-Guide {
253
253
  Write-Host ""
254
- Write-Host " Installation complete!" -ForegroundColor Green
254
+ Write-Host " 安装完成!正在启动 MyAgent..." -ForegroundColor Green
255
255
  Write-Host ""
256
- Write-Host " Quick start:" -ForegroundColor White
257
- Write-Host " myagent-ai # Interactive mode selection" -ForegroundColor Cyan
258
- Write-Host " myagent-ai web # Web dashboard (recommended)" -ForegroundColor Cyan
259
- Write-Host " myagent-ai cli # CLI mode" -ForegroundColor Cyan
260
- Write-Host ""
261
- Write-Host " First run:" -ForegroundColor White
262
- Write-Host " 1. Configure LLM API Key (OpenAI / Anthropic / ModelScope / Ollama)" -ForegroundColor Gray
263
- Write-Host " 2. Open http://localhost:8767" -ForegroundColor Gray
264
- Write-Host ""
265
- Write-Host " Docs: https://github.com/ctz168/myagent" -ForegroundColor Gray
256
+
257
+ # 刷新 PATH(刚安装的 npm 全局命令可能在新的 PATH 中)
258
+ Refresh-Path
259
+
260
+ # npm 全局命令实际是 .cmd 文件,必须通过 cmd /c 执行
261
+ $npmBinDir = ""
262
+ try {
263
+ $npmBinDir = (npm bin -g 2>$null).Trim()
264
+ } catch {}
265
+
266
+ $cmdPath = ""
267
+ if ($npmBinDir -and (Test-Path "$npmBinDir\myagent-ai.cmd")) {
268
+ $cmdPath = "$npmBinDir\myagent-ai.cmd"
269
+ }
270
+
271
+ if ($cmdPath) {
272
+ Write-Host " [i] 启动路径: $cmdPath" -ForegroundColor Gray
273
+ Start-Process cmd -ArgumentList "/c", "`"$cmdPath`" web" -WindowStyle Minimized
274
+ } else {
275
+ Write-Host " [i] 回退到 PATH 搜索..." -ForegroundColor Gray
276
+ Start-Process cmd -ArgumentList "/c", "myagent-ai web" -WindowStyle Minimized
277
+ }
278
+ Write-Host " [OK] MyAgent 已在后台启动" -ForegroundColor Green
279
+
280
+ # 由安装脚本自身轮询服务并打开浏览器(比 start.js 更可靠)
281
+ Write-Host " [i] 等待服务启动..." -ForegroundColor Gray
282
+ $url = "http://127.0.0.1:8767"
283
+ $maxWait = 120 # 最多等 120 秒
284
+ $waited = 0
285
+ while ($waited -lt $maxWait) {
286
+ Start-Sleep -Seconds 2
287
+ $waited += 2
288
+ try {
289
+ $null = Invoke-WebRequest -Uri "$url/api/status" -UseBasicParsing -TimeoutSec 3 -ErrorAction Stop
290
+ Write-Host " [OK] 服务已就绪,正在打开浏览器..." -ForegroundColor Green
291
+ Start-Process $url
292
+ Write-Host " [i] 如果没有自动打开,请访问: $url" -ForegroundColor Cyan
293
+ Write-Host ""
294
+ return
295
+ } catch {
296
+ # 服务还没启动,继续等待
297
+ if ($waited % 10 -eq 0) {
298
+ Write-Host " [i] 等待中... ($waited 秒)" -ForegroundColor Gray
299
+ }
300
+ }
301
+ }
302
+ Write-Host " [!] 等待超时" -ForegroundColor Yellow
303
+ Write-Host " [i] 服务可能仍在启动中,请稍等片刻后访问: $url" -ForegroundColor Cyan
266
304
  Write-Host ""
267
305
  }
268
306
 
@@ -21,7 +21,7 @@ NO_DEPS=false
21
21
  DRY_RUN=false
22
22
  SCRIPT_URL="https://raw.githubusercontent.com/ctz168/myagent/main/install/install.sh"
23
23
  PKG_NAME="myagent-ai"
24
- PKG_VERSION="1.4.3"
24
+ PKG_VERSION="1.5.2"
25
25
 
26
26
  for arg in "$@"; do
27
27
  case "$arg" in
@@ -382,23 +382,59 @@ install_python_deps() {
382
382
  info "启动时自动使用 venv,无需手动激活"
383
383
  }
384
384
 
385
- # ── 首次配置引导 ───────────────────────────────────
385
+ # ── 安装完成:直接启动 ───────────────────────────────
386
386
  post_install() {
387
387
  echo ""
388
- echo -e " ${BOLD}${SUCCESS}安装完成!${NC}"
388
+ echo -e " ${BOLD}${SUCCESS}安装完成!正在启动 MyAgent...${NC}"
389
389
  echo ""
390
- echo " 快速开始:"
391
- echo -e " ${ACCENT}myagent-ai${NC} # 交互式选择运行模式"
392
- echo -e " ${ACCENT}myagent-ai web${NC} # 直接启动 Web 管理后台 (推荐)"
393
- echo -e " ${ACCENT}myagent-ai cli${NC} # CLI 交互模式"
394
- echo -e " ${ACCENT}myagent-ai tray${NC} # 系统托盘模式"
395
- echo ""
396
- echo " 首次运行需要配置:"
397
- echo " 1. LLM API Key (支持 OpenAI / Anthropic / ModelScope / Ollama 等)"
398
- echo " 2. 访问 http://localhost:8767 进入 Web 管理界面"
399
- echo ""
400
- echo " 文档: https://github.com/ctz168/myagent#readme"
401
- echo " 问题: https://github.com/ctz168/myagent/issues"
390
+
391
+ # 直接启动 Web 模式,浏览器会自动打开配置向导
392
+ # 使用 nohup 在后台运行,不阻塞终端
393
+ if command -v myagent-ai &>/dev/null; then
394
+ nohup myagent-ai web > /dev/null 2>&1 &
395
+ echo -e " ${SUCCESS}[✓]${NC} MyAgent 已在后台启动"
396
+ else
397
+ # myagent-ai 不在 PATH 中,尝试通过 npm 全局目录启动
398
+ local npm_bin
399
+ npm_bin="$(npm bin -g 2>/dev/null)/myagent-ai"
400
+ if [ -x "$npm_bin" ]; then
401
+ nohup "$npm_bin" web > /dev/null 2>&1 &
402
+ echo -e " ${SUCCESS}[✓]${NC} MyAgent 已在后台启动"
403
+ else
404
+ echo -e " ${WARN}[!]${NC} 启动命令未找到,请重新打开终端后运行:"
405
+ echo -e " ${ACCENT}myagent-ai web${NC}"
406
+ echo ""
407
+ return
408
+ fi
409
+ fi
410
+
411
+ # 由安装脚本自身轮询服务并打开浏览器(比 start.js 更可靠)
412
+ local url="http://127.0.0.1:8767"
413
+ local max_wait=120
414
+ local waited=0
415
+
416
+ echo -e " ${INFO}[i]${NC} 等待服务启动..."
417
+ while [ $waited -lt $max_wait ]; do
418
+ sleep 2
419
+ waited=$((waited + 2))
420
+ if curl -sf "$url/api/status" > /dev/null 2>&1; then
421
+ echo -e " ${SUCCESS}[✓]${NC} 服务已就绪,正在打开浏览器..."
422
+ # 跨平台打开浏览器
423
+ if [ "$OS" = "macos" ]; then
424
+ open "$url" 2>/dev/null || true
425
+ elif [ "$OS" = "linux" ]; then
426
+ xdg-open "$url" 2>/dev/null || sensible-browser "$url" 2>/dev/null || true
427
+ fi
428
+ echo -e " ${INFO}[i]${NC} 如果没有自动打开,请访问: ${ACCENT}$url${NC}"
429
+ echo ""
430
+ return
431
+ fi
432
+ if [ $((waited % 10)) -eq 0 ]; then
433
+ echo -e " ${INFO}[i]${NC} 等待中... ($waited 秒)"
434
+ fi
435
+ done
436
+ echo -e " ${WARN}[!]${NC} 等待超时"
437
+ echo -e " ${INFO}[i]${NC} 服务可能仍在启动中,请稍等片刻后访问: ${ACCENT}$url${NC}"
402
438
  echo ""
403
439
  }
404
440
 
package/main.py CHANGED
@@ -1043,11 +1043,12 @@ def _first_run_setup(config_mgr: ConfigManager):
1043
1043
  print(" 1. OpenAI / 兼容 API (推荐)")
1044
1044
  print(" 2. Anthropic (Claude)")
1045
1045
  print(" 3. Ollama (本地模型,无需 API Key)")
1046
+ print(" 4. 自定义 / Custom (任意 OpenAI 兼容接口)")
1046
1047
  print()
1047
1048
 
1048
1049
  while True:
1049
1050
  try:
1050
- choice = input(" 请选择 [1/2/3]: ").strip()
1051
+ choice = input(" 请选择 [1/2/3/4]: ").strip()
1051
1052
  except (EOFError, KeyboardInterrupt):
1052
1053
  print("\n\n 已取消配置。可通过 myagent-ai setup 重新配置。")
1053
1054
  sys.exit(0)
@@ -1061,8 +1062,11 @@ def _first_run_setup(config_mgr: ConfigManager):
1061
1062
  elif choice == "3":
1062
1063
  _setup_ollama(config_mgr)
1063
1064
  break
1065
+ elif choice == "4":
1066
+ _setup_custom(config_mgr)
1067
+ break
1064
1068
  else:
1065
- print(" 无效选择,请输入 1/2/3")
1069
+ print(" 无效选择,请输入 1/2/3/4")
1066
1070
 
1067
1071
  # 保存配置
1068
1072
  config_mgr.save()
@@ -1252,6 +1256,96 @@ def _setup_ollama(config_mgr: ConfigManager):
1252
1256
  print(f" (已保存配置,启动后可在 Web 界面修改)")
1253
1257
 
1254
1258
 
1259
+ def _setup_custom(config_mgr: ConfigManager):
1260
+ """配置自定义 / Custom 模型 (OpenAI 兼容接口)"""
1261
+ print()
1262
+ print(" -- 自定义 / Custom 模型配置 --")
1263
+ print()
1264
+ print(" 支持任意 OpenAI API 兼容接口,包括:")
1265
+ print(" - 中转站 / 代理 API")
1266
+ print(" - 自部署的 vLLM / LocalAI")
1267
+ print(" - 企业内部 AI 网关")
1268
+ print()
1269
+
1270
+ try:
1271
+ name = input(" 模型显示名称 (如: 我的 GPT 镜像): ").strip()
1272
+ except (EOFError, KeyboardInterrupt):
1273
+ sys.exit(0)
1274
+
1275
+ while True:
1276
+ try:
1277
+ base_url = input(" Base URL (如 https://your-api.com/v1): ").strip().rstrip("/")
1278
+ except (EOFError, KeyboardInterrupt):
1279
+ sys.exit(0)
1280
+ if base_url:
1281
+ break
1282
+ print(" Base URL 不能为空!")
1283
+
1284
+ while True:
1285
+ try:
1286
+ model = input(" 模型名称 (如 gpt-4o / deepseek-chat): ").strip()
1287
+ except (EOFError, KeyboardInterrupt):
1288
+ sys.exit(0)
1289
+ if model:
1290
+ break
1291
+ print(" 模型名称不能为空!")
1292
+
1293
+ try:
1294
+ api_key = input(" API Key (选填,直接回车跳过): ").strip()
1295
+ except (EOFError, KeyboardInterrupt):
1296
+ api_key = ""
1297
+
1298
+ # 写入配置
1299
+ config_mgr.config.llm.provider = "custom"
1300
+ config_mgr.config.llm.api_key = api_key
1301
+ config_mgr.config.llm.base_url = base_url
1302
+ config_mgr.config.llm.model = model
1303
+
1304
+ # 同时添加到模型库
1305
+ model_id = f"custom-{model.replace('/', '-').lower()}"
1306
+ from config import ModelEntry
1307
+ entry = ModelEntry(
1308
+ id=model_id,
1309
+ name=name or f"Custom - {model}",
1310
+ provider="custom",
1311
+ model=model,
1312
+ base_url=base_url,
1313
+ api_key=api_key,
1314
+ max_tokens=4096,
1315
+ temperature=0.1,
1316
+ enabled=True,
1317
+ )
1318
+ # 避免重复
1319
+ existing_ids = [m.id for m in config_mgr.config.models_library]
1320
+ if model_id not in existing_ids:
1321
+ config_mgr.config.models_library.append(entry)
1322
+
1323
+ print()
1324
+ print(" 正在验证连接...")
1325
+ try:
1326
+ import requests
1327
+ headers = {}
1328
+ if api_key:
1329
+ headers["Authorization"] = f"Bearer {api_key}"
1330
+ test_body = {
1331
+ "model": model,
1332
+ "messages": [{"role": "user", "content": "hi"}],
1333
+ "max_tokens": 5,
1334
+ }
1335
+ resp = requests.post(
1336
+ f"{base_url}/chat/completions",
1337
+ headers=headers, json=test_body, timeout=15,
1338
+ )
1339
+ if resp.status_code == 200:
1340
+ print(" 连接成功!")
1341
+ else:
1342
+ print(f" 连接失败 (HTTP {resp.status_code}),请检查 Base URL 和模型名称")
1343
+ print(f" (已保存配置,启动后可在 Web 界面修改)")
1344
+ except Exception as e:
1345
+ print(f" 连接测试失败: {e}")
1346
+ print(f" (已保存配置,启动后可在 Web 界面修改)")
1347
+
1348
+
1255
1349
  # ==============================================================================
1256
1350
  # 主函数
1257
1351
  # ==============================================================================
@@ -1296,12 +1390,15 @@ def main():
1296
1390
  # ══════════════════════════════════════════════════════════
1297
1391
  # 首次运行: 引导配置 LLM API Key
1298
1392
  # ══════════════════════════════════════════════════════════
1299
- _first_run_setup(config_mgr)
1393
+ web_port = args.web if args.web else args.port if args.tray else None
1394
+ if not web_port:
1395
+ # 仅 CLI 模式才用命令行配置向导
1396
+ # Web 模式下由 chat.html 的 Web 向导处理 (检测 /api/setup/status)
1397
+ _first_run_setup(config_mgr)
1300
1398
 
1301
1399
  # 创建应用
1302
1400
  app = MyAgentApp()
1303
1401
  app._restart_requested = False
1304
- web_port = args.web if args.web else args.port if args.tray else None
1305
1402
 
1306
1403
  # 信号处理 — 仅设置标志, 不在信号处理器中调用 asyncio
1307
1404
  def signal_handler(sig, frame):
@@ -1329,6 +1426,14 @@ def main():
1329
1426
  await api_server.start(port=web_port)
1330
1427
  app.logger.info(f"管理后台: http://127.0.0.1:{web_port}/ui/")
1331
1428
 
1429
+ # 非 tray 模式(纯 web 模式)自动打开浏览器
1430
+ if not args.tray:
1431
+ import webbrowser
1432
+ try:
1433
+ webbrowser.open(f"http://127.0.0.1:{web_port}/ui/chat.html")
1434
+ except Exception:
1435
+ pass
1436
+
1332
1437
  # 系统托盘 (默认开启管理后台)
1333
1438
  if args.tray or web_port:
1334
1439
  try:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "myagent-ai",
3
- "version": "1.4.3",
3
+ "version": "1.5.2",
4
4
  "description": "本地桌面端执行型AI助手 - Open Interpreter 风格 | Local Desktop Execution-Oriented AI Assistant",
5
5
  "main": "main.py",
6
6
  "bin": {
package/setup.py CHANGED
@@ -9,7 +9,7 @@ from pathlib import Path
9
9
  _version_path = Path(__file__).parent / "core" / "version.py"
10
10
  _version_vars = {}
11
11
  exec(_version_path.read_text(), _version_vars)
12
- __version__ = _version_vars.get("BASE_VERSION", "1.4.3")
12
+ __version__ = _version_vars.get("BASE_VERSION", "1.5.2")
13
13
 
14
14
  setup(
15
15
  name="myagent",