myagent-ai 1.9.9 → 1.10.0

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/agents/base.py CHANGED
@@ -142,6 +142,12 @@ class BaseAgent(ABC):
142
142
  if tools:
143
143
  request_kwargs["tools"] = tools
144
144
  request_kwargs["tool_choice"] = "auto"
145
+ # ── 推理模式 (Reasoning) ──
146
+ if self.llm.reasoning:
147
+ if self.llm.provider in self.llm._OPENAI_COMPATIBLE_PROVIDERS or self.llm.provider == "zhipu":
148
+ request_kwargs["reasoning_effort"] = self.llm.reasoning_effort
149
+ if self.llm.max_tokens < 8192:
150
+ request_kwargs["max_tokens"] = 8192
145
151
  request_kwargs.update(kwargs)
146
152
 
147
153
  full_text = ""
@@ -351,9 +357,13 @@ class BaseAgent(ABC):
351
357
  "arguments": args,
352
358
  })
353
359
 
360
+ # 对于推理模型(如 o1/DeepSeek-R1),如果 content 为空但有 reasoning 内容,
361
+ # 使用 reasoning 内容作为最终回复
362
+ final_content = full_text if full_text.strip() else (full_reasoning if full_reasoning.strip() else full_text)
363
+
354
364
  return LLMResponse(
355
365
  success=True,
356
- content=full_text,
366
+ content=final_content,
357
367
  tool_calls=final_tool_calls,
358
368
  finish_reason=finish_reason,
359
369
  model=request_kwargs.get("model", self.llm.model),
@@ -39,8 +39,9 @@ class MainAgent(BaseAgent):
39
39
  # =========================================================================
40
40
  SYSTEM_PROMPT = """你是一个强内容分析格式转化引擎,要深入分析以下上下文内容:
41
41
 
42
- 严格格式化输出以下内容:
42
+ 严格以XML格式化输出以下内容:
43
43
  <output>
44
+ <response>直接回复用户的内容。这是一段友好、自然的话语,用于向用户说明你正在做什么,或者回应用户的问题/问候。要求简洁、有礼貌、符合对话场景。如果用户只是问候,简单回应即可;如果用户有具体任务,要说明你的计划。</response>
44
45
  <usersays_correct>根据用户输入的"usersays"内容,结合上下文优化为新的用户输入,如果"usersays"为空,这里输出为空。</usersays_correct>
45
46
  <task_plan>如"context"包含非空"task_plan",则更新它,变为当前输出。否则,根据"context", 以MD 的格式,制定新任务列表。</task_plan>
46
47
 
@@ -59,18 +60,19 @@ class MainAgent(BaseAgent):
59
60
 
60
61
  ## 核心规则
61
62
  1. 你必须且只能输出 <output> XML 结构,不要输出任何其他文本
62
- 2. <usersays_correct>: 如果 context 中 usersays 非空,则根据对话语境优化为更准确的用户意图表达
63
- 3. <task_plan>: 使用 Markdown 列表格式,每项包含任务描述和完成状态标记 [x]/[ ]
64
- 4. <toolstocal>: 列出所有需要执行的工具调用,每个工具包含完整的参数说明
65
- 5. <timeout>: 预估超时秒数(简单操作10-30s,文件操作30-60s,网络请求60-120s,数据处理120-300s)
66
- 6. <callback>: 如果该工具的执行结果对后续决策有影响,设为 true;否则设为 false
67
- 7. <remember>: 仅从最新用户输入(userprint usersays_correct)中提炼值得长期记忆的关键信息,不要重复提炼历史对话中已有的记忆。如果本轮没有新信息需要记忆,则为空
68
- 8. <recall>: 描述下一轮执行时需要从记忆库中检索的内容关键词
69
- 9. <get_knowledge>: 如果当前 <knowledge> 内容不足以完成任务,填写需要从知识库搜索的关键词;否则为空
70
- 10. <askuser>: 当信息不足需要用户补充时,在此填写要问的问题
71
- 11. <finish>: 当任务已完成或需要等待用户回应时为 true;否则为 false 继续执行
72
- 12. 使用中文输出所有内容
73
- 13. 优先使用技能系统(skill)而非直接写代码执行
63
+ 2. <response>: 必须输出一段直接回复用户的话语(这是用户实际看到的回复),要求简洁友好、自然流畅。不要只输出任务计划而不说话!
64
+ 3. <usersays_correct>: 如果 context usersays 非空,则根据对话语境优化为更准确的用户意图表达
65
+ 4. <task_plan>: 使用 Markdown 列表格式,每项包含任务描述和完成状态标记 [x]/[ ]
66
+ 5. <toolstocal>: 列出所有需要执行的工具调用,每个工具包含完整的参数说明
67
+ 6. <timeout>: 预估超时秒数(简单操作10-30s,文件操作30-60s,网络请求60-120s,数据处理120-300s)
68
+ 7. <callback>: 如果该工具的执行结果对后续决策有影响,设为 true;否则设为 false
69
+ 8. <remember>: 仅从最新用户输入(userprint 或 usersays_correct)中提炼值得长期记忆的关键信息,不要重复提炼历史对话中已有的记忆。如果本轮没有新信息需要记忆,则为空
70
+ 9. <recall>: 描述下一轮执行时需要从记忆库中检索的内容关键词
71
+ 10. <get_knowledge>: 如果当前 <knowledge> 内容不足以完成任务,填写需要从知识库搜索的关键词;否则为空
72
+ 11. <askuser>: 当信息不足需要用户补充时,在此填写要问的问题
73
+ 12. <finish>: 当任务已完成或需要等待用户回应时为 true;否则为 false 继续执行
74
+ 13. 使用中文输出所有内容
75
+ 14. 优先使用技能系统(skill)而非直接写代码执行
74
76
  """
75
77
 
76
78
  def __init__(self, tool_agent=None, memory_agent=None, **kwargs):
@@ -173,8 +175,6 @@ class MainAgent(BaseAgent):
173
175
  stream_callback(event)
174
176
  except Exception as e:
175
177
  logger.debug(f"V2 SSE 事件发送失败 ({event_type}): {e}")
176
- else:
177
- logger.debug(f"[v2-event] {event_type}: {data}")
178
178
 
179
179
  async def _merge_duplicate_memory(
180
180
  self,
@@ -391,7 +391,7 @@ class MainAgent(BaseAgent):
391
391
  + self.SYSTEM_PROMPT.split("\n", 1)[1]
392
392
  )
393
393
  system_content = _prompt_with_placeholder.replace(_CONTEXT_PLACEHOLDER, context_xml)
394
-
394
+ print(system_content)
395
395
  # Step 3: 调用 LLM
396
396
  messages = [Message(role="system", content=system_content)]
397
397
 
@@ -452,7 +452,17 @@ class MainAgent(BaseAgent):
452
452
  )
