deepcode-hku 1.0.2__tar.gz → 1.0.3__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.
Files changed (58) hide show
  1. {deepcode_hku-1.0.2/deepcode_hku.egg-info → deepcode_hku-1.0.3}/PKG-INFO +1 -1
  2. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/__init__.py +1 -1
  3. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3/deepcode_hku.egg-info}/PKG-INFO +1 -1
  4. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/deepcode_hku.egg-info/SOURCES.txt +1 -0
  5. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/mcp_agent.config.yaml +9 -0
  6. deepcode_hku-1.0.3/tools/bocha_search_server.py +219 -0
  7. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/workflows/agent_orchestration_engine.py +56 -7
  8. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/.pre-commit-config.yaml +0 -0
  9. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/LICENSE +0 -0
  10. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/MANIFEST.in +0 -0
  11. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/README.md +0 -0
  12. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/cli/__init__.py +0 -0
  13. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/cli/cli_app.py +0 -0
  14. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/cli/cli_interface.py +0 -0
  15. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/cli/cli_launcher.py +0 -0
  16. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/cli/main_cli.py +0 -0
  17. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/cli/workflows/__init__.py +0 -0
  18. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/cli/workflows/cli_workflow_adapter.py +0 -0
  19. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/deepcode.py +0 -0
  20. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/deepcode_hku.egg-info/dependency_links.txt +0 -0
  21. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/deepcode_hku.egg-info/entry_points.txt +0 -0
  22. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/deepcode_hku.egg-info/requires.txt +0 -0
  23. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/deepcode_hku.egg-info/top_level.txt +0 -0
  24. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/mcp_agent.secrets.yaml +0 -0
  25. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/prompts/code_prompts.py +0 -0
  26. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/requirements.txt +0 -0
  27. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/schema/mcp-agent.config.schema.json +0 -0
  28. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/setup.cfg +0 -0
  29. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/setup.py +0 -0
  30. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/tools/__init__.py +0 -0
  31. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/tools/code_implementation_server.py +0 -0
  32. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/tools/code_indexer.py +0 -0
  33. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/tools/code_reference_indexer.py +0 -0
  34. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/tools/command_executor.py +0 -0
  35. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/tools/git_command.py +0 -0
  36. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/tools/pdf_converter.py +0 -0
  37. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/tools/pdf_downloader.py +0 -0
  38. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/tools/pdf_utils.py +0 -0
  39. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/ui/__init__.py +0 -0
  40. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/ui/app.py +0 -0
  41. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/ui/components.py +0 -0
  42. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/ui/handlers.py +0 -0
  43. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/ui/layout.py +0 -0
  44. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/ui/streamlit_app.py +0 -0
  45. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/ui/styles.py +0 -0
  46. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/utils/__init__.py +0 -0
  47. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/utils/cli_interface.py +0 -0
  48. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/utils/dialogue_logger.py +0 -0
  49. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/utils/file_processor.py +0 -0
  50. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/utils/simple_llm_logger.py +0 -0
  51. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/workflows/__init__.py +0 -0
  52. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/workflows/agents/__init__.py +0 -0
  53. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/workflows/agents/code_implementation_agent.py +0 -0
  54. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/workflows/agents/memory_agent_concise.py +0 -0
  55. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/workflows/agents/memory_agent_concise_index.py +0 -0
  56. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/workflows/code_implementation_workflow.py +0 -0
  57. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/workflows/code_implementation_workflow_index.py +0 -0
  58. {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/workflows/codebase_index_workflow.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: deepcode-hku
3
- Version: 1.0.2
3
+ Version: 1.0.3
4
4
  Summary: AI Research Engine - Transform research papers into working code automatically
5
5
  Home-page: https://github.com/HKUDS/DeepCode
6
6
  Author: DeepCodeTeam
@@ -5,7 +5,7 @@ DeepCode - AI Research Engine
5
5
  ⚡ Transform research papers into working code automatically
6
6
  """
7
7
 
8
- __version__ = "1.0.2"
8
+ __version__ = "1.0.3"
9
9
  __author__ = "DeepCode Team"
10
10
  __url__ = "https://github.com/HKUDS/DeepCode"
11
11
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: deepcode-hku
3
- Version: 1.0.2
3
+ Version: 1.0.3
4
4
  Summary: AI Research Engine - Transform research papers into working code automatically
5
5
  Home-page: https://github.com/HKUDS/DeepCode
6
6
  Author: DeepCodeTeam
@@ -24,6 +24,7 @@ deepcode_hku.egg-info/top_level.txt
24
24
  prompts/code_prompts.py
25
25
  schema/mcp-agent.config.schema.json
26
26
  tools/__init__.py
27
+ tools/bocha_search_server.py
27
28
  tools/code_implementation_server.py
28
29
  tools/code_indexer.py
29
30
  tools/code_reference_indexer.py
@@ -1,5 +1,8 @@
1
1
  $schema: ./schema/mcp-agent.config.schema.json
2
2
 
3
+ # Default search server configuration
4
+ # Options: "brave" or "bocha-mcp"
5
+ default_search_server: "brave"
3
6
 
4
7
  execution_engine: asyncio
5
8
  logger:
@@ -64,6 +67,12 @@ mcp:
64
67
  env:
65
68
  PYTHONPATH: "."
66
69
  description: "Code reference indexer server - Provides intelligent code reference search from indexed repositories"
70
+ bocha-mcp:
71
+ command: "python3"
72
+ args: ["tools/bocha_search_server.py"]
73
+ env:
74
+ PYTHONPATH: "."
75
+ BOCHA_API_KEY: ""
67
76
 
68
77
  openai:
69
78
  # Secrets (API keys, etc.) are stored in an mcp_agent.secrets.yaml file which can be gitignored
@@ -0,0 +1,219 @@
1
+ import os
2
+ import sys
3
+ import json
4
+
5
+ import httpx
6
+ from dotenv import load_dotenv
7
+ from mcp.server.fastmcp import FastMCP
8
+
9
+ load_dotenv()
10
+
11
+
12
+ # Initialize FastMCP server
13
+ server = FastMCP(
14
+ "bocha-search-mcp",
15
+ prompt="""
16
+ # Bocha Search MCP Server
17
+
18
+ Bocha is a Chinese search engine for AI, This server provides tools for searching the web using Bocha Search API.
19
+ It allows you to get enhanced search details from billions of web documents, including weather, news, wikis, healthcare, train tickets, images, and more.
20
+
21
+ ## Available Tools
22
+
23
+ ### 1. bocha_web_search
24
+ Search with Bocha Web Search and get enhanced search details from billions of web documents, including page titles, urls, summaries, site names, site icons, publication dates, image links, and more.
25
+
26
+ ### 2. bocha_ai_search
27
+ Search with Bocha AI Search, recognizes the semantics of search terms and additionally returns structured modal cards with content from vertical domains.
28
+
29
+ ## Output Format
30
+
31
+ All search results will be formatted as text with clear sections for each
32
+ result item, including:
33
+
34
+ - Bocha Web search: Title, URL, Description, Published date and Site name
35
+ - Bocha AI search: Title, URL, Description, Published date, Site name, and structured data card
36
+
37
+ If the API key is missing or invalid, appropriate error messages will be returned.
38
+ """,
39
+ )
40
+
41
+
42
+ @server.tool()
43
+ async def bocha_web_search(
44
+ query: str, freshness: str = "noLimit", count: int = 10
45
+ ) -> str:
46
+ """Search with Bocha Web Search and get enhanced search details from billions of web documents,
47
+ including page titles, urls, summaries, site names, site icons, publication dates, image links, and more.
48
+
49
+ Args:
50
+ query: Search query (required)
51
+ freshness: The time range for the search results. (Available options YYYY-MM-DD, YYYY-MM-DD..YYYY-MM-DD, noLimit, oneYear, oneMonth, oneWeek, oneDay. Default is noLimit)
52
+ count: Number of results (1-50, default 10)
53
+ """
54
+ # Get API key from environment
55
+ boch_api_key = os.environ.get("BOCHA_API_KEY", "")
56
+
57
+ if not boch_api_key:
58
+ return (
59
+ "Error: Bocha API key is not configured. Please set the "
60
+ "BOCHA_API_KEY environment variable."
61
+ )
62
+
63
+ # Endpoint
64
+ endpoint = "https://api.bochaai.com/v1/web-search?utm_source=bocha-mcp-local"
65
+
66
+ try:
67
+ payload = {
68
+ "query": query,
69
+ "summary": True,
70
+ "freshness": freshness,
71
+ "count": count,
72
+ }
73
+
74
+ headers = {
75
+ "Authorization": f"Bearer {boch_api_key}",
76
+ "Content-Type": "application/json",
77
+ }
78
+
79
+ async with httpx.AsyncClient() as client:
80
+ response = await client.post(
81
+ endpoint, headers=headers, json=payload, timeout=10.0
82
+ )
83
+
84
+ response.raise_for_status()
85
+ resp = response.json()
86
+ if "data" not in resp:
87
+ return "Search error."
88
+
89
+ data = resp["data"]
90
+
91
+ if "webPages" not in data:
92
+ return "No results found."
93
+
94
+ results = []
95
+ for result in data["webPages"]["value"]:
96
+ results.append(
97
+ f"Title: {result['name']}\n"
98
+ f"URL: {result['url']}\n"
99
+ f"Description: {result['summary']}\n"
100
+ f"Published date: {result['datePublished']}\n"
101
+ f"Site name: {result['siteName']}"
102
+ )
103
+
104
+ return "\n\n".join(results)
105
+
106
+ except httpx.HTTPStatusError as e:
107
+ return f"Bocha Web Search API HTTP error occurred: {e.response.status_code} - {e.response.text}"
108
+ except httpx.RequestError as e:
109
+ return f"Error communicating with Bocha Web Search API: {str(e)}"
110
+ except Exception as e:
111
+ return f"Unexpected error: {str(e)}"
112
+
113
+
114
+ @server.tool()
115
+ async def bocha_ai_search(
116
+ query: str, freshness: str = "noLimit", count: int = 10
117
+ ) -> str:
118
+ """Search with Bocha AI Search, recognizes the semantics of search terms
119
+ and additionally returns structured modal cards with content from vertical domains.
120
+
121
+ Args:
122
+ query: Search query (required)
123
+ freshness: The time range for the search results. (Available options noLimit, oneYear, oneMonth, oneWeek, oneDay. Default is noLimit)
124
+ count: Number of results (1-50, default 10)
125
+ """
126
+ # Get API key from environment
127
+ boch_api_key = os.environ.get("BOCHA_API_KEY", "")
128
+
129
+ if not boch_api_key:
130
+ return (
131
+ "Error: Bocha API key is not configured. Please set the "
132
+ "BOCHA_API_KEY environment variable."
133
+ )
134
+
135
+ # Endpoint
136
+ endpoint = "https://api.bochaai.com/v1/ai-search?utm_source=bocha-mcp-local"
137
+
138
+ try:
139
+ payload = {
140
+ "query": query,
141
+ "freshness": freshness,
142
+ "count": count,
143
+ "answer": False,
144
+ "stream": False,
145
+ }
146
+
147
+ headers = {
148
+ "Authorization": f"Bearer {boch_api_key}",
149
+ "Content-Type": "application/json",
150
+ }
151
+
152
+ async with httpx.AsyncClient() as client:
153
+ response = await client.post(
154
+ endpoint, headers=headers, json=payload, timeout=10.0
155
+ )
156
+
157
+ response.raise_for_status()
158
+ response = response.json()
159
+ results = []
160
+ if "messages" in response:
161
+ for message in response["messages"]:
162
+ content = {}
163
+ try:
164
+ content = json.loads(message["content"])
165
+ except (json.JSONDecodeError, TypeError):
166
+ content = {}
167
+
168
+ # 网页
169
+ if message["content_type"] == "webpage":
170
+ if "value" in content:
171
+ for item in content["value"]:
172
+ results.append(
173
+ f"Title: {item['name']}\n"
174
+ f"URL: {item['url']}\n"
175
+ f"Description: {item['summary']}\n"
176
+ f"Published date: {item['datePublished']}\n"
177
+ f"Site name: {item['siteName']}"
178
+ )
179
+ elif (
180
+ message["content_type"] != "image"
181
+ and message["content"] != "{}"
182
+ ):
183
+ results.append(message["content"])
184
+
185
+ if not results:
186
+ return "No results found."
187
+
188
+ return "\n\n".join(results)
189
+
190
+ except httpx.HTTPStatusError as e:
191
+ return f"Bocha AI Search API HTTP error occurred: {e.response.status_code} - {e.response.text}"
192
+ except httpx.RequestError as e:
193
+ return f"Error communicating with Bocha AI Search API: {str(e)}"
194
+ except Exception as e:
195
+ return f"Unexpected error: {str(e)}"
196
+
197
+
198
+ def main():
199
+ """Initialize and run the MCP server."""
200
+
201
+ # Check for required environment variables
202
+ if "BOCHA_API_KEY" not in os.environ:
203
+ print(
204
+ "Error: BOCHA_API_KEY environment variable is required",
205
+ file=sys.stderr,
206
+ )
207
+ print(
208
+ "Get a Bocha API key from: " "https://open.bochaai.com",
209
+ file=sys.stderr,
210
+ )
211
+ sys.exit(1)
212
+
213
+ print("Starting Bocha Search MCP server...", file=sys.stderr)
214
+
215
+ server.run(transport="stdio")
216
+
217
+
218
+ if __name__ == "__main__":
219
+ main()
@@ -31,7 +31,7 @@ import json
31
31
  import os
32
32
  import re
33
33
  import yaml
34
- from typing import Callable, Dict, Optional, Tuple
34
+ from typing import Callable, Dict, List, Optional, Tuple
35
35
 
36
36
  # MCP Agent imports
37
37
  from mcp_agent.agents.agent import Agent
@@ -99,6 +99,57 @@ def get_preferred_llm_class(config_path: str = "mcp_agent.secrets.yaml"):
99
99
  return OpenAIAugmentedLLM
100
100
 
101
101
 
102
+ def get_default_search_server(config_path: str = "mcp_agent.config.yaml"):
103
+ """
104
+ Get the default search server from configuration.
105
+
106
+ Args:
107
+ config_path: Path to the main configuration file
108
+
109
+ Returns:
110
+ str: The default search server name ("brave" or "bocha-mcp")
111
+ """
112
+ try:
113
+ if os.path.exists(config_path):
114
+ with open(config_path, "r", encoding="utf-8") as f:
115
+ config = yaml.safe_load(f)
116
+
117
+ default_server = config.get("default_search_server", "brave")
118
+ print(f"🔍 Using search server: {default_server}")
119
+ return default_server
120
+ else:
121
+ print(f"⚠️ Config file {config_path} not found, using default: brave")
122
+ return "brave"
123
+ except Exception as e:
124
+ print(f"⚠️ Error reading config file {config_path}: {e}")
125
+ print("🔍 Falling back to default search server: brave")
126
+ return "brave"
127
+
128
+
129
+ def get_search_server_names(
130
+ additional_servers: Optional[List[str]] = None,
131
+ ) -> List[str]:
132
+ """
133
+ Get server names list with the configured default search server.
134
+
135
+ Args:
136
+ additional_servers: Optional list of additional servers to include
137
+
138
+ Returns:
139
+ List[str]: List of server names including the default search server
140
+ """
141
+ default_search = get_default_search_server()
142
+ server_names = [default_search]
143
+
144
+ if additional_servers:
145
+ # Add additional servers, avoiding duplicates
146
+ for server in additional_servers:
147
+ if server not in server_names:
148
+ server_names.append(server)
149
+
150
+ return server_names
151
+
152
+
102
153
  def extract_clean_json(llm_output: str) -> str:
103
154
  """
104
155
  Extract clean JSON from LLM output, removing all extra text and formatting.
@@ -193,7 +244,7 @@ async def run_research_analyzer(prompt_text: str, logger) -> str:
193
244
  analyzer_agent = Agent(
194
245
  name="ResearchAnalyzerAgent",
195
246
  instruction=PAPER_INPUT_ANALYZER_PROMPT,
196
- server_names=["brave"],
247
+ server_names=get_search_server_names(),
197
248
  )
198
249
 
199
250
  async with analyzer_agent:
@@ -341,12 +392,12 @@ async def run_code_analyzer(paper_dir: str, logger) -> str:
341
392
  algorithm_analysis_agent = Agent(
342
393
  name="AlgorithmAnalysisAgent",
343
394
  instruction=PAPER_ALGORITHM_ANALYSIS_PROMPT,
344
- server_names=["filesystem", "brave"],
395
+ server_names=get_search_server_names(additional_servers=["filesystem"]),
345
396
  )
346
397
  code_planner_agent = Agent(
347
398
  name="CodePlannerAgent",
348
399
  instruction=CODE_PLANNING_PROMPT,
349
- server_names=["brave"],
400
+ server_names=get_search_server_names(),
350
401
  )
351
402
 
352
403
  code_aggregator_agent = ParallelLLM(
@@ -931,9 +982,7 @@ async def run_chat_planning_agent(user_input: str, logger) -> str:
931
982
  chat_planning_agent = Agent(
932
983
  name="ChatPlanningAgent",
933
984
  instruction=CHAT_AGENT_PLANNING_PROMPT,
934
- server_names=[
935
- "brave"
936
- ], # Add tools if needed for web search or other capabilities
985
+ server_names=get_search_server_names(), # Dynamic search server configuration
937
986
  )
938
987
 
939
988
  async with chat_planning_agent:
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes