jarvis-ai-assistant 0.3.33__tar.gz → 0.4.0__tar.gz
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_ai_assistant-0.3.33/src/jarvis_ai_assistant.egg-info → jarvis_ai_assistant-0.4.0}/PKG-INFO +1 -1
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/pyproject.toml +1 -1
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/setup.py +1 -1
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/__init__.py +1 -1
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_agent/__init__.py +10 -5
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_agent/agent_manager.py +11 -8
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_agent/config.py +7 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_agent/jarvis.py +374 -10
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_agent/main.py +32 -2
- jarvis_ai_assistant-0.4.0/src/jarvis/jarvis_agent/stdio_redirect.py +296 -0
- jarvis_ai_assistant-0.4.0/src/jarvis/jarvis_agent/web_bridge.py +189 -0
- jarvis_ai_assistant-0.4.0/src/jarvis/jarvis_agent/web_output_sink.py +53 -0
- jarvis_ai_assistant-0.4.0/src/jarvis/jarvis_agent/web_server.py +647 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_code_agent/code_agent.py +32 -6
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_data/config_schema.json +5 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_multi_agent/main.py +27 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_platform/base.py +1 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_tools/execute_script.py +45 -8
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_tools/sub_agent.py +0 -3
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_utils/config.py +35 -2
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_utils/input.py +6 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0/src/jarvis_ai_assistant.egg-info}/PKG-INFO +1 -1
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis_ai_assistant.egg-info/SOURCES.txt +4 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/LICENSE +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/MANIFEST.in +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/README.md +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/setup.cfg +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_agent/builtin_input_handler.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_agent/config_editor.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_agent/edit_file_handler.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_agent/event_bus.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_agent/events.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_agent/file_context_handler.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_agent/file_methodology_manager.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_agent/memory_manager.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_agent/methodology_share_manager.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_agent/output_handler.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_agent/prompt_builder.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_agent/prompt_manager.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_agent/prompts.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_agent/protocols.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_agent/run_loop.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_agent/session_manager.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_agent/share_manager.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_agent/shell_input_handler.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_agent/task_analyzer.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_agent/task_manager.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_agent/tool_executor.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_agent/tool_share_manager.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_agent/user_interaction.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_agent/utils.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_code_agent/__init__.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_code_agent/lint.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_code_analysis/checklists/__init__.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_code_analysis/checklists/c_cpp.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_code_analysis/checklists/csharp.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_code_analysis/checklists/data_format.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_code_analysis/checklists/devops.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_code_analysis/checklists/docs.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_code_analysis/checklists/go.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_code_analysis/checklists/infrastructure.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_code_analysis/checklists/java.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_code_analysis/checklists/javascript.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_code_analysis/checklists/kotlin.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_code_analysis/checklists/loader.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_code_analysis/checklists/php.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_code_analysis/checklists/python.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_code_analysis/checklists/ruby.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_code_analysis/checklists/rust.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_code_analysis/checklists/shell.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_code_analysis/checklists/sql.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_code_analysis/checklists/swift.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_code_analysis/checklists/web.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_code_analysis/code_review.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_data/tiktoken/9b5ad71b2ce5302211f9c61530b329a4922fc6a4 +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_git_squash/__init__.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_git_squash/main.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_git_utils/git_commiter.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_mcp/__init__.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_mcp/sse_mcp_client.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_mcp/stdio_mcp_client.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_mcp/streamable_mcp_client.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_memory_organizer/__init__.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_memory_organizer/memory_organizer.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_methodology/main.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_multi_agent/__init__.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_platform/__init__.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_platform/ai8.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_platform/human.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_platform/kimi.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_platform/openai.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_platform/registry.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_platform/tongyi.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_platform/yuanbao.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_platform_manager/__init__.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_platform_manager/main.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_platform_manager/service.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_rag/__init__.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_rag/cache.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_rag/cli.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_rag/embedding_manager.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_rag/llm_interface.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_rag/query_rewriter.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_rag/rag_pipeline.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_rag/reranker.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_rag/retriever.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_smart_shell/__init__.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_smart_shell/main.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_stats/__init__.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_stats/cli.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_stats/stats.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_stats/storage.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_stats/visualizer.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_tools/__init__.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_tools/ask_user.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_tools/base.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_tools/clear_memory.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_tools/cli/__init__.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_tools/cli/main.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_tools/edit_file.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_tools/file_analyzer.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_tools/generate_new_tool.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_tools/methodology.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_tools/read_code.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_tools/read_webpage.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_tools/registry.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_tools/retrieve_memory.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_tools/rewrite_file.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_tools/save_memory.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_tools/search_web.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_tools/sub_code_agent.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_tools/virtual_tty.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_utils/__init__.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_utils/builtin_replace_map.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_utils/clipboard.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_utils/embedding.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_utils/file_processors.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_utils/fzf.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_utils/git_utils.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_utils/globals.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_utils/http.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_utils/methodology.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_utils/output.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_utils/tag.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_utils/utils.py +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis_ai_assistant.egg-info/dependency_links.txt +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis_ai_assistant.egg-info/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis_ai_assistant.egg-info/requires.txt +0 -0
- {jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis_ai_assistant.egg-info/top_level.txt +0 -0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
4
4
|
|
5
5
|
[project]
|
6
6
|
name = "jarvis-ai-assistant"
|
7
|
-
version = "0.
|
7
|
+
version = "0.4.0"
|
8
8
|
description = "Jarvis: An AI assistant that uses tools to interact with the system"
|
9
9
|
readme = "README.md"
|
10
10
|
authors = [{ name = "skyfire", email = "skyfireitdiy@hotmail.com" }]
|
@@ -3,7 +3,7 @@ from setuptools import setup, find_packages # type: ignore
|
|
3
3
|
|
4
4
|
setup(
|
5
5
|
name="jarvis-ai-assistant",
|
6
|
-
version="0.
|
6
|
+
version="0.4.0",
|
7
7
|
author="skyfire",
|
8
8
|
author_email="skyfireitdiy@hotmail.com",
|
9
9
|
description="An AI assistant that uses various tools to interact with the system",
|
{jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_agent/__init__.py
RENAMED
@@ -54,6 +54,9 @@ from jarvis.jarvis_agent.events import (
|
|
54
54
|
from jarvis.jarvis_agent.user_interaction import UserInteractionHandler
|
55
55
|
from jarvis.jarvis_agent.utils import join_prompts
|
56
56
|
from jarvis.jarvis_utils.methodology import _load_all_methodologies
|
57
|
+
from jarvis.jarvis_agent.shell_input_handler import shell_input_handler
|
58
|
+
from jarvis.jarvis_agent.file_context_handler import file_context_handler
|
59
|
+
from jarvis.jarvis_agent.builtin_input_handler import builtin_input_handler
|
57
60
|
|
58
61
|
# jarvis_platform 相关
|
59
62
|
from jarvis.jarvis_platform.base import BasePlatform
|
@@ -274,7 +277,6 @@ class Agent:
|
|
274
277
|
auto_complete: bool = False,
|
275
278
|
output_handler: Optional[List[OutputHandlerProtocol]] = None,
|
276
279
|
use_tools: Optional[List[str]] = None,
|
277
|
-
input_handler: Optional[List[Callable[[str, Any], Tuple[str, bool]]]] = None,
|
278
280
|
execute_tool_confirm: Optional[bool] = None,
|
279
281
|
need_summary: bool = True,
|
280
282
|
multiline_inputer: Optional[Callable[[str], str]] = None,
|
@@ -294,7 +296,6 @@ class Agent:
|
|
294
296
|
summary_prompt: 任务总结提示模板
|
295
297
|
auto_complete: 是否自动完成任务
|
296
298
|
output_handler: 输出处理器列表
|
297
|
-
input_handler: 输入处理器列表
|
298
299
|
execute_tool_confirm: 执行工具前是否需要确认
|
299
300
|
need_summary: 是否需要生成总结
|
300
301
|
multiline_inputer: 多行输入处理器
|
@@ -327,7 +328,6 @@ class Agent:
|
|
327
328
|
# 初始化处理器
|
328
329
|
self._init_handlers(
|
329
330
|
output_handler or [],
|
330
|
-
input_handler,
|
331
331
|
multiline_inputer,
|
332
332
|
use_tools or [],
|
333
333
|
)
|
@@ -395,14 +395,17 @@ class Agent:
|
|
395
395
|
def _init_handlers(
|
396
396
|
self,
|
397
397
|
output_handler: List[OutputHandlerProtocol],
|
398
|
-
input_handler: Optional[List[Callable[[str, Any], Tuple[str, bool]]]],
|
399
398
|
multiline_inputer: Optional[Callable[[str], str]],
|
400
399
|
use_tools: List[str],
|
401
400
|
):
|
402
401
|
"""初始化各种处理器"""
|
403
402
|
self.output_handler = output_handler or [ToolRegistry()]
|
404
403
|
self.set_use_tools(use_tools)
|
405
|
-
self.input_handler =
|
404
|
+
self.input_handler = [
|
405
|
+
builtin_input_handler,
|
406
|
+
shell_input_handler,
|
407
|
+
file_context_handler,
|
408
|
+
]
|
406
409
|
self.multiline_inputer = multiline_inputer or get_multiline_input
|
407
410
|
|
408
411
|
def _init_config(
|
@@ -439,6 +442,8 @@ class Agent:
|
|
439
442
|
self.summary_prompt = cfg.summary_prompt or DEFAULT_SUMMARY_PROMPT
|
440
443
|
self.max_token_count = int(cfg.max_token_count or get_max_token_count(model_group))
|
441
444
|
self.force_save_memory = bool(cfg.force_save_memory)
|
445
|
+
# 非交互模式下自动完成标志需要同步到 Agent 实例,避免循环
|
446
|
+
self.auto_complete = bool(cfg.auto_complete)
|
442
447
|
|
443
448
|
# 聚合配置到 AgentConfig,作为后续单一事实来源(保持兼容,不改变既有属性使用)
|
444
449
|
self.config = cfg
|
{jarvis_ai_assistant-0.3.33 → jarvis_ai_assistant-0.4.0}/src/jarvis/jarvis_agent/agent_manager.py
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
"""Agent管理器模块,负责Agent的初始化和任务执行"""
|
3
|
-
from typing import Optional
|
3
|
+
from typing import Optional, Callable
|
4
4
|
|
5
5
|
import typer
|
6
6
|
|
@@ -16,6 +16,7 @@ from jarvis.jarvis_agent.file_context_handler import file_context_handler
|
|
16
16
|
from jarvis.jarvis_agent.shell_input_handler import shell_input_handler
|
17
17
|
from jarvis.jarvis_agent.task_manager import TaskManager
|
18
18
|
from jarvis.jarvis_tools.registry import ToolRegistry
|
19
|
+
from jarvis.jarvis_utils.config import is_non_interactive
|
19
20
|
|
20
21
|
|
21
22
|
class AgentManager:
|
@@ -28,6 +29,8 @@ class AgentManager:
|
|
28
29
|
restore_session: bool = False,
|
29
30
|
use_methodology: Optional[bool] = None,
|
30
31
|
use_analysis: Optional[bool] = None,
|
32
|
+
multiline_inputer: Optional[Callable[[str], str]] = None,
|
33
|
+
confirm_callback: Optional[Callable[[str, bool], bool]] = None,
|
31
34
|
):
|
32
35
|
self.model_group = model_group
|
33
36
|
self.tool_group = tool_group
|
@@ -35,6 +38,9 @@ class AgentManager:
|
|
35
38
|
self.use_methodology = use_methodology
|
36
39
|
self.use_analysis = use_analysis
|
37
40
|
self.agent: Optional[Agent] = None
|
41
|
+
# 可选:注入输入与确认回调,用于Web模式等前端替代交互
|
42
|
+
self.multiline_inputer = multiline_inputer
|
43
|
+
self.confirm_callback = confirm_callback
|
38
44
|
|
39
45
|
def initialize(self) -> Agent:
|
40
46
|
"""初始化Agent"""
|
@@ -47,15 +53,12 @@ class AgentManager:
|
|
47
53
|
self.agent = Agent(
|
48
54
|
system_prompt=origin_agent_system_prompt,
|
49
55
|
model_group=self.model_group,
|
50
|
-
input_handler=[
|
51
|
-
shell_input_handler,
|
52
|
-
file_context_handler,
|
53
|
-
builtin_input_handler,
|
54
|
-
],
|
55
56
|
output_handler=[ToolRegistry()], # type: ignore
|
56
57
|
need_summary=False,
|
57
58
|
use_methodology=self.use_methodology,
|
58
59
|
use_analysis=self.use_analysis,
|
60
|
+
multiline_inputer=self.multiline_inputer,
|
61
|
+
confirm_callback=self.confirm_callback,
|
59
62
|
)
|
60
63
|
|
61
64
|
# 尝试恢复会话
|
@@ -77,8 +80,8 @@ class AgentManager:
|
|
77
80
|
self.agent.run(task_content)
|
78
81
|
raise typer.Exit(code=0)
|
79
82
|
|
80
|
-
#
|
81
|
-
if self.agent.first:
|
83
|
+
# 处理预定义任务(非交互模式下跳过)
|
84
|
+
if not is_non_interactive() and self.agent.first:
|
82
85
|
task_manager = TaskManager()
|
83
86
|
tasks = task_manager.load_tasks()
|
84
87
|
if tasks and (selected_task := task_manager.select_task(tasks)):
|
@@ -17,6 +17,7 @@ from jarvis.jarvis_utils.config import (
|
|
17
17
|
is_force_save_memory,
|
18
18
|
is_use_analysis,
|
19
19
|
is_use_methodology,
|
20
|
+
is_non_interactive,
|
20
21
|
)
|
21
22
|
|
22
23
|
|
@@ -30,6 +31,7 @@ class AgentConfig:
|
|
30
31
|
|
31
32
|
# 运行行为
|
32
33
|
auto_complete: bool = False
|
34
|
+
non_interactive: bool = False
|
33
35
|
need_summary: bool = True
|
34
36
|
|
35
37
|
# 可选配置(None 表示使用默认策略解析)
|
@@ -53,6 +55,7 @@ class AgentConfig:
|
|
53
55
|
description=self.description,
|
54
56
|
model_group=self.model_group,
|
55
57
|
auto_complete=self.auto_complete,
|
58
|
+
non_interactive=self.non_interactive,
|
56
59
|
need_summary=self.need_summary,
|
57
60
|
summary_prompt=self.summary_prompt,
|
58
61
|
execute_tool_confirm=self.execute_tool_confirm,
|
@@ -89,4 +92,8 @@ class AgentConfig:
|
|
89
92
|
if cfg.force_save_memory is None:
|
90
93
|
cfg.force_save_memory = is_force_save_memory()
|
91
94
|
|
95
|
+
# 非交互模式下默认开启自动完成
|
96
|
+
if is_non_interactive():
|
97
|
+
cfg.auto_complete = True
|
98
|
+
|
92
99
|
return cfg
|
@@ -19,6 +19,8 @@ from jarvis.jarvis_utils.config import (
|
|
19
19
|
get_multi_agent_dirs,
|
20
20
|
get_roles_dirs,
|
21
21
|
get_data_dir,
|
22
|
+
set_config,
|
23
|
+
is_non_interactive,
|
22
24
|
)
|
23
25
|
import jarvis.jarvis_utils.utils as jutils
|
24
26
|
from jarvis.jarvis_utils.input import user_confirm, get_single_line_input
|
@@ -26,10 +28,37 @@ from jarvis.jarvis_utils.fzf import fzf_select
|
|
26
28
|
import os
|
27
29
|
import subprocess
|
28
30
|
from pathlib import Path
|
31
|
+
import signal
|
29
32
|
import yaml # type: ignore
|
30
33
|
from rich.table import Table
|
31
34
|
from rich.console import Console
|
32
35
|
|
36
|
+
import sys
|
37
|
+
|
38
|
+
|
39
|
+
def _normalize_backup_data_argv(argv: List[str]) -> None:
|
40
|
+
"""
|
41
|
+
兼容旧版 Click/Typer 对可选参数的解析差异:
|
42
|
+
若用户仅提供 --backup-data 而不跟参数,则在解析前注入默认目录。
|
43
|
+
"""
|
44
|
+
try:
|
45
|
+
i = 0
|
46
|
+
while i < len(argv):
|
47
|
+
tok = argv[i]
|
48
|
+
if tok == "--backup-data":
|
49
|
+
# 情况1:位于末尾,无参数
|
50
|
+
# 情况2:后续是下一个选项(以 '-' 开头),表示未提供参数
|
51
|
+
if i == len(argv) - 1 or (i + 1 < len(argv) and argv[i + 1].startswith("-")):
|
52
|
+
argv.insert(i + 1, "~/jarvis_backups")
|
53
|
+
i += 1 # 跳过我们插入的默认值,避免重复插入
|
54
|
+
i += 1
|
55
|
+
except Exception:
|
56
|
+
# 静默忽略任何异常,避免影响主流程
|
57
|
+
pass
|
58
|
+
|
59
|
+
|
60
|
+
_normalize_backup_data_argv(sys.argv)
|
61
|
+
|
33
62
|
app = typer.Typer(help="Jarvis AI 助手")
|
34
63
|
|
35
64
|
|
@@ -187,9 +216,9 @@ def handle_interactive_config_option(
|
|
187
216
|
return True
|
188
217
|
|
189
218
|
|
190
|
-
def handle_backup_option(
|
219
|
+
def handle_backup_option(backup_dir_path: Optional[str]) -> bool:
|
191
220
|
"""处理数据备份选项,返回是否已处理并需提前结束。"""
|
192
|
-
if
|
221
|
+
if backup_dir_path is None:
|
193
222
|
return False
|
194
223
|
|
195
224
|
init_env("", config_file=None)
|
@@ -198,7 +227,8 @@ def handle_backup_option(backup: bool) -> bool:
|
|
198
227
|
PrettyOutput.print(f"数据目录不存在: {data_dir}", OutputType.ERROR)
|
199
228
|
return True
|
200
229
|
|
201
|
-
|
230
|
+
backup_dir_str = backup_dir_path if backup_dir_path.strip() else "~/jarvis_backups"
|
231
|
+
backup_dir = Path(os.path.expanduser(backup_dir_str))
|
202
232
|
backup_dir.mkdir(exist_ok=True)
|
203
233
|
|
204
234
|
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
@@ -290,6 +320,9 @@ def try_switch_to_jca_if_git_repo(
|
|
290
320
|
task: Optional[str],
|
291
321
|
) -> None:
|
292
322
|
"""在初始化环境前检测Git仓库,并可选择自动切换到代码开发模式(jca)。"""
|
323
|
+
# 非交互模式下跳过代码模式切换提示与相关输出
|
324
|
+
if is_non_interactive():
|
325
|
+
return
|
293
326
|
if is_enable_git_repo_jca_switch():
|
294
327
|
try:
|
295
328
|
res = subprocess.run(
|
@@ -632,12 +665,23 @@ def run_cli(
|
|
632
665
|
"--disable-methodology-analysis",
|
633
666
|
help="禁用方法论和任务分析(覆盖配置文件设置)",
|
634
667
|
),
|
635
|
-
backup_data:
|
636
|
-
|
668
|
+
backup_data: Optional[str] = typer.Option(
|
669
|
+
None,
|
670
|
+
"--backup-data",
|
671
|
+
help="备份 Jarvis 数据目录. 可选地传入备份目录. 默认为 '~/jarvis_backups'",
|
672
|
+
show_default=False,
|
673
|
+
flag_value="~/jarvis_backups",
|
637
674
|
),
|
638
675
|
restore_data: Optional[str] = typer.Option(
|
639
676
|
None, "--restore-data", help="从指定的压缩包恢复 Jarvis 数据"
|
640
677
|
),
|
678
|
+
non_interactive: bool = typer.Option(
|
679
|
+
False, "-n", "--non-interactive", help="启用非交互模式:用户无法与命令交互,脚本执行超时限制为5分钟"
|
680
|
+
),
|
681
|
+
web: bool = typer.Option(False, "--web", help="以 Web 模式启动,通过浏览器 WebSocket 交互"),
|
682
|
+
web_host: str = typer.Option("127.0.0.1", "--web-host", help="Web 服务主机"),
|
683
|
+
web_port: int = typer.Option(8765, "--web-port", help="Web 服务端口"),
|
684
|
+
stop: bool = typer.Option(False, "--stop", help="停止后台 Web 服务(需与 --web 一起使用)"),
|
641
685
|
) -> None:
|
642
686
|
"""Jarvis AI assistant command-line interface."""
|
643
687
|
if ctx.invoked_subcommand is not None:
|
@@ -646,6 +690,37 @@ def run_cli(
|
|
646
690
|
# 使用 rich 输出命令与快捷方式总览
|
647
691
|
print_commands_overview()
|
648
692
|
|
693
|
+
# CLI 标志:非交互模式(不依赖配置文件)
|
694
|
+
if non_interactive:
|
695
|
+
try:
|
696
|
+
os.environ["JARVIS_NON_INTERACTIVE"] = "true"
|
697
|
+
except Exception:
|
698
|
+
pass
|
699
|
+
# 注意:全局配置同步在 init_env 之后执行,避免被覆盖
|
700
|
+
|
701
|
+
# 同步其他 CLI 选项到全局配置,确保后续模块读取一致
|
702
|
+
try:
|
703
|
+
if model_group:
|
704
|
+
set_config("JARVIS_LLM_GROUP", str(model_group))
|
705
|
+
if tool_group:
|
706
|
+
set_config("JARVIS_TOOL_GROUP", str(tool_group))
|
707
|
+
if disable_methodology_analysis:
|
708
|
+
set_config("JARVIS_USE_METHODOLOGY", False)
|
709
|
+
set_config("JARVIS_USE_ANALYSIS", False)
|
710
|
+
if restore_session:
|
711
|
+
set_config("JARVIS_RESTORE_SESSION", True)
|
712
|
+
except Exception:
|
713
|
+
# 静默忽略同步异常,不影响主流程
|
714
|
+
pass
|
715
|
+
|
716
|
+
# 非交互模式要求从命令行传入任务
|
717
|
+
if non_interactive and not (task and str(task).strip()):
|
718
|
+
PrettyOutput.print(
|
719
|
+
"非交互模式已启用:必须使用 --task 传入任务内容,因多行输入不可用。",
|
720
|
+
OutputType.ERROR,
|
721
|
+
)
|
722
|
+
raise typer.Exit(code=2)
|
723
|
+
|
649
724
|
# 处理数据备份
|
650
725
|
if handle_backup_option(backup_data):
|
651
726
|
return
|
@@ -672,30 +747,319 @@ def run_cli(
|
|
672
747
|
|
673
748
|
# 预加载配置(仅用于读取功能开关),不会显示欢迎信息或影响后续 init_env
|
674
749
|
preload_config_for_flags(config_file)
|
750
|
+
# Web 模式后台管理:支持 --web 后台启动与 --web --stop 停止
|
751
|
+
if web:
|
752
|
+
# PID 文件路径(按端口区分,便于多实例)
|
753
|
+
pidfile = Path(os.path.expanduser("~/.jarvis")) / f"jarvis_web_{web_port}.pid"
|
754
|
+
# 停止后台服务
|
755
|
+
if stop:
|
756
|
+
try:
|
757
|
+
pf = pidfile
|
758
|
+
if not pf.exists():
|
759
|
+
# 兼容旧版本:回退检查数据目录中的旧 PID 文件位置
|
760
|
+
try:
|
761
|
+
pf_alt = Path(os.path.expanduser(os.path.expandvars(get_data_dir()))) / f"jarvis_web_{web_port}.pid"
|
762
|
+
except Exception:
|
763
|
+
pf_alt = None # type: ignore[assignment]
|
764
|
+
if pf_alt and pf_alt.exists(): # type: ignore[truthy-bool]
|
765
|
+
pf = pf_alt
|
766
|
+
if not pf.exists():
|
767
|
+
# 进一步回退:尝试按端口查找并停止(无 PID 文件)
|
768
|
+
killed_any = False
|
769
|
+
try:
|
770
|
+
res = subprocess.run(
|
771
|
+
["lsof", "-iTCP:%d" % web_port, "-sTCP:LISTEN", "-t"],
|
772
|
+
capture_output=True,
|
773
|
+
text=True,
|
774
|
+
)
|
775
|
+
if res.returncode == 0 and res.stdout.strip():
|
776
|
+
for ln in res.stdout.strip().splitlines():
|
777
|
+
try:
|
778
|
+
candidate_pid = int(ln.strip())
|
779
|
+
try:
|
780
|
+
os.kill(candidate_pid, signal.SIGTERM)
|
781
|
+
PrettyOutput.print(f"已按端口停止后台 Web 服务 (PID {candidate_pid})。", OutputType.SUCCESS)
|
782
|
+
killed_any = True
|
783
|
+
except Exception as e:
|
784
|
+
PrettyOutput.print(f"按端口停止失败: {e}", OutputType.WARNING)
|
785
|
+
except Exception:
|
786
|
+
continue
|
787
|
+
except Exception:
|
788
|
+
pass
|
789
|
+
if not killed_any:
|
790
|
+
try:
|
791
|
+
res2 = subprocess.run(["ss", "-ltpn"], capture_output=True, text=True)
|
792
|
+
if res2.returncode == 0 and res2.stdout:
|
793
|
+
for ln in res2.stdout.splitlines():
|
794
|
+
if f":{web_port} " in ln or f":{web_port}\n" in ln:
|
795
|
+
try:
|
796
|
+
idx = ln.find("pid=")
|
797
|
+
if idx != -1:
|
798
|
+
end = ln.find(",", idx)
|
799
|
+
pid_str2 = ln[idx+4:end if end != -1 else None]
|
800
|
+
candidate_pid = int(pid_str2)
|
801
|
+
try:
|
802
|
+
os.kill(candidate_pid, signal.SIGTERM)
|
803
|
+
PrettyOutput.print(f"已按端口停止后台 Web 服务 (PID {candidate_pid})。", OutputType.SUCCESS)
|
804
|
+
killed_any = True
|
805
|
+
except Exception as e:
|
806
|
+
PrettyOutput.print(f"按端口停止失败: {e}", OutputType.WARNING)
|
807
|
+
break
|
808
|
+
except Exception:
|
809
|
+
continue
|
810
|
+
except Exception:
|
811
|
+
pass
|
812
|
+
# 若仍未找到,扫描家目录下所有 Web PID 文件,尽力停止所有实例
|
813
|
+
if not killed_any:
|
814
|
+
try:
|
815
|
+
pid_dir = Path(os.path.expanduser("~/.jarvis"))
|
816
|
+
if pid_dir.is_dir():
|
817
|
+
for f in pid_dir.glob("jarvis_web_*.pid"):
|
818
|
+
try:
|
819
|
+
ptxt = f.read_text(encoding="utf-8").strip()
|
820
|
+
p = int(ptxt)
|
821
|
+
try:
|
822
|
+
os.kill(p, signal.SIGTERM)
|
823
|
+
PrettyOutput.print(f"已停止后台 Web 服务 (PID {p})。", OutputType.SUCCESS)
|
824
|
+
killed_any = True
|
825
|
+
except Exception as e:
|
826
|
+
PrettyOutput.print(f"停止 PID {p} 失败: {e}", OutputType.WARNING)
|
827
|
+
except Exception:
|
828
|
+
pass
|
829
|
+
try:
|
830
|
+
f.unlink(missing_ok=True)
|
831
|
+
except Exception:
|
832
|
+
pass
|
833
|
+
except Exception:
|
834
|
+
pass
|
835
|
+
if not killed_any:
|
836
|
+
PrettyOutput.print("未找到后台 Web 服务的 PID 文件,可能未启动或已停止。", OutputType.WARNING)
|
837
|
+
return
|
838
|
+
# 优先使用 PID 文件中的 PID
|
839
|
+
try:
|
840
|
+
pid_str = pf.read_text(encoding="utf-8").strip()
|
841
|
+
pid = int(pid_str)
|
842
|
+
except Exception:
|
843
|
+
pid = 0
|
844
|
+
killed = False
|
845
|
+
if pid > 0:
|
846
|
+
try:
|
847
|
+
os.kill(pid, signal.SIGTERM)
|
848
|
+
PrettyOutput.print(f"已向后台 Web 服务发送停止信号 (PID {pid})。", OutputType.SUCCESS)
|
849
|
+
killed = True
|
850
|
+
except Exception as e:
|
851
|
+
PrettyOutput.print(f"发送停止信号失败或进程不存在: {e}", OutputType.WARNING)
|
852
|
+
if not killed:
|
853
|
+
# 无 PID 文件或停止失败时,尝试按端口查找进程
|
854
|
+
candidate_pid = 0
|
855
|
+
try:
|
856
|
+
res = subprocess.run(
|
857
|
+
["lsof", "-iTCP:%d" % web_port, "-sTCP:LISTEN", "-t"],
|
858
|
+
capture_output=True,
|
859
|
+
text=True,
|
860
|
+
)
|
861
|
+
if res.returncode == 0 and res.stdout.strip():
|
862
|
+
for ln in res.stdout.strip().splitlines():
|
863
|
+
try:
|
864
|
+
candidate_pid = int(ln.strip())
|
865
|
+
break
|
866
|
+
except Exception:
|
867
|
+
continue
|
868
|
+
except Exception:
|
869
|
+
pass
|
870
|
+
if not candidate_pid:
|
871
|
+
try:
|
872
|
+
res2 = subprocess.run(["ss", "-ltpn"], capture_output=True, text=True)
|
873
|
+
if res2.returncode == 0 and res2.stdout:
|
874
|
+
for ln in res2.stdout.splitlines():
|
875
|
+
if f":{web_port} " in ln or f":{web_port}\n" in ln:
|
876
|
+
# 格式示例: LISTEN ... users:(("uvicorn",pid=12345,fd=7))
|
877
|
+
try:
|
878
|
+
idx = ln.find("pid=")
|
879
|
+
if idx != -1:
|
880
|
+
end = ln.find(",", idx)
|
881
|
+
pid_str2 = ln[idx+4:end if end != -1 else None]
|
882
|
+
candidate_pid = int(pid_str2)
|
883
|
+
break
|
884
|
+
except Exception:
|
885
|
+
continue
|
886
|
+
except Exception:
|
887
|
+
pass
|
888
|
+
if candidate_pid:
|
889
|
+
try:
|
890
|
+
os.kill(candidate_pid, signal.SIGTERM)
|
891
|
+
PrettyOutput.print(f"已按端口停止后台 Web 服务 (PID {candidate_pid})。", OutputType.SUCCESS)
|
892
|
+
killed = True
|
893
|
+
except Exception as e:
|
894
|
+
PrettyOutput.print(f"按端口停止失败: {e}", OutputType.WARNING)
|
895
|
+
# 清理可能存在的 PID 文件(两个位置)
|
896
|
+
try:
|
897
|
+
pidfile.unlink(missing_ok=True) # 家目录位置
|
898
|
+
except Exception:
|
899
|
+
pass
|
900
|
+
try:
|
901
|
+
alt_pf = Path(os.path.expanduser(os.path.expandvars(get_data_dir()))) / f"jarvis_web_{web_port}.pid"
|
902
|
+
alt_pf.unlink(missing_ok=True)
|
903
|
+
except Exception:
|
904
|
+
pass
|
905
|
+
except Exception as e:
|
906
|
+
PrettyOutput.print(f"停止后台 Web 服务失败: {e}", OutputType.ERROR)
|
907
|
+
finally:
|
908
|
+
return
|
909
|
+
# 后台启动:父进程拉起子进程并记录 PID
|
910
|
+
is_daemon = False
|
911
|
+
try:
|
912
|
+
is_daemon = os.environ.get("JARVIS_WEB_DAEMON") == "1"
|
913
|
+
except Exception:
|
914
|
+
is_daemon = False
|
915
|
+
if not is_daemon:
|
916
|
+
try:
|
917
|
+
# 构建子进程参数,传递关键配置
|
918
|
+
args = [
|
919
|
+
sys.executable,
|
920
|
+
"-m",
|
921
|
+
"jarvis.jarvis_agent.jarvis",
|
922
|
+
"--web",
|
923
|
+
"--web-host",
|
924
|
+
str(web_host),
|
925
|
+
"--web-port",
|
926
|
+
str(web_port),
|
927
|
+
]
|
928
|
+
if model_group:
|
929
|
+
args += ["-g", str(model_group)]
|
930
|
+
if tool_group:
|
931
|
+
args += ["-G", str(tool_group)]
|
932
|
+
if config_file:
|
933
|
+
args += ["-f", str(config_file)]
|
934
|
+
if restore_session:
|
935
|
+
args += ["--restore-session"]
|
936
|
+
if disable_methodology_analysis:
|
937
|
+
args += ["-D"]
|
938
|
+
if non_interactive:
|
939
|
+
args += ["-n"]
|
940
|
+
env = os.environ.copy()
|
941
|
+
env["JARVIS_WEB_DAEMON"] = "1"
|
942
|
+
# 启动子进程(后台运行)
|
943
|
+
proc = subprocess.Popen(
|
944
|
+
args,
|
945
|
+
env=env,
|
946
|
+
stdout=subprocess.DEVNULL,
|
947
|
+
stderr=subprocess.DEVNULL,
|
948
|
+
stdin=subprocess.DEVNULL,
|
949
|
+
close_fds=True,
|
950
|
+
)
|
951
|
+
# 记录 PID 到文件
|
952
|
+
try:
|
953
|
+
pidfile.parent.mkdir(parents=True, exist_ok=True)
|
954
|
+
except Exception:
|
955
|
+
pass
|
956
|
+
try:
|
957
|
+
pidfile.write_text(str(proc.pid), encoding="utf-8")
|
958
|
+
except Exception:
|
959
|
+
pass
|
960
|
+
PrettyOutput.print(
|
961
|
+
f"Web 服务已在后台启动 (PID {proc.pid}),地址: http://{web_host}:{web_port}",
|
962
|
+
OutputType.SUCCESS,
|
963
|
+
)
|
964
|
+
except Exception as e:
|
965
|
+
PrettyOutput.print(f"后台启动 Web 服务失败: {e}", OutputType.ERROR)
|
966
|
+
raise typer.Exit(code=1)
|
967
|
+
return
|
675
968
|
|
676
969
|
# 在初始化环境前检测Git仓库,并可选择自动切换到代码开发模式(jca)
|
677
|
-
|
678
|
-
|
679
|
-
|
970
|
+
if not non_interactive and not web:
|
971
|
+
try_switch_to_jca_if_git_repo(
|
972
|
+
model_group, tool_group, config_file, restore_session, task
|
973
|
+
)
|
680
974
|
|
681
975
|
# 在进入默认通用代理前,列出内置配置供选择(agent/multi_agent/roles)
|
682
|
-
|
976
|
+
# 非交互模式下跳过内置角色/配置选择
|
977
|
+
if not non_interactive and not web:
|
978
|
+
handle_builtin_config_selector(model_group, tool_group, config_file, task)
|
683
979
|
|
684
980
|
# 初始化环境
|
685
981
|
init_env(
|
686
982
|
"欢迎使用 Jarvis AI 助手,您的智能助理已准备就绪!", config_file=config_file
|
687
983
|
)
|
688
984
|
|
985
|
+
# 在初始化环境后同步 CLI 选项到全局配置,避免被 init_env 覆盖
|
986
|
+
try:
|
987
|
+
if model_group:
|
988
|
+
set_config("JARVIS_LLM_GROUP", str(model_group))
|
989
|
+
if tool_group:
|
990
|
+
set_config("JARVIS_TOOL_GROUP", str(tool_group))
|
991
|
+
if disable_methodology_analysis:
|
992
|
+
set_config("JARVIS_USE_METHODOLOGY", False)
|
993
|
+
set_config("JARVIS_USE_ANALYSIS", False)
|
994
|
+
if restore_session:
|
995
|
+
set_config("JARVIS_RESTORE_SESSION", True)
|
996
|
+
if non_interactive:
|
997
|
+
# 保持运行期非交互标志
|
998
|
+
set_config("JARVIS_NON_INTERACTIVE", True)
|
999
|
+
except Exception:
|
1000
|
+
# 静默忽略同步异常,不影响主流程
|
1001
|
+
pass
|
1002
|
+
|
689
1003
|
# 运行主流程
|
690
1004
|
try:
|
1005
|
+
# 在 Web 模式下注入基于 WebSocket 的输入/确认回调
|
1006
|
+
extra_kwargs = {}
|
1007
|
+
if web:
|
1008
|
+
try:
|
1009
|
+
from jarvis.jarvis_agent.web_bridge import web_multiline_input, web_user_confirm
|
1010
|
+
extra_kwargs["multiline_inputer"] = web_multiline_input
|
1011
|
+
extra_kwargs["confirm_callback"] = web_user_confirm
|
1012
|
+
except Exception as e:
|
1013
|
+
PrettyOutput.print(f"Web 模式初始化失败(加载 Web 桥接模块): {e}", OutputType.ERROR)
|
1014
|
+
raise typer.Exit(code=1)
|
1015
|
+
|
691
1016
|
agent_manager = AgentManager(
|
692
1017
|
model_group=model_group,
|
693
1018
|
tool_group=tool_group,
|
694
1019
|
restore_session=restore_session,
|
695
1020
|
use_methodology=False if disable_methodology_analysis else None,
|
696
1021
|
use_analysis=False if disable_methodology_analysis else None,
|
1022
|
+
**extra_kwargs,
|
697
1023
|
)
|
698
|
-
agent_manager.initialize()
|
1024
|
+
agent = agent_manager.initialize()
|
1025
|
+
|
1026
|
+
if web:
|
1027
|
+
try:
|
1028
|
+
|
1029
|
+
from jarvis.jarvis_agent.web_server import start_web_server
|
1030
|
+
from jarvis.jarvis_agent.stdio_redirect import enable_web_stdio_redirect, enable_web_stdin_redirect
|
1031
|
+
# 在 Web 模式下固定TTY宽度为200,改善前端显示效果
|
1032
|
+
try:
|
1033
|
+
import os as _os
|
1034
|
+
_os.environ["COLUMNS"] = "200"
|
1035
|
+
# 尝试固定全局 Console 的宽度(PrettyOutput 使用该 Console 实例)
|
1036
|
+
try:
|
1037
|
+
from jarvis.jarvis_utils.globals import console as _console
|
1038
|
+
try:
|
1039
|
+
_console._width = 200 # rich Console的固定宽度参数
|
1040
|
+
except Exception:
|
1041
|
+
pass
|
1042
|
+
except Exception:
|
1043
|
+
pass
|
1044
|
+
except Exception:
|
1045
|
+
pass
|
1046
|
+
# 使用 STDIO 重定向,取消 Sink 广播以避免重复输出
|
1047
|
+
# 启用标准输出/错误的WebSocket重定向(捕获工具直接打印的输出)
|
1048
|
+
enable_web_stdio_redirect()
|
1049
|
+
# 启用来自前端 xterm 的 STDIN 重定向,使交互式命令可从浏览器获取输入
|
1050
|
+
try:
|
1051
|
+
enable_web_stdin_redirect()
|
1052
|
+
except Exception:
|
1053
|
+
pass
|
1054
|
+
PrettyOutput.print("以 Web 模式启动,请在浏览器中打开提供的地址进行交互。", OutputType.INFO)
|
1055
|
+
# 启动 Web 服务(阻塞调用)
|
1056
|
+
start_web_server(agent_manager, host=web_host, port=web_port)
|
1057
|
+
return
|
1058
|
+
except Exception as e:
|
1059
|
+
PrettyOutput.print(f"Web 模式启动失败: {e}", OutputType.ERROR)
|
1060
|
+
raise typer.Exit(code=1)
|
1061
|
+
|
1062
|
+
# 默认 CLI 模式:运行任务(可能来自 --task 或交互输入)
|
699
1063
|
agent_manager.run_task(task)
|
700
1064
|
except typer.Exit:
|
701
1065
|
raise
|