jarvis-ai-assistant 0.3.34__tar.gz → 0.4.1__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.34/src/jarvis_ai_assistant.egg-info → jarvis_ai_assistant-0.4.1}/PKG-INFO +1 -1
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/pyproject.toml +1 -1
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/setup.py +1 -1
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/__init__.py +1 -1
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_agent/__init__.py +44 -12
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_agent/agent_manager.py +14 -10
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_agent/config.py +2 -1
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_agent/edit_file_handler.py +2 -2
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_agent/jarvis.py +305 -1
- jarvis_ai_assistant-0.4.1/src/jarvis/jarvis_agent/rewrite_file_handler.py +143 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_agent/run_loop.py +5 -4
- jarvis_ai_assistant-0.4.1/src/jarvis/jarvis_agent/stdio_redirect.py +296 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_agent/utils.py +5 -1
- jarvis_ai_assistant-0.4.1/src/jarvis/jarvis_agent/web_bridge.py +189 -0
- jarvis_ai_assistant-0.4.1/src/jarvis/jarvis_agent/web_output_sink.py +53 -0
- jarvis_ai_assistant-0.4.1/src/jarvis/jarvis_agent/web_server.py +745 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_code_agent/code_agent.py +10 -12
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_code_analysis/code_review.py +0 -1
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_data/config_schema.json +5 -0
- jarvis_ai_assistant-0.4.1/src/jarvis/jarvis_multi_agent/__init__.py +389 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_multi_agent/main.py +10 -2
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_platform/base.py +16 -6
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_tools/sub_agent.py +11 -38
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_tools/sub_code_agent.py +3 -1
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_utils/config.py +12 -2
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1/src/jarvis_ai_assistant.egg-info}/PKG-INFO +1 -1
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis_ai_assistant.egg-info/SOURCES.txt +5 -2
- jarvis_ai_assistant-0.3.34/src/jarvis/jarvis_multi_agent/__init__.py +0 -209
- jarvis_ai_assistant-0.3.34/src/jarvis/jarvis_tools/edit_file.py +0 -208
- jarvis_ai_assistant-0.3.34/src/jarvis/jarvis_tools/rewrite_file.py +0 -191
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/LICENSE +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/MANIFEST.in +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/README.md +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/setup.cfg +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_agent/builtin_input_handler.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_agent/config_editor.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_agent/event_bus.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_agent/events.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_agent/file_context_handler.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_agent/file_methodology_manager.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_agent/main.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_agent/memory_manager.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_agent/methodology_share_manager.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_agent/output_handler.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_agent/prompt_builder.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_agent/prompt_manager.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_agent/prompts.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_agent/protocols.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_agent/session_manager.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_agent/share_manager.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_agent/shell_input_handler.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_agent/task_analyzer.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_agent/task_manager.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_agent/tool_executor.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_agent/tool_share_manager.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_agent/user_interaction.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_code_agent/__init__.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_code_agent/lint.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_code_analysis/checklists/__init__.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_code_analysis/checklists/c_cpp.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_code_analysis/checklists/csharp.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_code_analysis/checklists/data_format.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_code_analysis/checklists/devops.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_code_analysis/checklists/docs.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_code_analysis/checklists/go.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_code_analysis/checklists/infrastructure.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_code_analysis/checklists/java.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_code_analysis/checklists/javascript.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_code_analysis/checklists/kotlin.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_code_analysis/checklists/loader.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_code_analysis/checklists/php.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_code_analysis/checklists/python.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_code_analysis/checklists/ruby.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_code_analysis/checklists/rust.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_code_analysis/checklists/shell.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_code_analysis/checklists/sql.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_code_analysis/checklists/swift.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_code_analysis/checklists/web.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_data/tiktoken/9b5ad71b2ce5302211f9c61530b329a4922fc6a4 +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_git_squash/__init__.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_git_squash/main.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_git_utils/git_commiter.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_mcp/__init__.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_mcp/sse_mcp_client.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_mcp/stdio_mcp_client.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_mcp/streamable_mcp_client.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_memory_organizer/__init__.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_memory_organizer/memory_organizer.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_methodology/main.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_platform/__init__.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_platform/ai8.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_platform/human.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_platform/kimi.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_platform/openai.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_platform/registry.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_platform/tongyi.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_platform/yuanbao.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_platform_manager/__init__.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_platform_manager/main.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_platform_manager/service.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_rag/__init__.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_rag/cache.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_rag/cli.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_rag/embedding_manager.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_rag/llm_interface.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_rag/query_rewriter.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_rag/rag_pipeline.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_rag/reranker.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_rag/retriever.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_smart_shell/__init__.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_smart_shell/main.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_stats/__init__.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_stats/cli.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_stats/stats.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_stats/storage.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_stats/visualizer.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_tools/__init__.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_tools/ask_user.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_tools/base.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_tools/clear_memory.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_tools/cli/__init__.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_tools/cli/main.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_tools/execute_script.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_tools/file_analyzer.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_tools/generate_new_tool.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_tools/methodology.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_tools/read_code.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_tools/read_webpage.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_tools/registry.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_tools/retrieve_memory.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_tools/save_memory.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_tools/search_web.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_tools/virtual_tty.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_utils/__init__.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_utils/builtin_replace_map.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_utils/clipboard.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_utils/embedding.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_utils/file_processors.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_utils/fzf.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_utils/git_utils.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_utils/globals.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_utils/http.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_utils/input.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_utils/methodology.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_utils/output.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_utils/tag.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_utils/utils.py +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis_ai_assistant.egg-info/dependency_links.txt +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis_ai_assistant.egg-info/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/src/jarvis_ai_assistant.egg-info/requires.txt +0 -0
- {jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/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.1"
|
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.1",
|
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.34 → jarvis_ai_assistant-0.4.1}/src/jarvis/jarvis_agent/__init__.py
RENAMED
@@ -31,6 +31,8 @@ from jarvis.jarvis_agent.prompts import (
|
|
31
31
|
TASK_ANALYSIS_PROMPT,
|
32
32
|
)
|
33
33
|
from jarvis.jarvis_tools.registry import ToolRegistry
|
34
|
+
from jarvis.jarvis_agent.edit_file_handler import EditFileHandler
|
35
|
+
from jarvis.jarvis_agent.rewrite_file_handler import RewriteFileHandler
|
34
36
|
from jarvis.jarvis_agent.prompt_manager import PromptManager
|
35
37
|
from jarvis.jarvis_agent.event_bus import EventBus
|
36
38
|
from jarvis.jarvis_agent.config import AgentConfig
|
@@ -54,6 +56,9 @@ from jarvis.jarvis_agent.events import (
|
|
54
56
|
from jarvis.jarvis_agent.user_interaction import UserInteractionHandler
|
55
57
|
from jarvis.jarvis_agent.utils import join_prompts
|
56
58
|
from jarvis.jarvis_utils.methodology import _load_all_methodologies
|
59
|
+
from jarvis.jarvis_agent.shell_input_handler import shell_input_handler
|
60
|
+
from jarvis.jarvis_agent.file_context_handler import file_context_handler
|
61
|
+
from jarvis.jarvis_agent.builtin_input_handler import builtin_input_handler
|
57
62
|
|
58
63
|
# jarvis_platform 相关
|
59
64
|
from jarvis.jarvis_platform.base import BasePlatform
|
@@ -71,6 +76,7 @@ from jarvis.jarvis_utils.config import (
|
|
71
76
|
is_use_methodology,
|
72
77
|
get_tool_filter_threshold,
|
73
78
|
get_after_tool_call_cb_dirs,
|
79
|
+
set_config,
|
74
80
|
)
|
75
81
|
from jarvis.jarvis_utils.embedding import get_context_token_count
|
76
82
|
from jarvis.jarvis_utils.globals import (
|
@@ -274,7 +280,6 @@ class Agent:
|
|
274
280
|
auto_complete: bool = False,
|
275
281
|
output_handler: Optional[List[OutputHandlerProtocol]] = None,
|
276
282
|
use_tools: Optional[List[str]] = None,
|
277
|
-
input_handler: Optional[List[Callable[[str, Any], Tuple[str, bool]]]] = None,
|
278
283
|
execute_tool_confirm: Optional[bool] = None,
|
279
284
|
need_summary: bool = True,
|
280
285
|
multiline_inputer: Optional[Callable[[str], str]] = None,
|
@@ -283,6 +288,8 @@ class Agent:
|
|
283
288
|
force_save_memory: Optional[bool] = None,
|
284
289
|
files: Optional[List[str]] = None,
|
285
290
|
confirm_callback: Optional[Callable[[str, bool], bool]] = None,
|
291
|
+
non_interactive: Optional[bool] = None,
|
292
|
+
**kwargs,
|
286
293
|
):
|
287
294
|
"""初始化Jarvis Agent实例
|
288
295
|
|
@@ -293,8 +300,6 @@ class Agent:
|
|
293
300
|
|
294
301
|
summary_prompt: 任务总结提示模板
|
295
302
|
auto_complete: 是否自动完成任务
|
296
|
-
output_handler: 输出处理器列表
|
297
|
-
input_handler: 输入处理器列表
|
298
303
|
execute_tool_confirm: 执行工具前是否需要确认
|
299
304
|
need_summary: 是否需要生成总结
|
300
305
|
multiline_inputer: 多行输入处理器
|
@@ -302,6 +307,7 @@ class Agent:
|
|
302
307
|
use_analysis: 是否使用任务分析
|
303
308
|
force_save_memory: 是否强制保存记忆
|
304
309
|
confirm_callback: 用户确认回调函数,签名为 (tip: str, default: bool) -> bool;默认使用CLI的user_confirm
|
310
|
+
non_interactive: 是否以非交互模式运行(优先级最高,覆盖环境变量与配置)
|
305
311
|
"""
|
306
312
|
# 基础属性初始化
|
307
313
|
self.files = files or []
|
@@ -326,15 +332,33 @@ class Agent:
|
|
326
332
|
|
327
333
|
# 初始化处理器
|
328
334
|
self._init_handlers(
|
329
|
-
output_handler or [],
|
330
|
-
input_handler,
|
331
335
|
multiline_inputer,
|
336
|
+
output_handler,
|
332
337
|
use_tools or [],
|
333
338
|
)
|
334
339
|
# 初始化用户交互封装,保持向后兼容
|
335
340
|
self.user_interaction = UserInteractionHandler(self.multiline_inputer, self.user_confirm)
|
336
341
|
# 将确认函数指向封装后的 confirm,保持既有调用不变
|
337
342
|
self.user_confirm = self.user_interaction.confirm # type: ignore[assignment]
|
343
|
+
# 非交互模式参数支持:允许通过构造参数显式控制,便于其他Agent调用时设置
|
344
|
+
try:
|
345
|
+
# 优先使用构造参数,其次回退到环境变量
|
346
|
+
self.non_interactive = (
|
347
|
+
bool(non_interactive)
|
348
|
+
if non_interactive is not None
|
349
|
+
else str(os.environ.get("JARVIS_NON_INTERACTIVE", "")).lower() in ("1", "true", "yes")
|
350
|
+
)
|
351
|
+
# 如果构造参数显式提供,则同步到环境变量与全局配置,供下游组件读取
|
352
|
+
if non_interactive is not None:
|
353
|
+
os.environ["JARVIS_NON_INTERACTIVE"] = "true" if self.non_interactive else "false"
|
354
|
+
try:
|
355
|
+
set_config("JARVIS_NON_INTERACTIVE", self.non_interactive)
|
356
|
+
except Exception:
|
357
|
+
# 配置同步失败不影响主流程
|
358
|
+
pass
|
359
|
+
except Exception:
|
360
|
+
# 防御式回退
|
361
|
+
self.non_interactive = False
|
338
362
|
|
339
363
|
# 初始化配置
|
340
364
|
self._init_config(
|
@@ -394,15 +418,18 @@ class Agent:
|
|
394
418
|
|
395
419
|
def _init_handlers(
|
396
420
|
self,
|
397
|
-
output_handler: List[OutputHandlerProtocol],
|
398
|
-
input_handler: Optional[List[Callable[[str, Any], Tuple[str, bool]]]],
|
399
421
|
multiline_inputer: Optional[Callable[[str], str]],
|
422
|
+
output_handler: Optional[List[OutputHandlerProtocol]],
|
400
423
|
use_tools: List[str],
|
401
424
|
):
|
402
425
|
"""初始化各种处理器"""
|
403
|
-
self.output_handler = output_handler or [ToolRegistry()]
|
426
|
+
self.output_handler = output_handler or [ToolRegistry(), EditFileHandler(), RewriteFileHandler()]
|
404
427
|
self.set_use_tools(use_tools)
|
405
|
-
self.input_handler =
|
428
|
+
self.input_handler = [
|
429
|
+
builtin_input_handler,
|
430
|
+
shell_input_handler,
|
431
|
+
file_context_handler,
|
432
|
+
]
|
406
433
|
self.multiline_inputer = multiline_inputer or get_multiline_input
|
407
434
|
|
408
435
|
def _init_config(
|
@@ -897,13 +924,17 @@ class Agent:
|
|
897
924
|
|
898
925
|
if self.need_summary:
|
899
926
|
|
900
|
-
|
927
|
+
# 确保总结提示词非空:若为None或仅空白,则回退到默认提示词
|
928
|
+
safe_summary_prompt = self.summary_prompt or ""
|
929
|
+
if isinstance(safe_summary_prompt, str) and safe_summary_prompt.strip() == "":
|
930
|
+
safe_summary_prompt = DEFAULT_SUMMARY_PROMPT
|
931
|
+
# 注意:不要写回 session.prompt,避免 BEFORE_SUMMARY 事件回调修改/清空后导致使用空prompt
|
901
932
|
# 广播将要生成总结事件
|
902
933
|
try:
|
903
934
|
self.event_bus.emit(
|
904
935
|
BEFORE_SUMMARY,
|
905
936
|
agent=self,
|
906
|
-
prompt=
|
937
|
+
prompt=safe_summary_prompt,
|
907
938
|
auto_completed=auto_completed,
|
908
939
|
need_summary=self.need_summary,
|
909
940
|
)
|
@@ -912,7 +943,8 @@ class Agent:
|
|
912
943
|
|
913
944
|
if not self.model:
|
914
945
|
raise RuntimeError("Model not initialized")
|
915
|
-
|
946
|
+
# 直接使用本地变量,避免受事件回调影响
|
947
|
+
ret = self.model.chat_until_success(safe_summary_prompt) # type: ignore
|
916
948
|
# 防御: 总结阶段模型可能返回空响应(None或空字符串),统一为空字符串并告警
|
917
949
|
if not ret:
|
918
950
|
try:
|
{jarvis_ai_assistant-0.3.34 → jarvis_ai_assistant-0.4.1}/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,7 +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
|
+
from jarvis.jarvis_utils.config import is_non_interactive, is_skip_predefined_tasks
|
20
20
|
|
21
21
|
|
22
22
|
class AgentManager:
|
@@ -29,6 +29,9 @@ class AgentManager:
|
|
29
29
|
restore_session: bool = False,
|
30
30
|
use_methodology: Optional[bool] = None,
|
31
31
|
use_analysis: Optional[bool] = None,
|
32
|
+
multiline_inputer: Optional[Callable[[str], str]] = None,
|
33
|
+
confirm_callback: Optional[Callable[[str, bool], bool]] = None,
|
34
|
+
non_interactive: Optional[bool] = None,
|
32
35
|
):
|
33
36
|
self.model_group = model_group
|
34
37
|
self.tool_group = tool_group
|
@@ -36,6 +39,10 @@ class AgentManager:
|
|
36
39
|
self.use_methodology = use_methodology
|
37
40
|
self.use_analysis = use_analysis
|
38
41
|
self.agent: Optional[Agent] = None
|
42
|
+
# 可选:注入输入与确认回调,用于Web模式等前端替代交互
|
43
|
+
self.multiline_inputer = multiline_inputer
|
44
|
+
self.confirm_callback = confirm_callback
|
45
|
+
self.non_interactive = non_interactive
|
39
46
|
|
40
47
|
def initialize(self) -> Agent:
|
41
48
|
"""初始化Agent"""
|
@@ -48,15 +55,12 @@ class AgentManager:
|
|
48
55
|
self.agent = Agent(
|
49
56
|
system_prompt=origin_agent_system_prompt,
|
50
57
|
model_group=self.model_group,
|
51
|
-
input_handler=[
|
52
|
-
shell_input_handler,
|
53
|
-
file_context_handler,
|
54
|
-
builtin_input_handler,
|
55
|
-
],
|
56
|
-
output_handler=[ToolRegistry()], # type: ignore
|
57
58
|
need_summary=False,
|
58
59
|
use_methodology=self.use_methodology,
|
59
60
|
use_analysis=self.use_analysis,
|
61
|
+
multiline_inputer=self.multiline_inputer,
|
62
|
+
confirm_callback=self.confirm_callback,
|
63
|
+
non_interactive=self.non_interactive,
|
60
64
|
)
|
61
65
|
|
62
66
|
# 尝试恢复会话
|
@@ -78,8 +82,8 @@ class AgentManager:
|
|
78
82
|
self.agent.run(task_content)
|
79
83
|
raise typer.Exit(code=0)
|
80
84
|
|
81
|
-
#
|
82
|
-
if not is_non_interactive() and self.agent.first:
|
85
|
+
# 处理预定义任务(非交互模式下跳过;支持配置跳过加载)
|
86
|
+
if not is_non_interactive() and not is_skip_predefined_tasks() and self.agent.first:
|
83
87
|
task_manager = TaskManager()
|
84
88
|
tasks = task_manager.load_tasks()
|
85
89
|
if tasks and (selected_task := task_manager.select_task(tasks)):
|
@@ -81,7 +81,8 @@ class AgentConfig:
|
|
81
81
|
cfg.execute_tool_confirm = is_execute_tool_confirm()
|
82
82
|
|
83
83
|
# summary_prompt
|
84
|
-
|
84
|
+
# Treat None or whitespace-only string as unset, fallback to default
|
85
|
+
if cfg.summary_prompt is None or (isinstance(cfg.summary_prompt, str) and cfg.summary_prompt.strip() == ""):
|
85
86
|
cfg.summary_prompt = DEFAULT_SUMMARY_PROMPT
|
86
87
|
|
87
88
|
# max_token_count
|
@@ -92,10 +92,10 @@ class EditFileHandler(OutputHandler):
|
|
92
92
|
if not patches:
|
93
93
|
return False, "未找到有效的文件编辑指令"
|
94
94
|
|
95
|
-
# 记录
|
95
|
+
# 记录 PATCH 操作调用统计
|
96
96
|
from jarvis.jarvis_stats.stats import StatsManager
|
97
97
|
|
98
|
-
StatsManager.increment("
|
98
|
+
StatsManager.increment("patch", group="tool")
|
99
99
|
|
100
100
|
results = []
|
101
101
|
|
@@ -28,6 +28,7 @@ from jarvis.jarvis_utils.fzf import fzf_select
|
|
28
28
|
import os
|
29
29
|
import subprocess
|
30
30
|
from pathlib import Path
|
31
|
+
import signal
|
31
32
|
import yaml # type: ignore
|
32
33
|
from rich.table import Table
|
33
34
|
from rich.console import Console
|
@@ -594,7 +595,10 @@ def handle_builtin_config_selector(
|
|
594
595
|
|
595
596
|
elif sel["category"] == "multi_agent":
|
596
597
|
# jarvis-multi-agent 需要 -c/--config,用户输入通过 -i/--input 传递
|
598
|
+
# 同时传递 -g/--llm-group 以继承 jvs 的模型组选择
|
597
599
|
args = [str(sel["cmd"]), "-c", str(sel["file"])]
|
600
|
+
if model_group:
|
601
|
+
args += ["-g", str(model_group)]
|
598
602
|
if task:
|
599
603
|
args += ["-i", str(task)]
|
600
604
|
|
@@ -677,6 +681,10 @@ def run_cli(
|
|
677
681
|
non_interactive: bool = typer.Option(
|
678
682
|
False, "-n", "--non-interactive", help="启用非交互模式:用户无法与命令交互,脚本执行超时限制为5分钟"
|
679
683
|
),
|
684
|
+
web: bool = typer.Option(False, "--web", help="以 Web 模式启动,通过浏览器 WebSocket 交互"),
|
685
|
+
web_host: str = typer.Option("127.0.0.1", "--web-host", help="Web 服务主机"),
|
686
|
+
web_port: int = typer.Option(8765, "--web-port", help="Web 服务端口"),
|
687
|
+
stop: bool = typer.Option(False, "--stop", help="停止后台 Web 服务(需与 --web 一起使用)"),
|
680
688
|
) -> None:
|
681
689
|
"""Jarvis AI assistant command-line interface."""
|
682
690
|
if ctx.invoked_subcommand is not None:
|
@@ -742,6 +750,224 @@ def run_cli(
|
|
742
750
|
|
743
751
|
# 预加载配置(仅用于读取功能开关),不会显示欢迎信息或影响后续 init_env
|
744
752
|
preload_config_for_flags(config_file)
|
753
|
+
# Web 模式后台管理:支持 --web 后台启动与 --web --stop 停止
|
754
|
+
if web:
|
755
|
+
# PID 文件路径(按端口区分,便于多实例)
|
756
|
+
pidfile = Path(os.path.expanduser("~/.jarvis")) / f"jarvis_web_{web_port}.pid"
|
757
|
+
# 停止后台服务
|
758
|
+
if stop:
|
759
|
+
try:
|
760
|
+
pf = pidfile
|
761
|
+
if not pf.exists():
|
762
|
+
# 兼容旧版本:回退检查数据目录中的旧 PID 文件位置
|
763
|
+
try:
|
764
|
+
pf_alt = Path(os.path.expanduser(os.path.expandvars(get_data_dir()))) / f"jarvis_web_{web_port}.pid"
|
765
|
+
except Exception:
|
766
|
+
pf_alt = None # type: ignore[assignment]
|
767
|
+
if pf_alt and pf_alt.exists(): # type: ignore[truthy-bool]
|
768
|
+
pf = pf_alt
|
769
|
+
if not pf.exists():
|
770
|
+
# 进一步回退:尝试按端口查找并停止(无 PID 文件)
|
771
|
+
killed_any = False
|
772
|
+
try:
|
773
|
+
res = subprocess.run(
|
774
|
+
["lsof", "-iTCP:%d" % web_port, "-sTCP:LISTEN", "-t"],
|
775
|
+
capture_output=True,
|
776
|
+
text=True,
|
777
|
+
)
|
778
|
+
if res.returncode == 0 and res.stdout.strip():
|
779
|
+
for ln in res.stdout.strip().splitlines():
|
780
|
+
try:
|
781
|
+
candidate_pid = int(ln.strip())
|
782
|
+
try:
|
783
|
+
os.kill(candidate_pid, signal.SIGTERM)
|
784
|
+
PrettyOutput.print(f"已按端口停止后台 Web 服务 (PID {candidate_pid})。", OutputType.SUCCESS)
|
785
|
+
killed_any = True
|
786
|
+
except Exception as e:
|
787
|
+
PrettyOutput.print(f"按端口停止失败: {e}", OutputType.WARNING)
|
788
|
+
except Exception:
|
789
|
+
continue
|
790
|
+
except Exception:
|
791
|
+
pass
|
792
|
+
if not killed_any:
|
793
|
+
try:
|
794
|
+
res2 = subprocess.run(["ss", "-ltpn"], capture_output=True, text=True)
|
795
|
+
if res2.returncode == 0 and res2.stdout:
|
796
|
+
for ln in res2.stdout.splitlines():
|
797
|
+
if f":{web_port} " in ln or f":{web_port}\n" in ln:
|
798
|
+
try:
|
799
|
+
idx = ln.find("pid=")
|
800
|
+
if idx != -1:
|
801
|
+
end = ln.find(",", idx)
|
802
|
+
pid_str2 = ln[idx+4:end if end != -1 else None]
|
803
|
+
candidate_pid = int(pid_str2)
|
804
|
+
try:
|
805
|
+
os.kill(candidate_pid, signal.SIGTERM)
|
806
|
+
PrettyOutput.print(f"已按端口停止后台 Web 服务 (PID {candidate_pid})。", OutputType.SUCCESS)
|
807
|
+
killed_any = True
|
808
|
+
except Exception as e:
|
809
|
+
PrettyOutput.print(f"按端口停止失败: {e}", OutputType.WARNING)
|
810
|
+
break
|
811
|
+
except Exception:
|
812
|
+
continue
|
813
|
+
except Exception:
|
814
|
+
pass
|
815
|
+
# 若仍未找到,扫描家目录下所有 Web PID 文件,尽力停止所有实例
|
816
|
+
if not killed_any:
|
817
|
+
try:
|
818
|
+
pid_dir = Path(os.path.expanduser("~/.jarvis"))
|
819
|
+
if pid_dir.is_dir():
|
820
|
+
for f in pid_dir.glob("jarvis_web_*.pid"):
|
821
|
+
try:
|
822
|
+
ptxt = f.read_text(encoding="utf-8").strip()
|
823
|
+
p = int(ptxt)
|
824
|
+
try:
|
825
|
+
os.kill(p, signal.SIGTERM)
|
826
|
+
PrettyOutput.print(f"已停止后台 Web 服务 (PID {p})。", OutputType.SUCCESS)
|
827
|
+
killed_any = True
|
828
|
+
except Exception as e:
|
829
|
+
PrettyOutput.print(f"停止 PID {p} 失败: {e}", OutputType.WARNING)
|
830
|
+
except Exception:
|
831
|
+
pass
|
832
|
+
try:
|
833
|
+
f.unlink(missing_ok=True)
|
834
|
+
except Exception:
|
835
|
+
pass
|
836
|
+
except Exception:
|
837
|
+
pass
|
838
|
+
if not killed_any:
|
839
|
+
PrettyOutput.print("未找到后台 Web 服务的 PID 文件,可能未启动或已停止。", OutputType.WARNING)
|
840
|
+
return
|
841
|
+
# 优先使用 PID 文件中的 PID
|
842
|
+
try:
|
843
|
+
pid_str = pf.read_text(encoding="utf-8").strip()
|
844
|
+
pid = int(pid_str)
|
845
|
+
except Exception:
|
846
|
+
pid = 0
|
847
|
+
killed = False
|
848
|
+
if pid > 0:
|
849
|
+
try:
|
850
|
+
os.kill(pid, signal.SIGTERM)
|
851
|
+
PrettyOutput.print(f"已向后台 Web 服务发送停止信号 (PID {pid})。", OutputType.SUCCESS)
|
852
|
+
killed = True
|
853
|
+
except Exception as e:
|
854
|
+
PrettyOutput.print(f"发送停止信号失败或进程不存在: {e}", OutputType.WARNING)
|
855
|
+
if not killed:
|
856
|
+
# 无 PID 文件或停止失败时,尝试按端口查找进程
|
857
|
+
candidate_pid = 0
|
858
|
+
try:
|
859
|
+
res = subprocess.run(
|
860
|
+
["lsof", "-iTCP:%d" % web_port, "-sTCP:LISTEN", "-t"],
|
861
|
+
capture_output=True,
|
862
|
+
text=True,
|
863
|
+
)
|
864
|
+
if res.returncode == 0 and res.stdout.strip():
|
865
|
+
for ln in res.stdout.strip().splitlines():
|
866
|
+
try:
|
867
|
+
candidate_pid = int(ln.strip())
|
868
|
+
break
|
869
|
+
except Exception:
|
870
|
+
continue
|
871
|
+
except Exception:
|
872
|
+
pass
|
873
|
+
if not candidate_pid:
|
874
|
+
try:
|
875
|
+
res2 = subprocess.run(["ss", "-ltpn"], capture_output=True, text=True)
|
876
|
+
if res2.returncode == 0 and res2.stdout:
|
877
|
+
for ln in res2.stdout.splitlines():
|
878
|
+
if f":{web_port} " in ln or f":{web_port}\n" in ln:
|
879
|
+
# 格式示例: LISTEN ... users:(("uvicorn",pid=12345,fd=7))
|
880
|
+
try:
|
881
|
+
idx = ln.find("pid=")
|
882
|
+
if idx != -1:
|
883
|
+
end = ln.find(",", idx)
|
884
|
+
pid_str2 = ln[idx+4:end if end != -1 else None]
|
885
|
+
candidate_pid = int(pid_str2)
|
886
|
+
break
|
887
|
+
except Exception:
|
888
|
+
continue
|
889
|
+
except Exception:
|
890
|
+
pass
|
891
|
+
if candidate_pid:
|
892
|
+
try:
|
893
|
+
os.kill(candidate_pid, signal.SIGTERM)
|
894
|
+
PrettyOutput.print(f"已按端口停止后台 Web 服务 (PID {candidate_pid})。", OutputType.SUCCESS)
|
895
|
+
killed = True
|
896
|
+
except Exception as e:
|
897
|
+
PrettyOutput.print(f"按端口停止失败: {e}", OutputType.WARNING)
|
898
|
+
# 清理可能存在的 PID 文件(两个位置)
|
899
|
+
try:
|
900
|
+
pidfile.unlink(missing_ok=True) # 家目录位置
|
901
|
+
except Exception:
|
902
|
+
pass
|
903
|
+
try:
|
904
|
+
alt_pf = Path(os.path.expanduser(os.path.expandvars(get_data_dir()))) / f"jarvis_web_{web_port}.pid"
|
905
|
+
alt_pf.unlink(missing_ok=True)
|
906
|
+
except Exception:
|
907
|
+
pass
|
908
|
+
except Exception as e:
|
909
|
+
PrettyOutput.print(f"停止后台 Web 服务失败: {e}", OutputType.ERROR)
|
910
|
+
finally:
|
911
|
+
return
|
912
|
+
# 后台启动:父进程拉起子进程并记录 PID
|
913
|
+
is_daemon = False
|
914
|
+
try:
|
915
|
+
is_daemon = os.environ.get("JARVIS_WEB_DAEMON") == "1"
|
916
|
+
except Exception:
|
917
|
+
is_daemon = False
|
918
|
+
if not is_daemon:
|
919
|
+
try:
|
920
|
+
# 构建子进程参数,传递关键配置
|
921
|
+
args = [
|
922
|
+
sys.executable,
|
923
|
+
"-m",
|
924
|
+
"jarvis.jarvis_agent.jarvis",
|
925
|
+
"--web",
|
926
|
+
"--web-host",
|
927
|
+
str(web_host),
|
928
|
+
"--web-port",
|
929
|
+
str(web_port),
|
930
|
+
]
|
931
|
+
if model_group:
|
932
|
+
args += ["-g", str(model_group)]
|
933
|
+
if tool_group:
|
934
|
+
args += ["-G", str(tool_group)]
|
935
|
+
if config_file:
|
936
|
+
args += ["-f", str(config_file)]
|
937
|
+
if restore_session:
|
938
|
+
args += ["--restore-session"]
|
939
|
+
if disable_methodology_analysis:
|
940
|
+
args += ["-D"]
|
941
|
+
if non_interactive:
|
942
|
+
args += ["-n"]
|
943
|
+
env = os.environ.copy()
|
944
|
+
env["JARVIS_WEB_DAEMON"] = "1"
|
945
|
+
# 启动子进程(后台运行)
|
946
|
+
proc = subprocess.Popen(
|
947
|
+
args,
|
948
|
+
env=env,
|
949
|
+
stdout=subprocess.DEVNULL,
|
950
|
+
stderr=subprocess.DEVNULL,
|
951
|
+
stdin=subprocess.DEVNULL,
|
952
|
+
close_fds=True,
|
953
|
+
)
|
954
|
+
# 记录 PID 到文件
|
955
|
+
try:
|
956
|
+
pidfile.parent.mkdir(parents=True, exist_ok=True)
|
957
|
+
except Exception:
|
958
|
+
pass
|
959
|
+
try:
|
960
|
+
pidfile.write_text(str(proc.pid), encoding="utf-8")
|
961
|
+
except Exception:
|
962
|
+
pass
|
963
|
+
PrettyOutput.print(
|
964
|
+
f"Web 服务已在后台启动 (PID {proc.pid}),地址: http://{web_host}:{web_port}",
|
965
|
+
OutputType.SUCCESS,
|
966
|
+
)
|
967
|
+
except Exception as e:
|
968
|
+
PrettyOutput.print(f"后台启动 Web 服务失败: {e}", OutputType.ERROR)
|
969
|
+
raise typer.Exit(code=1)
|
970
|
+
return
|
745
971
|
|
746
972
|
# 在初始化环境前检测Git仓库,并可选择自动切换到代码开发模式(jca)
|
747
973
|
if not non_interactive:
|
@@ -779,14 +1005,92 @@ def run_cli(
|
|
779
1005
|
|
780
1006
|
# 运行主流程
|
781
1007
|
try:
|
1008
|
+
# 在 Web 模式下注入基于 WebSocket 的输入/确认回调
|
1009
|
+
extra_kwargs = {}
|
1010
|
+
if web:
|
1011
|
+
# 纯 xterm 交互模式:不注入 WebBridge 的输入/确认回调,避免阻塞等待浏览器响应
|
1012
|
+
#(交互由 /terminal PTY 会话中的 jvs 进程处理)
|
1013
|
+
pass
|
1014
|
+
|
782
1015
|
agent_manager = AgentManager(
|
783
1016
|
model_group=model_group,
|
784
1017
|
tool_group=tool_group,
|
785
1018
|
restore_session=restore_session,
|
786
1019
|
use_methodology=False if disable_methodology_analysis else None,
|
787
1020
|
use_analysis=False if disable_methodology_analysis else None,
|
1021
|
+
non_interactive=non_interactive,
|
1022
|
+
**extra_kwargs,
|
788
1023
|
)
|
789
|
-
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
|
+
# 记录用于交互式终端(PTY)重启的 jvs 启动命令(移除 web 相关参数)
|
1055
|
+
try:
|
1056
|
+
import sys as _sys, os as _os, json as _json
|
1057
|
+
_argv = list(_sys.argv)
|
1058
|
+
# 去掉程序名(argv[0]),并过滤 --web 相关参数
|
1059
|
+
filtered = []
|
1060
|
+
i = 1
|
1061
|
+
while i < len(_argv):
|
1062
|
+
a = _argv[i]
|
1063
|
+
if a == "--web" or a.startswith("--web="):
|
1064
|
+
i += 1
|
1065
|
+
continue
|
1066
|
+
if a == "--web-host":
|
1067
|
+
i += 2
|
1068
|
+
continue
|
1069
|
+
if a.startswith("--web-host="):
|
1070
|
+
i += 1
|
1071
|
+
continue
|
1072
|
+
if a == "--web-port":
|
1073
|
+
i += 2
|
1074
|
+
continue
|
1075
|
+
if a.startswith("--web-port="):
|
1076
|
+
i += 1
|
1077
|
+
continue
|
1078
|
+
filtered.append(a)
|
1079
|
+
i += 1
|
1080
|
+
# 使用 jvs 命令作为可执行文件,保留其余业务参数
|
1081
|
+
cmd = ["jvs"] + filtered
|
1082
|
+
_os.environ["JARVIS_WEB_LAUNCH_JSON"] = _json.dumps(cmd, ensure_ascii=False)
|
1083
|
+
except Exception:
|
1084
|
+
pass
|
1085
|
+
PrettyOutput.print("以 Web 模式启动,请在浏览器中打开提供的地址进行交互。", OutputType.INFO)
|
1086
|
+
# 启动 Web 服务(阻塞调用)
|
1087
|
+
start_web_server(agent_manager, host=web_host, port=web_port)
|
1088
|
+
return
|
1089
|
+
except Exception as e:
|
1090
|
+
PrettyOutput.print(f"Web 模式启动失败: {e}", OutputType.ERROR)
|
1091
|
+
raise typer.Exit(code=1)
|
1092
|
+
|
1093
|
+
# 默认 CLI 模式:运行任务(可能来自 --task 或交互输入)
|
790
1094
|
agent_manager.run_task(task)
|
791
1095
|
except typer.Exit:
|
792
1096
|
raise
|