Skip to content

Commit 9514bdc

Browse files
committed
feat: webui_code_gengesis
1 parent 55199a9 commit 9514bdc

38 files changed

+2206
-587
lines changed

ms_agent/config/config.py

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) ModelScope Contributors. All rights reserved.
1+
# Copyright (c) Alibaba, Inc. and its affiliates.
22
import argparse
33
import os.path
44
from abc import abstractmethod
@@ -108,7 +108,10 @@ def fill_missing_fields(config: DictConfig) -> DictConfig:
108108
@staticmethod
109109
def is_workflow(config: DictConfig) -> bool:
110110
assert config.name is not None, 'Cannot find a valid name in this config'
111-
return config.name in ['workflow.yaml', 'workflow.yml']
111+
return config.name in [
112+
'workflow.yaml', 'workflow.yml', 'simple_workflow.yaml',
113+
'simple_workflow.yml'
114+
]
112115

113116
@staticmethod
114117
def parse_args() -> Dict[str, Any]:
@@ -124,15 +127,6 @@ def parse_args() -> Dict[str, Any]:
124127
_dict_config[key[2:]] = value
125128
return _dict_config
126129

127-
@staticmethod
128-
def safe_get_config(config: DictConfig, keys: str) -> Any:
129-
node = config
130-
for key in keys.split('.'):
131-
if not hasattr(node, key):
132-
return None
133-
node = getattr(node, key)
134-
return node
135-
136130
@staticmethod
137131
def _update_config(config: Union[DictConfig, ListConfig],
138132
extra: Dict[str, str] = None):
@@ -151,14 +145,42 @@ def traverse_config(_config: Union[DictConfig, ListConfig, Any],
151145
if current_path in extra:
152146
logger.info(
153147
f'Replacing {current_path} with extra value.')
154-
setattr(_config, name, extra[current_path])
148+
# Convert temperature to float and max_tokens to int if they're numeric strings
149+
value_to_set = extra[current_path]
150+
if name == 'temperature' and isinstance(
151+
value_to_set, str):
152+
try:
153+
value_to_set = float(value_to_set)
154+
except (ValueError, TypeError):
155+
pass
156+
elif name == 'max_tokens' and isinstance(
157+
value_to_set, str):
158+
try:
159+
value_to_set = int(value_to_set)
160+
except (ValueError, TypeError):
161+
pass
162+
setattr(_config, name, value_to_set)
155163
# Find the key in extra that matches name (case-insensitive)
156164
elif (key_match := next(
157165
(key
158166
for key in extra if key.lower() == name.lower()),
159167
None)) is not None:
160168
logger.info(f'Replacing {name} with extra value.')
161-
setattr(_config, name, extra[key_match])
169+
# Convert temperature to float and max_tokens to int if they're numeric strings
170+
value_to_set = extra[key_match]
171+
if name == 'temperature' and isinstance(
172+
value_to_set, str):
173+
try:
174+
value_to_set = float(value_to_set)
175+
except (ValueError, TypeError):
176+
pass
177+
elif name == 'max_tokens' and isinstance(
178+
value_to_set, str):
179+
try:
180+
value_to_set = int(value_to_set)
181+
except (ValueError, TypeError):
182+
pass
183+
setattr(_config, name, value_to_set)
162184
# Handle placeholder replacement like <api_key>
163185
elif (isinstance(value, str) and value.startswith('<')
164186
and value.endswith('>')

ms_agent/tools/filesystem_tool.py

Lines changed: 97 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) ModelScope Contributors. All rights reserved.
1+
# Copyright (c) Alibaba, Inc. and its affiliates.
22
import fnmatch
33
import os
44
import re
@@ -8,12 +8,12 @@
88
from typing import Optional
99

1010
import json
11-
from ms_agent.config import Config
1211
from ms_agent.llm import LLM
1312
from ms_agent.llm.utils import Message, Tool
1413
from ms_agent.tools.base import ToolBase
15-
from ms_agent.utils import get_logger
14+
from ms_agent.utils import MAX_CONTINUE_RUNS, get_logger, retry
1615
from ms_agent.utils.constants import DEFAULT_INDEX_DIR, DEFAULT_OUTPUT_DIR
16+
from openai import OpenAI
1717

1818
logger = get_logger()
1919

@@ -46,6 +46,13 @@ def __init__(self, config, **kwargs):
4646
super().__init__(config)
4747
self.exclude_func(getattr(config.tools, 'file_system', None))
4848
self.output_dir = getattr(config, 'output_dir', DEFAULT_OUTPUT_DIR)
49+
if self.exclude_functions and 'edit_file' not in self.exclude_functions \
50+
or self.include_functions and 'edit_file' in self.include_functions:
51+
self.edit_file_config = getattr(config.tools.file_system,
52+
'edit_file_config', None)
53+
self.edit_client = OpenAI(
54+
api_key=self.edit_file_config.api_key,
55+
base_url=self.edit_file_config.base_url)
4956
self.trust_remote_code = kwargs.get('trust_remote_code', False)
5057
self.allow_read_all_files = getattr(
5158
getattr(config.tools, 'file_system', {}), 'allow_read_all_files',
@@ -57,10 +64,8 @@ def __init__(self, config, **kwargs):
5764
index_dir = getattr(config, 'index_cache_dir', DEFAULT_INDEX_DIR)
5865
self.index_dir = os.path.join(self.output_dir, index_dir)
5966
self.system = self.SYSTEM_FOR_ABBREVIATIONS
60-
system = Config.safe_get_config(
61-
self.config, 'tools.file_system.system_for_abbreviations')
62-
if system:
63-
self.system = system
67+
if hasattr(self.config.tools.file_system, 'system_for_abbreviations'):
68+
self.system = self.config.tools.file_system.system_for_abbreviations
6469

6570
async def connect(self):
6671
logger.warning_once(
@@ -196,6 +201,65 @@ async def _get_tools_inner(self):
196201
'required': ['path'],
197202
'additionalProperties': False
198203
}),
204+
Tool(
205+
tool_name='edit_file',
206+
server_name='file_system',
207+
description=
208+
('Use this tool to make an edit to an existing file.\n\n'
209+
'This will be read by a less intelligent model, which will quickly apply the edit. '
210+
'You should make it clear what the edit is, while also minimizing the unchanged code you write.\n'
211+
'When writing the edit, you should specify each edit in sequence, with the special comment '
212+
'// ... existing code ... to represent unchanged code in between edited lines.\n\n'
213+
'For example:\n\n// ... existing code ...\nFIRST_EDIT\n// ... existing code ...\n'
214+
'SECOND_EDIT\n// ... existing code ...\nTHIRD_EDIT\n// ... existing code ...\n\n'
215+
'You should still bias towards repeating as few lines of the original file '
216+
'as possible to convey the change.\n'
217+
'But, each edit should contain minimally sufficient context of unchanged lines '
218+
"around the code you're editing to resolve ambiguity.\n"
219+
'DO NOT omit spans of pre-existing code (or comments) without using the '
220+
'// ... existing code ... comment to indicate its absence. '
221+
'If you omit the existing code comment, the model may inadvertently delete these lines.\n'
222+
'If you plan on deleting a section, you must provide context before and after to delete it. '
223+
'If the initial code is ```code \\n Block 1 \\n Block 2 \\n Block 3 \\n code```, '
224+
'and you want to remove Block 2, you would output '
225+
'```// ... existing code ... \\n Block 1 \\n Block 3 \\n // ... existing code ...```.\n'
226+
'Make sure it is clear what the edit should be, and where it should be applied.\n'
227+
'Make edits to a file in a single edit_file call '
228+
'instead of multiple edit_file calls to the same file. '
229+
'The apply model can handle many distinct edits at once.'
230+
),
231+
parameters={
232+
'type': 'object',
233+
'properties': {
234+
'path': {
235+
'type': 'string',
236+
'description':
237+
'Path of the target file to modify.'
238+
},
239+
'instructions': {
240+
'type':
241+
'string',
242+
'description':
243+
('A single sentence instruction describing '
244+
'what you are going to do for the sketched edit. '
245+
'This is used to assist the less intelligent model in applying the edit. '
246+
'Use the first person to describe what you are going to do. '
247+
'Use it to disambiguate uncertainty in the edit.'
248+
)
249+
},
250+
'code_edit': {
251+
'type':
252+
'string',
253+
'description':
254+
('Specify ONLY the precise lines of code that you wish to edit. '
255+
'NEVER specify or write out unchanged code. '
256+
'Instead, represent all unchanged code using the comment of the language '
257+
"you're editing in - example: // ... existing code ..."
258+
)
259+
}
260+
},
261+
'required': ['path', 'instructions', 'code_edit']
262+
}),
199263
Tool(
200264
tool_name='search_file_content',
201265
server_name='file_system',
@@ -936,3 +1000,29 @@ async def list_files(self, path: str = None):
9361000
except Exception as e:
9371001
return f'List files of <{path or "root path"}> failed, error: ' + str(
9381002
e)
1003+
1004+
@retry(max_attempts=MAX_CONTINUE_RUNS, delay=1.0)
1005+
async def edit_file(self,
1006+
path: str = None,
1007+
instructions: str = None,
1008+
code_edit: str = None):
1009+
try:
1010+
with open(os.path.join(self.output_dir, path), 'r') as f:
1011+
initial_code = f.read()
1012+
response = self.edit_client.chat.completions.create(
1013+
model=self.edit_file_config.diff_model,
1014+
messages=[{
1015+
'role':
1016+
'user',
1017+
'content':
1018+
(f'<instruction>{instructions}</instruction>\n'
1019+
f'<code>{initial_code}</code>\n'
1020+
f'<update>{code_edit}</update>')
1021+
}])
1022+
merged_code = response.choices[0].message.content
1023+
1024+
with open(os.path.join(self.output_dir, path), 'w') as f:
1025+
f.write(merged_code)
1026+
return f'Edit file <{path}> successfully.'
1027+
except Exception as e:
1028+
return f'Edit file <{path}> failed, error: ' + str(e)

0 commit comments

Comments
 (0)