myagent-ai 1.15.79 → 1.15.80

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "myagent-ai",
3
- "version": "1.15.79",
3
+ "version": "1.15.80",
4
4
  "description": "本地桌面端执行型AI助手 - Open Interpreter 风格 | Local Desktop Execution-Oriented AI Assistant",
5
5
  "main": "main.py",
6
6
  "bin": {
package/web/api_server.py CHANGED
@@ -344,6 +344,8 @@ class ApiServer:
344
344
  r.add_post("/api/knowledge/search", self.handle_knowledge_search)
345
345
  # ── 配置管理 (热重载/导入/导出) ──
346
346
  r.add_get("/api/config", self.handle_get_config)
347
+ r.add_post("/api/config/get", self.handle_get_config_key)
348
+ r.add_post("/api/config/set", self.handle_set_config_key)
347
349
  r.add_post("/api/config/reload", self.handle_reload_config)
348
350
  r.add_post("/api/config/export", self.handle_export_config)
349
351
  r.add_post("/api/config/import", self.handle_import_config)
@@ -3321,6 +3323,28 @@ class ApiServer:
3321
3323
  cfg = self.core.config_mgr.get_full_config()
3322
3324
  return web.json_response(cfg)
3323
3325
 
3326
+ async def handle_get_config_key(self, request):
3327
+ """POST /api/config/get - 获取单个配置项"""
3328
+ data = await request.json()
3329
+ key = data.get("key", "")
3330
+ value = getattr(self.core.config, key, None)
3331
+ return web.json_response({"ok": True, "value": value or ""})
3332
+
3333
+ async def handle_set_config_key(self, request):
3334
+ """POST /api/config/set - 设置单个配置项并保存"""
3335
+ data = await request.json()
3336
+ key = data.get("key", "")
3337
+ value = data.get("value", "")
3338
+ if not key:
3339
+ return web.json_response({"ok": False, "error": "缺少 key"})
3340
+ setattr(self.core.config, key, value)
3341
+ self.core.config_mgr.save()
3342
+ # 时区变更时清除缓存,下次调用 get_config_tz() 立即生效
3343
+ if key == "timezone":
3344
+ import core.utils as _u
3345
+ _u._tz_cache = None
3346
+ return web.json_response({"ok": True})
3347
+
3324
3348
  def _build_model_chain(self, agent_cfg: dict | None, agent_path: str) -> list[dict]:
3325
3349
  """构建模型链: [主模型, 备用模型1, 备用模型2, ...]"""
3326
3350
  if not agent_cfg:
package/web/ui/index.html CHANGED
@@ -2005,10 +2005,13 @@ async function uploadDeptKB(path,folderMode){
2005
2005
  async function renderSystem(){
2006
2006
  $('content').innerHTML=`
2007
2007
  <div class="card">
2008
- <h3>🔄 热重载</h3>
2009
- <p style="font-size:13px;color:var(--text2);margin-bottom:12px">从配置文件重新加载所有设置,立即生效,无需重启服务</p>
2010
- <button class="btn btn-primary" id="sysReloadBtn" onclick="sysHotReload()">热重载配置</button>
2011
- <div id="sysReloadMsg"></div>
2008
+ <h3>🕐 时区设置</h3>
2009
+ <p style="font-size:13px;color:var(--text2);margin-bottom:12px">设置系统时区,影响提示词中的当前时间、记忆时间戳、日志时间等所有时间显示</p>
2010
+ <div style="display:flex;align-items:center;gap:12px;margin-bottom:12px">
2011
+ <select id="sysTimezone" style="flex:1;padding:8px 12px;border:1px solid var(--border);border-radius:6px;background:var(--bg2);color:var(--text);font-size:14px"></select>
2012
+ <button class="btn btn-primary" id="sysTzSaveBtn" onclick="sysSaveTimezone()">保存</button>
2013
+ </div>
2014
+ <div id="sysTzMsg"></div>
2012
2015
  </div>
2013
2016
  <div class="card">
2014
2017
  <h3>📤 导出备份</h3>
@@ -2038,31 +2041,38 @@ async function renderSystem(){
2038
2041
  <h3>👁️ 配置预览</h3>
2039
2042
  <div class="config-preview" id="sysConfigPreview">加载中...</div>
2040
2043
  </div>`;
2044
+ sysLoadTimezone();
2041
2045
  sysLoadPreview();
2042
2046
  }
2043
2047
 
2044
- function sysSetMsg(id,type,msg){
2045
- const el=$(id);if(!el)return;
2046
- el.className='status-msg '+type;el.textContent=msg;
2047
- if(type!=='loading')setTimeout(()=>{if(el.className.includes(type))el.className='status-msg';},8000);
2048
+ const COMMON_TIMEZONES=['Asia/Shanghai','Asia/Kuala_Lumpur','Asia/Singapore','Asia/Tokyo','Asia/Seoul','Asia/Ho_Chi_Minh','Asia/Bangkok','Asia/Jakarta','Asia/Kolkata','Asia/Dubai','Europe/London','Europe/Paris','Europe/Berlin','Europe/Moscow','America/New_York','America/Chicago','America/Denver','America/Los_Angeles','Australia/Sydney','Pacific/Auckland','UTC'];
2049
+
2050
+ async function sysLoadTimezone(){
2051
+ try{
2052
+ const r=await api('/api/config/get',{method:'POST',body:JSON.stringify({key:'timezone'})});
2053
+ const sel=$('sysTimezone');
2054
+ sel.innerHTML=COMMON_TIMEZONES.map(tz=>`<option value="${tz}"${tz===(r.value||'Asia/Shanghai')?' selected':''}>${tz}</option>`).join('');
2055
+ }catch(e){console.error('Load timezone failed:',e);}
2048
2056
  }
2049
2057
 
2050
- async function sysHotReload(){
2051
- const btn=$('sysReloadBtn');btn.disabled=true;
2052
- sysSetMsg('sysReloadMsg','loading','正在热重载配置...');
2058
+ async function sysSaveTimezone(){
2059
+ const btn=$('sysTzSaveBtn');btn.disabled=true;
2060
+ sysSetMsg('sysTzMsg','loading','正在保存时区...');
2053
2061
  try{
2054
- const r=await api('/api/config/reload',{method:'POST',body:JSON.stringify({})});
2055
- if(r.ok){
2056
- const changes=r.changes||[];
2057
- let msg=' 配置已热重载';
2058
- msg+=changes.length>0?' — 变更: '+changes.join(', '):' 无显著变更';
2059
- sysSetMsg('sysReloadMsg','success',msg);showToast(msg,'success');
2060
- sysLoadPreview();
2061
- }else{sysSetMsg('sysReloadMsg','error','❌ 热重载失败: '+(r.error||'未知错误'));}
2062
- }catch(e){sysSetMsg('sysReloadMsg','error','❌ 热重载失败: '+e.message);}
2062
+ const tz=$('sysTimezone').value;
2063
+ const r=await api('/api/config/set',{method:'POST',body:JSON.stringify({key:'timezone',value:tz})});
2064
+ if(r.ok){sysSetMsg('sysTzMsg','success','✅ 时区已保存为 '+tz);showToast('时区已更新为 '+tz,'success');}
2065
+ else{sysSetMsg('sysTzMsg','error','❌ 保存失败: '+(r.error||'未知错误'));}
2066
+ }catch(e){sysSetMsg('sysTzMsg','error',' 保存失败: '+e.message);}
2063
2067
  btn.disabled=false;
2064
2068
  }
2065
2069
 
2070
+ function sysSetMsg(id,type,msg){
2071
+ const el=$(id);if(!el)return;
2072
+ el.className='status-msg '+type;el.textContent=msg;
2073
+ if(type!=='loading')setTimeout(()=>{if(el.className.includes(type))el.className='status-msg';},8000);
2074
+ }
2075
+
2066
2076
  async function sysExport(includeSecrets){
2067
2077
  const btnId=includeSecrets?'sysExportFull':'sysExportSafe';
2068
2078
  const btn=$(btnId);btn.disabled=true;