jarvis-ai-assistant 0.3.27__py3-none-any.whl → 0.3.29__py3-none-any.whl
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.
- jarvis/__init__.py +1 -1
- jarvis/jarvis_agent/__init__.py +73 -29
- jarvis/jarvis_agent/agent_manager.py +6 -0
- jarvis/jarvis_agent/config_editor.py +1 -1
- jarvis/jarvis_agent/event_bus.py +2 -2
- jarvis/jarvis_agent/events.py +157 -0
- jarvis/jarvis_agent/file_methodology_manager.py +18 -7
- jarvis/jarvis_agent/jarvis.py +11 -4
- jarvis/jarvis_agent/memory_manager.py +4 -4
- jarvis/jarvis_agent/prompts.py +2 -2
- jarvis/jarvis_agent/protocols.py +4 -1
- jarvis/jarvis_agent/run_loop.py +9 -24
- jarvis/jarvis_agent/shell_input_handler.py +7 -2
- jarvis/jarvis_agent/task_analyzer.py +19 -15
- jarvis/jarvis_agent/task_manager.py +6 -4
- jarvis/jarvis_agent/user_interaction.py +1 -1
- jarvis/jarvis_agent/utils.py +50 -0
- jarvis/jarvis_code_agent/code_agent.py +2 -2
- jarvis/jarvis_code_analysis/code_review.py +0 -1
- jarvis/jarvis_git_utils/git_commiter.py +13 -4
- jarvis/jarvis_mcp/sse_mcp_client.py +1 -1
- jarvis/jarvis_mcp/stdio_mcp_client.py +1 -1
- jarvis/jarvis_memory_organizer/memory_organizer.py +6 -9
- jarvis/jarvis_methodology/main.py +0 -2
- jarvis/jarvis_multi_agent/__init__.py +3 -3
- jarvis/jarvis_platform/base.py +1 -1
- jarvis/jarvis_platform/kimi.py +1 -1
- jarvis/jarvis_platform/registry.py +1 -1
- jarvis/jarvis_platform/tongyi.py +1 -1
- jarvis/jarvis_platform/yuanbao.py +1 -2
- jarvis/jarvis_platform_manager/service.py +1 -1
- jarvis/jarvis_rag/cli.py +1 -1
- jarvis/jarvis_rag/embedding_manager.py +0 -1
- jarvis/jarvis_rag/llm_interface.py +0 -3
- jarvis/jarvis_rag/retriever.py +3 -3
- jarvis/jarvis_smart_shell/main.py +0 -1
- jarvis/jarvis_stats/cli.py +2 -3
- jarvis/jarvis_stats/stats.py +3 -4
- jarvis/jarvis_stats/storage.py +3 -3
- jarvis/jarvis_tools/clear_memory.py +1 -3
- jarvis/jarvis_tools/cli/main.py +0 -1
- jarvis/jarvis_tools/edit_file.py +3 -4
- jarvis/jarvis_tools/execute_script.py +2 -2
- jarvis/jarvis_tools/generate_new_tool.py +3 -5
- jarvis/jarvis_tools/registry.py +2 -3
- jarvis/jarvis_tools/retrieve_memory.py +2 -3
- jarvis/jarvis_tools/save_memory.py +3 -3
- jarvis/jarvis_tools/search_web.py +2 -2
- jarvis/jarvis_tools/sub_agent.py +21 -2
- jarvis/jarvis_tools/sub_code_agent.py +18 -2
- jarvis/jarvis_tools/virtual_tty.py +3 -14
- jarvis/jarvis_utils/builtin_replace_map.py +4 -4
- jarvis/jarvis_utils/config.py +32 -17
- jarvis/jarvis_utils/fzf.py +4 -3
- jarvis/jarvis_utils/git_utils.py +1 -1
- jarvis/jarvis_utils/globals.py +1 -2
- jarvis/jarvis_utils/input.py +5 -5
- jarvis/jarvis_utils/methodology.py +3 -5
- jarvis/jarvis_utils/output.py +1 -1
- jarvis/jarvis_utils/utils.py +160 -31
- {jarvis_ai_assistant-0.3.27.dist-info → jarvis_ai_assistant-0.3.29.dist-info}/METADATA +1 -1
- {jarvis_ai_assistant-0.3.27.dist-info → jarvis_ai_assistant-0.3.29.dist-info}/RECORD +66 -64
- {jarvis_ai_assistant-0.3.27.dist-info → jarvis_ai_assistant-0.3.29.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.3.27.dist-info → jarvis_ai_assistant-0.3.29.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.3.27.dist-info → jarvis_ai_assistant-0.3.29.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.3.27.dist-info → jarvis_ai_assistant-0.3.29.dist-info}/top_level.txt +0 -0
jarvis/__init__.py
CHANGED
jarvis/jarvis_agent/__init__.py
CHANGED
@@ -34,7 +34,23 @@ from jarvis.jarvis_agent.prompt_manager import PromptManager
|
|
34
34
|
from jarvis.jarvis_agent.event_bus import EventBus
|
35
35
|
from jarvis.jarvis_agent.config import AgentConfig
|
36
36
|
from jarvis.jarvis_agent.run_loop import AgentRunLoop
|
37
|
+
from jarvis.jarvis_agent.events import (
|
38
|
+
BEFORE_SUMMARY,
|
39
|
+
AFTER_SUMMARY,
|
40
|
+
TASK_COMPLETED,
|
41
|
+
TASK_STARTED,
|
42
|
+
BEFORE_ADDON_PROMPT,
|
43
|
+
AFTER_ADDON_PROMPT,
|
44
|
+
BEFORE_HISTORY_CLEAR,
|
45
|
+
AFTER_HISTORY_CLEAR,
|
46
|
+
BEFORE_MODEL_CALL,
|
47
|
+
AFTER_MODEL_CALL,
|
48
|
+
INTERRUPT_TRIGGERED,
|
49
|
+
BEFORE_TOOL_FILTER,
|
50
|
+
TOOL_FILTERED,
|
51
|
+
)
|
37
52
|
from jarvis.jarvis_agent.user_interaction import UserInteractionHandler
|
53
|
+
from jarvis.jarvis_agent.utils import join_prompts
|
38
54
|
from jarvis.jarvis_utils.methodology import _load_all_methodologies
|
39
55
|
|
40
56
|
# jarvis_platform 相关
|
@@ -67,7 +83,10 @@ from jarvis.jarvis_utils.tag import ot
|
|
67
83
|
|
68
84
|
|
69
85
|
def show_agent_startup_stats(
|
70
|
-
agent_name: str,
|
86
|
+
agent_name: str,
|
87
|
+
model_name: str,
|
88
|
+
tool_registry_instance: Optional[Any] = None,
|
89
|
+
platform_name: Optional[str] = None,
|
71
90
|
) -> None:
|
72
91
|
"""输出启动时的统计信息
|
73
92
|
|
@@ -112,7 +131,8 @@ def show_agent_startup_stats(
|
|
112
131
|
current_dir = os.getcwd()
|
113
132
|
|
114
133
|
# 构建欢迎信息
|
115
|
-
|
134
|
+
platform = platform_name or get_normal_platform_name()
|
135
|
+
welcome_message = f"{agent_name} 初始化完成 - 使用 {platform} 平台 {model_name} 模型"
|
116
136
|
|
117
137
|
stats_parts = [
|
118
138
|
f"📚 本地方法论: [bold cyan]{methodology_count}[/bold cyan]",
|
@@ -208,6 +228,15 @@ class LoopAction(Enum):
|
|
208
228
|
|
209
229
|
|
210
230
|
class Agent:
|
231
|
+
# Attribute type annotations to satisfy static type checkers
|
232
|
+
event_bus: EventBus
|
233
|
+
memory_manager: MemoryManager
|
234
|
+
task_analyzer: TaskAnalyzer
|
235
|
+
file_methodology_manager: FileMethodologyManager
|
236
|
+
prompt_manager: PromptManager
|
237
|
+
model: BasePlatform
|
238
|
+
session: SessionManager
|
239
|
+
|
211
240
|
def clear_history(self):
|
212
241
|
"""
|
213
242
|
Clears the current conversation history by delegating to the session manager.
|
@@ -215,7 +244,7 @@ class Agent:
|
|
215
244
|
self.session.clear_history()
|
216
245
|
# 广播清理历史后的事件
|
217
246
|
try:
|
218
|
-
self.event_bus.emit(
|
247
|
+
self.event_bus.emit(AFTER_HISTORY_CLEAR, agent=self)
|
219
248
|
except Exception:
|
220
249
|
pass
|
221
250
|
|
@@ -326,19 +355,27 @@ class Agent:
|
|
326
355
|
self._setup_system_prompt()
|
327
356
|
|
328
357
|
# 输出统计信息(包含欢迎信息)
|
329
|
-
show_agent_startup_stats(
|
358
|
+
show_agent_startup_stats(
|
359
|
+
name,
|
360
|
+
self.model.name(),
|
361
|
+
self.get_tool_registry(), # type: ignore
|
362
|
+
platform_name=self.model.platform_name(), # type: ignore
|
363
|
+
)
|
330
364
|
|
331
365
|
def _init_model(self, model_group: Optional[str]):
|
332
366
|
"""初始化模型平台(统一使用 normal 平台/模型)"""
|
333
367
|
platform_name = get_normal_platform_name(model_group)
|
334
368
|
model_name = get_normal_model_name(model_group)
|
335
369
|
|
336
|
-
|
337
|
-
if
|
370
|
+
maybe_model = PlatformRegistry().create_platform(platform_name)
|
371
|
+
if maybe_model is None:
|
338
372
|
PrettyOutput.print(
|
339
373
|
f"平台 {platform_name} 不存在,将使用普通模型", OutputType.WARNING
|
340
374
|
)
|
341
|
-
|
375
|
+
maybe_model = PlatformRegistry().get_normal_platform()
|
376
|
+
|
377
|
+
# 在此处收敛为非可选类型,确保后续赋值满足类型检查
|
378
|
+
self.model = maybe_model
|
342
379
|
|
343
380
|
if model_name:
|
344
381
|
self.model.set_model_name(model_name)
|
@@ -546,7 +583,7 @@ class Agent:
|
|
546
583
|
# 广播添加附加提示前事件(不影响主流程)
|
547
584
|
try:
|
548
585
|
self.event_bus.emit(
|
549
|
-
|
586
|
+
BEFORE_ADDON_PROMPT,
|
550
587
|
agent=self,
|
551
588
|
need_complete=need_complete,
|
552
589
|
current_message=message,
|
@@ -558,16 +595,16 @@ class Agent:
|
|
558
595
|
addon_text = ""
|
559
596
|
if self.session.addon_prompt:
|
560
597
|
addon_text = self.session.addon_prompt
|
561
|
-
message
|
598
|
+
message = join_prompts([message, addon_text])
|
562
599
|
self.session.addon_prompt = ""
|
563
600
|
else:
|
564
601
|
addon_text = self.make_default_addon_prompt(need_complete)
|
565
|
-
message
|
602
|
+
message = join_prompts([message, addon_text])
|
566
603
|
|
567
604
|
# 广播添加附加提示后事件(不影响主流程)
|
568
605
|
try:
|
569
606
|
self.event_bus.emit(
|
570
|
-
|
607
|
+
AFTER_ADDON_PROMPT,
|
571
608
|
agent=self,
|
572
609
|
need_complete=need_complete,
|
573
610
|
addon_text=addon_text,
|
@@ -584,7 +621,7 @@ class Agent:
|
|
584
621
|
if self.session.conversation_length > self.max_token_count:
|
585
622
|
summary = self._summarize_and_clear_history()
|
586
623
|
if summary:
|
587
|
-
message = summary
|
624
|
+
message = join_prompts([summary, message])
|
588
625
|
self.session.conversation_length = get_context_token_count(message)
|
589
626
|
|
590
627
|
return message
|
@@ -597,7 +634,7 @@ class Agent:
|
|
597
634
|
# 事件:模型调用前
|
598
635
|
try:
|
599
636
|
self.event_bus.emit(
|
600
|
-
|
637
|
+
BEFORE_MODEL_CALL,
|
601
638
|
agent=self,
|
602
639
|
message=message,
|
603
640
|
)
|
@@ -609,7 +646,7 @@ class Agent:
|
|
609
646
|
# 事件:模型调用后
|
610
647
|
try:
|
611
648
|
self.event_bus.emit(
|
612
|
-
|
649
|
+
AFTER_MODEL_CALL,
|
613
650
|
agent=self,
|
614
651
|
message=message,
|
615
652
|
response=response,
|
@@ -639,7 +676,7 @@ class Agent:
|
|
639
676
|
) # type: ignore
|
640
677
|
|
641
678
|
return summary
|
642
|
-
except Exception
|
679
|
+
except Exception:
|
643
680
|
PrettyOutput.print("总结对话历史失败", OutputType.ERROR)
|
644
681
|
return ""
|
645
682
|
|
@@ -688,7 +725,7 @@ class Agent:
|
|
688
725
|
if self.model:
|
689
726
|
# 广播清理历史前事件
|
690
727
|
try:
|
691
|
-
self.event_bus.emit(
|
728
|
+
self.event_bus.emit(BEFORE_HISTORY_CLEAR, agent=self)
|
692
729
|
except Exception:
|
693
730
|
pass
|
694
731
|
self.model.reset()
|
@@ -698,7 +735,7 @@ class Agent:
|
|
698
735
|
self.session.clear_history()
|
699
736
|
# 广播清理历史后的事件
|
700
737
|
try:
|
701
|
-
self.event_bus.emit(
|
738
|
+
self.event_bus.emit(AFTER_HISTORY_CLEAR, agent=self)
|
702
739
|
except Exception:
|
703
740
|
pass
|
704
741
|
|
@@ -708,13 +745,13 @@ class Agent:
|
|
708
745
|
"""使用文件上传方式处理历史"""
|
709
746
|
# 广播清理历史前事件
|
710
747
|
try:
|
711
|
-
self.event_bus.emit(
|
748
|
+
self.event_bus.emit(BEFORE_HISTORY_CLEAR, agent=self)
|
712
749
|
except Exception:
|
713
750
|
pass
|
714
751
|
result = self.file_methodology_manager.handle_history_with_file_upload()
|
715
752
|
# 广播清理历史后的事件
|
716
753
|
try:
|
717
|
-
self.event_bus.emit(
|
754
|
+
self.event_bus.emit(AFTER_HISTORY_CLEAR, agent=self)
|
718
755
|
except Exception:
|
719
756
|
pass
|
720
757
|
return result
|
@@ -762,7 +799,7 @@ class Agent:
|
|
762
799
|
# 广播将要生成总结事件
|
763
800
|
try:
|
764
801
|
self.event_bus.emit(
|
765
|
-
|
802
|
+
BEFORE_SUMMARY,
|
766
803
|
agent=self,
|
767
804
|
prompt=self.session.prompt,
|
768
805
|
auto_completed=auto_completed,
|
@@ -779,7 +816,7 @@ class Agent:
|
|
779
816
|
# 广播完成总结事件
|
780
817
|
try:
|
781
818
|
self.event_bus.emit(
|
782
|
-
|
819
|
+
AFTER_SUMMARY,
|
783
820
|
agent=self,
|
784
821
|
summary=result,
|
785
822
|
)
|
@@ -789,7 +826,7 @@ class Agent:
|
|
789
826
|
# 广播任务完成事件(不影响主流程)
|
790
827
|
try:
|
791
828
|
self.event_bus.emit(
|
792
|
-
|
829
|
+
TASK_COMPLETED,
|
793
830
|
agent=self,
|
794
831
|
auto_completed=auto_completed,
|
795
832
|
need_summary=self.need_summary,
|
@@ -833,6 +870,7 @@ class Agent:
|
|
833
870
|
{complete_prompt}
|
834
871
|
如果没有完成,请进行下一步操作:
|
835
872
|
- 仅包含一个操作
|
873
|
+
- 不要询问用户是否继续,直接继续执行直至完成
|
836
874
|
- 如果信息不明确,请请求用户补充
|
837
875
|
- 如果执行过程中连续失败5次,请使用ask_user询问用户操作
|
838
876
|
- 操作列表:{action_handlers}{memory_prompts}
|
@@ -864,7 +902,7 @@ class Agent:
|
|
864
902
|
# 广播任务开始事件(不影响主流程)
|
865
903
|
try:
|
866
904
|
self.event_bus.emit(
|
867
|
-
|
905
|
+
TASK_STARTED,
|
868
906
|
agent=self,
|
869
907
|
name=self.name,
|
870
908
|
description=self.description,
|
@@ -901,7 +939,7 @@ class Agent:
|
|
901
939
|
# 广播中断事件(包含用户输入,可能为空字符串)
|
902
940
|
try:
|
903
941
|
self.event_bus.emit(
|
904
|
-
|
942
|
+
INTERRUPT_TRIGGERED,
|
905
943
|
agent=self,
|
906
944
|
current_response=current_response,
|
907
945
|
user_input=user_input,
|
@@ -917,10 +955,16 @@ class Agent:
|
|
917
955
|
|
918
956
|
if any(handler.can_handle(current_response) for handler in self.output_handler):
|
919
957
|
if self.user_confirm("检测到有工具调用,是否继续处理工具调用?", True):
|
920
|
-
self.session.prompt =
|
958
|
+
self.session.prompt = join_prompts([
|
959
|
+
f"被用户中断,用户补充信息为:{user_input}",
|
960
|
+
"用户同意继续工具调用。"
|
961
|
+
])
|
921
962
|
return None # 继续执行工具调用
|
922
963
|
else:
|
923
|
-
self.session.prompt =
|
964
|
+
self.session.prompt = join_prompts([
|
965
|
+
f"被用户中断,用户补充信息为:{user_input}",
|
966
|
+
"检测到有工具调用,但被用户拒绝执行。请根据用户的补充信息重新考虑下一步操作。"
|
967
|
+
])
|
924
968
|
return LoopAction.SKIP_TURN # 请求主循环 continue
|
925
969
|
else:
|
926
970
|
self.session.prompt = f"被用户中断,用户补充信息为:{user_input}"
|
@@ -1011,7 +1055,7 @@ class Agent:
|
|
1011
1055
|
# 广播工具筛选开始事件
|
1012
1056
|
try:
|
1013
1057
|
self.event_bus.emit(
|
1014
|
-
|
1058
|
+
BEFORE_TOOL_FILTER,
|
1015
1059
|
agent=self,
|
1016
1060
|
task=task,
|
1017
1061
|
total_tools=len(all_tools),
|
@@ -1050,7 +1094,7 @@ class Agent:
|
|
1050
1094
|
# 广播工具筛选事件
|
1051
1095
|
try:
|
1052
1096
|
self.event_bus.emit(
|
1053
|
-
|
1097
|
+
TOOL_FILTERED,
|
1054
1098
|
agent=self,
|
1055
1099
|
task=task,
|
1056
1100
|
selected_tools=selected_tool_names,
|
@@ -1066,7 +1110,7 @@ class Agent:
|
|
1066
1110
|
# 广播工具筛选事件(无筛选结果)
|
1067
1111
|
try:
|
1068
1112
|
self.event_bus.emit(
|
1069
|
-
|
1113
|
+
TOOL_FILTERED,
|
1070
1114
|
agent=self,
|
1071
1115
|
task=task,
|
1072
1116
|
selected_tools=[],
|
@@ -25,10 +25,14 @@ class AgentManager:
|
|
25
25
|
model_group: Optional[str] = None,
|
26
26
|
tool_group: Optional[str] = None,
|
27
27
|
restore_session: bool = False,
|
28
|
+
use_methodology: Optional[bool] = None,
|
29
|
+
use_analysis: Optional[bool] = None,
|
28
30
|
):
|
29
31
|
self.model_group = model_group
|
30
32
|
self.tool_group = tool_group
|
31
33
|
self.restore_session = restore_session
|
34
|
+
self.use_methodology = use_methodology
|
35
|
+
self.use_analysis = use_analysis
|
32
36
|
self.agent: Optional[Agent] = None
|
33
37
|
|
34
38
|
def initialize(self) -> Agent:
|
@@ -45,6 +49,8 @@ class AgentManager:
|
|
45
49
|
input_handler=[shell_input_handler, builtin_input_handler],
|
46
50
|
output_handler=[ToolRegistry()], # type: ignore
|
47
51
|
need_summary=False,
|
52
|
+
use_methodology=self.use_methodology,
|
53
|
+
use_analysis=self.use_analysis,
|
48
54
|
)
|
49
55
|
|
50
56
|
# 尝试恢复会话
|
@@ -51,7 +51,7 @@ class ConfigEditor:
|
|
51
51
|
raise typer.Exit(code=1)
|
52
52
|
else:
|
53
53
|
PrettyOutput.print(
|
54
|
-
|
54
|
+
"No suitable editor found. Please install one of: vim, nano, emacs, code",
|
55
55
|
OutputType.ERROR,
|
56
56
|
)
|
57
57
|
raise typer.Exit(code=1)
|
jarvis/jarvis_agent/event_bus.py
CHANGED
@@ -8,7 +8,7 @@
|
|
8
8
|
- 不引入额外依赖,便于在 Agent 中渐进集成
|
9
9
|
"""
|
10
10
|
from collections import defaultdict
|
11
|
-
from typing import Callable, DefaultDict, Dict, List
|
11
|
+
from typing import Callable, DefaultDict, Dict, List, Any
|
12
12
|
|
13
13
|
|
14
14
|
|
@@ -36,7 +36,7 @@ class EventBus:
|
|
36
36
|
except ValueError:
|
37
37
|
pass
|
38
38
|
|
39
|
-
def emit(self, event: str, **payload:
|
39
|
+
def emit(self, event: str, **payload: Any) -> None:
|
40
40
|
"""
|
41
41
|
广播事件。回调中的异常将被捕获并忽略,以保证主流程稳定。
|
42
42
|
"""
|
@@ -0,0 +1,157 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
"""
|
3
|
+
事件主题与负载类型定义(jarvis_agent.events)
|
4
|
+
|
5
|
+
目的:
|
6
|
+
- 统一事件名称,避免在代码各处硬编码字符串导致的漂移
|
7
|
+
- 提供事件负载的类型提示,便于静态检查与后续文档化
|
8
|
+
- 本文件仅提供常量与类型定义,不改变现有行为
|
9
|
+
"""
|
10
|
+
from typing import Any, TypedDict, List
|
11
|
+
|
12
|
+
# 事件主题常量
|
13
|
+
BEFORE_TOOL_CALL = "before_tool_call"
|
14
|
+
AFTER_TOOL_CALL = "after_tool_call"
|
15
|
+
|
16
|
+
# 会话与任务生命周期相关
|
17
|
+
TASK_STARTED = "task_started"
|
18
|
+
TASK_COMPLETED = "task_completed"
|
19
|
+
|
20
|
+
# 总结阶段
|
21
|
+
BEFORE_SUMMARY = "before_summary"
|
22
|
+
AFTER_SUMMARY = "after_summary"
|
23
|
+
|
24
|
+
# 附加提示
|
25
|
+
BEFORE_ADDON_PROMPT = "before_addon_prompt"
|
26
|
+
AFTER_ADDON_PROMPT = "after_addon_prompt"
|
27
|
+
|
28
|
+
# 历史清理
|
29
|
+
BEFORE_HISTORY_CLEAR = "before_history_clear"
|
30
|
+
AFTER_HISTORY_CLEAR = "after_history_clear"
|
31
|
+
|
32
|
+
# 模型调用
|
33
|
+
BEFORE_MODEL_CALL = "before_model_call"
|
34
|
+
AFTER_MODEL_CALL = "after_model_call"
|
35
|
+
|
36
|
+
# 其他
|
37
|
+
INTERRUPT_TRIGGERED = "interrupt_triggered"
|
38
|
+
BEFORE_TOOL_FILTER = "before_tool_filter"
|
39
|
+
TOOL_FILTERED = "tool_filtered"
|
40
|
+
|
41
|
+
|
42
|
+
# 事件负载类型(仅用于类型提示)
|
43
|
+
class BeforeToolCallEvent(TypedDict, total=False):
|
44
|
+
agent: Any
|
45
|
+
current_response: str
|
46
|
+
|
47
|
+
class AfterToolCallEvent(TypedDict, total=False):
|
48
|
+
agent: Any
|
49
|
+
current_response: str
|
50
|
+
need_return: bool
|
51
|
+
tool_prompt: str
|
52
|
+
|
53
|
+
# 任务生命周期
|
54
|
+
class TaskStartedEvent(TypedDict, total=False):
|
55
|
+
agent: Any
|
56
|
+
name: str
|
57
|
+
description: str
|
58
|
+
user_input: str
|
59
|
+
|
60
|
+
class TaskCompletedEvent(TypedDict, total=False):
|
61
|
+
agent: Any
|
62
|
+
auto_completed: bool
|
63
|
+
need_summary: bool
|
64
|
+
|
65
|
+
# 总结阶段
|
66
|
+
class BeforeSummaryEvent(TypedDict, total=False):
|
67
|
+
agent: Any
|
68
|
+
prompt: str
|
69
|
+
auto_completed: bool
|
70
|
+
need_summary: bool
|
71
|
+
|
72
|
+
class AfterSummaryEvent(TypedDict, total=False):
|
73
|
+
agent: Any
|
74
|
+
summary: str
|
75
|
+
|
76
|
+
# 附加提示
|
77
|
+
class BeforeAddonPromptEvent(TypedDict, total=False):
|
78
|
+
agent: Any
|
79
|
+
need_complete: bool
|
80
|
+
current_message: str
|
81
|
+
has_session_addon: bool
|
82
|
+
|
83
|
+
class AfterAddonPromptEvent(TypedDict, total=False):
|
84
|
+
agent: Any
|
85
|
+
need_complete: bool
|
86
|
+
addon_text: str
|
87
|
+
final_message: str
|
88
|
+
|
89
|
+
# 历史清理
|
90
|
+
class BeforeHistoryClearEvent(TypedDict, total=False):
|
91
|
+
agent: Any
|
92
|
+
|
93
|
+
class AfterHistoryClearEvent(TypedDict, total=False):
|
94
|
+
agent: Any
|
95
|
+
|
96
|
+
# 模型调用
|
97
|
+
class BeforeModelCallEvent(TypedDict, total=False):
|
98
|
+
agent: Any
|
99
|
+
message: str
|
100
|
+
|
101
|
+
class AfterModelCallEvent(TypedDict, total=False):
|
102
|
+
agent: Any
|
103
|
+
message: str
|
104
|
+
response: str
|
105
|
+
|
106
|
+
# 中断
|
107
|
+
class InterruptTriggeredEvent(TypedDict, total=False):
|
108
|
+
agent: Any
|
109
|
+
current_response: str
|
110
|
+
user_input: str
|
111
|
+
|
112
|
+
# 工具筛选
|
113
|
+
class BeforeToolFilterEvent(TypedDict, total=False):
|
114
|
+
agent: Any
|
115
|
+
task: str
|
116
|
+
total_tools: int
|
117
|
+
threshold: int
|
118
|
+
|
119
|
+
class ToolFilteredEvent(TypedDict, total=False):
|
120
|
+
agent: Any
|
121
|
+
task: str
|
122
|
+
selected_tools: List[str]
|
123
|
+
total_tools: int
|
124
|
+
threshold: int
|
125
|
+
|
126
|
+
__all__ = [
|
127
|
+
"BEFORE_TOOL_CALL",
|
128
|
+
"AFTER_TOOL_CALL",
|
129
|
+
"TASK_STARTED",
|
130
|
+
"TASK_COMPLETED",
|
131
|
+
"BEFORE_SUMMARY",
|
132
|
+
"AFTER_SUMMARY",
|
133
|
+
"BEFORE_ADDON_PROMPT",
|
134
|
+
"AFTER_ADDON_PROMPT",
|
135
|
+
"BEFORE_HISTORY_CLEAR",
|
136
|
+
"AFTER_HISTORY_CLEAR",
|
137
|
+
"BEFORE_MODEL_CALL",
|
138
|
+
"AFTER_MODEL_CALL",
|
139
|
+
"INTERRUPT_TRIGGERED",
|
140
|
+
"BEFORE_TOOL_FILTER",
|
141
|
+
"TOOL_FILTERED",
|
142
|
+
"BeforeToolCallEvent",
|
143
|
+
"AfterToolCallEvent",
|
144
|
+
"TaskStartedEvent",
|
145
|
+
"TaskCompletedEvent",
|
146
|
+
"BeforeSummaryEvent",
|
147
|
+
"AfterSummaryEvent",
|
148
|
+
"BeforeAddonPromptEvent",
|
149
|
+
"AfterAddonPromptEvent",
|
150
|
+
"BeforeHistoryClearEvent",
|
151
|
+
"AfterHistoryClearEvent",
|
152
|
+
"BeforeModelCallEvent",
|
153
|
+
"AfterModelCallEvent",
|
154
|
+
"InterruptTriggeredEvent",
|
155
|
+
"BeforeToolFilterEvent",
|
156
|
+
"ToolFilteredEvent",
|
157
|
+
]
|
@@ -5,10 +5,10 @@
|
|
5
5
|
"""
|
6
6
|
import os
|
7
7
|
import tempfile
|
8
|
-
from typing import List, Optional
|
9
8
|
|
10
9
|
from jarvis.jarvis_utils.methodology import load_methodology, upload_methodology
|
11
10
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
11
|
+
from jarvis.jarvis_agent.utils import join_prompts
|
12
12
|
|
13
13
|
|
14
14
|
class FileMethodologyManager:
|
@@ -46,19 +46,27 @@ class FileMethodologyManager:
|
|
46
46
|
self._load_local_methodology()
|
47
47
|
else:
|
48
48
|
# 上传成功
|
49
|
-
from jarvis.jarvis_agent.memory_manager import MemoryManager
|
50
49
|
|
51
50
|
if self.agent.files:
|
52
|
-
self.agent.session.prompt =
|
51
|
+
self.agent.session.prompt = join_prompts([
|
52
|
+
self.agent.session.prompt,
|
53
|
+
"上传的文件包含历史对话信息和方法论文件,可以从中获取一些经验信息。"
|
54
|
+
])
|
53
55
|
else:
|
54
|
-
self.agent.session.prompt =
|
56
|
+
self.agent.session.prompt = join_prompts([
|
57
|
+
self.agent.session.prompt,
|
58
|
+
"上传的文件包含历史对话信息,可以从中获取一些经验信息。"
|
59
|
+
])
|
55
60
|
|
56
61
|
def _handle_files_upload(self):
|
57
62
|
"""处理普通文件上传"""
|
58
63
|
if not self.agent.model.upload_files(self.agent.files): # type: ignore
|
59
64
|
PrettyOutput.print("文件上传失败,将忽略文件列表", OutputType.WARNING)
|
60
65
|
else:
|
61
|
-
self.agent.session.prompt =
|
66
|
+
self.agent.session.prompt = join_prompts([
|
67
|
+
self.agent.session.prompt,
|
68
|
+
"上传的文件包含历史对话信息,可以从中获取一些经验信息。"
|
69
|
+
])
|
62
70
|
|
63
71
|
def _handle_local_mode(self):
|
64
72
|
"""处理本地模式(不支持文件上传)"""
|
@@ -75,14 +83,17 @@ class FileMethodologyManager:
|
|
75
83
|
|
76
84
|
from jarvis.jarvis_agent.memory_manager import MemoryManager
|
77
85
|
|
78
|
-
|
86
|
+
MemoryManager(self.agent)
|
79
87
|
methodology = load_methodology(
|
80
88
|
msg,
|
81
89
|
self.agent.get_tool_registry(),
|
82
90
|
platform_name=self.agent.model.platform_name(),
|
83
91
|
model_name=self.agent.model.name(),
|
84
92
|
)
|
85
|
-
self.agent.session.prompt =
|
93
|
+
self.agent.session.prompt = join_prompts([
|
94
|
+
self.agent.session.prompt,
|
95
|
+
f"以下是历史类似问题的执行经验,可参考:\n{methodology}"
|
96
|
+
])
|
86
97
|
|
87
98
|
def handle_history_with_file_upload(self) -> str:
|
88
99
|
"""使用文件上传方式处理历史"""
|
jarvis/jarvis_agent/jarvis.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
"""Jarvis AI 助手主入口模块"""
|
3
|
-
from typing import Optional
|
3
|
+
from typing import Optional, List
|
4
4
|
|
5
5
|
import typer
|
6
6
|
|
@@ -21,7 +21,6 @@ import jarvis.jarvis_utils.utils as jutils
|
|
21
21
|
from jarvis.jarvis_utils.input import user_confirm, get_single_line_input
|
22
22
|
from jarvis.jarvis_utils.fzf import fzf_select
|
23
23
|
import os
|
24
|
-
import sys
|
25
24
|
import subprocess
|
26
25
|
from pathlib import Path
|
27
26
|
import yaml # type: ignore
|
@@ -392,7 +391,7 @@ def handle_builtin_config_selector(
|
|
392
391
|
if category == "roles":
|
393
392
|
count = opt.get("roles_count")
|
394
393
|
details_val = opt.get("details", "")
|
395
|
-
parts:
|
394
|
+
parts: List[str] = []
|
396
395
|
if isinstance(count, int) and count > 0:
|
397
396
|
parts.append(f"{count} 个角色")
|
398
397
|
if isinstance(details_val, str) and details_val:
|
@@ -443,7 +442,7 @@ def handle_builtin_config_selector(
|
|
443
442
|
if choice_index != -1:
|
444
443
|
try:
|
445
444
|
sel = options[choice_index]
|
446
|
-
args:
|
445
|
+
args: List[str] = []
|
447
446
|
|
448
447
|
if sel["category"] == "agent":
|
449
448
|
# jarvis-agent 支持 -f/--config(全局配置)与 -c/--agent-definition
|
@@ -516,6 +515,12 @@ def run_cli(
|
|
516
515
|
"--interactive-config",
|
517
516
|
help="启动交互式配置向导(基于当前配置补充设置)",
|
518
517
|
),
|
518
|
+
disable_methodology_analysis: bool = typer.Option(
|
519
|
+
False,
|
520
|
+
"-D",
|
521
|
+
"--disable-methodology-analysis",
|
522
|
+
help="禁用方法论和任务分析(覆盖配置文件设置)",
|
523
|
+
),
|
519
524
|
) -> None:
|
520
525
|
"""Jarvis AI assistant command-line interface."""
|
521
526
|
if ctx.invoked_subcommand is not None:
|
@@ -562,6 +567,8 @@ def run_cli(
|
|
562
567
|
model_group=model_group,
|
563
568
|
tool_group=tool_group,
|
564
569
|
restore_session=restore_session,
|
570
|
+
use_methodology=False if disable_methodology_analysis else None,
|
571
|
+
use_analysis=False if disable_methodology_analysis else None,
|
565
572
|
)
|
566
573
|
agent_manager.initialize()
|
567
574
|
agent_manager.run_task(task)
|
@@ -3,10 +3,10 @@
|
|
3
3
|
记忆管理器模块
|
4
4
|
负责处理Agent的记忆保存和检索功能
|
5
5
|
"""
|
6
|
-
from typing import Optional, Dict, List, Any
|
7
6
|
|
8
7
|
from jarvis.jarvis_utils.globals import get_all_memory_tags
|
9
8
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
9
|
+
from jarvis.jarvis_agent.events import TASK_STARTED, BEFORE_HISTORY_CLEAR, TASK_COMPLETED
|
10
10
|
|
11
11
|
|
12
12
|
class MemoryManager:
|
@@ -160,11 +160,11 @@ class MemoryManager:
|
|
160
160
|
def _subscribe_events(self) -> None:
|
161
161
|
bus = self.agent.get_event_bus() # type: ignore[attr-defined]
|
162
162
|
# 任务开始时重置去重标记
|
163
|
-
bus.subscribe(
|
163
|
+
bus.subscribe(TASK_STARTED, self._on_task_started)
|
164
164
|
# 在清理历史前尝试保存记忆(若开启强制保存且尚未处理)
|
165
|
-
bus.subscribe(
|
165
|
+
bus.subscribe(BEFORE_HISTORY_CLEAR, self._ensure_memory_prompt)
|
166
166
|
# 任务完成时作为兜底再尝试一次
|
167
|
-
bus.subscribe(
|
167
|
+
bus.subscribe(TASK_COMPLETED, self._ensure_memory_prompt)
|
168
168
|
|
169
169
|
def _on_task_started(self, **payload) -> None:
|
170
170
|
self._memory_prompted = False
|
jarvis/jarvis_agent/prompts.py
CHANGED
@@ -81,7 +81,7 @@ TASK_ANALYSIS_PROMPT = f"""<task_analysis>
|
|
81
81
|
2. 方法论应该具备足够的通用性,可应用于同类问题
|
82
82
|
3. 特别注意用户在执行过程中提供的修正、反馈和改进建议
|
83
83
|
4. 如果用户明确指出了某个解决步骤的优化方向,这应该被纳入方法论
|
84
|
-
5.
|
84
|
+
5. 方法论应面向未来复用,总结“下次遇到同类问题应该如何处理”的通用流程与检查清单,避免局限于本次执行细节
|
85
85
|
</evaluation_criteria>
|
86
86
|
<tool_requirements>
|
87
87
|
工具代码要求:
|
@@ -157,7 +157,7 @@ TASK_ANALYSIS_PROMPT = f"""<task_analysis>
|
|
157
157
|
<methodology_requirements>
|
158
158
|
方法论格式要求:
|
159
159
|
1. 问题重述: 简明扼要的问题归纳,不含特定细节
|
160
|
-
2.
|
160
|
+
2. 可复用解决流程: 面向“下次遇到同类问题”的步骤化方案(列出每步可用的工具),避免与本次特定上下文绑定
|
161
161
|
3. 注意事项: 执行中可能遇到的常见问题和注意点,尤其是用户指出的问题
|
162
162
|
4. 可选步骤: 对于有多种解决路径的问题,标注出可选步骤和适用场景
|
163
163
|
</methodology_requirements>
|