453
453
  break
454
454
  else:
455
- context.working_memory["final_response"] = llm_raw
455
+ # XML 解析失败且无法提取文本,发送原始输出作为备选
456
+ logger.warning(f"[{task_id}] 无法提取文本,发送原始 LLM 输出")
457
+ final_text = llm_raw.strip() if llm_raw.strip() else "处理完毕。"
458
+ context.working_memory["final_response"] = final_text
459
+ await self._emit_v2_event("v2_reasoning", {"content": final_text}, stream_callback)
460
+ if self.memory:
461
+ self.memory.add_short_term(
462
+ session_id=context.session_id,
463
+ role="assistant",
464
+ content=final_text,
465
+ )
456
466
  break
457
467
 
458
468
  warnings = validate_output(parsed)
@@ -463,6 +473,18 @@ class MainAgent(BaseAgent):
463
473
  if parsed.usersays_correct:
464
474
  context.working_memory["usersays_correct"] = parsed.usersays_correct
465
475
 
476
+ # Step 5.5: 处理 response — 直接回复用户的内容
477
+ if parsed.response:
478
+ response_text = parsed.response.strip()
479
+ if response_text:
480
+ logger.debug(f"[{task_id}] 模型回复用户: {response_text[:100]}")
481
+ context.working_memory["model_response"] = response_text
482
+ await self._emit_v2_event(
483
+ "v2_reasoning",
484
+ {"content": response_text},
485
+ stream_callback,
486
+ )
487
+
466
488
  # Step 6: 处理 remember — 查重+LLM合并后存入长期记忆
467
489
  if parsed.remember:
468
490
  try:
package/config.py CHANGED
@@ -23,11 +23,15 @@ from typing import Optional, Dict, Any, List
23
23
  class LLMConfig:
24
24
  """LLM 大模型配置"""
25
25
  provider: str = "openai" # openai | anthropic | ollama | custom
