jarvis-ai-assistant 0.7.8__py3-none-any.whl → 1.0.2__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 +567 -222
- jarvis/jarvis_agent/agent_manager.py +19 -12
- jarvis/jarvis_agent/builtin_input_handler.py +79 -11
- jarvis/jarvis_agent/config_editor.py +7 -2
- jarvis/jarvis_agent/event_bus.py +24 -13
- jarvis/jarvis_agent/events.py +19 -1
- jarvis/jarvis_agent/file_context_handler.py +67 -64
- jarvis/jarvis_agent/file_methodology_manager.py +38 -24
- jarvis/jarvis_agent/jarvis.py +186 -114
- jarvis/jarvis_agent/language_extractors/__init__.py +8 -1
- jarvis/jarvis_agent/language_extractors/c_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/cpp_extractor.py +9 -4
- jarvis/jarvis_agent/language_extractors/go_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/java_extractor.py +27 -20
- jarvis/jarvis_agent/language_extractors/javascript_extractor.py +22 -17
- jarvis/jarvis_agent/language_extractors/python_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/rust_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/typescript_extractor.py +22 -17
- jarvis/jarvis_agent/language_support_info.py +250 -219
- jarvis/jarvis_agent/main.py +19 -23
- jarvis/jarvis_agent/memory_manager.py +9 -6
- jarvis/jarvis_agent/methodology_share_manager.py +21 -15
- jarvis/jarvis_agent/output_handler.py +4 -2
- jarvis/jarvis_agent/prompt_builder.py +7 -6
- jarvis/jarvis_agent/prompt_manager.py +113 -8
- jarvis/jarvis_agent/prompts.py +317 -85
- jarvis/jarvis_agent/protocols.py +5 -2
- jarvis/jarvis_agent/run_loop.py +192 -32
- jarvis/jarvis_agent/session_manager.py +7 -3
- jarvis/jarvis_agent/share_manager.py +23 -13
- jarvis/jarvis_agent/shell_input_handler.py +12 -8
- jarvis/jarvis_agent/stdio_redirect.py +25 -26
- jarvis/jarvis_agent/task_analyzer.py +29 -23
- jarvis/jarvis_agent/task_list.py +869 -0
- jarvis/jarvis_agent/task_manager.py +26 -23
- jarvis/jarvis_agent/tool_executor.py +6 -5
- jarvis/jarvis_agent/tool_share_manager.py +24 -14
- jarvis/jarvis_agent/user_interaction.py +3 -3
- jarvis/jarvis_agent/utils.py +9 -1
- jarvis/jarvis_agent/web_bridge.py +37 -17
- jarvis/jarvis_agent/web_output_sink.py +5 -2
- jarvis/jarvis_agent/web_server.py +165 -36
- jarvis/jarvis_c2rust/__init__.py +1 -1
- jarvis/jarvis_c2rust/cli.py +260 -141
- jarvis/jarvis_c2rust/collector.py +37 -18
- jarvis/jarvis_c2rust/constants.py +60 -0
- jarvis/jarvis_c2rust/library_replacer.py +242 -1010
- jarvis/jarvis_c2rust/library_replacer_checkpoint.py +133 -0
- jarvis/jarvis_c2rust/library_replacer_llm.py +287 -0
- jarvis/jarvis_c2rust/library_replacer_loader.py +191 -0
- jarvis/jarvis_c2rust/library_replacer_output.py +134 -0
- jarvis/jarvis_c2rust/library_replacer_prompts.py +124 -0
- jarvis/jarvis_c2rust/library_replacer_utils.py +188 -0
- jarvis/jarvis_c2rust/llm_module_agent.py +98 -1044
- jarvis/jarvis_c2rust/llm_module_agent_apply.py +170 -0
- jarvis/jarvis_c2rust/llm_module_agent_executor.py +288 -0
- jarvis/jarvis_c2rust/llm_module_agent_loader.py +170 -0
- jarvis/jarvis_c2rust/llm_module_agent_prompts.py +268 -0
- jarvis/jarvis_c2rust/llm_module_agent_types.py +57 -0
- jarvis/jarvis_c2rust/llm_module_agent_utils.py +150 -0
- jarvis/jarvis_c2rust/llm_module_agent_validator.py +119 -0
- jarvis/jarvis_c2rust/loaders.py +28 -10
- jarvis/jarvis_c2rust/models.py +5 -2
- jarvis/jarvis_c2rust/optimizer.py +192 -1974
- jarvis/jarvis_c2rust/optimizer_build_fix.py +286 -0
- jarvis/jarvis_c2rust/optimizer_clippy.py +766 -0
- jarvis/jarvis_c2rust/optimizer_config.py +49 -0
- jarvis/jarvis_c2rust/optimizer_docs.py +183 -0
- jarvis/jarvis_c2rust/optimizer_options.py +48 -0
- jarvis/jarvis_c2rust/optimizer_progress.py +469 -0
- jarvis/jarvis_c2rust/optimizer_report.py +52 -0
- jarvis/jarvis_c2rust/optimizer_unsafe.py +309 -0
- jarvis/jarvis_c2rust/optimizer_utils.py +469 -0
- jarvis/jarvis_c2rust/optimizer_visibility.py +185 -0
- jarvis/jarvis_c2rust/scanner.py +229 -166
- jarvis/jarvis_c2rust/transpiler.py +531 -2732
- jarvis/jarvis_c2rust/transpiler_agents.py +503 -0
- jarvis/jarvis_c2rust/transpiler_build.py +1294 -0
- jarvis/jarvis_c2rust/transpiler_codegen.py +204 -0
- jarvis/jarvis_c2rust/transpiler_compile.py +146 -0
- jarvis/jarvis_c2rust/transpiler_config.py +178 -0
- jarvis/jarvis_c2rust/transpiler_context.py +122 -0
- jarvis/jarvis_c2rust/transpiler_executor.py +516 -0
- jarvis/jarvis_c2rust/transpiler_generation.py +278 -0
- jarvis/jarvis_c2rust/transpiler_git.py +163 -0
- jarvis/jarvis_c2rust/transpiler_mod_utils.py +225 -0
- jarvis/jarvis_c2rust/transpiler_modules.py +336 -0
- jarvis/jarvis_c2rust/transpiler_planning.py +394 -0
- jarvis/jarvis_c2rust/transpiler_review.py +1196 -0
- jarvis/jarvis_c2rust/transpiler_symbols.py +176 -0
- jarvis/jarvis_c2rust/utils.py +269 -79
- jarvis/jarvis_code_agent/after_change.py +233 -0
- jarvis/jarvis_code_agent/build_validation_config.py +37 -30
- jarvis/jarvis_code_agent/builtin_rules.py +68 -0
- jarvis/jarvis_code_agent/code_agent.py +976 -1517
- jarvis/jarvis_code_agent/code_agent_build.py +227 -0
- jarvis/jarvis_code_agent/code_agent_diff.py +246 -0
- jarvis/jarvis_code_agent/code_agent_git.py +525 -0
- jarvis/jarvis_code_agent/code_agent_impact.py +177 -0
- jarvis/jarvis_code_agent/code_agent_lint.py +283 -0
- jarvis/jarvis_code_agent/code_agent_llm.py +159 -0
- jarvis/jarvis_code_agent/code_agent_postprocess.py +105 -0
- jarvis/jarvis_code_agent/code_agent_prompts.py +46 -0
- jarvis/jarvis_code_agent/code_agent_rules.py +305 -0
- jarvis/jarvis_code_agent/code_analyzer/__init__.py +52 -48
- jarvis/jarvis_code_agent/code_analyzer/base_language.py +12 -10
- jarvis/jarvis_code_agent/code_analyzer/build_validator/__init__.py +12 -11
- jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +16 -12
- jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +26 -17
- jarvis/jarvis_code_agent/code_analyzer/build_validator/detector.py +558 -104
- jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +27 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +22 -18
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +21 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +20 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +27 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +47 -23
- jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +71 -37
- jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +162 -35
- jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +111 -57
- jarvis/jarvis_code_agent/code_analyzer/build_validator.py +18 -12
- jarvis/jarvis_code_agent/code_analyzer/context_manager.py +185 -183
- jarvis/jarvis_code_agent/code_analyzer/context_recommender.py +2 -1
- jarvis/jarvis_code_agent/code_analyzer/dependency_analyzer.py +24 -15
- jarvis/jarvis_code_agent/code_analyzer/file_ignore.py +227 -141
- jarvis/jarvis_code_agent/code_analyzer/impact_analyzer.py +321 -247
- jarvis/jarvis_code_agent/code_analyzer/language_registry.py +37 -29
- jarvis/jarvis_code_agent/code_analyzer/language_support.py +21 -13
- jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +15 -9
- jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +75 -45
- jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +87 -52
- jarvis/jarvis_code_agent/code_analyzer/languages/java_language.py +84 -51
- jarvis/jarvis_code_agent/code_analyzer/languages/javascript_language.py +94 -64
- jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +109 -71
- jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +97 -63
- jarvis/jarvis_code_agent/code_analyzer/languages/typescript_language.py +103 -69
- jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +271 -268
- jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +76 -64
- jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +92 -19
- jarvis/jarvis_code_agent/diff_visualizer.py +998 -0
- jarvis/jarvis_code_agent/lint.py +223 -524
- jarvis/jarvis_code_agent/rule_share_manager.py +158 -0
- jarvis/jarvis_code_agent/rules/clean_code.md +144 -0
- jarvis/jarvis_code_agent/rules/code_review.md +115 -0
- jarvis/jarvis_code_agent/rules/documentation.md +165 -0
- jarvis/jarvis_code_agent/rules/generate_rules.md +52 -0
- jarvis/jarvis_code_agent/rules/performance.md +158 -0
- jarvis/jarvis_code_agent/rules/refactoring.md +139 -0
- jarvis/jarvis_code_agent/rules/security.md +160 -0
- jarvis/jarvis_code_agent/rules/tdd.md +78 -0
- jarvis/jarvis_code_agent/test_rules/cpp_test.md +118 -0
- jarvis/jarvis_code_agent/test_rules/go_test.md +98 -0
- jarvis/jarvis_code_agent/test_rules/java_test.md +99 -0
- jarvis/jarvis_code_agent/test_rules/javascript_test.md +113 -0
- jarvis/jarvis_code_agent/test_rules/php_test.md +117 -0
- jarvis/jarvis_code_agent/test_rules/python_test.md +91 -0
- jarvis/jarvis_code_agent/test_rules/ruby_test.md +102 -0
- jarvis/jarvis_code_agent/test_rules/rust_test.md +86 -0
- jarvis/jarvis_code_agent/utils.py +36 -26
- jarvis/jarvis_code_analysis/checklists/loader.py +21 -21
- jarvis/jarvis_code_analysis/code_review.py +64 -33
- jarvis/jarvis_data/config_schema.json +285 -192
- jarvis/jarvis_git_squash/main.py +8 -6
- jarvis/jarvis_git_utils/git_commiter.py +53 -76
- jarvis/jarvis_mcp/__init__.py +5 -2
- jarvis/jarvis_mcp/sse_mcp_client.py +40 -30
- jarvis/jarvis_mcp/stdio_mcp_client.py +27 -19
- jarvis/jarvis_mcp/streamable_mcp_client.py +35 -26
- jarvis/jarvis_memory_organizer/memory_organizer.py +78 -55
- jarvis/jarvis_methodology/main.py +48 -39
- jarvis/jarvis_multi_agent/__init__.py +56 -23
- jarvis/jarvis_multi_agent/main.py +15 -18
- jarvis/jarvis_platform/base.py +179 -111
- jarvis/jarvis_platform/human.py +27 -16
- jarvis/jarvis_platform/kimi.py +52 -45
- jarvis/jarvis_platform/openai.py +101 -40
- jarvis/jarvis_platform/registry.py +51 -33
- jarvis/jarvis_platform/tongyi.py +68 -38
- jarvis/jarvis_platform/yuanbao.py +59 -43
- jarvis/jarvis_platform_manager/main.py +68 -76
- jarvis/jarvis_platform_manager/service.py +24 -14
- jarvis/jarvis_rag/README_CONFIG.md +314 -0
- jarvis/jarvis_rag/README_DYNAMIC_LOADING.md +311 -0
- jarvis/jarvis_rag/README_ONLINE_MODELS.md +230 -0
- jarvis/jarvis_rag/__init__.py +57 -4
- jarvis/jarvis_rag/cache.py +3 -1
- jarvis/jarvis_rag/cli.py +48 -68
- jarvis/jarvis_rag/embedding_interface.py +39 -0
- jarvis/jarvis_rag/embedding_manager.py +7 -230
- jarvis/jarvis_rag/embeddings/__init__.py +41 -0
- jarvis/jarvis_rag/embeddings/base.py +114 -0
- jarvis/jarvis_rag/embeddings/cohere.py +66 -0
- jarvis/jarvis_rag/embeddings/edgefn.py +117 -0
- jarvis/jarvis_rag/embeddings/local.py +260 -0
- jarvis/jarvis_rag/embeddings/openai.py +62 -0
- jarvis/jarvis_rag/embeddings/registry.py +293 -0
- jarvis/jarvis_rag/llm_interface.py +8 -6
- jarvis/jarvis_rag/query_rewriter.py +8 -9
- jarvis/jarvis_rag/rag_pipeline.py +61 -52
- jarvis/jarvis_rag/reranker.py +7 -75
- jarvis/jarvis_rag/reranker_interface.py +32 -0
- jarvis/jarvis_rag/rerankers/__init__.py +41 -0
- jarvis/jarvis_rag/rerankers/base.py +109 -0
- jarvis/jarvis_rag/rerankers/cohere.py +67 -0
- jarvis/jarvis_rag/rerankers/edgefn.py +140 -0
- jarvis/jarvis_rag/rerankers/jina.py +79 -0
- jarvis/jarvis_rag/rerankers/local.py +89 -0
- jarvis/jarvis_rag/rerankers/registry.py +293 -0
- jarvis/jarvis_rag/retriever.py +58 -43
- jarvis/jarvis_sec/__init__.py +66 -141
- jarvis/jarvis_sec/agents.py +21 -17
- jarvis/jarvis_sec/analysis.py +80 -33
- jarvis/jarvis_sec/checkers/__init__.py +7 -13
- jarvis/jarvis_sec/checkers/c_checker.py +356 -164
- jarvis/jarvis_sec/checkers/rust_checker.py +47 -29
- jarvis/jarvis_sec/cli.py +43 -21
- jarvis/jarvis_sec/clustering.py +430 -272
- jarvis/jarvis_sec/file_manager.py +99 -55
- jarvis/jarvis_sec/parsers.py +9 -6
- jarvis/jarvis_sec/prompts.py +4 -3
- jarvis/jarvis_sec/report.py +44 -22
- jarvis/jarvis_sec/review.py +180 -107
- jarvis/jarvis_sec/status.py +50 -41
- jarvis/jarvis_sec/types.py +3 -0
- jarvis/jarvis_sec/utils.py +160 -83
- jarvis/jarvis_sec/verification.py +411 -181
- jarvis/jarvis_sec/workflow.py +132 -21
- jarvis/jarvis_smart_shell/main.py +28 -41
- jarvis/jarvis_stats/cli.py +14 -12
- jarvis/jarvis_stats/stats.py +28 -19
- jarvis/jarvis_stats/storage.py +14 -8
- jarvis/jarvis_stats/visualizer.py +12 -7
- jarvis/jarvis_tools/base.py +5 -2
- jarvis/jarvis_tools/clear_memory.py +13 -9
- jarvis/jarvis_tools/cli/main.py +23 -18
- jarvis/jarvis_tools/edit_file.py +572 -873
- jarvis/jarvis_tools/execute_script.py +10 -7
- jarvis/jarvis_tools/file_analyzer.py +7 -8
- jarvis/jarvis_tools/meta_agent.py +287 -0
- jarvis/jarvis_tools/methodology.py +5 -3
- jarvis/jarvis_tools/read_code.py +305 -1438
- jarvis/jarvis_tools/read_symbols.py +50 -17
- jarvis/jarvis_tools/read_webpage.py +19 -18
- jarvis/jarvis_tools/registry.py +435 -156
- jarvis/jarvis_tools/retrieve_memory.py +16 -11
- jarvis/jarvis_tools/save_memory.py +8 -6
- jarvis/jarvis_tools/search_web.py +31 -31
- jarvis/jarvis_tools/sub_agent.py +32 -28
- jarvis/jarvis_tools/sub_code_agent.py +44 -60
- jarvis/jarvis_tools/task_list_manager.py +1811 -0
- jarvis/jarvis_tools/virtual_tty.py +29 -19
- jarvis/jarvis_utils/__init__.py +4 -0
- jarvis/jarvis_utils/builtin_replace_map.py +2 -1
- jarvis/jarvis_utils/clipboard.py +9 -8
- jarvis/jarvis_utils/collections.py +331 -0
- jarvis/jarvis_utils/config.py +699 -194
- jarvis/jarvis_utils/dialogue_recorder.py +294 -0
- jarvis/jarvis_utils/embedding.py +6 -3
- jarvis/jarvis_utils/file_processors.py +7 -1
- jarvis/jarvis_utils/fzf.py +9 -3
- jarvis/jarvis_utils/git_utils.py +71 -42
- jarvis/jarvis_utils/globals.py +116 -32
- jarvis/jarvis_utils/http.py +6 -2
- jarvis/jarvis_utils/input.py +318 -83
- jarvis/jarvis_utils/jsonnet_compat.py +119 -104
- jarvis/jarvis_utils/methodology.py +37 -28
- jarvis/jarvis_utils/output.py +201 -44
- jarvis/jarvis_utils/utils.py +986 -628
- {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/METADATA +49 -33
- jarvis_ai_assistant-1.0.2.dist-info/RECORD +304 -0
- jarvis/jarvis_code_agent/code_analyzer/structured_code.py +0 -556
- jarvis/jarvis_tools/generate_new_tool.py +0 -205
- jarvis/jarvis_tools/lsp_client.py +0 -1552
- jarvis/jarvis_tools/rewrite_file.py +0 -105
- jarvis_ai_assistant-0.7.8.dist-info/RECORD +0 -218
- {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/top_level.txt +0 -0
jarvis/jarvis_platform/base.py
CHANGED
|
@@ -1,40 +1,52 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
1
3
|
# -*- coding: utf-8 -*-
|
|
2
4
|
import re
|
|
3
|
-
import
|
|
5
|
+
from abc import ABC
|
|
6
|
+
from abc import abstractmethod
|
|
4
7
|
from datetime import datetime
|
|
5
|
-
from abc import ABC, abstractmethod
|
|
6
8
|
from types import TracebackType
|
|
7
|
-
from typing import
|
|
8
|
-
|
|
9
|
+
from typing import Any
|
|
10
|
+
from typing import Dict
|
|
11
|
+
from typing import Generator
|
|
12
|
+
from typing import List
|
|
13
|
+
from typing import Optional
|
|
14
|
+
from typing import Tuple
|
|
15
|
+
from typing import Type
|
|
16
|
+
|
|
17
|
+
from rich import box
|
|
18
|
+
from rich.live import Live
|
|
19
|
+
from rich.panel import Panel
|
|
20
|
+
from rich.status import Status
|
|
21
|
+
from rich.text import Text
|
|
9
22
|
from typing_extensions import Self
|
|
10
23
|
|
|
11
|
-
from rich import box # type: ignore
|
|
12
|
-
from rich.live import Live # type: ignore
|
|
13
|
-
from rich.panel import Panel # type: ignore
|
|
14
|
-
from rich.status import Status # type: ignore
|
|
15
|
-
from rich.text import Text # type: ignore
|
|
16
|
-
|
|
17
|
-
from jarvis.jarvis_utils.config import (
|
|
18
|
-
get_pretty_output,
|
|
19
|
-
is_print_prompt,
|
|
20
|
-
is_immediate_abort,
|
|
21
|
-
is_save_session_history,
|
|
22
|
-
get_data_dir,
|
|
23
|
-
get_max_input_token_count,
|
|
24
|
-
get_conversation_turn_threshold,
|
|
25
|
-
)
|
|
26
|
-
from jarvis.jarvis_utils.globals import set_in_chat, get_interrupt, console
|
|
27
24
|
import jarvis.jarvis_utils.globals as G
|
|
28
|
-
from jarvis.jarvis_utils.
|
|
29
|
-
from jarvis.jarvis_utils.
|
|
30
|
-
from jarvis.jarvis_utils.
|
|
25
|
+
from jarvis.jarvis_utils.config import get_cheap_max_input_token_count
|
|
26
|
+
from jarvis.jarvis_utils.config import get_conversation_turn_threshold
|
|
27
|
+
from jarvis.jarvis_utils.config import get_data_dir
|
|
28
|
+
from jarvis.jarvis_utils.config import get_max_input_token_count
|
|
29
|
+
from jarvis.jarvis_utils.config import get_pretty_output
|
|
30
|
+
from jarvis.jarvis_utils.config import get_smart_max_input_token_count
|
|
31
|
+
from jarvis.jarvis_utils.config import is_immediate_abort
|
|
32
|
+
from jarvis.jarvis_utils.config import is_print_prompt
|
|
33
|
+
from jarvis.jarvis_utils.config import is_save_session_history
|
|
31
34
|
from jarvis.jarvis_utils.embedding import get_context_token_count
|
|
35
|
+
from jarvis.jarvis_utils.globals import console
|
|
36
|
+
from jarvis.jarvis_utils.globals import get_interrupt
|
|
37
|
+
from jarvis.jarvis_utils.globals import set_in_chat
|
|
38
|
+
from jarvis.jarvis_utils.output import OutputType # 保留用于语法高亮
|
|
39
|
+
from jarvis.jarvis_utils.output import PrettyOutput
|
|
40
|
+
from jarvis.jarvis_utils.tag import ct
|
|
41
|
+
from jarvis.jarvis_utils.tag import ot
|
|
42
|
+
from jarvis.jarvis_utils.utils import while_success
|
|
43
|
+
from jarvis.jarvis_utils.utils import while_true
|
|
32
44
|
|
|
33
45
|
|
|
34
46
|
class BasePlatform(ABC):
|
|
35
47
|
"""大语言模型基类"""
|
|
36
48
|
|
|
37
|
-
def __init__(self):
|
|
49
|
+
def __init__(self, llm_config: Optional[Dict[str, Any]] = None):
|
|
38
50
|
"""初始化模型"""
|
|
39
51
|
self.suppress_output = True # 添加输出控制标志
|
|
40
52
|
self.web = False # 添加web属性,默认false
|
|
@@ -42,6 +54,7 @@ class BasePlatform(ABC):
|
|
|
42
54
|
self.model_group: Optional[str] = None
|
|
43
55
|
self._session_history_file: Optional[str] = None
|
|
44
56
|
self._conversation_turn = 0 # 对话轮次计数器
|
|
57
|
+
self.platform_type: str = "normal" # 平台类型:normal/cheap/smart
|
|
45
58
|
|
|
46
59
|
def __enter__(self) -> Self:
|
|
47
60
|
"""进入上下文管理器"""
|
|
@@ -84,21 +97,21 @@ class BasePlatform(ABC):
|
|
|
84
97
|
|
|
85
98
|
def _format_progress_bar(self, percent: float, width: int = 20) -> str:
|
|
86
99
|
"""格式化进度条字符串
|
|
87
|
-
|
|
100
|
+
|
|
88
101
|
参数:
|
|
89
102
|
percent: 百分比 (0-100)
|
|
90
103
|
width: 进度条宽度(字符数)
|
|
91
|
-
|
|
104
|
+
|
|
92
105
|
返回:
|
|
93
106
|
str: 格式化的进度条字符串
|
|
94
107
|
"""
|
|
95
108
|
# 限制百分比范围
|
|
96
109
|
percent = max(0, min(100, percent))
|
|
97
|
-
|
|
110
|
+
|
|
98
111
|
# 计算填充的字符数
|
|
99
112
|
filled = int(width * percent / 100)
|
|
100
113
|
empty = width - filled
|
|
101
|
-
|
|
114
|
+
|
|
102
115
|
# 根据百分比选择颜色
|
|
103
116
|
if percent >= 90:
|
|
104
117
|
color = "red"
|
|
@@ -106,18 +119,20 @@ class BasePlatform(ABC):
|
|
|
106
119
|
color = "yellow"
|
|
107
120
|
else:
|
|
108
121
|
color = "green"
|
|
109
|
-
|
|
122
|
+
|
|
110
123
|
# 构建进度条:使用 █ 表示已填充,░ 表示未填充
|
|
111
124
|
bar = "█" * filled + "░" * empty
|
|
112
|
-
|
|
125
|
+
|
|
113
126
|
return f"[{color}]{bar}[/{color}]"
|
|
114
127
|
|
|
115
|
-
def _get_token_usage_info(
|
|
128
|
+
def _get_token_usage_info(
|
|
129
|
+
self, current_response: str = ""
|
|
130
|
+
) -> Tuple[float, str, str]:
|
|
116
131
|
"""获取 token 使用信息
|
|
117
|
-
|
|
132
|
+
|
|
118
133
|
参数:
|
|
119
134
|
current_response: 当前响应内容(用于计算流式输出时的 token)
|
|
120
|
-
|
|
135
|
+
|
|
121
136
|
返回:
|
|
122
137
|
Tuple[float, str, str]: (usage_percent, percent_color, progress_bar)
|
|
123
138
|
"""
|
|
@@ -125,8 +140,8 @@ class BasePlatform(ABC):
|
|
|
125
140
|
history_tokens = self.get_used_token_count()
|
|
126
141
|
current_response_tokens = get_context_token_count(current_response)
|
|
127
142
|
total_tokens = history_tokens + current_response_tokens
|
|
128
|
-
max_tokens =
|
|
129
|
-
|
|
143
|
+
max_tokens = self._get_platform_max_input_token_count()
|
|
144
|
+
|
|
130
145
|
if max_tokens > 0:
|
|
131
146
|
usage_percent = (total_tokens / max_tokens) * 100
|
|
132
147
|
if usage_percent >= 90:
|
|
@@ -142,10 +157,14 @@ class BasePlatform(ABC):
|
|
|
142
157
|
return 0.0, "green", ""
|
|
143
158
|
|
|
144
159
|
def _update_panel_subtitle_with_token(
|
|
145
|
-
self,
|
|
160
|
+
self,
|
|
161
|
+
panel: Panel,
|
|
162
|
+
response: str,
|
|
163
|
+
is_completed: bool = False,
|
|
164
|
+
duration: float = 0.0,
|
|
146
165
|
) -> None:
|
|
147
166
|
"""更新面板的 subtitle,包含 token 使用信息
|
|
148
|
-
|
|
167
|
+
|
|
149
168
|
参数:
|
|
150
169
|
panel: 要更新的面板
|
|
151
170
|
response: 当前响应内容
|
|
@@ -153,13 +172,17 @@ class BasePlatform(ABC):
|
|
|
153
172
|
duration: 耗时(秒)
|
|
154
173
|
"""
|
|
155
174
|
from datetime import datetime
|
|
156
|
-
|
|
175
|
+
|
|
157
176
|
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
158
177
|
try:
|
|
159
|
-
usage_percent, percent_color, progress_bar = self._get_token_usage_info(
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
178
|
+
usage_percent, percent_color, progress_bar = self._get_token_usage_info(
|
|
179
|
+
response
|
|
180
|
+
)
|
|
181
|
+
max_tokens = self._get_platform_max_input_token_count()
|
|
182
|
+
total_tokens = self.get_used_token_count() + get_context_token_count(
|
|
183
|
+
response
|
|
184
|
+
)
|
|
185
|
+
|
|
163
186
|
threshold = get_conversation_turn_threshold()
|
|
164
187
|
if is_completed:
|
|
165
188
|
if max_tokens > 0 and progress_bar:
|
|
@@ -188,21 +211,21 @@ class BasePlatform(ABC):
|
|
|
188
211
|
|
|
189
212
|
def _chat_with_pretty_output(self, message: str, start_time: float) -> str:
|
|
190
213
|
"""使用 pretty output 模式进行聊天
|
|
191
|
-
|
|
214
|
+
|
|
192
215
|
参数:
|
|
193
216
|
message: 用户消息
|
|
194
217
|
start_time: 开始时间
|
|
195
|
-
|
|
218
|
+
|
|
196
219
|
返回:
|
|
197
220
|
str: 模型响应
|
|
198
221
|
"""
|
|
199
222
|
import time
|
|
200
|
-
|
|
223
|
+
|
|
201
224
|
chat_iterator = self.chat(message)
|
|
202
225
|
first_chunk = None
|
|
203
226
|
|
|
204
227
|
with Status(
|
|
205
|
-
f"🤔 {(G.
|
|
228
|
+
f"🤔 {(G.get_current_agent_name() + ' · ') if G.get_current_agent_name() else ''}{self.name()} 正在思考中...",
|
|
206
229
|
spinner="dots",
|
|
207
230
|
console=console,
|
|
208
231
|
):
|
|
@@ -218,7 +241,7 @@ class BasePlatform(ABC):
|
|
|
218
241
|
text_content = Text(overflow="fold")
|
|
219
242
|
panel = Panel(
|
|
220
243
|
text_content,
|
|
221
|
-
title=f"[bold cyan]{(G.
|
|
244
|
+
title=f"[bold cyan]{(G.get_current_agent_name() + ' · ') if G.get_current_agent_name() else ''}{self.name()}[/bold cyan]",
|
|
222
245
|
subtitle="[yellow]正在回答... (按 Ctrl+C 中断)[/yellow]",
|
|
223
246
|
border_style="bright_blue",
|
|
224
247
|
box=box.ROUNDED,
|
|
@@ -227,14 +250,17 @@ class BasePlatform(ABC):
|
|
|
227
250
|
|
|
228
251
|
response = ""
|
|
229
252
|
last_subtitle_update_time = time.time()
|
|
230
|
-
subtitle_update_interval =
|
|
253
|
+
subtitle_update_interval = (
|
|
254
|
+
3 # subtitle 更新间隔(秒),减少更新频率避免重复渲染标题
|
|
255
|
+
)
|
|
231
256
|
update_count = 0 # 更新计数器,用于控制 subtitle 更新频率
|
|
232
|
-
with Live(panel, refresh_per_second=4, transient=
|
|
257
|
+
with Live(panel, refresh_per_second=4, transient=True) as live:
|
|
258
|
+
|
|
233
259
|
def _update_panel_content(content: str, update_subtitle: bool = False):
|
|
234
260
|
nonlocal response, last_subtitle_update_time, update_count
|
|
235
261
|
text_content.append(content, style="bright_white")
|
|
236
262
|
update_count += 1
|
|
237
|
-
|
|
263
|
+
|
|
238
264
|
# Scrolling Logic - 只在内容超过一定行数时才应用滚动
|
|
239
265
|
max_text_height = console.height - 5
|
|
240
266
|
if max_text_height <= 0:
|
|
@@ -250,27 +276,32 @@ class BasePlatform(ABC):
|
|
|
250
276
|
text_content.plain = "\n".join(
|
|
251
277
|
[line.plain for line in lines[-max_text_height:]]
|
|
252
278
|
)
|
|
253
|
-
|
|
279
|
+
|
|
254
280
|
# 只在需要时更新 subtitle(减少更新频率,避免重复渲染标题)
|
|
255
281
|
# 策略:每 10 次内容更新或每 3 秒更新一次 subtitle
|
|
256
282
|
current_time = time.time()
|
|
257
283
|
should_update_subtitle = (
|
|
258
|
-
update_subtitle
|
|
284
|
+
update_subtitle
|
|
259
285
|
or update_count % 10 == 0 # 每 10 次更新一次
|
|
260
|
-
or (current_time - last_subtitle_update_time)
|
|
286
|
+
or (current_time - last_subtitle_update_time)
|
|
287
|
+
>= subtitle_update_interval
|
|
261
288
|
)
|
|
262
|
-
|
|
289
|
+
|
|
263
290
|
if should_update_subtitle:
|
|
264
|
-
self._update_panel_subtitle_with_token(
|
|
291
|
+
self._update_panel_subtitle_with_token(
|
|
292
|
+
panel, response, is_completed=False
|
|
293
|
+
)
|
|
265
294
|
last_subtitle_update_time = current_time
|
|
266
|
-
|
|
295
|
+
|
|
267
296
|
# 更新 panel(只更新内容,subtitle 更新频率已降低)
|
|
268
297
|
live.update(panel)
|
|
269
298
|
|
|
270
299
|
# Process first chunk
|
|
271
300
|
response += first_chunk
|
|
272
301
|
if first_chunk:
|
|
273
|
-
_update_panel_content(
|
|
302
|
+
_update_panel_content(
|
|
303
|
+
first_chunk, update_subtitle=True
|
|
304
|
+
) # 第一次更新时更新 subtitle
|
|
274
305
|
|
|
275
306
|
# 缓存机制:降低更新频率,减少界面闪烁
|
|
276
307
|
buffer = ""
|
|
@@ -308,33 +339,22 @@ class BasePlatform(ABC):
|
|
|
308
339
|
|
|
309
340
|
_flush_buffer()
|
|
310
341
|
# 在结束前,将面板内容替换为完整响应,确保最后一次渲染的 panel 显示全部内容
|
|
311
|
-
if response:
|
|
312
|
-
text_content.plain = response
|
|
313
|
-
# 最后更新 subtitle 和 panel
|
|
314
|
-
end_time = time.time()
|
|
315
|
-
duration = end_time - start_time
|
|
316
|
-
self._update_panel_subtitle_with_token(panel, response, is_completed=True, duration=duration)
|
|
317
|
-
# 最后更新 panel,Live 上下文退出时会自动打印(transient=False)
|
|
318
|
-
live.update(panel)
|
|
319
|
-
# 注意:不要在这里调用 console.print(),因为 Live 退出时会自动打印 panel
|
|
320
|
-
# Live 退出后仅添加空行分隔,不再重复打印 panel,避免内容重复
|
|
321
|
-
console.print()
|
|
322
342
|
return response
|
|
323
343
|
|
|
324
344
|
def _chat_with_simple_output(self, message: str, start_time: float) -> str:
|
|
325
345
|
"""使用简单输出模式进行聊天
|
|
326
|
-
|
|
346
|
+
|
|
327
347
|
参数:
|
|
328
348
|
message: 用户消息
|
|
329
349
|
start_time: 开始时间
|
|
330
|
-
|
|
350
|
+
|
|
331
351
|
返回:
|
|
332
352
|
str: 模型响应
|
|
333
353
|
"""
|
|
334
354
|
import time
|
|
335
|
-
|
|
355
|
+
|
|
336
356
|
console.print(
|
|
337
|
-
f"🤖 模型输出 - {(G.
|
|
357
|
+
f"🤖 模型输出 - {(G.get_current_agent_name() + ' · ') if G.get_current_agent_name() else ''}{self.name()} (按 Ctrl+C 中断)",
|
|
338
358
|
soft_wrap=False,
|
|
339
359
|
)
|
|
340
360
|
response = ""
|
|
@@ -352,10 +372,10 @@ class BasePlatform(ABC):
|
|
|
352
372
|
|
|
353
373
|
def _chat_with_suppressed_output(self, message: str) -> str:
|
|
354
374
|
"""使用静默模式进行聊天
|
|
355
|
-
|
|
375
|
+
|
|
356
376
|
参数:
|
|
357
377
|
message: 用户消息
|
|
358
|
-
|
|
378
|
+
|
|
359
379
|
返回:
|
|
360
380
|
str: 模型响应
|
|
361
381
|
"""
|
|
@@ -369,10 +389,10 @@ class BasePlatform(ABC):
|
|
|
369
389
|
|
|
370
390
|
def _process_response(self, response: str) -> str:
|
|
371
391
|
"""处理响应,移除 think 标签
|
|
372
|
-
|
|
392
|
+
|
|
373
393
|
参数:
|
|
374
394
|
response: 原始响应
|
|
375
|
-
|
|
395
|
+
|
|
376
396
|
返回:
|
|
377
397
|
str: 处理后的响应
|
|
378
398
|
"""
|
|
@@ -391,7 +411,7 @@ class BasePlatform(ABC):
|
|
|
391
411
|
|
|
392
412
|
# 当输入为空白字符串时,打印警告并直接返回空字符串
|
|
393
413
|
if message.strip() == "":
|
|
394
|
-
|
|
414
|
+
PrettyOutput.auto_print("⚠️ 输入为空白字符串,已忽略本次请求")
|
|
395
415
|
return ""
|
|
396
416
|
|
|
397
417
|
# 检查并截断消息以避免超出剩余token限制
|
|
@@ -403,12 +423,18 @@ class BasePlatform(ABC):
|
|
|
403
423
|
response = self._chat_with_pretty_output(message, start_time)
|
|
404
424
|
else:
|
|
405
425
|
response = self._chat_with_simple_output(message, start_time)
|
|
426
|
+
|
|
427
|
+
# 计算响应时间并打印总结
|
|
428
|
+
end_time = time.time()
|
|
429
|
+
duration = end_time - start_time
|
|
430
|
+
PrettyOutput.auto_print(f"✅ {self.name()}模型响应完成: {duration:.2f}秒")
|
|
406
431
|
else:
|
|
407
432
|
response = self._chat_with_suppressed_output(message)
|
|
408
433
|
|
|
409
434
|
# 处理响应并保存会话历史
|
|
410
435
|
response = self._process_response(response)
|
|
411
436
|
self._append_session_history(message, response)
|
|
437
|
+
|
|
412
438
|
# 增加对话轮次计数
|
|
413
439
|
self._conversation_turn += 1
|
|
414
440
|
return response
|
|
@@ -419,17 +445,25 @@ class BasePlatform(ABC):
|
|
|
419
445
|
set_in_chat(True)
|
|
420
446
|
if not self.suppress_output and is_print_prompt():
|
|
421
447
|
PrettyOutput.print(f"{message}", OutputType.USER) # 保留用于语法高亮
|
|
422
|
-
|
|
448
|
+
|
|
449
|
+
# 记录用户输入(模型输入)
|
|
450
|
+
from jarvis.jarvis_utils.dialogue_recorder import record_user_message
|
|
451
|
+
|
|
452
|
+
record_user_message(message)
|
|
453
|
+
|
|
423
454
|
result: str = ""
|
|
424
|
-
result = while_true(
|
|
425
|
-
|
|
426
|
-
)
|
|
427
|
-
|
|
455
|
+
result = while_true(lambda: while_success(lambda: self._chat(message)))
|
|
456
|
+
|
|
428
457
|
# Check if result is empty or False (retry exhausted)
|
|
429
458
|
# Convert False to empty string for type safety
|
|
430
459
|
if result is False or result == "":
|
|
431
460
|
raise ValueError("返回结果为空")
|
|
432
|
-
|
|
461
|
+
|
|
462
|
+
# 记录模型输出
|
|
463
|
+
from jarvis.jarvis_utils.dialogue_recorder import record_assistant_message
|
|
464
|
+
|
|
465
|
+
record_assistant_message(result)
|
|
466
|
+
|
|
433
467
|
from jarvis.jarvis_utils.globals import set_last_message
|
|
434
468
|
|
|
435
469
|
set_last_message(result)
|
|
@@ -437,6 +471,14 @@ class BasePlatform(ABC):
|
|
|
437
471
|
finally:
|
|
438
472
|
set_in_chat(False)
|
|
439
473
|
|
|
474
|
+
def get_conversation_turn(self) -> int:
|
|
475
|
+
"""获取当前对话轮次数
|
|
476
|
+
|
|
477
|
+
返回:
|
|
478
|
+
int: 当前对话轮次数
|
|
479
|
+
"""
|
|
480
|
+
return self._conversation_turn
|
|
481
|
+
|
|
440
482
|
@abstractmethod
|
|
441
483
|
def name(self) -> str:
|
|
442
484
|
"""模型名称"""
|
|
@@ -523,6 +565,27 @@ class BasePlatform(ABC):
|
|
|
523
565
|
"""设置网页标志"""
|
|
524
566
|
self.web = web
|
|
525
567
|
|
|
568
|
+
def set_platform_type(self, platform_type: str):
|
|
569
|
+
"""设置平台类型
|
|
570
|
+
|
|
571
|
+
参数:
|
|
572
|
+
platform_type: 平台类型,可选值为 'normal'、'cheap' 或 'smart'
|
|
573
|
+
"""
|
|
574
|
+
self.platform_type = platform_type
|
|
575
|
+
|
|
576
|
+
def _get_platform_max_input_token_count(self) -> int:
|
|
577
|
+
"""根据平台类型获取对应的最大输入token数量
|
|
578
|
+
|
|
579
|
+
返回:
|
|
580
|
+
int: 模型能处理的最大输入token数量
|
|
581
|
+
"""
|
|
582
|
+
if self.platform_type == "cheap":
|
|
583
|
+
return get_cheap_max_input_token_count(self.model_group)
|
|
584
|
+
elif self.platform_type == "smart":
|
|
585
|
+
return get_smart_max_input_token_count(self.model_group)
|
|
586
|
+
else:
|
|
587
|
+
return get_max_input_token_count(self.model_group)
|
|
588
|
+
|
|
526
589
|
def _append_session_history(self, user_input: str, model_output: str) -> None:
|
|
527
590
|
"""
|
|
528
591
|
Append the user input and model output to a session history file if enabled.
|
|
@@ -554,11 +617,14 @@ class BasePlatform(ABC):
|
|
|
554
617
|
ts = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
555
618
|
|
|
556
619
|
self._session_history_file = os.path.join(
|
|
557
|
-
session_dir,
|
|
620
|
+
session_dir,
|
|
621
|
+
f"session_history_{safe_platform}_{safe_model}_{ts}.log",
|
|
558
622
|
)
|
|
559
623
|
|
|
560
624
|
# Append record
|
|
561
|
-
with open(
|
|
625
|
+
with open(
|
|
626
|
+
self._session_history_file, "a", encoding="utf-8", errors="ignore"
|
|
627
|
+
) as f:
|
|
562
628
|
ts_line = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
563
629
|
f.write(f"===== {ts_line} =====\n")
|
|
564
630
|
f.write("USER:\n")
|
|
@@ -571,10 +637,10 @@ class BasePlatform(ABC):
|
|
|
571
637
|
|
|
572
638
|
def get_conversation_history(self) -> List[Dict[str, str]]:
|
|
573
639
|
"""获取当前对话历史
|
|
574
|
-
|
|
640
|
+
|
|
575
641
|
返回:
|
|
576
642
|
List[Dict[str, str]]: 对话历史列表,每个元素包含 role 和 content
|
|
577
|
-
|
|
643
|
+
|
|
578
644
|
注意:
|
|
579
645
|
默认实现检查是否有 messages 属性,子类可以重写此方法以提供自定义实现
|
|
580
646
|
"""
|
|
@@ -584,88 +650,90 @@ class BasePlatform(ABC):
|
|
|
584
650
|
|
|
585
651
|
def get_used_token_count(self) -> int:
|
|
586
652
|
"""计算当前对话历史使用的token数量
|
|
587
|
-
|
|
653
|
+
|
|
588
654
|
返回:
|
|
589
655
|
int: 当前对话历史使用的token数量
|
|
590
656
|
"""
|
|
591
657
|
history = self.get_conversation_history()
|
|
592
658
|
if not history:
|
|
593
659
|
return 0
|
|
594
|
-
|
|
660
|
+
|
|
595
661
|
total_tokens = 0
|
|
596
662
|
for message in history:
|
|
597
663
|
content = message.get("content", "")
|
|
598
664
|
if content:
|
|
599
665
|
total_tokens += get_context_token_count(content)
|
|
600
|
-
|
|
666
|
+
|
|
601
667
|
return total_tokens
|
|
602
668
|
|
|
603
669
|
def get_remaining_token_count(self) -> int:
|
|
604
670
|
"""获取剩余可用的token数量
|
|
605
|
-
|
|
671
|
+
|
|
606
672
|
返回:
|
|
607
673
|
int: 剩余可用的token数量(输入窗口限制 - 当前使用的token数量)
|
|
608
674
|
"""
|
|
609
|
-
max_tokens =
|
|
675
|
+
max_tokens = self._get_platform_max_input_token_count()
|
|
610
676
|
used_tokens = self.get_used_token_count()
|
|
611
677
|
remaining = max_tokens - used_tokens
|
|
612
678
|
return max(0, remaining) # 确保返回值不为负数
|
|
613
679
|
|
|
614
680
|
def _truncate_message_if_needed(self, message: str) -> str:
|
|
615
681
|
"""如果消息超出剩余token限制,则截断消息
|
|
616
|
-
|
|
682
|
+
|
|
617
683
|
参数:
|
|
618
684
|
message: 原始消息
|
|
619
|
-
|
|
685
|
+
|
|
620
686
|
返回:
|
|
621
687
|
str: 截断后的消息(如果不需要截断则返回原消息)
|
|
622
688
|
"""
|
|
623
689
|
try:
|
|
624
690
|
# 获取剩余token数量
|
|
625
691
|
remaining_tokens = self.get_remaining_token_count()
|
|
626
|
-
|
|
692
|
+
|
|
627
693
|
# 如果剩余token为0或负数,返回空消息
|
|
628
694
|
if remaining_tokens <= 0:
|
|
629
|
-
|
|
695
|
+
PrettyOutput.auto_print("⚠️ 警告:剩余token为0,无法发送消息")
|
|
630
696
|
return ""
|
|
631
|
-
|
|
697
|
+
|
|
632
698
|
# 计算消息的token数量
|
|
633
699
|
message_tokens = get_context_token_count(message)
|
|
634
|
-
|
|
700
|
+
|
|
635
701
|
# 如果消息token数小于等于剩余token数,不需要截断
|
|
636
702
|
if message_tokens <= remaining_tokens:
|
|
637
703
|
return message
|
|
638
|
-
|
|
704
|
+
|
|
639
705
|
# 需要截断:保留剩余token的80%用于消息,20%作为安全余量
|
|
640
706
|
target_tokens = int(remaining_tokens * 0.8)
|
|
641
707
|
if target_tokens <= 0:
|
|
642
|
-
|
|
708
|
+
PrettyOutput.auto_print("⚠️ 警告:剩余token不足,无法发送消息")
|
|
643
709
|
return ""
|
|
644
|
-
|
|
710
|
+
|
|
645
711
|
# 估算字符数(1 token ≈ 4字符)
|
|
646
712
|
target_chars = target_tokens * 4
|
|
647
|
-
|
|
713
|
+
|
|
648
714
|
# 如果消息长度小于目标字符数,不需要截断(token估算可能有误差)
|
|
649
715
|
if len(message) <= target_chars:
|
|
650
716
|
return message
|
|
651
|
-
|
|
717
|
+
|
|
652
718
|
# 截断消息:保留前面的内容,添加截断提示
|
|
653
719
|
truncated_message = message[:target_chars]
|
|
654
720
|
# 尝试在最后一个完整句子处截断
|
|
655
|
-
last_period = truncated_message.rfind(
|
|
656
|
-
last_newline = truncated_message.rfind(
|
|
721
|
+
last_period = truncated_message.rfind(".")
|
|
722
|
+
last_newline = truncated_message.rfind("\n")
|
|
657
723
|
last_break = max(last_period, last_newline)
|
|
658
|
-
|
|
724
|
+
|
|
659
725
|
if last_break > target_chars * 0.5: # 如果找到的断点不太靠前
|
|
660
|
-
truncated_message = truncated_message[:last_break + 1]
|
|
661
|
-
|
|
726
|
+
truncated_message = truncated_message[: last_break + 1]
|
|
727
|
+
|
|
662
728
|
truncated_message += "\n\n... (消息过长,已截断以避免超出上下文限制)"
|
|
663
|
-
|
|
664
|
-
|
|
729
|
+
PrettyOutput.auto_print(
|
|
730
|
+
f"⚠️ 警告:消息过长({message_tokens} tokens),已截断至约 {target_tokens} tokens"
|
|
731
|
+
)
|
|
732
|
+
|
|
665
733
|
return truncated_message
|
|
666
734
|
except Exception as e:
|
|
667
735
|
# 如果截断过程中出错,返回原消息(避免阻塞对话)
|
|
668
|
-
|
|
736
|
+
PrettyOutput.auto_print(f"⚠️ 警告:检查消息长度时出错: {e},使用原消息")
|
|
669
737
|
return message
|
|
670
738
|
|
|
671
739
|
@abstractmethod
|
jarvis/jarvis_platform/human.py
CHANGED
|
@@ -1,17 +1,23 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
|
-
# 人类交互平台实现模块
|
|
4
|
-
|
|
5
|
-
# 提供与真实人类交互的模拟接口
|
|
6
|
-
|
|
7
1
|
import json
|
|
8
2
|
import random
|
|
9
3
|
import string
|
|
10
|
-
from typing import
|
|
4
|
+
from typing import Any
|
|
5
|
+
from typing import Dict
|
|
6
|
+
from typing import Generator
|
|
7
|
+
from typing import List
|
|
8
|
+
from typing import Optional
|
|
9
|
+
from typing import Tuple
|
|
11
10
|
|
|
12
11
|
from jarvis.jarvis_platform.base import BasePlatform
|
|
13
12
|
from jarvis.jarvis_utils.clipboard import copy_to_clipboard
|
|
14
13
|
from jarvis.jarvis_utils.input import get_multiline_input
|
|
14
|
+
from jarvis.jarvis_utils.output import PrettyOutput
|
|
15
|
+
|
|
16
|
+
# -*- coding: utf-8 -*-
|
|
17
|
+
|
|
18
|
+
# 人类交互平台实现模块
|
|
19
|
+
|
|
20
|
+
# 提供与真实人类交互的模拟接口
|
|
15
21
|
|
|
16
22
|
|
|
17
23
|
class HumanPlatform(BasePlatform):
|
|
@@ -21,8 +27,13 @@ class HumanPlatform(BasePlatform):
|
|
|
21
27
|
"""获取支持的模型列表"""
|
|
22
28
|
return [("human", "Human Interaction")]
|
|
23
29
|
|
|
24
|
-
def __init__(self):
|
|
25
|
-
"""
|
|
30
|
+
def __init__(self, llm_config: Optional[Dict[str, Any]] = None):
|
|
31
|
+
"""
|
|
32
|
+
初始化人类交互平台
|
|
33
|
+
|
|
34
|
+
参数:
|
|
35
|
+
llm_config: LLM配置字典(人类平台不使用此配置,但为保持接口一致而接受)
|
|
36
|
+
"""
|
|
26
37
|
super().__init__()
|
|
27
38
|
self.conversation_id = "" # 会话ID,用于标识当前对话
|
|
28
39
|
self.model_name = "human" # 默认模型名称
|
|
@@ -38,7 +49,7 @@ class HumanPlatform(BasePlatform):
|
|
|
38
49
|
if model_name == "human":
|
|
39
50
|
self.model_name = model_name
|
|
40
51
|
else:
|
|
41
|
-
|
|
52
|
+
PrettyOutput.auto_print(f"❌ 错误:不支持的模型: {model_name}")
|
|
42
53
|
|
|
43
54
|
def chat(self, message: str) -> Generator[str, None, None]:
|
|
44
55
|
"""发送消息并获取人类响应"""
|
|
@@ -65,7 +76,7 @@ class HumanPlatform(BasePlatform):
|
|
|
65
76
|
|
|
66
77
|
def upload_files(self, file_list: List[str]) -> bool:
|
|
67
78
|
"""文件上传功能,人类平台不需要实际处理"""
|
|
68
|
-
|
|
79
|
+
PrettyOutput.auto_print("⚠️ 人类交互平台不支持文件上传")
|
|
69
80
|
return False
|
|
70
81
|
|
|
71
82
|
def delete_chat(self) -> bool:
|
|
@@ -87,10 +98,10 @@ class HumanPlatform(BasePlatform):
|
|
|
87
98
|
with open(file_path, "w", encoding="utf-8") as f:
|
|
88
99
|
json.dump(state, f, ensure_ascii=False, indent=4)
|
|
89
100
|
self._saved = True
|
|
90
|
-
|
|
101
|
+
PrettyOutput.auto_print(f"✅ 会话已成功保存到 {file_path}")
|
|
91
102
|
return True
|
|
92
103
|
except Exception as e:
|
|
93
|
-
|
|
104
|
+
PrettyOutput.auto_print(f"❌ 保存会话失败: {str(e)}")
|
|
94
105
|
return False
|
|
95
106
|
|
|
96
107
|
def restore(self, file_path: str) -> bool:
|
|
@@ -105,13 +116,13 @@ class HumanPlatform(BasePlatform):
|
|
|
105
116
|
self.first_message = state.get("first_message", True)
|
|
106
117
|
self._saved = True
|
|
107
118
|
|
|
108
|
-
|
|
119
|
+
PrettyOutput.auto_print(f"✅ 从 {file_path} 成功恢复会话")
|
|
109
120
|
return True
|
|
110
121
|
except FileNotFoundError:
|
|
111
|
-
|
|
122
|
+
PrettyOutput.auto_print(f"❌ 会话文件未找到: {file_path}")
|
|
112
123
|
return False
|
|
113
124
|
except Exception as e:
|
|
114
|
-
|
|
125
|
+
PrettyOutput.auto_print(f"❌ 恢复会话失败: {str(e)}")
|
|
115
126
|
return False
|
|
116
127
|
|
|
117
128
|
def name(self) -> str:
|