26
+ api_type: str = "openai-completions" # API 类型
26
27
  api_key: str = ""
27
28
  base_url: str = "https://api.openai.com/v1"
28
29
  model: str = "gpt-4"
29
30
  temperature: float = 0.1
30
31
  max_tokens: int = 4096
32
+ context_window: int = 128000 # 上下文窗口大小
33
+ input_modes: List[str] = field(default_factory=lambda: ["text"]) # 支持的输入模式
34
+ reasoning: bool = False # 是否支持推理
31
35
  timeout: int = 120 # 请求超时(秒)
32
36
  max_retries: int = 3 # 最大重试次数
33
37
  # Anthropic 专用
@@ -86,11 +90,15 @@ class ModelEntry:
86
90
  id: str = "" # 唯一标识符,如 "gpt-4o", "claude-3.5-sonnet"
87
91
  name: str = "" # 显示名称
88
92
  provider: str = "" # openai | anthropic | ollama | zhipu | custom
93
+ api_type: str = "openai-completions" # API 类型:openai-completions | openai-chat | anthropic | ollama | custom
89
94
  model: str = "" # API 调用使用的实际模型字符串
90
95
  base_url: str = "" # 自定义 Base URL(空=使用 provider 默认值)
91
96
  api_key: str = "" # 专用 API Key(空=使用全局默认值)
92
97
  max_tokens: int = 4096
93
98
  temperature: float = 0.1
99
+ context_window: int = 128000 # 上下文窗口大小(token)
100
+ input_modes: List[str] = field(default_factory=lambda: ["text"]) # 支持的输入模式: text, image, video, audio
101
+ reasoning: bool = True # 是否支持推理(如 o1 系列)
94
102
  enabled: bool = True
95
103
 
96
104
 
package/core/logger.py CHANGED
@@ -148,6 +148,12 @@ def setup_logger(
148
148
  # 控制台输出
149
149
  if console:
150
150
  ch = logging.StreamHandler(sys.stdout)
151
+ # Windows 兼容 UTF-8
152
+ if sys.platform == "win32":
153
+ try:
154
+ sys.stdout.reconfigure(encoding="utf-8")
155
+ except Exception:
156
+ pass
151
157
  ch.setFormatter(ColorFormatter(fmt, datefmt=datefmt))
152
158
  ch.setLevel(logging.DEBUG) # 控制台始终显示所有级别
153
159
  logger.addHandler(ch)
@@ -216,7 +222,16 @@ def get_logger(name: str = "myagent") -> logging.Logger:
216
222
  """获取已存在的 Logger,如果不存在则创建默认的"""
217
223
  logger = logging.getLogger(name)
218
224
  if not logger.handlers:
219
- return setup_logger(name)
225
+ # 子 logger 继承父 logger 的 handlers(如文件 handler)
226
+ parent_logger = logging.getLogger()
227
+ if parent_logger.handlers:
228
+ for handler in parent_logger.handlers:
229
+ logger.addHandler(handler)
230
+ logger.setLevel(parent_logger.level)
231
+ logger.propagate = parent_logger.propagate
232
+ else:
233
+ # 没有父 logger,创建默认配置
234
+ return setup_logger(name)
220
235
  return logger
221
236
 
222
237
 
@@ -43,6 +43,10 @@ import xml.etree.ElementTree as ET
43
43
  from dataclasses import dataclass, field
44
44
  from typing import Any, Dict, List
45
45
 
46
+ from core.logger import get_logger
47
+
48
+ logger = get_logger("myagent.output_parser")
49
+
46
50
  # ---------------------------------------------------------------------------
47
51
  # Constants
48
52
  # ---------------------------------------------------------------------------
@@ -95,6 +99,7 @@ class ParsedOutput:
95
99
  ask_user: str = ""
96
100
  get_knowledge: str = ""
97
101
  finish: bool = False
102
+ response: str = "" # 模型对用户的直接回复(友好自然的话语)
98
103
  raw_text: str = ""
99
104
  parse_success: bool = False
100
105
 
@@ -207,21 +212,149 @@ def _parse_tools_element(tools_element: ET.Element | None) -> List[Dict[str, Any
207
212
  return tools
208
213
 
209
214
 
215
+ def _fix_incomplete_xml(xml_content: str) -> str:
216
+ """修复不完整的 XML,使用正则表达式补齐格式。
217
+
218
+ 支持修复的问题类型:
219
+ 1. 自闭合标签误用:<tag /> → <tag></tag>
220
+ 2. 缺少闭合标签:<tag>value → <tag>value</tag>
221
+ 3. 标签大小写混乱:<TAG>value</TAG> → <tag>value</tag>
222
+ 4. 空白字符问题:< tag >value</ tag >
223
+ 5. 嵌套标签未闭合
224
+ 6. 特殊字符转义:& → &amp; (在属性值中)
225
+ """
226
+ if not xml_content:
227
+ return xml_content
228
+
229
+ # 标准标签列表(用于修复缺少闭合标签)
230
+ STANDARD_TAGS = [
231
+ "usersays_correct", "task_plan", "toolstocal", "remember",
232
+ "recall", "askuser", "get_knowledge", "finish", "response",
233
+ "tool", "beforecalltext", "toolname", "parms", "timeout", "callback"
234
+ ]
235
+
236
+ # 1. 修复自闭合标签为普通标签
237
+ # <tag /> → <tag></tag>
238
+ # <tag/> → <tag></tag>
239
+ xml_content = re.sub(r'<(\w+)\s*/\s*>', r'<\1></\1>', xml_content)
240
+
241
+ # 2. 修复空白字符在标签内的问题:< tag > → <tag>
242
+ # 同时规范化大小写
243
+ def normalize_tag(match):
244
+ inner = match.group(1).strip()
245
+ tag_name = inner.split()[0].lower()
246
+ rest = ' '.join(inner.split()[1:]) # 保留可能的属性
247
+ if rest:
248
+ return f'<{tag_name} {rest}>'
249
+ return f'<{tag_name}>'
250
+ xml_content = re.sub(r'<([a-z_][a-z_0-9]*)[^>]*>', normalize_tag, xml_content, flags=re.IGNORECASE)
251
+
252
+ # 3. 修复闭合标签的大小写和空白:</ TAG > → </tag>
253
+ def normalize_close_tag(match):
254
+ tag_name = match.group(1).strip().lower()
255
+ return f'</{tag_name}>'
256
+ xml_content = re.sub(r'</\s*([a-z_][a-z_0-9]*)\s*>', normalize_close_tag, xml_content, flags=re.IGNORECASE)
257
+
258
+ # 4. 修复缺少闭合标签的问题
259
+ # 策略:对于标准标签,如果后面跟着另一个标签或 </output>,则添加闭合标签
260
+ for tag in STANDARD_TAGS:
261
+ # 修复 <tag>value<下一个标签> 格式(缺少 </tag>)
262
+ # 例如:<finish>true<task_plan> → <finish>true</finish><task_plan>
263
+ next_tag_pattern = '|'.join([re.escape(t) for t in STANDARD_TAGS if t != tag])
264
+ if next_tag_pattern:
265
+ # 匹配 <tag>...后面跟着其他标签或 </output>
266
+ pattern = rf'(<{tag}>)([^<]*?)(?=(?:<{next_tag_pattern}|</output>))'
267
+ replacement = rf'\1\2</{tag}>'
268
+ xml_content = re.sub(pattern, replacement, xml_content, flags=re.IGNORECASE | re.DOTALL)
269
+
270
+ # 5. 修复 <toolstocal> 和 </toolstocal> 标签
271
+ xml_content = re.sub(r'<toolstocal\s*>', '<toolstocal>', xml_content, flags=re.IGNORECASE)
272
+ xml_content = re.sub(r'</toolstocal\s*>', '</toolstocal>', xml_content, flags=re.IGNORECASE)
273
+
274
+ # 6. 修复 askuser 标签(系统提示中用的是 askuser,但有时可能写成 ask_user)
275
+ xml_content = re.sub(r'<ask_user\s*>', '<askuser>', xml_content, flags=re.IGNORECASE)
276
+ xml_content = re.sub(r'</ask_user\s*>', '</askuser>', xml_content, flags=re.IGNORECASE)
277
+
278
+ # 7. 修复单独的 <tool> 块中的标签
279
+ # 匹配 <tool>... 中缺少闭合标签的情况
280
+ tool_tags = ["beforecalltext", "toolname", "parms", "timeout", "callback"]
281
+ tool_next_pattern = '|'.join([re.escape(t) for t in tool_tags])
282
+
283
+ for tag in tool_tags:
284
+ pattern = rf'(<{tag}>)([^<]*?)(?=(?:<{tool_next_pattern}|</tool>|</toolstocal>|</output>))'
285
+ replacement = rf'\1\2</{tag}>'
286
+ xml_content = re.sub(pattern, replacement, xml_content, flags=re.IGNORECASE | re.DOTALL)
287
+
288
+ # 8. 处理文本内容中的特殊 XML 字符(简单处理 &)
289
+ # 只在标签外的内容中处理
290
+ # 这个比较复杂,简单处理:在文本内容中 & 后没有 ; 的转为 &amp;
291
+ # 但更安全的做法是只在必要时处理
292
+
293
+ # 9. 确保 <output> 标签周围没有多余空白
294
+ xml_content = xml_content.strip()
295
+
296
+ return xml_content
297
+
298
+
299
+ def _aggressive_clean_xml(xml_content: str) -> str:
300
+ """激进清理 XML 内容,移除可能导致解析失败的字符。"""
301
+ # 移除控制字符(除了换行和 tab)
302
+ xml_content = re.sub(r'[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]', '', xml_content)
303
+
304
+ # 修复 & 字符(确保它是有效的 XML 实体)
305
+ # 匹配 & 不在有效实体前的情况
306
+ xml_content = re.sub(r'&(?!amp;|lt;|gt;|quot;|apos;|#\d+;|#x[0-9a-fA-F]+;)', '&amp;', xml_content)
307
+
308
+ # 移除多余的空白(连续多个空白合并为一个)
309
+ xml_content = re.sub(r'>\s+<', '><', xml_content)
310
+ xml_content = re.sub(r'\s{2,}', ' ', xml_content)
311
+
312
+ return xml_content
313
+
314
+
210
315
  def _parse_xml_content(xml_content: str) -> ParsedOutput:
211
316
  """Attempt to parse *xml_content* (the inner body of ``<output>``) as XML.
212
317
 
213
318
  Assumes *xml_content* has already been extracted from the surrounding
214
319
  ``<output>`` tags. If parsing fails a :class:`ParsedOutput` with
215
320
  ``parse_success=False`` is returned.
321
+
322
+ 解析策略:
323
+ 1. 首先尝试直接解析
324
+ 2. 如果失败,使用正则表达式修复后再解析
325
+ 3. 如果仍然失败,尝试激进清理
216
326
  """
217
327
  parsed = ParsedOutput(parse_success=False)
218
328
 
329
+ # Strategy 1: 尝试直接解析原始 XML
219
330
  try:
220
- root = ET.fromstring(f"<output>{xml_content}</output>")
221
- except ET.ParseError:
222
- return parsed
223
-
224
- parsed.parse_success = True
331
+ root = ET.fromstring("<output>" + xml_content + "</output>")
332
+ parsed.parse_success = True
333
+ logger.debug(f"XML 直接解析成功")
334
+ except ET.ParseError as e1:
335
+ logger.debug(f"XML 直接解析失败: {e1},尝试修复...")
336
+
337
+ # Strategy 2: 修复不完整的 XML 后再解析
338
+ fixed_xml = _fix_incomplete_xml(xml_content)
339
+ logger.debug(f"修复后 XML 前200字符: {fixed_xml[:200]}...")
340
+
341
+ try:
342
+ root = ET.fromstring("<output>" + fixed_xml + "</output>")
343
+ parsed.parse_success = True
344
+ logger.debug(f"XML 修复后解析成功")
345
+ except ET.ParseError as e2:
346
+ logger.warning(f"XML 修复后仍然解析失败: {e2},尝试激进清理...")
347
+ # Strategy 3: 激进清理
348
+ cleaned = _aggressive_clean_xml(fixed_xml)
349
+ try:
350
+ root = ET.fromstring("<output>" + cleaned + "</output>")
351
+ parsed.parse_success = True
352
+ logger.debug(f"XML 激进清理后解析成功")
353
+ except ET.ParseError as e3:
354
+ logger.warning(f"XML 解析最终失败: {e3}")
355
+ return parsed
356
+
357
+ # 提取各字段
225
358
  parsed.usersays_correct = _safe_strip(root.findtext("usersays_correct"))
226
359
  parsed.task_plan = _safe_strip(root.findtext("task_plan"))
227
360
  parsed.tools_to_call = _parse_tools_element(root.find("toolstocal"))
@@ -230,6 +363,7 @@ def _parse_xml_content(xml_content: str) -> ParsedOutput:
230
363
  parsed.ask_user = _safe_strip(root.findtext("askuser"))
231
364
  parsed.get_knowledge = _safe_strip(root.findtext("get_knowledge"))
232
365
  parsed.finish = _parse_bool(root.findtext("finish"), False)
366
+ parsed.response = _safe_strip(root.findtext("response"))
233
367
 
234
368
  return parsed
235
369
 
@@ -259,6 +393,7 @@ def _fallback_regex_parse(raw_text: str) -> ParsedOutput:
259
393
  parsed.ask_user = _safe_strip(tag_map.get("askuser"))
260
394
  parsed.get_knowledge = _safe_strip(tag_map.get("get_knowledge"))
261
395
  parsed.finish = _parse_bool(tag_map.get("finish"), False)
396
+ parsed.response = _safe_strip(tag_map.get("response"))
262
397
 
263
398
  # For toolstocal we attempt to find individual <tool> blocks.
264
399
  tools_raw = tag_map.get("toolstocal", "")
@@ -347,6 +482,7 @@ def parse_output(raw_text: str) -> ParsedOutput:
347
482
  parsed.ask_user = _safe_strip(root.findtext("askuser"))
348
483
  parsed.get_knowledge = _safe_strip(root.findtext("get_knowledge"))
349
484
  parsed.finish = _parse_bool(root.findtext("finish"), False)
485
+ parsed.response = _safe_strip(root.findtext("response"))
350
486
  return parsed
351
487
  except ET.ParseError:
352
488
  pass
package/main.py CHANGED
@@ -199,6 +199,7 @@ class MyAgentApp:
199
199
  max_tokens=llm_cfg.max_tokens,
200
200
  timeout=llm_cfg.timeout,
201
201
  max_retries=llm_cfg.max_retries,
202
+ reasoning=llm_cfg.reasoning,
202
203
  anthropic_api_key=llm_cfg.anthropic_api_key,
203
204
  )
204
205
  self.logger.info(f"LLM: {llm_cfg.provider}/{llm_cfg.model}")
@@ -487,7 +488,7 @@ class MyAgentApp:
487
488
 
488
489
  print()
489
490
  print("=" * 60)
490
- print(" 🤖 MyAgent - 本地桌面端执行型AI助手")
491
+ print(" MyAgent - 本地桌面端执行型AI助手")
491
492
  print(f" 版本: v{get_version()}")
492
493
  print(f" LLM: {self.config.llm.provider}/{self.config.llm.model}")
493
494
  print(f" 技能: {len(self.skill_registry.list_skills())} 个已注册")
@@ -499,14 +500,14 @@ class MyAgentApp:
499
500
  while self._running:
500
501
  try:
501
502
  # 读取用户输入
502
- user_input = input("👤 你: ").strip()
503
+ user_input = input("> ").strip()
503
504
 
504
505
  if not user_input:
505
506
  continue
506
507
 
507
508
  # 内置命令
508
509
  if user_input.lower() in ("quit", "exit", "q"):
509
- print("👋 再见!")
510
+ print("再见!")
510
511
  break
511
512
  elif user_input.lower() == "help":
512
513
  self._print_help()
@@ -1499,7 +1500,7 @@ def main():
1499
1500
  args.web = args.port
1500
1501
  if args.server and not args.host:
1501
1502
  args.host = "0.0.0.0"
1502
- web_port = args.web if args.web else args.port if args.tray else None
1503
+ web_port = args.web if args.web else args.port
1503
1504
  web_host = args.host or "127.0.0.1"
1504
1505
  if not web_port:
1505
1506
  # 仅 CLI 模式才用命令行配置向导
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "myagent-ai",
3
- "version": "1.9.9",
4
- "description": "\u672c\u5730\u684c\u9762\u7aef\u6267\u884c\u578bAI\u52a9\u624b - Open Interpreter \u98ce\u683c | Local Desktop Execution-Oriented AI Assistant",
3
+ "version": "1.10.0",
4
+ "description": "本地桌面端执行型AI助手 - Open Interpreter 风格 | Local Desktop Execution-Oriented AI Assistant",
5
5
  "main": "main.py",
6
6
  "bin": {
7
7
  "myagent-ai": "start.js"
@@ -65,4 +65,4 @@
65
65
  "departments/",
66
66
  "web/"
67
67
  ]
68
- }
68
+ }