auto-coder 0.1.268__py3-none-any.whl → 0.1.270__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of auto-coder might be problematic. Click here for more details.
- {auto_coder-0.1.268.dist-info → auto_coder-0.1.270.dist-info}/METADATA +2 -2
- {auto_coder-0.1.268.dist-info → auto_coder-0.1.270.dist-info}/RECORD +23 -20
- autocoder/agent/auto_learn_from_commit.py +209 -0
- autocoder/auto_coder.py +4 -0
- autocoder/auto_coder_runner.py +2647 -0
- autocoder/chat_auto_coder.py +54 -2630
- autocoder/commands/auto_command.py +23 -33
- autocoder/common/__init__.py +6 -2
- autocoder/common/auto_coder_lang.py +21 -4
- autocoder/common/auto_configure.py +41 -30
- autocoder/common/code_modification_ranker.py +55 -11
- autocoder/common/command_templates.py +2 -3
- autocoder/common/context_pruner.py +214 -14
- autocoder/common/conversation_pruner.py +11 -10
- autocoder/index/entry.py +44 -22
- autocoder/index/index.py +1 -1
- autocoder/utils/auto_project_type.py +120 -0
- autocoder/utils/model_provider_selector.py +23 -23
- autocoder/version.py +1 -1
- {auto_coder-0.1.268.dist-info → auto_coder-0.1.270.dist-info}/LICENSE +0 -0
- {auto_coder-0.1.268.dist-info → auto_coder-0.1.270.dist-info}/WHEEL +0 -0
- {auto_coder-0.1.268.dist-info → auto_coder-0.1.270.dist-info}/entry_points.txt +0 -0
- {auto_coder-0.1.268.dist-info → auto_coder-0.1.270.dist-info}/top_level.txt +0 -0
autocoder/chat_auto_coder.py
CHANGED
|
@@ -1,73 +1,53 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
from prompt_toolkit import prompt
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
5
4
|
import os
|
|
6
|
-
import yaml
|
|
7
|
-
import json
|
|
8
|
-
import sys
|
|
9
|
-
import io
|
|
10
|
-
import uuid
|
|
11
|
-
import glob
|
|
12
|
-
import time
|
|
13
|
-
import hashlib
|
|
14
|
-
from contextlib import contextmanager
|
|
15
|
-
from typing import List, Dict, Any, Optional
|
|
16
5
|
from prompt_toolkit import PromptSession
|
|
6
|
+
from prompt_toolkit.key_binding import KeyBindings
|
|
17
7
|
from prompt_toolkit.history import InMemoryHistory
|
|
18
8
|
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
|
|
19
9
|
from prompt_toolkit.styles import Style
|
|
20
|
-
from prompt_toolkit.formatted_text import FormattedText
|
|
21
|
-
from prompt_toolkit.key_binding import KeyBindings
|
|
22
|
-
from prompt_toolkit.completion import WordCompleter, Completer, Completion
|
|
23
|
-
from prompt_toolkit.shortcuts import confirm
|
|
24
|
-
from autocoder.common import AutoCoderArgs
|
|
25
|
-
from pydantic import Field, BaseModel
|
|
26
|
-
from autocoder.common.result_manager import ResultManager
|
|
27
10
|
from autocoder.version import __version__
|
|
28
|
-
from autocoder.auto_coder import main as auto_coder_main
|
|
29
|
-
from autocoder.common.command_completer import CommandTextParser
|
|
30
|
-
from autocoder.utils import get_last_yaml_file
|
|
31
|
-
from autocoder.index.symbols_utils import (
|
|
32
|
-
extract_symbols,
|
|
33
|
-
SymbolType,
|
|
34
|
-
)
|
|
35
|
-
import platform
|
|
36
|
-
import subprocess
|
|
37
|
-
from rich.console import Console
|
|
38
|
-
from rich.panel import Panel
|
|
39
|
-
from rich.table import Table
|
|
40
|
-
from rich.live import Live
|
|
41
|
-
from rich.text import Text
|
|
42
|
-
from rich.live import Live
|
|
43
|
-
from rich.markdown import Markdown
|
|
44
|
-
from byzerllm.utils.nontext import Image
|
|
45
|
-
import git
|
|
46
|
-
from autocoder.common import git_utils
|
|
47
11
|
from autocoder.chat_auto_coder_lang import get_message
|
|
48
|
-
from
|
|
49
|
-
from autocoder.
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
12
|
+
from prompt_toolkit.formatted_text import FormattedText
|
|
13
|
+
from autocoder.auto_coder_runner import (
|
|
14
|
+
auto_command,
|
|
15
|
+
load_memory,
|
|
16
|
+
save_memory,
|
|
17
|
+
configure,
|
|
18
|
+
manage_models,
|
|
19
|
+
print_conf,
|
|
20
|
+
exclude_dirs,
|
|
21
|
+
exclude_files,
|
|
22
|
+
ask,
|
|
23
|
+
coding,
|
|
24
|
+
load_tokenizer,
|
|
25
|
+
initialize_system,
|
|
26
|
+
InitializeSystemRequest,
|
|
27
|
+
add_files,
|
|
28
|
+
remove_files,
|
|
29
|
+
index_query,
|
|
30
|
+
index_build,
|
|
31
|
+
index_export,
|
|
32
|
+
index_import,
|
|
33
|
+
list_files,
|
|
34
|
+
lib_command,
|
|
35
|
+
mcp,
|
|
36
|
+
revert,
|
|
37
|
+
commit,
|
|
38
|
+
design,
|
|
39
|
+
voice_input,
|
|
40
|
+
chat,
|
|
41
|
+
gen_and_exec_shell_command,
|
|
42
|
+
execute_shell_command,
|
|
43
|
+
get_mcp_server,
|
|
44
|
+
completer,
|
|
45
|
+
summon,
|
|
46
|
+
get_memory
|
|
47
|
+
)
|
|
68
48
|
|
|
69
49
|
def parse_arguments():
|
|
70
|
-
|
|
50
|
+
|
|
71
51
|
|
|
72
52
|
parser = argparse.ArgumentParser(description="Chat Auto Coder")
|
|
73
53
|
parser.add_argument("--debug", action="store_true",
|
|
@@ -97,60 +77,6 @@ def parse_arguments():
|
|
|
97
77
|
return parser.parse_args()
|
|
98
78
|
|
|
99
79
|
|
|
100
|
-
ARGS = None
|
|
101
|
-
|
|
102
|
-
if platform.system() == "Windows":
|
|
103
|
-
from colorama import init
|
|
104
|
-
|
|
105
|
-
init()
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
memory = {
|
|
109
|
-
"conversation": [],
|
|
110
|
-
"current_files": {"files": [], "groups": {}},
|
|
111
|
-
"conf": {},
|
|
112
|
-
"exclude_dirs": [],
|
|
113
|
-
"mode": "auto_detect", # 新增mode字段,默认为 auto_detect 模式
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
project_root = os.getcwd()
|
|
117
|
-
|
|
118
|
-
base_persist_dir = os.path.join(".auto-coder", "plugins", "chat-auto-coder")
|
|
119
|
-
|
|
120
|
-
defaut_exclude_dirs = [".git", "node_modules", "dist", "build", "__pycache__"]
|
|
121
|
-
|
|
122
|
-
commands = [
|
|
123
|
-
"/add_files",
|
|
124
|
-
"/remove_files",
|
|
125
|
-
"/list_files",
|
|
126
|
-
"/conf",
|
|
127
|
-
"/coding",
|
|
128
|
-
"/chat",
|
|
129
|
-
"/ask",
|
|
130
|
-
"/commit",
|
|
131
|
-
"/revert",
|
|
132
|
-
"/index/query",
|
|
133
|
-
"/index/build",
|
|
134
|
-
"/index/export",
|
|
135
|
-
"/index/import",
|
|
136
|
-
"/exclude_files",
|
|
137
|
-
"/help",
|
|
138
|
-
"/shell",
|
|
139
|
-
"/voice_input",
|
|
140
|
-
"/exit",
|
|
141
|
-
"/summon",
|
|
142
|
-
"/mode",
|
|
143
|
-
"/lib",
|
|
144
|
-
"/design",
|
|
145
|
-
"/mcp",
|
|
146
|
-
"/models",
|
|
147
|
-
"/auto",
|
|
148
|
-
"/conf/export",
|
|
149
|
-
"/conf/import",
|
|
150
|
-
"/exclude_dirs",
|
|
151
|
-
]
|
|
152
|
-
|
|
153
|
-
|
|
154
80
|
def show_help():
|
|
155
81
|
print(f"\033[1m{get_message('official_doc')}\033[0m")
|
|
156
82
|
print()
|
|
@@ -212,2521 +138,11 @@ def show_help():
|
|
|
212
138
|
f" \033[94m/exit\033[0m - \033[92m{get_message('exit_desc')}\033[0m")
|
|
213
139
|
print()
|
|
214
140
|
|
|
215
|
-
|
|
216
|
-
def configure_project_type():
|
|
217
|
-
from prompt_toolkit.lexers import PygmentsLexer
|
|
218
|
-
from pygments.lexers.markup import MarkdownLexer
|
|
219
|
-
from prompt_toolkit.formatted_text import HTML
|
|
220
|
-
from prompt_toolkit.shortcuts import print_formatted_text
|
|
221
|
-
from prompt_toolkit.styles import Style
|
|
222
|
-
from html import escape
|
|
223
|
-
|
|
224
|
-
style = Style.from_dict(
|
|
225
|
-
{
|
|
226
|
-
"info": "#ansicyan",
|
|
227
|
-
"warning": "#ansiyellow",
|
|
228
|
-
"input-area": "#ansigreen",
|
|
229
|
-
"header": "#ansibrightyellow bold",
|
|
230
|
-
}
|
|
231
|
-
)
|
|
232
|
-
|
|
233
|
-
def print_info(text):
|
|
234
|
-
print_formatted_text(HTML(f"<info>{escape(text)}</info>"), style=style)
|
|
235
|
-
|
|
236
|
-
def print_warning(text):
|
|
237
|
-
print_formatted_text(
|
|
238
|
-
HTML(f"<warning>{escape(text)}</warning>"), style=style)
|
|
239
|
-
|
|
240
|
-
def print_header(text):
|
|
241
|
-
print_formatted_text(
|
|
242
|
-
HTML(f"<header>{escape(text)}</header>"), style=style)
|
|
243
|
-
|
|
244
|
-
print_header(f"\n=== {get_message('project_type_config')} ===\n")
|
|
245
|
-
print_info(get_message("project_type_supports"))
|
|
246
|
-
print_info(get_message("language_suffixes"))
|
|
247
|
-
print_info(get_message("predefined_types"))
|
|
248
|
-
print_info(get_message("mixed_projects"))
|
|
249
|
-
print_info(get_message("examples"))
|
|
250
|
-
|
|
251
|
-
print_warning(f"{get_message('default_type')}\n")
|
|
252
|
-
|
|
253
|
-
project_type = prompt(
|
|
254
|
-
get_message("enter_project_type"), default="py", style=style
|
|
255
|
-
).strip()
|
|
256
|
-
|
|
257
|
-
if project_type:
|
|
258
|
-
configure(f"project_type:{project_type}", skip_print=True)
|
|
259
|
-
configure("skip_build_index:false", skip_print=True)
|
|
260
|
-
print_info(f"\n{get_message('project_type_set')} {project_type}")
|
|
261
|
-
else:
|
|
262
|
-
print_info(f"\n{get_message('using_default_type')}")
|
|
263
|
-
|
|
264
|
-
print_warning(f"\n{get_message('change_setting_later')}:")
|
|
265
|
-
print_warning("/conf project_type:<new_type>\n")
|
|
266
|
-
|
|
267
|
-
return project_type
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
def initialize_system(args):
|
|
271
|
-
from autocoder.utils.model_provider_selector import ModelProviderSelector
|
|
272
|
-
from autocoder import models as models_module
|
|
273
|
-
print(f"\n\033[1;34m{get_message('initializing')}\033[0m")
|
|
274
|
-
|
|
275
|
-
first_time = [False]
|
|
276
|
-
configure_success = [False]
|
|
277
|
-
|
|
278
|
-
def print_status(message, status):
|
|
279
|
-
if status == "success":
|
|
280
|
-
print(f"\033[32m✓ {message}\033[0m")
|
|
281
|
-
elif status == "warning":
|
|
282
|
-
print(f"\033[33m! {message}\033[0m")
|
|
283
|
-
elif status == "error":
|
|
284
|
-
print(f"\033[31m✗ {message}\033[0m")
|
|
285
|
-
else:
|
|
286
|
-
print(f" {message}")
|
|
287
|
-
|
|
288
|
-
def init_project():
|
|
289
|
-
if not os.path.exists(".auto-coder"):
|
|
290
|
-
first_time[0] = True
|
|
291
|
-
print_status(get_message("not_initialized"), "warning")
|
|
292
|
-
init_choice = input(
|
|
293
|
-
f" {get_message('init_prompt')}").strip().lower()
|
|
294
|
-
if init_choice == "y":
|
|
295
|
-
try:
|
|
296
|
-
subprocess.run(
|
|
297
|
-
["auto-coder", "init", "--source_dir", "."], check=True
|
|
298
|
-
)
|
|
299
|
-
print_status(get_message("init_success"), "success")
|
|
300
|
-
except subprocess.CalledProcessError:
|
|
301
|
-
print_status(get_message("init_fail"), "error")
|
|
302
|
-
print_status(get_message("init_manual"), "warning")
|
|
303
|
-
exit(1)
|
|
304
|
-
else:
|
|
305
|
-
print_status(get_message("exit_no_init"), "warning")
|
|
306
|
-
exit(1)
|
|
307
|
-
|
|
308
|
-
if not os.path.exists(base_persist_dir):
|
|
309
|
-
os.makedirs(base_persist_dir, exist_ok=True)
|
|
310
|
-
print_status(get_message("created_dir").format(
|
|
311
|
-
base_persist_dir), "success")
|
|
312
|
-
|
|
313
|
-
if first_time[0]:
|
|
314
|
-
configure_project_type()
|
|
315
|
-
configure_success[0] = True
|
|
316
|
-
|
|
317
|
-
print_status(get_message("init_complete"), "success")
|
|
318
|
-
|
|
319
|
-
init_project()
|
|
320
|
-
|
|
321
|
-
if not args.skip_provider_selection and first_time[0]:
|
|
322
|
-
if args.product_mode == "lite":
|
|
323
|
-
## 如果已经是配置过的项目,就无需再选择
|
|
324
|
-
if first_time[0]:
|
|
325
|
-
if not models_module.check_model_exists("v3_chat") or not models_module.check_model_exists("r1_chat"):
|
|
326
|
-
model_provider_selector = ModelProviderSelector()
|
|
327
|
-
model_provider_info = model_provider_selector.select_provider()
|
|
328
|
-
if model_provider_info is not None:
|
|
329
|
-
models_json_list = model_provider_selector.to_models_json(model_provider_info)
|
|
330
|
-
models_module.add_and_activate_models(models_json_list)
|
|
331
|
-
|
|
332
|
-
if args.product_mode == "pro":
|
|
333
|
-
# Check if Ray is running
|
|
334
|
-
print_status(get_message("checking_ray"), "")
|
|
335
|
-
ray_status = subprocess.run(
|
|
336
|
-
["ray", "status"], capture_output=True, text=True)
|
|
337
|
-
if ray_status.returncode != 0:
|
|
338
|
-
print_status(get_message("ray_not_running"), "warning")
|
|
339
|
-
try:
|
|
340
|
-
subprocess.run(["ray", "start", "--head"], check=True)
|
|
341
|
-
print_status(get_message("ray_start_success"), "success")
|
|
342
|
-
except subprocess.CalledProcessError:
|
|
343
|
-
print_status(get_message("ray_start_fail"), "error")
|
|
344
|
-
return
|
|
345
|
-
else:
|
|
346
|
-
print_status(get_message("ray_running"), "success")
|
|
347
|
-
|
|
348
|
-
# Check if deepseek_chat model is available
|
|
349
|
-
print_status(get_message("checking_model"), "")
|
|
350
|
-
try:
|
|
351
|
-
result = subprocess.run(
|
|
352
|
-
["easy-byzerllm", "chat", "v3_chat", "你好"],
|
|
353
|
-
capture_output=True,
|
|
354
|
-
text=True,
|
|
355
|
-
timeout=30,
|
|
356
|
-
)
|
|
357
|
-
if result.returncode == 0:
|
|
358
|
-
print_status(get_message("model_available"), "success")
|
|
359
|
-
init_project()
|
|
360
|
-
print_status(get_message("init_complete_final"), "success")
|
|
361
|
-
return
|
|
362
|
-
except subprocess.TimeoutExpired:
|
|
363
|
-
print_status(get_message("model_timeout"), "error")
|
|
364
|
-
except subprocess.CalledProcessError:
|
|
365
|
-
print_status(get_message("model_error"), "error")
|
|
366
|
-
|
|
367
|
-
# If deepseek_chat is not available
|
|
368
|
-
print_status(get_message("model_not_available"), "warning")
|
|
369
|
-
api_key = prompt(HTML(f"<b>{get_message('enter_api_key')} </b>"))
|
|
370
|
-
|
|
371
|
-
print_status(get_message("deploying_model").format("Deepseek官方"), "")
|
|
372
|
-
deploy_cmd = [
|
|
373
|
-
"byzerllm",
|
|
374
|
-
"deploy",
|
|
375
|
-
"--pretrained_model_type",
|
|
376
|
-
"saas/openai",
|
|
377
|
-
"--cpus_per_worker",
|
|
378
|
-
"0.001",
|
|
379
|
-
"--gpus_per_worker",
|
|
380
|
-
"0",
|
|
381
|
-
"--worker_concurrency",
|
|
382
|
-
"1000",
|
|
383
|
-
"--num_workers",
|
|
384
|
-
"1",
|
|
385
|
-
"--infer_params",
|
|
386
|
-
f"saas.base_url=https://api.deepseek.com/v1 saas.api_key={api_key} saas.model=deepseek-chat",
|
|
387
|
-
"--model",
|
|
388
|
-
"v3_chat",
|
|
389
|
-
]
|
|
390
|
-
|
|
391
|
-
try:
|
|
392
|
-
subprocess.run(deploy_cmd, check=True)
|
|
393
|
-
print_status(get_message("deploy_complete"), "success")
|
|
394
|
-
except subprocess.CalledProcessError:
|
|
395
|
-
print_status(get_message("deploy_fail"), "error")
|
|
396
|
-
return
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
deploy_cmd = [
|
|
400
|
-
"byzerllm",
|
|
401
|
-
"deploy",
|
|
402
|
-
"--pretrained_model_type",
|
|
403
|
-
"saas/reasoning_openai",
|
|
404
|
-
"--cpus_per_worker",
|
|
405
|
-
"0.001",
|
|
406
|
-
"--gpus_per_worker",
|
|
407
|
-
"0",
|
|
408
|
-
"--worker_concurrency",
|
|
409
|
-
"1000",
|
|
410
|
-
"--num_workers",
|
|
411
|
-
"1",
|
|
412
|
-
"--infer_params",
|
|
413
|
-
f"saas.base_url=https://api.deepseek.com/v1 saas.api_key={api_key} saas.model=deepseek-reasoner",
|
|
414
|
-
"--model",
|
|
415
|
-
"r1_chat",
|
|
416
|
-
]
|
|
417
|
-
|
|
418
|
-
try:
|
|
419
|
-
subprocess.run(deploy_cmd, check=True)
|
|
420
|
-
print_status(get_message("deploy_complete"), "success")
|
|
421
|
-
except subprocess.CalledProcessError:
|
|
422
|
-
print_status(get_message("deploy_fail"), "error")
|
|
423
|
-
return
|
|
424
|
-
|
|
425
|
-
# Validate the deployment
|
|
426
|
-
print_status(get_message("validating_deploy"), "")
|
|
427
|
-
try:
|
|
428
|
-
validation_result = subprocess.run(
|
|
429
|
-
["easy-byzerllm", "chat", "v3_chat", "你好"],
|
|
430
|
-
capture_output=True,
|
|
431
|
-
text=True,
|
|
432
|
-
timeout=30,
|
|
433
|
-
check=True,
|
|
434
|
-
)
|
|
435
|
-
print_status(get_message("validation_success"), "success")
|
|
436
|
-
except (subprocess.TimeoutExpired, subprocess.CalledProcessError):
|
|
437
|
-
print_status(get_message("validation_fail"), "error")
|
|
438
|
-
print_status(get_message("manual_start"), "warning")
|
|
439
|
-
print_status("easy-byzerllm chat v3_chat 你好", "")
|
|
440
|
-
|
|
441
|
-
print_status(get_message("init_complete_final"), "success")
|
|
442
|
-
configure_success[0] = True
|
|
443
|
-
|
|
444
|
-
if first_time[0] and args.product_mode == "pro" and configure_success[0]:
|
|
445
|
-
configure(f"model:v3_chat", skip_print=True)
|
|
446
|
-
configure(f"chat_model:r1_chat", skip_print=True)
|
|
447
|
-
configure(f"generate_rerank_model:r1_chat", skip_print=True)
|
|
448
|
-
configure(f"code_model:v3_chat", skip_print=True)
|
|
449
|
-
configure(f"index_filter_model:r1_chat", skip_print=True)
|
|
450
|
-
|
|
451
|
-
if first_time[0] and args.product_mode == "lite" and models_module.check_model_exists("v3_chat"):
|
|
452
|
-
configure(f"model:v3_chat", skip_print=True)
|
|
453
|
-
configure(f"chat_model:r1_chat", skip_print=True)
|
|
454
|
-
configure(f"generate_rerank_model:r1_chat", skip_print=True)
|
|
455
|
-
configure(f"code_model:v3_chat", skip_print=True)
|
|
456
|
-
configure(f"index_filter_model:r1_chat", skip_print=True)
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
def convert_yaml_config_to_str(yaml_config):
|
|
460
|
-
yaml_content = yaml.safe_dump(
|
|
461
|
-
yaml_config,
|
|
462
|
-
allow_unicode=True,
|
|
463
|
-
default_flow_style=False,
|
|
464
|
-
default_style=None,
|
|
465
|
-
)
|
|
466
|
-
return yaml_content
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
def get_all_file_names_in_project() -> List[str]:
|
|
470
|
-
|
|
471
|
-
file_names = []
|
|
472
|
-
final_exclude_dirs = defaut_exclude_dirs + memory.get("exclude_dirs", [])
|
|
473
|
-
for root, dirs, files in os.walk(project_root, followlinks=True):
|
|
474
|
-
dirs[:] = [d for d in dirs if d not in final_exclude_dirs]
|
|
475
|
-
file_names.extend(files)
|
|
476
|
-
return file_names
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
def get_all_file_in_project() -> List[str]:
|
|
480
|
-
|
|
481
|
-
file_names = []
|
|
482
|
-
final_exclude_dirs = defaut_exclude_dirs + memory.get("exclude_dirs", [])
|
|
483
|
-
for root, dirs, files in os.walk(project_root, followlinks=True):
|
|
484
|
-
dirs[:] = [d for d in dirs if d not in final_exclude_dirs]
|
|
485
|
-
for file in files:
|
|
486
|
-
file_names.append(os.path.join(root, file))
|
|
487
|
-
return file_names
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
def get_all_file_in_project_with_dot() -> List[str]:
|
|
491
|
-
file_names = []
|
|
492
|
-
final_exclude_dirs = defaut_exclude_dirs + memory.get("exclude_dirs", [])
|
|
493
|
-
for root, dirs, files in os.walk(project_root, followlinks=True):
|
|
494
|
-
dirs[:] = [d for d in dirs if d not in final_exclude_dirs]
|
|
495
|
-
for file in files:
|
|
496
|
-
file_names.append(os.path.join(
|
|
497
|
-
root, file).replace(project_root, "."))
|
|
498
|
-
return file_names
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
def get_all_dir_names_in_project() -> List[str]:
|
|
502
|
-
dir_names = []
|
|
503
|
-
final_exclude_dirs = defaut_exclude_dirs + memory.get("exclude_dirs", [])
|
|
504
|
-
for root, dirs, files in os.walk(project_root, followlinks=True):
|
|
505
|
-
dirs[:] = [d for d in dirs if d not in final_exclude_dirs]
|
|
506
|
-
for dir in dirs:
|
|
507
|
-
dir_names.append(dir)
|
|
508
|
-
return dir_names
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
def find_files_in_project(patterns: List[str]) -> List[str]:
|
|
512
|
-
matched_files = []
|
|
513
|
-
final_exclude_dirs = defaut_exclude_dirs + memory.get("exclude_dirs", [])
|
|
514
|
-
|
|
515
|
-
for pattern in patterns:
|
|
516
|
-
if "*" in pattern or "?" in pattern:
|
|
517
|
-
for file_path in glob.glob(pattern, recursive=True):
|
|
518
|
-
if os.path.isfile(file_path):
|
|
519
|
-
abs_path = os.path.abspath(file_path)
|
|
520
|
-
if not any(
|
|
521
|
-
exclude_dir in abs_path.split(os.sep)
|
|
522
|
-
for exclude_dir in final_exclude_dirs
|
|
523
|
-
):
|
|
524
|
-
matched_files.append(abs_path)
|
|
525
|
-
else:
|
|
526
|
-
is_added = False
|
|
527
|
-
# add files belongs to project
|
|
528
|
-
for root, dirs, files in os.walk(project_root, followlinks=True):
|
|
529
|
-
dirs[:] = [d for d in dirs if d not in final_exclude_dirs]
|
|
530
|
-
if pattern in files:
|
|
531
|
-
matched_files.append(os.path.join(root, pattern))
|
|
532
|
-
is_added = True
|
|
533
|
-
else:
|
|
534
|
-
for file in files:
|
|
535
|
-
_pattern = os.path.abspath(pattern)
|
|
536
|
-
if _pattern in os.path.join(root, file):
|
|
537
|
-
matched_files.append(os.path.join(root, file))
|
|
538
|
-
is_added = True
|
|
539
|
-
# add files not belongs to project
|
|
540
|
-
if not is_added:
|
|
541
|
-
matched_files.append(pattern)
|
|
542
|
-
|
|
543
|
-
return list(set(matched_files))
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
def convert_config_value(key, value):
|
|
547
|
-
field_info = AutoCoderArgs.model_fields.get(key)
|
|
548
|
-
if field_info:
|
|
549
|
-
if value.lower() in ["true", "false"]:
|
|
550
|
-
return value.lower() == "true"
|
|
551
|
-
elif "int" in str(field_info.annotation):
|
|
552
|
-
return int(value)
|
|
553
|
-
elif "float" in str(field_info.annotation):
|
|
554
|
-
return float(value)
|
|
555
|
-
else:
|
|
556
|
-
return value
|
|
557
|
-
else:
|
|
558
|
-
print(f"Invalid configuration key: {key}")
|
|
559
|
-
return None
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
@contextmanager
|
|
563
|
-
def redirect_stdout():
|
|
564
|
-
original_stdout = sys.stdout
|
|
565
|
-
sys.stdout = f = io.StringIO()
|
|
566
|
-
try:
|
|
567
|
-
yield f
|
|
568
|
-
finally:
|
|
569
|
-
sys.stdout = original_stdout
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
def configure(conf: str, skip_print=False):
|
|
573
|
-
printer = Printer()
|
|
574
|
-
parts = conf.split(None, 1)
|
|
575
|
-
if len(parts) == 2 and parts[0] in ["/drop", "/unset", "/remove"]:
|
|
576
|
-
key = parts[1].strip()
|
|
577
|
-
if key in memory["conf"]:
|
|
578
|
-
del memory["conf"][key]
|
|
579
|
-
save_memory()
|
|
580
|
-
printer.print_in_terminal("config_delete_success", style="green", key=key)
|
|
581
|
-
else:
|
|
582
|
-
printer.print_in_terminal("config_not_found", style="yellow", key=key)
|
|
583
|
-
else:
|
|
584
|
-
parts = conf.split(":", 1)
|
|
585
|
-
if len(parts) != 2:
|
|
586
|
-
printer.print_in_terminal("config_invalid_format", style="red")
|
|
587
|
-
return
|
|
588
|
-
key, value = parts
|
|
589
|
-
key = key.strip()
|
|
590
|
-
value = value.strip()
|
|
591
|
-
if not value:
|
|
592
|
-
printer.print_in_terminal("config_value_empty", style="red")
|
|
593
|
-
return
|
|
594
|
-
product_mode = memory["conf"].get("product_mode",None)
|
|
595
|
-
if product_mode:
|
|
596
|
-
ConfigValidator.validate(key, value, product_mode)
|
|
597
|
-
memory["conf"][key] = value
|
|
598
|
-
save_memory()
|
|
599
|
-
if not skip_print:
|
|
600
|
-
printer.print_in_terminal("config_set_success", style="green", key=key, value=value)
|
|
601
|
-
|
|
602
|
-
# word_completer = WordCompleter(commands)
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
def get_symbol_list() -> List[SymbolItem]:
|
|
606
|
-
list_of_symbols = []
|
|
607
|
-
index_file = os.path.join(".auto-coder", "index.json")
|
|
608
|
-
|
|
609
|
-
if os.path.exists(index_file):
|
|
610
|
-
with open(index_file, "r",encoding="utf-8") as file:
|
|
611
|
-
index_data = json.load(file)
|
|
612
|
-
else:
|
|
613
|
-
index_data = {}
|
|
614
|
-
|
|
615
|
-
for item in index_data.values():
|
|
616
|
-
symbols_str = item["symbols"]
|
|
617
|
-
module_name = item["module_name"]
|
|
618
|
-
info1 = extract_symbols(symbols_str)
|
|
619
|
-
for name in info1.classes:
|
|
620
|
-
list_of_symbols.append(
|
|
621
|
-
SymbolItem(
|
|
622
|
-
symbol_name=name,
|
|
623
|
-
symbol_type=SymbolType.CLASSES,
|
|
624
|
-
file_name=module_name,
|
|
625
|
-
)
|
|
626
|
-
)
|
|
627
|
-
for name in info1.functions:
|
|
628
|
-
list_of_symbols.append(
|
|
629
|
-
SymbolItem(
|
|
630
|
-
symbol_name=name,
|
|
631
|
-
symbol_type=SymbolType.FUNCTIONS,
|
|
632
|
-
file_name=module_name,
|
|
633
|
-
)
|
|
634
|
-
)
|
|
635
|
-
for name in info1.variables:
|
|
636
|
-
list_of_symbols.append(
|
|
637
|
-
SymbolItem(
|
|
638
|
-
symbol_name=name,
|
|
639
|
-
symbol_type=SymbolType.VARIABLES,
|
|
640
|
-
file_name=module_name,
|
|
641
|
-
)
|
|
642
|
-
)
|
|
643
|
-
return list_of_symbols
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
def save_memory():
|
|
647
|
-
with open(os.path.join(base_persist_dir, "memory.json"), "w",encoding="utf-8") as f:
|
|
648
|
-
json.dump(memory, f, indent=2, ensure_ascii=False)
|
|
649
|
-
load_memory()
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
def load_memory():
|
|
653
|
-
global memory
|
|
654
|
-
memory_path = os.path.join(base_persist_dir, "memory.json")
|
|
655
|
-
if os.path.exists(memory_path):
|
|
656
|
-
with open(memory_path, "r", encoding="utf-8") as f:
|
|
657
|
-
memory = json.load(f)
|
|
658
|
-
completer.update_current_files(memory["current_files"]["files"])
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
completer = CommandCompleter(commands,
|
|
662
|
-
file_system_model=CCFileSystemModel(project_root=project_root,
|
|
663
|
-
defaut_exclude_dirs=defaut_exclude_dirs,
|
|
664
|
-
get_all_file_names_in_project=get_all_file_names_in_project,
|
|
665
|
-
get_all_file_in_project=get_all_file_in_project,
|
|
666
|
-
get_all_dir_names_in_project=get_all_dir_names_in_project,
|
|
667
|
-
get_all_file_in_project_with_dot=get_all_file_in_project_with_dot,
|
|
668
|
-
get_symbol_list=get_symbol_list
|
|
669
|
-
),
|
|
670
|
-
memory_model=CCMemoryModel(memory=memory,
|
|
671
|
-
save_memory_func=save_memory))
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
def print_conf(content:Dict[str,Any]):
|
|
677
|
-
"""Display configuration dictionary in a Rich table format with enhanced visual styling.
|
|
678
|
-
|
|
679
|
-
Args:
|
|
680
|
-
conf (Dict[str, Any]): Configuration dictionary to display
|
|
681
|
-
"""
|
|
682
|
-
console = Console()
|
|
683
|
-
|
|
684
|
-
# Create a styled table with rounded borders
|
|
685
|
-
table = Table(
|
|
686
|
-
show_header=True,
|
|
687
|
-
header_style="bold magenta",
|
|
688
|
-
title=get_message("conf_title"),
|
|
689
|
-
title_style="bold blue",
|
|
690
|
-
border_style="blue",
|
|
691
|
-
show_lines=True
|
|
692
|
-
)
|
|
693
|
-
|
|
694
|
-
# Add columns with explicit width and alignment
|
|
695
|
-
table.add_column(get_message("conf_key"), style="cyan", justify="right", width=30, no_wrap=False)
|
|
696
|
-
table.add_column(get_message("conf_value"), style="green", justify="left", width=50, no_wrap=False)
|
|
697
|
-
|
|
698
|
-
# Sort keys for consistent display
|
|
699
|
-
for key in sorted(content.keys()):
|
|
700
|
-
value = content[key]
|
|
701
|
-
# Format value based on type
|
|
702
|
-
if isinstance(value, (dict, list)):
|
|
703
|
-
formatted_value = Text(json.dumps(value, indent=2), style="yellow")
|
|
704
|
-
elif isinstance(value, bool):
|
|
705
|
-
formatted_value = Text(str(value), style="bright_green" if value else "red")
|
|
706
|
-
elif isinstance(value, (int, float)):
|
|
707
|
-
formatted_value = Text(str(value), style="bright_cyan")
|
|
708
|
-
else:
|
|
709
|
-
formatted_value = Text(str(value), style="green")
|
|
710
|
-
|
|
711
|
-
table.add_row(str(key), formatted_value)
|
|
712
|
-
|
|
713
|
-
# Add padding and print with a panel
|
|
714
|
-
console.print(Panel(
|
|
715
|
-
table,
|
|
716
|
-
padding=(1, 2),
|
|
717
|
-
subtitle=f"[italic]{get_message('conf_subtitle')}[/italic]",
|
|
718
|
-
border_style="blue"
|
|
719
|
-
))
|
|
720
|
-
|
|
721
|
-
def revert():
|
|
722
|
-
result_manager = ResultManager()
|
|
723
|
-
last_yaml_file = get_last_yaml_file("actions")
|
|
724
|
-
if last_yaml_file:
|
|
725
|
-
file_path = os.path.join("actions", last_yaml_file)
|
|
726
|
-
|
|
727
|
-
with redirect_stdout() as output:
|
|
728
|
-
auto_coder_main(["revert", "--file", file_path])
|
|
729
|
-
s = output.getvalue()
|
|
730
|
-
print(s, flush=True)
|
|
731
|
-
if "Successfully reverted changes" in s:
|
|
732
|
-
result_manager.append(content=s, meta={"action": "revert","success":False, "input":{
|
|
733
|
-
}})
|
|
734
|
-
print(
|
|
735
|
-
"Reverted the last chat action successfully. Remove the yaml file {file_path}"
|
|
736
|
-
)
|
|
737
|
-
os.remove(file_path)
|
|
738
|
-
else:
|
|
739
|
-
result_manager.append(content=s, meta={"action": "revert","success":False, "input":{
|
|
740
|
-
}})
|
|
741
|
-
else:
|
|
742
|
-
result_manager.append(content="No previous chat action found to revert.", meta={"action": "revert","success":False, "input":{
|
|
743
|
-
}})
|
|
744
|
-
print("No previous chat action found to revert.")
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
def add_files(args: List[str]):
|
|
748
|
-
|
|
749
|
-
result_manager = ResultManager()
|
|
750
|
-
if "groups" not in memory["current_files"]:
|
|
751
|
-
memory["current_files"]["groups"] = {}
|
|
752
|
-
if "groups_info" not in memory["current_files"]:
|
|
753
|
-
memory["current_files"]["groups_info"] = {}
|
|
754
|
-
if "current_groups" not in memory["current_files"]:
|
|
755
|
-
memory["current_files"]["current_groups"] = []
|
|
756
|
-
groups = memory["current_files"]["groups"]
|
|
757
|
-
groups_info = memory["current_files"]["groups_info"]
|
|
758
|
-
|
|
759
|
-
console = Console()
|
|
760
|
-
printer = Printer()
|
|
761
|
-
|
|
762
|
-
if not args:
|
|
763
|
-
printer.print_in_terminal("add_files_no_args", style="red")
|
|
764
|
-
result_manager.append(content=printer.get_message_from_key("add_files_no_args"),
|
|
765
|
-
meta={"action": "add_files","success":False, "input":{ "args": args}})
|
|
766
|
-
return
|
|
767
|
-
|
|
768
|
-
if args[0] == "/refresh":
|
|
769
|
-
completer.refresh_files()
|
|
770
|
-
load_memory()
|
|
771
|
-
console.print(
|
|
772
|
-
Panel("Refreshed file list.",
|
|
773
|
-
title="Files Refreshed", border_style="green")
|
|
774
|
-
)
|
|
775
|
-
result_manager.append(content="Files refreshed.",
|
|
776
|
-
meta={"action": "add_files","success":True, "input":{ "args": args}})
|
|
777
|
-
return
|
|
778
|
-
|
|
779
|
-
if args[0] == "/group":
|
|
780
|
-
if len(args) == 1 or (len(args) == 2 and args[1] == "list"):
|
|
781
|
-
if not groups:
|
|
782
|
-
console.print(
|
|
783
|
-
Panel("No groups defined.", title="Groups",
|
|
784
|
-
border_style="yellow")
|
|
785
|
-
)
|
|
786
|
-
result_manager.append(content="No groups defined.",
|
|
787
|
-
meta={"action": "add_files","success":False, "input":{ "args": args}})
|
|
788
|
-
else:
|
|
789
|
-
table = Table(
|
|
790
|
-
title="Defined Groups",
|
|
791
|
-
show_header=True,
|
|
792
|
-
header_style="bold magenta",
|
|
793
|
-
show_lines=True,
|
|
794
|
-
)
|
|
795
|
-
table.add_column("Group Name", style="cyan", no_wrap=True)
|
|
796
|
-
table.add_column("Files", style="green")
|
|
797
|
-
table.add_column("Query Prefix", style="yellow")
|
|
798
|
-
table.add_column("Active", style="magenta")
|
|
799
|
-
|
|
800
|
-
for i, (group_name, files) in enumerate(groups.items()):
|
|
801
|
-
query_prefix = groups_info.get(group_name, {}).get(
|
|
802
|
-
"query_prefix", ""
|
|
803
|
-
)
|
|
804
|
-
is_active = (
|
|
805
|
-
"✓"
|
|
806
|
-
if group_name in memory["current_files"]["current_groups"]
|
|
807
|
-
else ""
|
|
808
|
-
)
|
|
809
|
-
table.add_row(
|
|
810
|
-
group_name,
|
|
811
|
-
"\n".join([os.path.relpath(f, project_root)
|
|
812
|
-
for f in files]),
|
|
813
|
-
query_prefix,
|
|
814
|
-
is_active,
|
|
815
|
-
end_section=(i == len(groups) - 1),
|
|
816
|
-
)
|
|
817
|
-
console.print(Panel(table, border_style="blue"))
|
|
818
|
-
result_manager.append(content="Defined groups.",
|
|
819
|
-
meta={"action": "add_files","success":True, "input":{ "args": args}})
|
|
820
|
-
elif len(args) >= 2 and args[1] == "/reset":
|
|
821
|
-
memory["current_files"]["current_groups"] = []
|
|
822
|
-
console.print(
|
|
823
|
-
Panel(
|
|
824
|
-
"Active group names have been reset. If you want to clear the active files, you should use the command /remove_files /all.",
|
|
825
|
-
title="Groups Reset",
|
|
826
|
-
border_style="green",
|
|
827
|
-
)
|
|
828
|
-
)
|
|
829
|
-
result_manager.append(content="Active group names have been reset. If you want to clear the active files, you should use the command /remove_files /all.",
|
|
830
|
-
meta={"action": "add_files","success":True, "input":{ "args": args}})
|
|
831
|
-
elif len(args) >= 3 and args[1] == "/add":
|
|
832
|
-
group_name = args[2]
|
|
833
|
-
groups[group_name] = memory["current_files"]["files"].copy()
|
|
834
|
-
console.print(
|
|
835
|
-
Panel(
|
|
836
|
-
f"Added group '{group_name}' with current files.",
|
|
837
|
-
title="Group Added",
|
|
838
|
-
border_style="green",
|
|
839
|
-
)
|
|
840
|
-
)
|
|
841
|
-
result_manager.append(content=f"Added group '{group_name}' with current files.",
|
|
842
|
-
meta={"action": "add_files","success":True, "input":{ "args": args}})
|
|
843
|
-
|
|
844
|
-
elif len(args) >= 3 and args[1] == "/drop":
|
|
845
|
-
group_name = args[2]
|
|
846
|
-
if group_name in groups:
|
|
847
|
-
del memory["current_files"]["groups"][group_name]
|
|
848
|
-
if group_name in groups_info:
|
|
849
|
-
del memory["current_files"]["groups_info"][group_name]
|
|
850
|
-
if group_name in memory["current_files"]["current_groups"]:
|
|
851
|
-
memory["current_files"]["current_groups"].remove(
|
|
852
|
-
group_name)
|
|
853
|
-
console.print(
|
|
854
|
-
Panel(
|
|
855
|
-
f"Dropped group '{group_name}'.",
|
|
856
|
-
title="Group Dropped",
|
|
857
|
-
border_style="green",
|
|
858
|
-
)
|
|
859
|
-
)
|
|
860
|
-
result_manager.append(content=f"Dropped group '{group_name}'.",
|
|
861
|
-
meta={"action": "add_files","success":True, "input":{ "args": args}})
|
|
862
|
-
else:
|
|
863
|
-
console.print(
|
|
864
|
-
Panel(
|
|
865
|
-
f"Group '{group_name}' not found.",
|
|
866
|
-
title="Error",
|
|
867
|
-
border_style="red",
|
|
868
|
-
)
|
|
869
|
-
)
|
|
870
|
-
result_manager.append(content=f"Group '{group_name}' not found.",
|
|
871
|
-
meta={"action": "add_files","success":False, "input":{ "args": args}})
|
|
872
|
-
elif len(args) == 3 and args[1] == "/set":
|
|
873
|
-
group_name = args[2]
|
|
874
|
-
|
|
875
|
-
def multiline_edit():
|
|
876
|
-
from prompt_toolkit.lexers import PygmentsLexer
|
|
877
|
-
from pygments.lexers.markup import MarkdownLexer
|
|
878
|
-
from prompt_toolkit.formatted_text import HTML
|
|
879
|
-
from prompt_toolkit.shortcuts import print_formatted_text
|
|
880
|
-
|
|
881
|
-
style = Style.from_dict(
|
|
882
|
-
{
|
|
883
|
-
"dialog": "bg:#88ff88",
|
|
884
|
-
"dialog frame.label": "bg:#ffffff #000000",
|
|
885
|
-
"dialog.body": "bg:#000000 #00ff00",
|
|
886
|
-
"dialog shadow": "bg:#00aa00",
|
|
887
|
-
}
|
|
888
|
-
)
|
|
889
|
-
|
|
890
|
-
print_formatted_text(
|
|
891
|
-
HTML(
|
|
892
|
-
"<b>Type Atom Group Desc (Prese [Esc] + [Enter] to finish.)</b><br/>"
|
|
893
|
-
)
|
|
894
|
-
)
|
|
895
|
-
text = prompt(
|
|
896
|
-
HTML("<ansicyan>║</ansicyan> "),
|
|
897
|
-
multiline=True,
|
|
898
|
-
lexer=PygmentsLexer(MarkdownLexer),
|
|
899
|
-
style=style,
|
|
900
|
-
wrap_lines=True,
|
|
901
|
-
prompt_continuation=HTML("<ansicyan>║</ansicyan> "),
|
|
902
|
-
rprompt=HTML("<ansicyan>║</ansicyan>"),
|
|
903
|
-
)
|
|
904
|
-
return text
|
|
905
|
-
|
|
906
|
-
query_prefix = multiline_edit()
|
|
907
|
-
if group_name in groups:
|
|
908
|
-
groups_info[group_name] = {"query_prefix": query_prefix}
|
|
909
|
-
console.print(
|
|
910
|
-
Panel(
|
|
911
|
-
f"Set Atom Group Desc for group '{group_name}'.",
|
|
912
|
-
title="Group Info Updated",
|
|
913
|
-
border_style="green",
|
|
914
|
-
)
|
|
915
|
-
)
|
|
916
|
-
else:
|
|
917
|
-
console.print(
|
|
918
|
-
Panel(
|
|
919
|
-
f"Group '{group_name}' not found.",
|
|
920
|
-
title="Error",
|
|
921
|
-
border_style="red",
|
|
922
|
-
)
|
|
923
|
-
)
|
|
924
|
-
elif len(args) >= 2:
|
|
925
|
-
# 支持多个组的合并,允许组名之间使用逗号或空格分隔
|
|
926
|
-
group_names = " ".join(args[1:]).replace(",", " ").split()
|
|
927
|
-
merged_files = set()
|
|
928
|
-
missing_groups = []
|
|
929
|
-
for group_name in group_names:
|
|
930
|
-
if group_name in groups:
|
|
931
|
-
merged_files.update(groups[group_name])
|
|
932
|
-
else:
|
|
933
|
-
missing_groups.append(group_name)
|
|
934
|
-
|
|
935
|
-
if missing_groups:
|
|
936
|
-
console.print(
|
|
937
|
-
Panel(
|
|
938
|
-
f"Group(s) not found: {', '.join(missing_groups)}",
|
|
939
|
-
title="Error",
|
|
940
|
-
border_style="red",
|
|
941
|
-
)
|
|
942
|
-
)
|
|
943
|
-
result_manager.append(content=f"Group(s) not found: {', '.join(missing_groups)}",
|
|
944
|
-
meta={"action": "add_files","success":False, "input":{ "args": args}})
|
|
945
|
-
|
|
946
|
-
if merged_files:
|
|
947
|
-
memory["current_files"]["files"] = list(merged_files)
|
|
948
|
-
memory["current_files"]["current_groups"] = [
|
|
949
|
-
name for name in group_names if name in groups
|
|
950
|
-
]
|
|
951
|
-
console.print(
|
|
952
|
-
Panel(
|
|
953
|
-
f"Merged files from groups: {', '.join(group_names)}",
|
|
954
|
-
title="Files Merged",
|
|
955
|
-
border_style="green",
|
|
956
|
-
)
|
|
957
|
-
)
|
|
958
|
-
table = Table(
|
|
959
|
-
title="Current Files",
|
|
960
|
-
show_header=True,
|
|
961
|
-
header_style="bold magenta",
|
|
962
|
-
show_lines=True, # 这会在每行之间添加分割线
|
|
963
|
-
)
|
|
964
|
-
table.add_column("File", style="green")
|
|
965
|
-
for i, f in enumerate(memory["current_files"]["files"]):
|
|
966
|
-
table.add_row(
|
|
967
|
-
os.path.relpath(f, project_root),
|
|
968
|
-
end_section=(
|
|
969
|
-
i == len(memory["current_files"]["files"]) - 1
|
|
970
|
-
), # 在最后一行之后不添加分割线
|
|
971
|
-
)
|
|
972
|
-
console.print(Panel(table, border_style="blue"))
|
|
973
|
-
console.print(
|
|
974
|
-
Panel(
|
|
975
|
-
f"Active groups: {', '.join(memory['current_files']['current_groups'])}",
|
|
976
|
-
title="Active Groups",
|
|
977
|
-
border_style="green",
|
|
978
|
-
)
|
|
979
|
-
)
|
|
980
|
-
result_manager.append(content=f"Active groups: {', '.join(memory['current_files']['current_groups'])}",
|
|
981
|
-
meta={"action": "add_files","success":True, "input":{ "args": args}})
|
|
982
|
-
elif not missing_groups:
|
|
983
|
-
console.print(
|
|
984
|
-
Panel(
|
|
985
|
-
"No files in the specified groups.",
|
|
986
|
-
title="No Files Added",
|
|
987
|
-
border_style="yellow",
|
|
988
|
-
)
|
|
989
|
-
)
|
|
990
|
-
result_manager.append(content="No files in the specified groups.",
|
|
991
|
-
meta={"action": "add_files","success":False, "input":{ "args": args}})
|
|
992
|
-
else:
|
|
993
|
-
existing_files = memory["current_files"]["files"]
|
|
994
|
-
matched_files = find_files_in_project(args)
|
|
995
|
-
|
|
996
|
-
files_to_add = [f for f in matched_files if f not in existing_files]
|
|
997
|
-
if files_to_add:
|
|
998
|
-
memory["current_files"]["files"].extend(files_to_add)
|
|
999
|
-
table = Table(
|
|
1000
|
-
title=get_message("add_files_added_files"),
|
|
1001
|
-
show_header=True,
|
|
1002
|
-
header_style="bold magenta",
|
|
1003
|
-
show_lines=True, # 这会在每行之间添加分割线
|
|
1004
|
-
)
|
|
1005
|
-
table.add_column("File", style="green")
|
|
1006
|
-
for i, f in enumerate(files_to_add):
|
|
1007
|
-
table.add_row(
|
|
1008
|
-
os.path.relpath(f, project_root),
|
|
1009
|
-
end_section=(
|
|
1010
|
-
i == len(files_to_add) - 1
|
|
1011
|
-
), # 在最后一行之后不添加分割线
|
|
1012
|
-
)
|
|
1013
|
-
console.print(Panel(table, border_style="green"))
|
|
1014
|
-
result_manager.append(content=f"Added files: {', '.join(files_to_add)}",
|
|
1015
|
-
meta={"action": "add_files","success":True, "input":{ "args": args}})
|
|
1016
|
-
else:
|
|
1017
|
-
printer.print_in_terminal("add_files_matched", style="yellow")
|
|
1018
|
-
result_manager.append(content=f"No files matched.",
|
|
1019
|
-
meta={"action": "add_files","success":False, "input":{ "args": args}})
|
|
1020
|
-
|
|
1021
|
-
completer.update_current_files(memory["current_files"]["files"])
|
|
1022
|
-
save_memory()
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
def remove_files(file_names: List[str]):
|
|
1026
|
-
project_root = os.getcwd()
|
|
1027
|
-
printer = Printer()
|
|
1028
|
-
result_manager = ResultManager()
|
|
1029
|
-
|
|
1030
|
-
if "/all" in file_names:
|
|
1031
|
-
memory["current_files"]["files"] = []
|
|
1032
|
-
memory["current_files"]["current_groups"] = []
|
|
1033
|
-
printer.print_in_terminal("remove_files_all", style="green")
|
|
1034
|
-
result_manager.append(content="All files removed.",
|
|
1035
|
-
meta={"action": "remove_files","success":True, "input":{ "file_names": file_names}})
|
|
1036
|
-
else:
|
|
1037
|
-
removed_files = []
|
|
1038
|
-
for file in memory["current_files"]["files"]:
|
|
1039
|
-
if os.path.basename(file) in file_names:
|
|
1040
|
-
removed_files.append(file)
|
|
1041
|
-
elif file in file_names:
|
|
1042
|
-
removed_files.append(file)
|
|
1043
|
-
for file in removed_files:
|
|
1044
|
-
memory["current_files"]["files"].remove(file)
|
|
1045
|
-
|
|
1046
|
-
if removed_files:
|
|
1047
|
-
table = Table(
|
|
1048
|
-
show_header=True,
|
|
1049
|
-
header_style="bold magenta"
|
|
1050
|
-
)
|
|
1051
|
-
table.add_column("File", style="green")
|
|
1052
|
-
for f in removed_files:
|
|
1053
|
-
table.add_row(os.path.relpath(f, project_root))
|
|
1054
|
-
|
|
1055
|
-
console = Console()
|
|
1056
|
-
console.print(
|
|
1057
|
-
Panel(table, border_style="green",
|
|
1058
|
-
title=printer.get_message_from_key("files_removed")))
|
|
1059
|
-
result_manager.append(content=f"Removed files: {', '.join(removed_files)}",
|
|
1060
|
-
meta={"action": "remove_files","success":True, "input":{ "file_names": file_names}})
|
|
1061
|
-
else:
|
|
1062
|
-
printer.print_in_terminal("remove_files_none", style="yellow")
|
|
1063
|
-
result_manager.append(content=printer.get_message_from_key("remove_files_none"),
|
|
1064
|
-
meta={"action": "remove_files","success":False, "input":{ "file_names": file_names}})
|
|
1065
|
-
|
|
1066
|
-
completer.update_current_files(memory["current_files"]["files"])
|
|
1067
|
-
save_memory()
|
|
1068
|
-
|
|
1069
|
-
@run_in_raw_thread()
|
|
1070
|
-
def ask(query: str):
|
|
1071
|
-
conf = memory.get("conf", {})
|
|
1072
|
-
yaml_config = {
|
|
1073
|
-
"include_file": ["./base/base.yml"],
|
|
1074
|
-
}
|
|
1075
|
-
yaml_config["query"] = query
|
|
1076
|
-
|
|
1077
|
-
if "project_type" in conf:
|
|
1078
|
-
yaml_config["project_type"] = conf["project_type"]
|
|
1079
|
-
|
|
1080
|
-
if "model" in conf:
|
|
1081
|
-
yaml_config["model"] = conf["model"]
|
|
1082
|
-
|
|
1083
|
-
if "index_model" in conf:
|
|
1084
|
-
yaml_config["index_model"] = conf["index_model"]
|
|
1085
|
-
|
|
1086
|
-
if "vl_model" in conf:
|
|
1087
|
-
yaml_config["vl_model"] = conf["vl_model"]
|
|
1088
|
-
|
|
1089
|
-
if "code_model" in conf:
|
|
1090
|
-
yaml_config["code_model"] = conf["code_model"]
|
|
1091
|
-
|
|
1092
|
-
if "product_mode" in conf:
|
|
1093
|
-
yaml_config["product_mode"] = conf["product_mode"]
|
|
1094
|
-
|
|
1095
|
-
yaml_content = convert_yaml_config_to_str(yaml_config=yaml_config)
|
|
1096
|
-
|
|
1097
|
-
execute_file = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
1098
|
-
|
|
1099
|
-
with open(os.path.join(execute_file), "w",encoding="utf-8") as f:
|
|
1100
|
-
f.write(yaml_content)
|
|
1101
|
-
|
|
1102
|
-
def execute_ask():
|
|
1103
|
-
auto_coder_main(["agent", "project_reader", "--file", execute_file])
|
|
1104
|
-
|
|
1105
|
-
try:
|
|
1106
|
-
execute_ask()
|
|
1107
|
-
finally:
|
|
1108
|
-
os.remove(execute_file)
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
def get_llm_friendly_package_docs(
|
|
1112
|
-
package_name: Optional[str] = None, return_paths: bool = False
|
|
1113
|
-
) -> List[str]:
|
|
1114
|
-
lib_dir = os.path.join(".auto-coder", "libs")
|
|
1115
|
-
llm_friendly_packages_dir = os.path.join(lib_dir, "llm_friendly_packages")
|
|
1116
|
-
docs = []
|
|
1117
|
-
|
|
1118
|
-
if not os.path.exists(llm_friendly_packages_dir):
|
|
1119
|
-
return docs
|
|
1120
|
-
|
|
1121
|
-
libs = list(memory.get("libs", {}).keys())
|
|
1122
|
-
|
|
1123
|
-
for domain in os.listdir(llm_friendly_packages_dir):
|
|
1124
|
-
domain_path = os.path.join(llm_friendly_packages_dir, domain)
|
|
1125
|
-
if os.path.isdir(domain_path):
|
|
1126
|
-
for username in os.listdir(domain_path):
|
|
1127
|
-
username_path = os.path.join(domain_path, username)
|
|
1128
|
-
if os.path.isdir(username_path):
|
|
1129
|
-
for lib_name in os.listdir(username_path):
|
|
1130
|
-
lib_path = os.path.join(username_path, lib_name)
|
|
1131
|
-
if (
|
|
1132
|
-
os.path.isdir(lib_path)
|
|
1133
|
-
and (
|
|
1134
|
-
package_name is None
|
|
1135
|
-
or lib_name == package_name
|
|
1136
|
-
or package_name == os.path.join(username, lib_name)
|
|
1137
|
-
)
|
|
1138
|
-
and lib_name in libs
|
|
1139
|
-
):
|
|
1140
|
-
for root, _, files in os.walk(lib_path):
|
|
1141
|
-
for file in files:
|
|
1142
|
-
if file.endswith(".md"):
|
|
1143
|
-
file_path = os.path.join(root, file)
|
|
1144
|
-
if return_paths:
|
|
1145
|
-
docs.append(file_path)
|
|
1146
|
-
else:
|
|
1147
|
-
with open(file_path, "r",encoding="utf-8") as f:
|
|
1148
|
-
docs.append(f.read())
|
|
1149
|
-
|
|
1150
|
-
return docs
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
def convert_yaml_to_config(yaml_file: str):
|
|
1154
|
-
from autocoder.auto_coder import AutoCoderArgs, load_include_files, Template
|
|
1155
|
-
|
|
1156
|
-
args = AutoCoderArgs()
|
|
1157
|
-
with open(yaml_file, "r",encoding="utf-8") as f:
|
|
1158
|
-
config = yaml.safe_load(f)
|
|
1159
|
-
config = load_include_files(config, yaml_file)
|
|
1160
|
-
for key, value in config.items():
|
|
1161
|
-
if key != "file": # 排除 --file 参数本身
|
|
1162
|
-
# key: ENV {{VARIABLE_NAME}}
|
|
1163
|
-
if isinstance(value, str) and value.startswith("ENV"):
|
|
1164
|
-
template = Template(value.removeprefix("ENV").strip())
|
|
1165
|
-
value = template.render(os.environ)
|
|
1166
|
-
setattr(args, key, value)
|
|
1167
|
-
return args
|
|
1168
|
-
|
|
1169
|
-
@run_in_raw_thread()
|
|
1170
|
-
def mcp(query: str):
|
|
1171
|
-
query = query.strip()
|
|
1172
|
-
mcp_server = get_mcp_server()
|
|
1173
|
-
printer = Printer()
|
|
1174
|
-
|
|
1175
|
-
# Handle remove command
|
|
1176
|
-
if query.startswith("/remove"):
|
|
1177
|
-
server_name = query.replace("/remove", "", 1).strip()
|
|
1178
|
-
response = mcp_server.send_request(
|
|
1179
|
-
McpRemoveRequest(server_name=server_name))
|
|
1180
|
-
if response.error:
|
|
1181
|
-
printer.print_in_terminal("mcp_remove_error", style="red", error=response.error)
|
|
1182
|
-
else:
|
|
1183
|
-
printer.print_in_terminal("mcp_remove_success", style="green", result=response.result)
|
|
1184
|
-
return
|
|
1185
|
-
|
|
1186
|
-
# Handle list command
|
|
1187
|
-
if query.startswith("/list_running"):
|
|
1188
|
-
response = mcp_server.send_request(McpListRunningRequest())
|
|
1189
|
-
if response.error:
|
|
1190
|
-
printer.print_in_terminal("mcp_list_running_error", style="red", error=response.error)
|
|
1191
|
-
else:
|
|
1192
|
-
printer.print_in_terminal("mcp_list_running_title")
|
|
1193
|
-
printer.print_str_in_terminal(response.result)
|
|
1194
|
-
return
|
|
1195
|
-
|
|
1196
|
-
# Handle list command
|
|
1197
|
-
if query.startswith("/list"):
|
|
1198
|
-
response = mcp_server.send_request(McpListRequest())
|
|
1199
|
-
if response.error:
|
|
1200
|
-
printer.print_in_terminal("mcp_list_builtin_error", style="red", error=response.error)
|
|
1201
|
-
else:
|
|
1202
|
-
printer.print_in_terminal("mcp_list_builtin_title")
|
|
1203
|
-
printer.print_str_in_terminal(response.result)
|
|
1204
|
-
return
|
|
1205
|
-
|
|
1206
|
-
# Handle refresh command
|
|
1207
|
-
if query.startswith("/refresh"):
|
|
1208
|
-
server_name = query.replace("/refresh", "", 1).strip()
|
|
1209
|
-
response = mcp_server.send_request(McpRefreshRequest(name=server_name or None))
|
|
1210
|
-
if response.error:
|
|
1211
|
-
printer.print_in_terminal("mcp_refresh_error", style="red", error=response.error)
|
|
1212
|
-
else:
|
|
1213
|
-
printer.print_in_terminal("mcp_refresh_success", style="green")
|
|
1214
|
-
return
|
|
1215
|
-
|
|
1216
|
-
# Handle add command
|
|
1217
|
-
if query.startswith("/add"):
|
|
1218
|
-
query = query.replace("/add", "", 1).strip()
|
|
1219
|
-
request = McpInstallRequest(server_name_or_config=query)
|
|
1220
|
-
response = mcp_server.send_request(request)
|
|
1221
|
-
|
|
1222
|
-
if response.error:
|
|
1223
|
-
printer.print_in_terminal("mcp_install_error", style="red", error=response.error)
|
|
1224
|
-
else:
|
|
1225
|
-
printer.print_in_terminal("mcp_install_success", style="green", result=response.result)
|
|
1226
|
-
return
|
|
1227
|
-
|
|
1228
|
-
# Handle default query
|
|
1229
|
-
conf = memory.get("conf", {})
|
|
1230
|
-
yaml_config = {
|
|
1231
|
-
"include_file": ["./base/base.yml"],
|
|
1232
|
-
"auto_merge": conf.get("auto_merge", "editblock"),
|
|
1233
|
-
"human_as_model": conf.get("human_as_model", "false") == "true",
|
|
1234
|
-
"skip_build_index": conf.get("skip_build_index", "true") == "true",
|
|
1235
|
-
"skip_confirm": conf.get("skip_confirm", "true") == "true",
|
|
1236
|
-
"silence": conf.get("silence", "true") == "true",
|
|
1237
|
-
"include_project_structure": conf.get("include_project_structure", "true")
|
|
1238
|
-
== "true",
|
|
1239
|
-
}
|
|
1240
|
-
for key, value in conf.items():
|
|
1241
|
-
converted_value = convert_config_value(key, value)
|
|
1242
|
-
if converted_value is not None:
|
|
1243
|
-
yaml_config[key] = converted_value
|
|
1244
|
-
|
|
1245
|
-
temp_yaml = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
1246
|
-
try:
|
|
1247
|
-
with open(temp_yaml, "w",encoding="utf-8") as f:
|
|
1248
|
-
f.write(convert_yaml_config_to_str(yaml_config=yaml_config))
|
|
1249
|
-
args = convert_yaml_to_config(temp_yaml)
|
|
1250
|
-
finally:
|
|
1251
|
-
if os.path.exists(temp_yaml):
|
|
1252
|
-
os.remove(temp_yaml)
|
|
1253
|
-
|
|
1254
|
-
mcp_server = get_mcp_server()
|
|
1255
|
-
response = mcp_server.send_request(
|
|
1256
|
-
McpRequest(
|
|
1257
|
-
query=query,
|
|
1258
|
-
model=args.inference_model or args.model,
|
|
1259
|
-
product_mode=args.product_mode
|
|
1260
|
-
)
|
|
1261
|
-
)
|
|
1262
|
-
|
|
1263
|
-
if response.error:
|
|
1264
|
-
printer.print_panel(
|
|
1265
|
-
f"Error from MCP server: {response.error}",
|
|
1266
|
-
text_options={"justify": "left"},
|
|
1267
|
-
panel_options={
|
|
1268
|
-
"title": printer.get_message_from_key("mcp_error_title"),
|
|
1269
|
-
"border_style": "red"
|
|
1270
|
-
}
|
|
1271
|
-
)
|
|
1272
|
-
else:
|
|
1273
|
-
# Save conversation
|
|
1274
|
-
mcp_dir = os.path.join(".auto-coder", "mcp", "conversations")
|
|
1275
|
-
os.makedirs(mcp_dir, exist_ok=True)
|
|
1276
|
-
timestamp = str(int(time.time()))
|
|
1277
|
-
file_path = os.path.join(mcp_dir, f"{timestamp}.md")
|
|
1278
|
-
|
|
1279
|
-
# Format response as markdown
|
|
1280
|
-
markdown_content = response.result
|
|
1281
|
-
|
|
1282
|
-
# Save to file
|
|
1283
|
-
with open(file_path, "w", encoding="utf-8") as f:
|
|
1284
|
-
f.write(markdown_content)
|
|
1285
|
-
|
|
1286
|
-
console = Console()
|
|
1287
|
-
console.print(
|
|
1288
|
-
Panel(
|
|
1289
|
-
Markdown(markdown_content, justify="left"),
|
|
1290
|
-
title=printer.get_message_from_key('mcp_response_title'),
|
|
1291
|
-
border_style="green"
|
|
1292
|
-
)
|
|
1293
|
-
)
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
@run_in_raw_thread()
|
|
1297
|
-
def code_next(query: str):
|
|
1298
|
-
conf = memory.get("conf", {})
|
|
1299
|
-
yaml_config = {
|
|
1300
|
-
"include_file": ["./base/base.yml"],
|
|
1301
|
-
"auto_merge": conf.get("auto_merge", "editblock"),
|
|
1302
|
-
"human_as_model": conf.get("human_as_model", "false") == "true",
|
|
1303
|
-
"skip_build_index": conf.get("skip_build_index", "true") == "true",
|
|
1304
|
-
"skip_confirm": conf.get("skip_confirm", "true") == "true",
|
|
1305
|
-
"silence": conf.get("silence", "true") == "true",
|
|
1306
|
-
"include_project_structure": conf.get("include_project_structure", "true")
|
|
1307
|
-
== "true",
|
|
1308
|
-
}
|
|
1309
|
-
for key, value in conf.items():
|
|
1310
|
-
converted_value = convert_config_value(key, value)
|
|
1311
|
-
if converted_value is not None:
|
|
1312
|
-
yaml_config[key] = converted_value
|
|
1313
|
-
|
|
1314
|
-
temp_yaml = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
1315
|
-
try:
|
|
1316
|
-
with open(temp_yaml, "w",encoding="utf-8") as f:
|
|
1317
|
-
f.write(convert_yaml_config_to_str(yaml_config=yaml_config))
|
|
1318
|
-
args = convert_yaml_to_config(temp_yaml)
|
|
1319
|
-
finally:
|
|
1320
|
-
if os.path.exists(temp_yaml):
|
|
1321
|
-
os.remove(temp_yaml)
|
|
1322
|
-
|
|
1323
|
-
product_mode = conf.get("product_mode", "lite")
|
|
1324
|
-
llm = get_single_llm(args.chat_model or args.model, product_mode=product_mode)
|
|
1325
|
-
|
|
1326
|
-
auto_guesser = AutoGuessQuery(
|
|
1327
|
-
llm=llm, project_dir=os.getcwd(), skip_diff=True)
|
|
1328
|
-
|
|
1329
|
-
predicted_tasks = auto_guesser.predict_next_tasks(
|
|
1330
|
-
5, is_human_as_model=args.human_as_model
|
|
1331
|
-
)
|
|
1332
|
-
|
|
1333
|
-
if not predicted_tasks:
|
|
1334
|
-
console = Console()
|
|
1335
|
-
console.print(Panel("No task predictions available", style="yellow"))
|
|
1336
|
-
return
|
|
1337
|
-
|
|
1338
|
-
console = Console()
|
|
1339
|
-
|
|
1340
|
-
# Create main panel for all predicted tasks
|
|
1341
|
-
table = Table(show_header=True,
|
|
1342
|
-
header_style="bold magenta", show_lines=True)
|
|
1343
|
-
table.add_column("Priority", style="cyan", width=8)
|
|
1344
|
-
table.add_column("Task Description", style="green",
|
|
1345
|
-
width=40, overflow="fold")
|
|
1346
|
-
table.add_column("Files", style="yellow", width=30, overflow="fold")
|
|
1347
|
-
table.add_column("Reason", style="blue", width=30, overflow="fold")
|
|
1348
|
-
table.add_column("Dependencies", style="magenta",
|
|
1349
|
-
width=30, overflow="fold")
|
|
1350
|
-
|
|
1351
|
-
for task in predicted_tasks:
|
|
1352
|
-
# Format file paths to be more readable
|
|
1353
|
-
file_list = "\n".join([os.path.relpath(f, os.getcwd())
|
|
1354
|
-
for f in task.urls])
|
|
1355
|
-
|
|
1356
|
-
# Format dependencies to be more readable
|
|
1357
|
-
dependencies = (
|
|
1358
|
-
"\n".join(
|
|
1359
|
-
task.dependency_queries) if task.dependency_queries else "None"
|
|
1360
|
-
)
|
|
1361
|
-
|
|
1362
|
-
table.add_row(
|
|
1363
|
-
str(task.priority), task.query, file_list, task.reason, dependencies
|
|
1364
|
-
)
|
|
1365
|
-
|
|
1366
|
-
console.print(
|
|
1367
|
-
Panel(
|
|
1368
|
-
table,
|
|
1369
|
-
title="[bold]Predicted Next Tasks[/bold]",
|
|
1370
|
-
border_style="blue",
|
|
1371
|
-
padding=(1, 2), # Add more horizontal padding
|
|
1372
|
-
)
|
|
1373
|
-
)
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
@run_in_raw_thread()
|
|
1377
|
-
def commit(query: str):
|
|
1378
|
-
conf = memory.get("conf", {})
|
|
1379
|
-
product_mode = conf.get("product_mode", "lite")
|
|
1380
|
-
def prepare_commit_yaml():
|
|
1381
|
-
auto_coder_main(["next", "chat_action"])
|
|
1382
|
-
|
|
1383
|
-
prepare_commit_yaml()
|
|
1384
|
-
|
|
1385
|
-
# no_diff = query.strip().startswith("/no_diff")
|
|
1386
|
-
# if no_diff:
|
|
1387
|
-
# query = query.replace("/no_diff", "", 1).strip()
|
|
1388
|
-
|
|
1389
|
-
latest_yaml_file = get_last_yaml_file("actions")
|
|
1390
|
-
|
|
1391
|
-
conf = memory.get("conf", {})
|
|
1392
|
-
current_files = memory["current_files"]["files"]
|
|
1393
|
-
execute_file = None
|
|
1394
|
-
|
|
1395
|
-
if latest_yaml_file:
|
|
1396
|
-
try:
|
|
1397
|
-
execute_file = os.path.join("actions", latest_yaml_file)
|
|
1398
|
-
yaml_config = {
|
|
1399
|
-
"include_file": ["./base/base.yml"],
|
|
1400
|
-
"auto_merge": conf.get("auto_merge", "editblock"),
|
|
1401
|
-
"human_as_model": conf.get("human_as_model", "false") == "true",
|
|
1402
|
-
"skip_build_index": conf.get("skip_build_index", "true") == "true",
|
|
1403
|
-
"skip_confirm": conf.get("skip_confirm", "true") == "true",
|
|
1404
|
-
"silence": conf.get("silence", "true") == "true",
|
|
1405
|
-
"include_project_structure": conf.get("include_project_structure", "true")
|
|
1406
|
-
== "true",
|
|
1407
|
-
}
|
|
1408
|
-
for key, value in conf.items():
|
|
1409
|
-
converted_value = convert_config_value(key, value)
|
|
1410
|
-
if converted_value is not None:
|
|
1411
|
-
yaml_config[key] = converted_value
|
|
1412
|
-
|
|
1413
|
-
yaml_config["urls"] = current_files + get_llm_friendly_package_docs(
|
|
1414
|
-
return_paths=True
|
|
1415
|
-
)
|
|
1416
|
-
|
|
1417
|
-
if conf.get("enable_global_memory", "true") in ["true", "True",True]:
|
|
1418
|
-
yaml_config["urls"] += get_global_memory_file_paths()
|
|
1419
|
-
|
|
1420
|
-
# 临时保存yaml文件,然后读取yaml文件,转换为args
|
|
1421
|
-
temp_yaml = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
1422
|
-
try:
|
|
1423
|
-
with open(temp_yaml, "w",encoding="utf-8") as f:
|
|
1424
|
-
f.write(convert_yaml_config_to_str(
|
|
1425
|
-
yaml_config=yaml_config))
|
|
1426
|
-
args = convert_yaml_to_config(temp_yaml)
|
|
1427
|
-
finally:
|
|
1428
|
-
if os.path.exists(temp_yaml):
|
|
1429
|
-
os.remove(temp_yaml)
|
|
1430
|
-
|
|
1431
|
-
target_model = args.commit_model or args.model
|
|
1432
|
-
llm = get_single_llm(target_model, product_mode)
|
|
1433
|
-
printer = Printer()
|
|
1434
|
-
printer.print_in_terminal("commit_generating", style="yellow", model_name=target_model)
|
|
1435
|
-
commit_message = ""
|
|
1436
|
-
|
|
1437
|
-
try:
|
|
1438
|
-
uncommitted_changes = git_utils.get_uncommitted_changes(".")
|
|
1439
|
-
commit_message = git_utils.generate_commit_message.with_llm(llm).run(
|
|
1440
|
-
uncommitted_changes
|
|
1441
|
-
)
|
|
1442
|
-
memory["conversation"].append(
|
|
1443
|
-
{"role": "user", "content": commit_message})
|
|
1444
|
-
except Exception as e:
|
|
1445
|
-
printer.print_in_terminal("commit_failed", style="red", error=str(e), model_name=target_model)
|
|
1446
|
-
return
|
|
1447
|
-
|
|
1448
|
-
yaml_config["query"] = commit_message
|
|
1449
|
-
yaml_content = convert_yaml_config_to_str(yaml_config=yaml_config)
|
|
1450
|
-
with open(os.path.join(execute_file), "w",encoding="utf-8") as f:
|
|
1451
|
-
f.write(yaml_content)
|
|
1452
|
-
|
|
1453
|
-
file_content = open(execute_file).read()
|
|
1454
|
-
md5 = hashlib.md5(file_content.encode("utf-8")).hexdigest()
|
|
1455
|
-
file_name = os.path.basename(execute_file)
|
|
1456
|
-
commit_result = git_utils.commit_changes(
|
|
1457
|
-
".", f"auto_coder_{file_name}_{md5}\n{commit_message}"
|
|
1458
|
-
)
|
|
1459
|
-
git_utils.print_commit_info(commit_result=commit_result)
|
|
1460
|
-
if commit_message:
|
|
1461
|
-
printer.print_in_terminal("commit_message", style="green", model_name=target_model, message=commit_message)
|
|
1462
|
-
except Exception as e:
|
|
1463
|
-
import traceback
|
|
1464
|
-
traceback.print_exc()
|
|
1465
|
-
print(f"Failed to commit: {e}")
|
|
1466
|
-
if execute_file:
|
|
1467
|
-
os.remove(execute_file)
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
@run_in_raw_thread()
|
|
1471
|
-
def coding(query: str):
|
|
1472
|
-
console = Console()
|
|
1473
|
-
is_apply = query.strip().startswith("/apply")
|
|
1474
|
-
if is_apply:
|
|
1475
|
-
query = query.replace("/apply", "", 1).strip()
|
|
1476
|
-
|
|
1477
|
-
is_next = query.strip().startswith("/next")
|
|
1478
|
-
if is_next:
|
|
1479
|
-
query = query.replace("/next", "", 1).strip()
|
|
1480
|
-
|
|
1481
|
-
if is_next:
|
|
1482
|
-
code_next(query)
|
|
1483
|
-
return
|
|
1484
|
-
|
|
1485
|
-
memory["conversation"].append({"role": "user", "content": query})
|
|
1486
|
-
conf = memory.get("conf", {})
|
|
1487
|
-
|
|
1488
|
-
current_files = memory["current_files"]["files"]
|
|
1489
|
-
current_groups = memory["current_files"].get("current_groups", [])
|
|
1490
|
-
groups = memory["current_files"].get("groups", {})
|
|
1491
|
-
groups_info = memory["current_files"].get("groups_info", {})
|
|
1492
|
-
|
|
1493
|
-
def prepare_chat_yaml():
|
|
1494
|
-
auto_coder_main(["next", "chat_action"])
|
|
1495
|
-
|
|
1496
|
-
prepare_chat_yaml()
|
|
1497
|
-
|
|
1498
|
-
latest_yaml_file = get_last_yaml_file("actions")
|
|
1499
|
-
|
|
1500
|
-
if latest_yaml_file:
|
|
1501
|
-
yaml_config = {
|
|
1502
|
-
"include_file": ["./base/base.yml"],
|
|
1503
|
-
"auto_merge": conf.get("auto_merge", "editblock"),
|
|
1504
|
-
"human_as_model": conf.get("human_as_model", "false") == "true",
|
|
1505
|
-
"skip_build_index": conf.get("skip_build_index", "true") == "true",
|
|
1506
|
-
"skip_confirm": conf.get("skip_confirm", "true") == "true",
|
|
1507
|
-
"silence": conf.get("silence", "true") == "true",
|
|
1508
|
-
"include_project_structure": conf.get("include_project_structure", "true")
|
|
1509
|
-
== "true",
|
|
1510
|
-
"exclude_files": memory.get("exclude_files", []),
|
|
1511
|
-
}
|
|
1512
|
-
|
|
1513
|
-
yaml_config["context"] = ""
|
|
1514
|
-
yaml_config["in_code_apply"] = is_apply
|
|
1515
|
-
|
|
1516
|
-
for key, value in conf.items():
|
|
1517
|
-
converted_value = convert_config_value(key, value)
|
|
1518
|
-
if converted_value is not None:
|
|
1519
|
-
yaml_config[key] = converted_value
|
|
1520
|
-
|
|
1521
|
-
yaml_config["urls"] = current_files + get_llm_friendly_package_docs(
|
|
1522
|
-
return_paths=True
|
|
1523
|
-
)
|
|
1524
|
-
|
|
1525
|
-
if conf.get("enable_global_memory", "true") in ["true", "True",True]:
|
|
1526
|
-
yaml_config["urls"] += get_global_memory_file_paths()
|
|
1527
|
-
|
|
1528
|
-
# handle image
|
|
1529
|
-
v = Image.convert_image_paths_from(query)
|
|
1530
|
-
yaml_config["query"] = v
|
|
1531
|
-
|
|
1532
|
-
# Add context for active groups and their query prefixes
|
|
1533
|
-
if current_groups:
|
|
1534
|
-
active_groups_context = "下面是对上面文件按分组给到的一些描述,当用户的需求正好匹配描述的时候,参考描述来做修改:\n"
|
|
1535
|
-
for group in current_groups:
|
|
1536
|
-
group_files = groups.get(group, [])
|
|
1537
|
-
query_prefix = groups_info.get(
|
|
1538
|
-
group, {}).get("query_prefix", "")
|
|
1539
|
-
active_groups_context += f"组名: {group}\n"
|
|
1540
|
-
active_groups_context += f"文件列表:\n"
|
|
1541
|
-
for file in group_files:
|
|
1542
|
-
active_groups_context += f"- {file}\n"
|
|
1543
|
-
active_groups_context += f"组描述: {query_prefix}\n\n"
|
|
1544
|
-
|
|
1545
|
-
yaml_config["context"] = active_groups_context + "\n"
|
|
1546
|
-
|
|
1547
|
-
if is_apply:
|
|
1548
|
-
memory_dir = os.path.join(".auto-coder", "memory")
|
|
1549
|
-
os.makedirs(memory_dir, exist_ok=True)
|
|
1550
|
-
memory_file = os.path.join(memory_dir, "chat_history.json")
|
|
1551
|
-
|
|
1552
|
-
def error_message():
|
|
1553
|
-
console.print(
|
|
1554
|
-
Panel(
|
|
1555
|
-
"No chat history found to apply.",
|
|
1556
|
-
title="Chat History",
|
|
1557
|
-
expand=False,
|
|
1558
|
-
border_style="yellow",
|
|
1559
|
-
)
|
|
1560
|
-
)
|
|
1561
|
-
|
|
1562
|
-
if not os.path.exists(memory_file):
|
|
1563
|
-
error_message()
|
|
1564
|
-
return
|
|
1565
|
-
|
|
1566
|
-
with open(memory_file, "r",encoding="utf-8") as f:
|
|
1567
|
-
chat_history = json.load(f)
|
|
1568
|
-
|
|
1569
|
-
if not chat_history["ask_conversation"]:
|
|
1570
|
-
error_message()
|
|
1571
|
-
return
|
|
1572
|
-
|
|
1573
|
-
conversations = chat_history["ask_conversation"]
|
|
1574
|
-
|
|
1575
|
-
yaml_config[
|
|
1576
|
-
"context"
|
|
1577
|
-
] += f"下面是我们的历史对话,参考我们的历史对话从而更好的理解需求和修改代码: \n\n<history>\n"
|
|
1578
|
-
for conv in conversations:
|
|
1579
|
-
if conv["role"] == "user":
|
|
1580
|
-
yaml_config["context"] += f"用户: {conv['content']}\n"
|
|
1581
|
-
elif conv["role"] == "assistant":
|
|
1582
|
-
yaml_config["context"] += f"你: {conv['content']}\n"
|
|
1583
|
-
yaml_config["context"] += "</history>\n"
|
|
1584
|
-
|
|
1585
|
-
yaml_content = convert_yaml_config_to_str(yaml_config=yaml_config)
|
|
1586
|
-
|
|
1587
|
-
md5 = hashlib.md5(yaml_content.encode("utf-8")).hexdigest()
|
|
1588
|
-
|
|
1589
|
-
execute_file = os.path.join("actions", latest_yaml_file)
|
|
1590
|
-
with open(os.path.join(execute_file), "w",encoding="utf-8") as f:
|
|
1591
|
-
f.write(yaml_content)
|
|
1592
|
-
|
|
1593
|
-
def execute_chat():
|
|
1594
|
-
cmd = ["--file", execute_file]
|
|
1595
|
-
auto_coder_main(cmd)
|
|
1596
|
-
result_manager = ResultManager()
|
|
1597
|
-
result_manager.append(content="", meta={"commit_message": f"auto_coder_{latest_yaml_file}_{md5}","action": "coding", "input":{
|
|
1598
|
-
"query": query
|
|
1599
|
-
}})
|
|
1600
|
-
|
|
1601
|
-
execute_chat()
|
|
1602
|
-
else:
|
|
1603
|
-
print("Failed to create new YAML file.")
|
|
1604
|
-
|
|
1605
|
-
save_memory()
|
|
1606
|
-
completer.refresh_files()
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
@byzerllm.prompt()
|
|
1610
|
-
def code_review(query: str) -> str:
|
|
1611
|
-
"""
|
|
1612
|
-
掐面提供了上下文,对代码进行review,参考如下检查点。
|
|
1613
|
-
1. 有没有调用不符合方法,类的签名的调用,包括对第三方类,模块,方法的检查(如果上下文提供了这些信息)
|
|
1614
|
-
2. 有没有未声明直接使用的变量,方法,类
|
|
1615
|
-
3. 有没有明显的语法错误
|
|
1616
|
-
4. 如果是python代码,检查有没有缩进方面的错误
|
|
1617
|
-
5. 如果是python代码,检查是否 try 后面缺少 except 或者 finally
|
|
1618
|
-
{% if query %}
|
|
1619
|
-
6. 用户的额外的检查需求:{{ query }}
|
|
1620
|
-
{% endif %}
|
|
1621
|
-
|
|
1622
|
-
如果用户的需求包含了@一个文件名 或者 @@符号, 那么重点关注这些文件或者符号(函数,类)进行上述的review。
|
|
1623
|
-
review 过程中严格遵循上述的检查点,不要遗漏,没有发现异常的点直接跳过,只对发现的异常点,给出具体的修改后的代码。
|
|
1624
|
-
"""
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
@run_in_raw_thread()
|
|
1628
|
-
def chat(query: str):
|
|
1629
|
-
conf = memory.get("conf", {})
|
|
1630
|
-
|
|
1631
|
-
yaml_config = {
|
|
1632
|
-
"include_file": ["./base/base.yml"],
|
|
1633
|
-
"include_project_structure": conf.get("include_project_structure", "true")
|
|
1634
|
-
in ["true", "True"],
|
|
1635
|
-
"human_as_model": conf.get("human_as_model", "false") == "true",
|
|
1636
|
-
"skip_build_index": conf.get("skip_build_index", "true") == "true",
|
|
1637
|
-
"skip_confirm": conf.get("skip_confirm", "true") == "true",
|
|
1638
|
-
"silence": conf.get("silence", "true") == "true",
|
|
1639
|
-
"exclude_files": memory.get("exclude_files", []),
|
|
1640
|
-
}
|
|
1641
|
-
|
|
1642
|
-
current_files = memory["current_files"]["files"] + get_llm_friendly_package_docs(
|
|
1643
|
-
return_paths=True
|
|
1644
|
-
)
|
|
1645
|
-
|
|
1646
|
-
if conf.get("enable_global_memory", "true") in ["true", "True",True]:
|
|
1647
|
-
current_files += get_global_memory_file_paths()
|
|
1648
|
-
|
|
1649
|
-
yaml_config["urls"] = current_files
|
|
1650
|
-
|
|
1651
|
-
if "emb_model" in conf:
|
|
1652
|
-
yaml_config["emb_model"] = conf["emb_model"]
|
|
1653
|
-
|
|
1654
|
-
is_new = "/new" in query
|
|
1655
|
-
if is_new:
|
|
1656
|
-
query = query.replace("/new", "", 1).strip()
|
|
1657
|
-
|
|
1658
|
-
yaml_config["action"] = []
|
|
1659
|
-
|
|
1660
|
-
if "/mcp " in query:
|
|
1661
|
-
yaml_config["action"].append("mcp")
|
|
1662
|
-
query = query.replace("/mcp ", "", 1).strip()
|
|
1663
|
-
|
|
1664
|
-
if "/rag " in query:
|
|
1665
|
-
yaml_config["action"].append("rag")
|
|
1666
|
-
query = query.replace("/rag ", "", 1).strip()
|
|
1667
|
-
|
|
1668
|
-
if "/copy" in query:
|
|
1669
|
-
yaml_config["action"].append("copy")
|
|
1670
|
-
query = query.replace("/copy", "", 1).strip()
|
|
1671
|
-
|
|
1672
|
-
if "/save" in query:
|
|
1673
|
-
yaml_config["action"].append("save")
|
|
1674
|
-
query = query.replace("/save", "", 1).strip()
|
|
1675
|
-
|
|
1676
|
-
if "/review" in query and "/commit" in query:
|
|
1677
|
-
yaml_config["action"].append("review_commit")
|
|
1678
|
-
query = query.replace("/review", "", 1).replace("/commit", "", 1).strip()
|
|
1679
|
-
else:
|
|
1680
|
-
is_review = query.strip().startswith("/review")
|
|
1681
|
-
if is_review:
|
|
1682
|
-
query = query.replace("/review", "", 1).strip()
|
|
1683
|
-
if "prompt_review" in conf:
|
|
1684
|
-
query = format_str_jinja2(conf["prompt_review"], query=query)
|
|
1685
|
-
else:
|
|
1686
|
-
query = code_review.prompt(query)
|
|
1687
|
-
|
|
1688
|
-
is_no_context = "/no_context" in query.strip()
|
|
1689
|
-
if is_no_context:
|
|
1690
|
-
query = query.replace("/no_context", "", 1).strip()
|
|
1691
|
-
yaml_config["action"].append("no_context")
|
|
1692
|
-
|
|
1693
|
-
for key, value in conf.items():
|
|
1694
|
-
converted_value = convert_config_value(key, value)
|
|
1695
|
-
if converted_value is not None:
|
|
1696
|
-
yaml_config[key] = converted_value
|
|
1697
|
-
|
|
1698
|
-
query = Image.convert_image_paths_from(query)
|
|
1699
|
-
|
|
1700
|
-
yaml_config["query"] = query
|
|
1701
|
-
|
|
1702
|
-
yaml_content = convert_yaml_config_to_str(yaml_config=yaml_config)
|
|
1703
|
-
|
|
1704
|
-
execute_file = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
1705
|
-
|
|
1706
|
-
with open(os.path.join(execute_file), "w",encoding="utf-8") as f:
|
|
1707
|
-
f.write(yaml_content)
|
|
1708
|
-
|
|
1709
|
-
def execute_ask():
|
|
1710
|
-
cmd = ["agent", "chat", "--file", execute_file]
|
|
1711
|
-
if is_new:
|
|
1712
|
-
cmd.append("--new_session")
|
|
1713
|
-
auto_coder_main(cmd)
|
|
1714
|
-
|
|
1715
|
-
try:
|
|
1716
|
-
execute_ask()
|
|
1717
|
-
finally:
|
|
1718
|
-
os.remove(execute_file)
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
@run_in_raw_thread()
|
|
1722
|
-
def summon(query: str):
|
|
1723
|
-
conf = memory.get("conf", {})
|
|
1724
|
-
current_files = memory["current_files"]["files"]
|
|
1725
|
-
|
|
1726
|
-
file_contents = []
|
|
1727
|
-
for file in current_files:
|
|
1728
|
-
if os.path.exists(file):
|
|
1729
|
-
try:
|
|
1730
|
-
with open(file, "r",encoding="utf-8") as f:
|
|
1731
|
-
content = f.read()
|
|
1732
|
-
s = f"##File: {file}\n{content}\n\n"
|
|
1733
|
-
file_contents.append(s)
|
|
1734
|
-
except Exception as e:
|
|
1735
|
-
print(f"Failed to read file: {file}. Error: {str(e)}")
|
|
1736
|
-
|
|
1737
|
-
all_file_content = "".join(file_contents)
|
|
1738
|
-
|
|
1739
|
-
yaml_config = {
|
|
1740
|
-
"include_file": ["./base/base.yml"],
|
|
1741
|
-
}
|
|
1742
|
-
yaml_config["query"] = query
|
|
1743
|
-
yaml_config["context"] = json.dumps(
|
|
1744
|
-
{"file_content": all_file_content}, ensure_ascii=False
|
|
1745
|
-
)
|
|
1746
|
-
|
|
1747
|
-
if "emb_model" in conf:
|
|
1748
|
-
yaml_config["emb_model"] = conf["emb_model"]
|
|
1749
|
-
|
|
1750
|
-
if "vl_model" in conf:
|
|
1751
|
-
yaml_config["vl_model"] = conf["vl_model"]
|
|
1752
|
-
|
|
1753
|
-
if "code_model" in conf:
|
|
1754
|
-
yaml_config["code_model"] = conf["code_model"]
|
|
1755
|
-
|
|
1756
|
-
if "model" in conf:
|
|
1757
|
-
yaml_config["model"] = conf["model"]
|
|
1758
|
-
|
|
1759
|
-
if "product_mode" in conf:
|
|
1760
|
-
yaml_config["product_mode"] = conf["product_mode"]
|
|
1761
|
-
|
|
1762
|
-
yaml_content = convert_yaml_config_to_str(yaml_config=yaml_config)
|
|
1763
|
-
|
|
1764
|
-
execute_file = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
1765
|
-
|
|
1766
|
-
with open(os.path.join(execute_file), "w",encoding="utf-8") as f:
|
|
1767
|
-
f.write(yaml_content)
|
|
1768
|
-
|
|
1769
|
-
def execute_summon():
|
|
1770
|
-
auto_coder_main(["agent", "auto_tool", "--file", execute_file])
|
|
1771
|
-
|
|
1772
|
-
try:
|
|
1773
|
-
execute_summon()
|
|
1774
|
-
finally:
|
|
1775
|
-
os.remove(execute_file)
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
@run_in_raw_thread()
|
|
1779
|
-
def design(query: str):
|
|
1780
|
-
|
|
1781
|
-
conf = memory.get("conf", {})
|
|
1782
|
-
yaml_config = {
|
|
1783
|
-
"include_file": ["./base/base.yml"],
|
|
1784
|
-
}
|
|
1785
|
-
|
|
1786
|
-
if query.strip().startswith("/svg"):
|
|
1787
|
-
query = query.replace("/svg", "", 1).strip()
|
|
1788
|
-
yaml_config["agent_designer_mode"] = "svg"
|
|
1789
|
-
elif query.strip().startswith("/sd"):
|
|
1790
|
-
query = query.replace("/svg", "", 1).strip()
|
|
1791
|
-
yaml_config["agent_designer_mode"] = "sd"
|
|
1792
|
-
elif query.strip().startswith("/logo"):
|
|
1793
|
-
query = query.replace("/logo", "", 1).strip()
|
|
1794
|
-
yaml_config["agent_designer_mode"] = "logo"
|
|
1795
|
-
else:
|
|
1796
|
-
yaml_config["agent_designer_mode"] = "svg"
|
|
1797
|
-
|
|
1798
|
-
yaml_config["query"] = query
|
|
1799
|
-
|
|
1800
|
-
if "model" in conf:
|
|
1801
|
-
yaml_config["model"] = conf["model"]
|
|
1802
|
-
|
|
1803
|
-
if "designer_model" in conf:
|
|
1804
|
-
yaml_config["designer_model"] = conf["designer_model"]
|
|
1805
|
-
|
|
1806
|
-
if "sd_model" in conf:
|
|
1807
|
-
yaml_config["sd_model"] = conf["sd_model"]
|
|
1808
|
-
|
|
1809
|
-
yaml_content = convert_yaml_config_to_str(yaml_config=yaml_config)
|
|
1810
|
-
|
|
1811
|
-
execute_file = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
1812
|
-
|
|
1813
|
-
with open(os.path.join(execute_file), "w",encoding="utf-8") as f:
|
|
1814
|
-
f.write(yaml_content)
|
|
1815
|
-
|
|
1816
|
-
def execute_design():
|
|
1817
|
-
auto_coder_main(["agent", "designer", "--file", execute_file])
|
|
1818
|
-
|
|
1819
|
-
try:
|
|
1820
|
-
execute_design()
|
|
1821
|
-
finally:
|
|
1822
|
-
os.remove(execute_file)
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
def voice_input():
|
|
1826
|
-
conf = memory.get("conf", {})
|
|
1827
|
-
yaml_config = {
|
|
1828
|
-
"include_file": ["./base/base.yml"],
|
|
1829
|
-
}
|
|
1830
|
-
|
|
1831
|
-
if "voice2text_model" not in conf:
|
|
1832
|
-
print(
|
|
1833
|
-
"Please set voice2text_model in configuration. /conf voice2text_model:<model>"
|
|
1834
|
-
)
|
|
1835
|
-
return
|
|
1836
|
-
|
|
1837
|
-
yaml_config["voice2text_model"] = conf["voice2text_model"]
|
|
1838
|
-
yaml_content = convert_yaml_config_to_str(yaml_config=yaml_config)
|
|
1839
|
-
|
|
1840
|
-
execute_file = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
1841
|
-
|
|
1842
|
-
with open(os.path.join(execute_file), "w",encoding="utf-8") as f:
|
|
1843
|
-
f.write(yaml_content)
|
|
1844
|
-
|
|
1845
|
-
def execute_voice2text_command():
|
|
1846
|
-
auto_coder_main(["agent", "voice2text", "--file", execute_file])
|
|
1847
|
-
|
|
1848
|
-
try:
|
|
1849
|
-
execute_voice2text_command()
|
|
1850
|
-
with open(os.path.join(".auto-coder", "exchange.txt"), "r",encoding="utf-8") as f:
|
|
1851
|
-
return f.read()
|
|
1852
|
-
finally:
|
|
1853
|
-
os.remove(execute_file)
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
@run_in_raw_thread()
|
|
1857
|
-
def generate_shell_command(input_text):
|
|
1858
|
-
conf = memory.get("conf", {})
|
|
1859
|
-
yaml_config = {
|
|
1860
|
-
"include_file": ["./base/base.yml"],
|
|
1861
|
-
}
|
|
1862
|
-
|
|
1863
|
-
if "model" in conf:
|
|
1864
|
-
yaml_config["model"] = conf["model"]
|
|
1865
|
-
|
|
1866
|
-
yaml_config["query"] = input_text
|
|
1867
|
-
|
|
1868
|
-
yaml_content = convert_yaml_config_to_str(yaml_config=yaml_config)
|
|
1869
|
-
|
|
1870
|
-
execute_file = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
1871
|
-
|
|
1872
|
-
with open(os.path.join(execute_file), "w",encoding="utf-8") as f:
|
|
1873
|
-
f.write(yaml_content)
|
|
1874
|
-
|
|
1875
|
-
try:
|
|
1876
|
-
auto_coder_main(["agent", "generate_command", "--file", execute_file])
|
|
1877
|
-
with open(os.path.join(".auto-coder", "exchange.txt"), "r",encoding="utf-8") as f:
|
|
1878
|
-
shell_script = f.read()
|
|
1879
|
-
result_manager = ResultManager()
|
|
1880
|
-
result_manager.add_result(content=shell_script,meta={
|
|
1881
|
-
"action": "generate_shell_command",
|
|
1882
|
-
"input": {
|
|
1883
|
-
"query": input_text
|
|
1884
|
-
}
|
|
1885
|
-
})
|
|
1886
|
-
return shell_script
|
|
1887
|
-
finally:
|
|
1888
|
-
os.remove(execute_file)
|
|
1889
|
-
|
|
1890
|
-
def manage_models(query: str):
|
|
1891
|
-
"""
|
|
1892
|
-
Handle /models subcommands:
|
|
1893
|
-
/models /list - List all models (default + custom)
|
|
1894
|
-
/models /add <name> <api_key> - Add model with simplified params
|
|
1895
|
-
/models /add_model name=xxx base_url=xxx ... - Add model with custom params
|
|
1896
|
-
/models /remove <name> - Remove model by name
|
|
1897
|
-
"""
|
|
1898
|
-
printer = Printer()
|
|
1899
|
-
console = Console()
|
|
1900
|
-
|
|
1901
|
-
product_mode = memory.get("product_mode", "lite")
|
|
1902
|
-
if product_mode != "lite":
|
|
1903
|
-
printer.print_in_terminal("models_lite_only", style="red")
|
|
1904
|
-
return
|
|
1905
|
-
|
|
1906
|
-
models_data = models_module.load_models()
|
|
1907
|
-
subcmd = ""
|
|
1908
|
-
if "/list" in query:
|
|
1909
|
-
subcmd = "/list"
|
|
1910
|
-
query = query.replace("/list", "", 1).strip()
|
|
1911
|
-
|
|
1912
|
-
if "/add_model" in query:
|
|
1913
|
-
subcmd = "/add_model"
|
|
1914
|
-
query = query.replace("/add_model", "", 1).strip()
|
|
1915
|
-
|
|
1916
|
-
if "/add" in query:
|
|
1917
|
-
subcmd = "/add"
|
|
1918
|
-
query = query.replace("/add", "", 1).strip()
|
|
1919
|
-
|
|
1920
|
-
# alias to /add
|
|
1921
|
-
if "/activate" in query:
|
|
1922
|
-
subcmd = "/add"
|
|
1923
|
-
query = query.replace("/activate", "", 1).strip()
|
|
1924
|
-
|
|
1925
|
-
if "/remove" in query:
|
|
1926
|
-
subcmd = "/remove"
|
|
1927
|
-
query = query.replace("/remove", "", 1).strip()
|
|
1928
|
-
|
|
1929
|
-
if "/speed-test" in query:
|
|
1930
|
-
subcmd = "/speed-test"
|
|
1931
|
-
query = query.replace("/speed-test", "", 1).strip()
|
|
1932
|
-
|
|
1933
|
-
if "/speed_test" in query:
|
|
1934
|
-
subcmd = "/speed-test"
|
|
1935
|
-
query = query.replace("/speed_test", "", 1).strip()
|
|
1936
|
-
|
|
1937
|
-
if "input_price" in query:
|
|
1938
|
-
subcmd = "/input_price"
|
|
1939
|
-
query = query.replace("/input_price", "", 1).strip()
|
|
1940
|
-
|
|
1941
|
-
if "output_price" in query:
|
|
1942
|
-
subcmd = "/output_price"
|
|
1943
|
-
query = query.replace("/output_price", "", 1).strip()
|
|
1944
|
-
|
|
1945
|
-
if "/speed" in query:
|
|
1946
|
-
subcmd = "/speed"
|
|
1947
|
-
query = query.replace("/speed", "", 1).strip()
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
if not subcmd:
|
|
1952
|
-
printer.print_in_terminal("models_usage")
|
|
1953
|
-
|
|
1954
|
-
result_manager = ResultManager()
|
|
1955
|
-
if subcmd == "/list":
|
|
1956
|
-
if models_data:
|
|
1957
|
-
# Sort models by speed (average_speed)
|
|
1958
|
-
sorted_models = sorted(models_data, key=lambda x: float(x.get('average_speed', 0)))
|
|
1959
|
-
sorted_models.reverse()
|
|
1960
|
-
|
|
1961
|
-
table = Table(
|
|
1962
|
-
title=printer.get_message_from_key("models_title"),
|
|
1963
|
-
expand=True,
|
|
1964
|
-
show_lines=True
|
|
1965
|
-
)
|
|
1966
|
-
table.add_column("Name", style="cyan", width=30, overflow="fold", no_wrap=False)
|
|
1967
|
-
table.add_column("Model Name", style="magenta", width=30, overflow="fold", no_wrap=False)
|
|
1968
|
-
table.add_column("Base URL", style="white", width=40, overflow="fold", no_wrap=False)
|
|
1969
|
-
table.add_column("Input Price (M)", style="magenta", width=15, overflow="fold", no_wrap=False)
|
|
1970
|
-
table.add_column("Output Price (M)", style="magenta", width=15, overflow="fold", no_wrap=False)
|
|
1971
|
-
table.add_column("Speed (s/req)", style="blue", width=15, overflow="fold", no_wrap=False)
|
|
1972
|
-
for m in sorted_models:
|
|
1973
|
-
# Check if api_key_path exists and file exists
|
|
1974
|
-
is_api_key_set = "api_key" in m
|
|
1975
|
-
name = m.get("name", "")
|
|
1976
|
-
if is_api_key_set:
|
|
1977
|
-
api_key = m.get("api_key", "").strip()
|
|
1978
|
-
if not api_key:
|
|
1979
|
-
printer.print_in_terminal("models_api_key_empty", style="yellow", name=name)
|
|
1980
|
-
name = f"{name} *"
|
|
1981
|
-
|
|
1982
|
-
table.add_row(
|
|
1983
|
-
name,
|
|
1984
|
-
m.get("model_name", ""),
|
|
1985
|
-
m.get("base_url", ""),
|
|
1986
|
-
f"{m.get('input_price', 0.0):.2f}",
|
|
1987
|
-
f"{m.get('output_price', 0.0):.2f}",
|
|
1988
|
-
f"{m.get('average_speed', 0.0):.3f}"
|
|
1989
|
-
)
|
|
1990
|
-
console.print(table)
|
|
1991
|
-
result_manager.add_result(content=json.dumps(sorted_models,ensure_ascii=False),meta={
|
|
1992
|
-
"action": "models",
|
|
1993
|
-
"input": {
|
|
1994
|
-
"query": query
|
|
1995
|
-
}
|
|
1996
|
-
})
|
|
1997
|
-
|
|
1998
|
-
else:
|
|
1999
|
-
printer.print_in_terminal("models_no_models", style="yellow")
|
|
2000
|
-
result_manager.add_result(content="No models found",meta={
|
|
2001
|
-
"action": "models",
|
|
2002
|
-
"input": {
|
|
2003
|
-
"query": query
|
|
2004
|
-
}
|
|
2005
|
-
})
|
|
2006
|
-
|
|
2007
|
-
elif subcmd == "/input_price":
|
|
2008
|
-
args = query.strip().split()
|
|
2009
|
-
if len(args) >= 2:
|
|
2010
|
-
name = args[0]
|
|
2011
|
-
try:
|
|
2012
|
-
price = float(args[1])
|
|
2013
|
-
if models_module.update_model_input_price(name, price):
|
|
2014
|
-
printer.print_in_terminal("models_input_price_updated", style="green", name=name, price=price)
|
|
2015
|
-
result_manager.add_result(content=f"models_input_price_updated: {name} {price}",meta={
|
|
2016
|
-
"action": "models",
|
|
2017
|
-
"input": {
|
|
2018
|
-
"query": query
|
|
2019
|
-
}
|
|
2020
|
-
})
|
|
2021
|
-
else:
|
|
2022
|
-
printer.print_in_terminal("models_not_found", style="red", name=name)
|
|
2023
|
-
result_manager.add_result(content=f"models_not_found: {name}",meta={
|
|
2024
|
-
"action": "models",
|
|
2025
|
-
"input": {
|
|
2026
|
-
"query": query
|
|
2027
|
-
}
|
|
2028
|
-
})
|
|
2029
|
-
except ValueError as e:
|
|
2030
|
-
result_manager.add_result(content=f"models_invalid_price: {str(e)}",meta={
|
|
2031
|
-
"action": "models",
|
|
2032
|
-
"input": {
|
|
2033
|
-
"query": query
|
|
2034
|
-
}
|
|
2035
|
-
})
|
|
2036
|
-
printer.print_in_terminal("models_invalid_price", style="red", error=str(e))
|
|
2037
|
-
else:
|
|
2038
|
-
result_manager.add_result(content=printer.get_message_from_key("models_input_price_usage"),meta={
|
|
2039
|
-
"action": "models",
|
|
2040
|
-
"input": {
|
|
2041
|
-
"query": query
|
|
2042
|
-
}
|
|
2043
|
-
})
|
|
2044
|
-
printer.print_in_terminal("models_input_price_usage", style="red")
|
|
2045
|
-
|
|
2046
|
-
elif subcmd == "/output_price":
|
|
2047
|
-
args = query.strip().split()
|
|
2048
|
-
if len(args) >= 2:
|
|
2049
|
-
name = args[0]
|
|
2050
|
-
try:
|
|
2051
|
-
price = float(args[1])
|
|
2052
|
-
if models_module.update_model_output_price(name, price):
|
|
2053
|
-
printer.print_in_terminal("models_output_price_updated", style="green", name=name, price=price)
|
|
2054
|
-
result_manager.add_result(content=f"models_output_price_updated: {name} {price}",meta={
|
|
2055
|
-
"action": "models",
|
|
2056
|
-
"input": {
|
|
2057
|
-
"query": query
|
|
2058
|
-
}
|
|
2059
|
-
})
|
|
2060
|
-
else:
|
|
2061
|
-
printer.print_in_terminal("models_not_found", style="red", name=name)
|
|
2062
|
-
result_manager.add_result(content=f"models_not_found: {name}",meta={
|
|
2063
|
-
"action": "models",
|
|
2064
|
-
"input": {
|
|
2065
|
-
"query": query
|
|
2066
|
-
}
|
|
2067
|
-
})
|
|
2068
|
-
except ValueError as e:
|
|
2069
|
-
printer.print_in_terminal("models_invalid_price", style="red", error=str(e))
|
|
2070
|
-
result_manager.add_result(content=f"models_invalid_price: {str(e)}",meta={
|
|
2071
|
-
"action": "models",
|
|
2072
|
-
"input": {
|
|
2073
|
-
"query": query
|
|
2074
|
-
}
|
|
2075
|
-
})
|
|
2076
|
-
else:
|
|
2077
|
-
result_manager.add_result(content=printer.get_message_from_key("models_output_price_usage"),meta={
|
|
2078
|
-
"action": "models",
|
|
2079
|
-
"input": {
|
|
2080
|
-
"query": query
|
|
2081
|
-
}
|
|
2082
|
-
})
|
|
2083
|
-
printer.print_in_terminal("models_output_price_usage", style="red")
|
|
2084
|
-
|
|
2085
|
-
elif subcmd == "/speed":
|
|
2086
|
-
args = query.strip().split()
|
|
2087
|
-
if len(args) >= 2:
|
|
2088
|
-
name = args[0]
|
|
2089
|
-
try:
|
|
2090
|
-
speed = float(args[1])
|
|
2091
|
-
if models_module.update_model_speed(name, speed):
|
|
2092
|
-
printer.print_in_terminal("models_speed_updated", style="green", name=name, speed=speed)
|
|
2093
|
-
result_manager.add_result(content=f"models_speed_updated: {name} {speed}",meta={
|
|
2094
|
-
"action": "models",
|
|
2095
|
-
"input": {
|
|
2096
|
-
"query": query
|
|
2097
|
-
}
|
|
2098
|
-
})
|
|
2099
|
-
else:
|
|
2100
|
-
printer.print_in_terminal("models_not_found", style="red", name=name)
|
|
2101
|
-
result_manager.add_result(content=f"models_not_found: {name}",meta={
|
|
2102
|
-
"action": "models",
|
|
2103
|
-
"input": {
|
|
2104
|
-
"query": query
|
|
2105
|
-
}
|
|
2106
|
-
})
|
|
2107
|
-
except ValueError as e:
|
|
2108
|
-
printer.print_in_terminal("models_invalid_speed", style="red", error=str(e))
|
|
2109
|
-
result_manager.add_result(content=f"models_invalid_speed: {str(e)}",meta={
|
|
2110
|
-
"action": "models",
|
|
2111
|
-
"input": {
|
|
2112
|
-
"query": query
|
|
2113
|
-
}
|
|
2114
|
-
})
|
|
2115
|
-
else:
|
|
2116
|
-
result_manager.add_result(content=printer.get_message_from_key("models_speed_usage"),meta={
|
|
2117
|
-
"action": "models",
|
|
2118
|
-
"input": {
|
|
2119
|
-
"query": query
|
|
2120
|
-
}
|
|
2121
|
-
})
|
|
2122
|
-
printer.print_in_terminal("models_speed_usage", style="red")
|
|
2123
|
-
|
|
2124
|
-
elif subcmd == "/speed-test":
|
|
2125
|
-
from autocoder.common.model_speed_test import render_speed_test_in_terminal
|
|
2126
|
-
test_rounds = 1 # 默认测试轮数
|
|
2127
|
-
|
|
2128
|
-
enable_long_context = False
|
|
2129
|
-
if "/long_context" in query:
|
|
2130
|
-
enable_long_context = True
|
|
2131
|
-
query = query.replace("/long_context", "", 1).strip()
|
|
2132
|
-
|
|
2133
|
-
if "/long-context" in query:
|
|
2134
|
-
enable_long_context = True
|
|
2135
|
-
query = query.replace("/long-context", "", 1).strip()
|
|
2136
|
-
|
|
2137
|
-
# 解析可选的测试轮数参数
|
|
2138
|
-
args = query.strip().split()
|
|
2139
|
-
if args and args[0].isdigit():
|
|
2140
|
-
test_rounds = int(args[0])
|
|
2141
|
-
|
|
2142
|
-
render_speed_test_in_terminal(product_mode, test_rounds,enable_long_context=enable_long_context)
|
|
2143
|
-
## 等待优化,获取明细数据
|
|
2144
|
-
result_manager.add_result(content="models test success",meta={
|
|
2145
|
-
"action": "models",
|
|
2146
|
-
"input": {
|
|
2147
|
-
"query": query
|
|
2148
|
-
}
|
|
2149
|
-
})
|
|
2150
|
-
|
|
2151
|
-
elif subcmd == "/add":
|
|
2152
|
-
# Support both simplified and legacy formats
|
|
2153
|
-
args = query.strip().split(" ")
|
|
2154
|
-
if len(args) == 2:
|
|
2155
|
-
# Simplified: /models /add <name> <api_key>
|
|
2156
|
-
name, api_key = args[0], args[1]
|
|
2157
|
-
result = models_module.update_model_with_api_key(name, api_key)
|
|
2158
|
-
if result:
|
|
2159
|
-
result_manager.add_result(content=f"models_added: {name}",meta={
|
|
2160
|
-
"action": "models",
|
|
2161
|
-
"input": {
|
|
2162
|
-
"query": query
|
|
2163
|
-
}
|
|
2164
|
-
})
|
|
2165
|
-
printer.print_in_terminal("models_added", style="green", name=name)
|
|
2166
|
-
else:
|
|
2167
|
-
result_manager.add_result(content=f"models_add_failed: {name}",meta={
|
|
2168
|
-
"action": "models",
|
|
2169
|
-
"input": {
|
|
2170
|
-
"query": query
|
|
2171
|
-
}
|
|
2172
|
-
})
|
|
2173
|
-
printer.print_in_terminal("models_add_failed", style="red", name=name)
|
|
2174
|
-
else:
|
|
2175
|
-
printer.print_in_terminal("models_add_usage", style="red")
|
|
2176
|
-
result_manager.add_result(content=printer.get_message_from_key("models_add_usage"),meta={
|
|
2177
|
-
"action": "models",
|
|
2178
|
-
"input": {
|
|
2179
|
-
"query": query
|
|
2180
|
-
}
|
|
2181
|
-
})
|
|
2182
|
-
|
|
2183
|
-
elif subcmd == "/add_model":
|
|
2184
|
-
# Parse key=value pairs: /models /add_model name=abc base_url=http://xx ...
|
|
2185
|
-
# Collect key=value pairs
|
|
2186
|
-
kv_pairs = shlex.split(query)
|
|
2187
|
-
data_dict = {}
|
|
2188
|
-
for pair in kv_pairs:
|
|
2189
|
-
if '=' not in pair:
|
|
2190
|
-
printer.print_in_terminal("models_add_model_params", style="red")
|
|
2191
|
-
continue
|
|
2192
|
-
k, v = pair.split('=', 1)
|
|
2193
|
-
data_dict[k.strip()] = v.strip()
|
|
2194
|
-
|
|
2195
|
-
# Name is required
|
|
2196
|
-
if "name" not in data_dict:
|
|
2197
|
-
printer.print_in_terminal("models_add_model_name_required", style="red")
|
|
2198
|
-
return
|
|
2199
|
-
|
|
2200
|
-
# Check duplication
|
|
2201
|
-
if any(m["name"] == data_dict["name"] for m in models_data):
|
|
2202
|
-
printer.print_in_terminal("models_add_model_exists", style="yellow", name=data_dict["name"])
|
|
2203
|
-
result_manager.add_result(content=printer.get_message_from_key("models_add_model_exists",name=data_dict["name"]),meta={
|
|
2204
|
-
"action": "models",
|
|
2205
|
-
"input": {
|
|
2206
|
-
"query": query
|
|
2207
|
-
}
|
|
2208
|
-
})
|
|
2209
|
-
return
|
|
2210
|
-
|
|
2211
|
-
# Create model with defaults
|
|
2212
|
-
final_model = {
|
|
2213
|
-
"name": data_dict["name"],
|
|
2214
|
-
"model_type": data_dict.get("model_type", "saas/openai"),
|
|
2215
|
-
"model_name": data_dict.get("model_name", data_dict["name"]),
|
|
2216
|
-
"base_url": data_dict.get("base_url", "https://api.openai.com/v1"),
|
|
2217
|
-
"api_key_path": data_dict.get("api_key_path", "api.openai.com"),
|
|
2218
|
-
"description": data_dict.get("description", ""),
|
|
2219
|
-
"is_reasoning": data_dict.get("is_reasoning", "false") in ["true", "True", "TRUE", "1"]
|
|
2220
|
-
}
|
|
2221
|
-
|
|
2222
|
-
models_data.append(final_model)
|
|
2223
|
-
models_module.save_models(models_data)
|
|
2224
|
-
printer.print_in_terminal("models_add_model_success", style="green", name=data_dict["name"])
|
|
2225
|
-
result_manager.add_result(content=f"models_add_model_success: {data_dict['name']}",meta={
|
|
2226
|
-
"action": "models",
|
|
2227
|
-
"input": {
|
|
2228
|
-
"query": query
|
|
2229
|
-
}
|
|
2230
|
-
})
|
|
2231
|
-
|
|
2232
|
-
elif subcmd == "/remove":
|
|
2233
|
-
args = query.strip().split(" ")
|
|
2234
|
-
if len(args) < 1:
|
|
2235
|
-
printer.print_in_terminal("models_add_usage", style="red")
|
|
2236
|
-
result_manager.add_result(content=printer.get_message_from_key("models_add_usage"),meta={
|
|
2237
|
-
"action": "models",
|
|
2238
|
-
"input": {
|
|
2239
|
-
"query": query
|
|
2240
|
-
}
|
|
2241
|
-
})
|
|
2242
|
-
return
|
|
2243
|
-
name = args[0]
|
|
2244
|
-
filtered_models = [m for m in models_data if m["name"] != name]
|
|
2245
|
-
if len(filtered_models) == len(models_data):
|
|
2246
|
-
printer.print_in_terminal("models_add_model_remove", style="yellow", name=name)
|
|
2247
|
-
result_manager.add_result(content=printer.get_message_from_key("models_add_model_remove",name=name),meta={
|
|
2248
|
-
"action": "models",
|
|
2249
|
-
"input": {
|
|
2250
|
-
"query": query
|
|
2251
|
-
}
|
|
2252
|
-
})
|
|
2253
|
-
return
|
|
2254
|
-
models_module.save_models(filtered_models)
|
|
2255
|
-
printer.print_in_terminal("models_add_model_removed", style="green", name=name)
|
|
2256
|
-
result_manager.add_result(content=printer.get_message_from_key("models_add_model_removed",name=name),meta={
|
|
2257
|
-
"action": "models",
|
|
2258
|
-
"input": {
|
|
2259
|
-
"query": query
|
|
2260
|
-
}
|
|
2261
|
-
})
|
|
2262
|
-
else:
|
|
2263
|
-
printer.print_in_terminal("models_unknown_subcmd", style="yellow", subcmd=subcmd)
|
|
2264
|
-
result_manager.add_result(content=printer.get_message_from_key("models_unknown_subcmd",subcmd=subcmd),meta={
|
|
2265
|
-
"action": "models",
|
|
2266
|
-
"input": {
|
|
2267
|
-
"query": query
|
|
2268
|
-
}
|
|
2269
|
-
})
|
|
2270
|
-
|
|
2271
|
-
def exclude_dirs(dir_names: List[str]):
|
|
2272
|
-
new_dirs = dir_names
|
|
2273
|
-
existing_dirs = memory.get("exclude_dirs", [])
|
|
2274
|
-
dirs_to_add = [d for d in new_dirs if d not in existing_dirs]
|
|
2275
|
-
|
|
2276
|
-
if dirs_to_add:
|
|
2277
|
-
existing_dirs.extend(dirs_to_add)
|
|
2278
|
-
if "exclude_dirs" not in memory:
|
|
2279
|
-
memory["exclude_dirs"] = existing_dirs
|
|
2280
|
-
print(f"Added exclude dirs: {dirs_to_add}")
|
|
2281
|
-
exclude_files([f"regex://.*/{d}/*." for d in dirs_to_add])
|
|
2282
|
-
else:
|
|
2283
|
-
print("All specified dirs are already in the exclude list.")
|
|
2284
|
-
save_memory()
|
|
2285
|
-
completer.refresh_files()
|
|
2286
|
-
|
|
2287
|
-
def exclude_files(query: str):
|
|
2288
|
-
result_manager = ResultManager()
|
|
2289
|
-
printer = Printer()
|
|
2290
|
-
if "/list" in query:
|
|
2291
|
-
query = query.replace("/list", "", 1).strip()
|
|
2292
|
-
existing_file_patterns = memory.get("exclude_files", [])
|
|
2293
|
-
console = Console()
|
|
2294
|
-
# 打印表格
|
|
2295
|
-
table = Table(title="Exclude Files")
|
|
2296
|
-
table.add_column("File Pattern")
|
|
2297
|
-
for file_pattern in existing_file_patterns:
|
|
2298
|
-
table.add_row(file_pattern)
|
|
2299
|
-
console.print(table)
|
|
2300
|
-
result_manager.add_result(content=f"Exclude files: {existing_file_patterns}",meta={
|
|
2301
|
-
"action": "exclude_files",
|
|
2302
|
-
"input": {
|
|
2303
|
-
"query": query
|
|
2304
|
-
}
|
|
2305
|
-
})
|
|
2306
|
-
return
|
|
2307
|
-
|
|
2308
|
-
if "/drop" in query:
|
|
2309
|
-
query = query.replace("/drop", "", 1).strip()
|
|
2310
|
-
existing_file_patterns = memory.get("exclude_files", [])
|
|
2311
|
-
existing_file_patterns.remove(query.strip())
|
|
2312
|
-
memory["exclude_files"] = existing_file_patterns
|
|
2313
|
-
save_memory()
|
|
2314
|
-
completer.refresh_files()
|
|
2315
|
-
result_manager.add_result(content=f"Dropped exclude files: {query}",meta={
|
|
2316
|
-
"action": "exclude_files",
|
|
2317
|
-
"input": {
|
|
2318
|
-
"query": query
|
|
2319
|
-
}
|
|
2320
|
-
})
|
|
2321
|
-
return
|
|
2322
|
-
|
|
2323
|
-
new_file_patterns = query.strip().split(",")
|
|
2324
|
-
|
|
2325
|
-
existing_file_patterns = memory.get("exclude_files", [])
|
|
2326
|
-
file_patterns_to_add = [f for f in new_file_patterns if f not in existing_file_patterns]
|
|
2327
|
-
|
|
2328
|
-
for file_pattern in file_patterns_to_add:
|
|
2329
|
-
if not file_pattern.startswith("regex://"):
|
|
2330
|
-
result_manager.add_result(content=printer.get_message_from_key_with_format("invalid_file_pattern", file_pattern=file_pattern),meta={
|
|
2331
|
-
"action": "exclude_files",
|
|
2332
|
-
"input": {
|
|
2333
|
-
"query": file_pattern
|
|
2334
|
-
}
|
|
2335
|
-
})
|
|
2336
|
-
raise ValueError(printer.get_message_from_key_with_format("invalid_file_pattern", file_pattern=file_pattern))
|
|
2337
|
-
|
|
2338
|
-
if file_patterns_to_add:
|
|
2339
|
-
existing_file_patterns.extend(file_patterns_to_add)
|
|
2340
|
-
if "exclude_files" not in memory:
|
|
2341
|
-
memory["exclude_files"] = existing_file_patterns
|
|
2342
|
-
|
|
2343
|
-
result_manager.add_result(content=f"Added exclude files: {file_patterns_to_add}",meta={
|
|
2344
|
-
"action": "exclude_files",
|
|
2345
|
-
"input": {
|
|
2346
|
-
"query": file_patterns_to_add
|
|
2347
|
-
}
|
|
2348
|
-
})
|
|
2349
|
-
save_memory()
|
|
2350
|
-
print(f"Added exclude files: {file_patterns_to_add}")
|
|
2351
|
-
else:
|
|
2352
|
-
result_manager.add_result(content=f"All specified files are already in the exclude list.",meta={
|
|
2353
|
-
"action": "exclude_files",
|
|
2354
|
-
"input": {
|
|
2355
|
-
"query": file_patterns_to_add
|
|
2356
|
-
}
|
|
2357
|
-
})
|
|
2358
|
-
print("All specified files are already in the exclude list.")
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
@run_in_raw_thread()
|
|
2363
|
-
def index_build():
|
|
2364
|
-
conf = memory.get("conf", {})
|
|
2365
|
-
yaml_config = {
|
|
2366
|
-
"include_file": ["./base/base.yml"],
|
|
2367
|
-
}
|
|
2368
|
-
|
|
2369
|
-
for key, value in conf.items():
|
|
2370
|
-
converted_value = convert_config_value(key, value)
|
|
2371
|
-
if converted_value is not None:
|
|
2372
|
-
yaml_config[key] = converted_value
|
|
2373
|
-
|
|
2374
|
-
yaml_content = convert_yaml_config_to_str(yaml_config=yaml_config)
|
|
2375
|
-
yaml_file = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
2376
|
-
|
|
2377
|
-
with open(yaml_file, "w",encoding="utf-8") as f:
|
|
2378
|
-
f.write(yaml_content)
|
|
2379
|
-
try:
|
|
2380
|
-
with redirect_stdout() as output:
|
|
2381
|
-
auto_coder_main(["index", "--file", yaml_file])
|
|
2382
|
-
print(output.getvalue(), flush=True)
|
|
2383
|
-
completer.refresh_files()
|
|
2384
|
-
finally:
|
|
2385
|
-
os.remove(yaml_file)
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
def get_final_config()->AutoCoderArgs:
|
|
2389
|
-
conf = memory.get("conf", {})
|
|
2390
|
-
yaml_config = {
|
|
2391
|
-
"include_file": ["./base/base.yml"],
|
|
2392
|
-
"auto_merge": conf.get("auto_merge", "editblock"),
|
|
2393
|
-
"human_as_model": conf.get("human_as_model", "false") == "true",
|
|
2394
|
-
"skip_build_index": conf.get("skip_build_index", "true") == "true",
|
|
2395
|
-
"skip_confirm": conf.get("skip_confirm", "true") == "true",
|
|
2396
|
-
"silence": conf.get("silence", "true") == "true",
|
|
2397
|
-
"include_project_structure": conf.get("include_project_structure", "true")
|
|
2398
|
-
== "true",
|
|
2399
|
-
}
|
|
2400
|
-
for key, value in conf.items():
|
|
2401
|
-
converted_value = convert_config_value(key, value)
|
|
2402
|
-
if converted_value is not None:
|
|
2403
|
-
yaml_config[key] = converted_value
|
|
2404
|
-
|
|
2405
|
-
temp_yaml = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
2406
|
-
try:
|
|
2407
|
-
with open(temp_yaml, "w",encoding="utf-8") as f:
|
|
2408
|
-
f.write(convert_yaml_config_to_str(yaml_config=yaml_config))
|
|
2409
|
-
args = convert_yaml_to_config(temp_yaml)
|
|
2410
|
-
finally:
|
|
2411
|
-
if os.path.exists(temp_yaml):
|
|
2412
|
-
os.remove(temp_yaml)
|
|
2413
|
-
return args
|
|
2414
|
-
|
|
2415
|
-
def help(query: str):
|
|
2416
|
-
from autocoder.common.auto_configure import ConfigAutoTuner,MemoryConfig,AutoConfigRequest
|
|
2417
|
-
args = get_final_config()
|
|
2418
|
-
product_mode = memory.get("product_mode", "lite")
|
|
2419
|
-
llm = get_single_llm(args.chat_model or args.model, product_mode=product_mode)
|
|
2420
|
-
auto_config_tuner = ConfigAutoTuner(args=args, llm=llm, memory_config=MemoryConfig(memory=memory, save_memory_func=save_memory))
|
|
2421
|
-
auto_config_tuner.tune(AutoConfigRequest(query=query))
|
|
2422
|
-
|
|
2423
|
-
@run_in_raw_thread()
|
|
2424
|
-
def index_export(path: str):
|
|
2425
|
-
from autocoder.common.index_import_export import export_index
|
|
2426
|
-
from autocoder.common.printer import Printer
|
|
2427
|
-
printer = Printer()
|
|
2428
|
-
project_root = os.getcwd()
|
|
2429
|
-
if export_index(project_root, path):
|
|
2430
|
-
printer.print_in_terminal("index_export_success", path=path)
|
|
2431
|
-
else:
|
|
2432
|
-
printer.print_in_terminal("index_export_fail", path=path)
|
|
2433
|
-
|
|
2434
|
-
@run_in_raw_thread()
|
|
2435
|
-
def index_import(path: str):
|
|
2436
|
-
from autocoder.common.index_import_export import import_index
|
|
2437
|
-
from autocoder.common.printer import Printer
|
|
2438
|
-
printer = Printer()
|
|
2439
|
-
project_root = os.getcwd()
|
|
2440
|
-
if import_index(project_root, path):
|
|
2441
|
-
printer.print_in_terminal("index_import_success", path=path)
|
|
2442
|
-
else:
|
|
2443
|
-
printer.print_in_terminal("index_import_fail", path=path)
|
|
2444
|
-
|
|
2445
|
-
@run_in_raw_thread()
|
|
2446
|
-
def index_query(query: str):
|
|
2447
|
-
conf = memory.get("conf", {})
|
|
2448
|
-
yaml_config = {
|
|
2449
|
-
"include_file": ["./base/base.yml"],
|
|
2450
|
-
}
|
|
2451
|
-
|
|
2452
|
-
for key, value in conf.items():
|
|
2453
|
-
converted_value = convert_config_value(key, value)
|
|
2454
|
-
if converted_value is not None:
|
|
2455
|
-
yaml_config[key] = converted_value
|
|
2456
|
-
|
|
2457
|
-
yaml_config["query"] = query
|
|
2458
|
-
|
|
2459
|
-
yaml_content = convert_yaml_config_to_str(yaml_config=yaml_config)
|
|
2460
|
-
yaml_file = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
2461
|
-
|
|
2462
|
-
with open(yaml_file, "w",encoding="utf-8") as f:
|
|
2463
|
-
f.write(yaml_content)
|
|
2464
|
-
try:
|
|
2465
|
-
with redirect_stdout() as output:
|
|
2466
|
-
auto_coder_main(["index-query", "--file", yaml_file])
|
|
2467
|
-
print(output.getvalue(), flush=True)
|
|
2468
|
-
finally:
|
|
2469
|
-
os.remove(yaml_file)
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
def list_files():
|
|
2473
|
-
console = Console()
|
|
2474
|
-
project_root = os.getcwd()
|
|
2475
|
-
current_files = memory["current_files"]["files"]
|
|
2476
|
-
|
|
2477
|
-
if current_files:
|
|
2478
|
-
table = Table(
|
|
2479
|
-
title="Current Files", show_header=True, header_style="bold magenta"
|
|
2480
|
-
)
|
|
2481
|
-
table.add_column("File", style="green")
|
|
2482
|
-
for file in current_files:
|
|
2483
|
-
table.add_row(os.path.relpath(file, project_root))
|
|
2484
|
-
console.print(Panel(table, border_style="blue"))
|
|
2485
|
-
else:
|
|
2486
|
-
console.print(
|
|
2487
|
-
Panel(
|
|
2488
|
-
"No files in the current session.",
|
|
2489
|
-
title="Current Files",
|
|
2490
|
-
border_style="yellow",
|
|
2491
|
-
)
|
|
2492
|
-
)
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
def gen_and_exec_shell_command(query: str):
|
|
2496
|
-
from rich.prompt import Confirm
|
|
2497
|
-
from autocoder.common.printer import Printer
|
|
2498
|
-
from rich.console import Console
|
|
2499
|
-
|
|
2500
|
-
printer = Printer()
|
|
2501
|
-
console = Console()
|
|
2502
|
-
# Generate the shell script
|
|
2503
|
-
shell_script = generate_shell_command(query)
|
|
2504
|
-
|
|
2505
|
-
# Ask for confirmation using rich
|
|
2506
|
-
if Confirm.ask(
|
|
2507
|
-
printer.get_message_from_key("confirm_execute_shell_script"),
|
|
2508
|
-
default=False
|
|
2509
|
-
):
|
|
2510
|
-
execute_shell_command(shell_script)
|
|
2511
|
-
else:
|
|
2512
|
-
console.print(
|
|
2513
|
-
Panel(
|
|
2514
|
-
printer.get_message_from_key("shell_script_not_executed"),
|
|
2515
|
-
border_style="yellow"
|
|
2516
|
-
)
|
|
2517
|
-
)
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
def lib_command(args: List[str]):
|
|
2521
|
-
console = Console()
|
|
2522
|
-
lib_dir = os.path.join(".auto-coder", "libs")
|
|
2523
|
-
llm_friendly_packages_dir = os.path.join(lib_dir, "llm_friendly_packages")
|
|
2524
|
-
|
|
2525
|
-
if not os.path.exists(lib_dir):
|
|
2526
|
-
os.makedirs(lib_dir)
|
|
2527
|
-
|
|
2528
|
-
if "libs" not in memory:
|
|
2529
|
-
memory["libs"] = {}
|
|
2530
|
-
|
|
2531
|
-
if not args:
|
|
2532
|
-
console.print(
|
|
2533
|
-
"Please specify a subcommand: /add, /remove, /list, /set-proxy, /refresh, or /get"
|
|
2534
|
-
)
|
|
2535
|
-
return
|
|
2536
|
-
|
|
2537
|
-
subcommand = args[0]
|
|
2538
|
-
|
|
2539
|
-
if subcommand == "/add":
|
|
2540
|
-
if len(args) < 2:
|
|
2541
|
-
console.print("Please specify a library name to add")
|
|
2542
|
-
return
|
|
2543
|
-
lib_name = args[1].strip()
|
|
2544
|
-
|
|
2545
|
-
# Clone the repository if it doesn't exist
|
|
2546
|
-
if not os.path.exists(llm_friendly_packages_dir):
|
|
2547
|
-
console.print("Cloning llm_friendly_packages repository...")
|
|
2548
|
-
try:
|
|
2549
|
-
proxy_url = memory.get(
|
|
2550
|
-
"lib-proxy", "https://github.com/allwefantasy/llm_friendly_packages"
|
|
2551
|
-
)
|
|
2552
|
-
git.Repo.clone_from(
|
|
2553
|
-
proxy_url,
|
|
2554
|
-
llm_friendly_packages_dir,
|
|
2555
|
-
)
|
|
2556
|
-
console.print(
|
|
2557
|
-
"Successfully cloned llm_friendly_packages repository")
|
|
2558
|
-
except git.exc.GitCommandError as e:
|
|
2559
|
-
console.print(f"Error cloning repository: {e}")
|
|
2560
|
-
|
|
2561
|
-
if lib_name in memory["libs"]:
|
|
2562
|
-
console.print(f"Library {lib_name} is already added")
|
|
2563
|
-
else:
|
|
2564
|
-
memory["libs"][lib_name] = {}
|
|
2565
|
-
console.print(f"Added library: {lib_name}")
|
|
2566
|
-
|
|
2567
|
-
save_memory()
|
|
2568
|
-
|
|
2569
|
-
elif subcommand == "/remove":
|
|
2570
|
-
if len(args) < 2:
|
|
2571
|
-
console.print("Please specify a library name to remove")
|
|
2572
|
-
return
|
|
2573
|
-
lib_name = args[1].strip()
|
|
2574
|
-
if lib_name in memory["libs"]:
|
|
2575
|
-
del memory["libs"][lib_name]
|
|
2576
|
-
console.print(f"Removed library: {lib_name}")
|
|
2577
|
-
save_memory()
|
|
2578
|
-
else:
|
|
2579
|
-
console.print(f"Library {lib_name} is not in the list")
|
|
2580
|
-
|
|
2581
|
-
elif subcommand == "/list":
|
|
2582
|
-
if memory["libs"]:
|
|
2583
|
-
table = Table(title="Added Libraries")
|
|
2584
|
-
table.add_column("Library Name", style="cyan")
|
|
2585
|
-
for lib_name in memory["libs"]:
|
|
2586
|
-
table.add_row(lib_name)
|
|
2587
|
-
console.print(table)
|
|
2588
|
-
else:
|
|
2589
|
-
console.print("No libraries added yet")
|
|
2590
|
-
|
|
2591
|
-
elif subcommand == "/set-proxy":
|
|
2592
|
-
if len(args) == 1:
|
|
2593
|
-
current_proxy = memory.get("lib-proxy", "No proxy set")
|
|
2594
|
-
console.print(f"Current proxy: {current_proxy}")
|
|
2595
|
-
elif len(args) == 2:
|
|
2596
|
-
proxy_url = args[1]
|
|
2597
|
-
memory["lib-proxy"] = proxy_url
|
|
2598
|
-
console.print(f"Set proxy to: {proxy_url}")
|
|
2599
|
-
save_memory()
|
|
2600
|
-
else:
|
|
2601
|
-
console.print("Invalid number of arguments for /set-proxy")
|
|
2602
|
-
|
|
2603
|
-
elif subcommand == "/refresh":
|
|
2604
|
-
if os.path.exists(llm_friendly_packages_dir):
|
|
2605
|
-
try:
|
|
2606
|
-
repo = git.Repo(llm_friendly_packages_dir)
|
|
2607
|
-
origin = repo.remotes.origin
|
|
2608
|
-
proxy_url = memory.get("lib-proxy")
|
|
2609
|
-
|
|
2610
|
-
current_url = origin.url
|
|
2611
|
-
|
|
2612
|
-
if proxy_url and proxy_url != current_url:
|
|
2613
|
-
new_url = proxy_url
|
|
2614
|
-
origin.set_url(new_url)
|
|
2615
|
-
console.print(f"Updated remote URL to: {new_url}")
|
|
2616
|
-
|
|
2617
|
-
origin.pull()
|
|
2618
|
-
console.print(
|
|
2619
|
-
"Successfully updated llm_friendly_packages repository")
|
|
2620
|
-
|
|
2621
|
-
except git.exc.GitCommandError as e:
|
|
2622
|
-
console.print(f"Error updating repository: {e}")
|
|
2623
|
-
else:
|
|
2624
|
-
console.print(
|
|
2625
|
-
"llm_friendly_packages repository does not exist. Please run /lib /add <library_name> command first to clone it."
|
|
2626
|
-
)
|
|
2627
|
-
|
|
2628
|
-
elif subcommand == "/get":
|
|
2629
|
-
if len(args) < 2:
|
|
2630
|
-
console.print("Please specify a package name to get")
|
|
2631
|
-
return
|
|
2632
|
-
package_name = args[1].strip()
|
|
2633
|
-
docs = get_llm_friendly_package_docs(package_name, return_paths=True)
|
|
2634
|
-
if docs:
|
|
2635
|
-
table = Table(title=f"Markdown Files for {package_name}")
|
|
2636
|
-
table.add_column("File Path", style="cyan")
|
|
2637
|
-
for doc in docs:
|
|
2638
|
-
table.add_row(doc)
|
|
2639
|
-
console.print(table)
|
|
2640
|
-
else:
|
|
2641
|
-
console.print(
|
|
2642
|
-
f"No markdown files found for package: {package_name}")
|
|
2643
|
-
|
|
2644
|
-
else:
|
|
2645
|
-
console.print(f"Unknown subcommand: {subcommand}")
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
def execute_shell_command(command: str):
|
|
2649
|
-
from autocoder.common.shells import execute_shell_command as shell_exec
|
|
2650
|
-
shell_exec(command)
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
def conf_export(path: str):
|
|
2654
|
-
from autocoder.common.conf_import_export import export_conf
|
|
2655
|
-
export_conf(os.getcwd(), path)
|
|
2656
|
-
|
|
2657
|
-
def conf_import(path: str):
|
|
2658
|
-
from autocoder.common.conf_import_export import import_conf
|
|
2659
|
-
import_conf(os.getcwd(), path)
|
|
2660
|
-
|
|
2661
|
-
@run_in_raw_thread()
|
|
2662
|
-
def auto_command(params,query: str):
|
|
2663
|
-
"""处理/auto指令"""
|
|
2664
|
-
from autocoder.commands.auto_command import CommandAutoTuner, AutoCommandRequest, CommandConfig, MemoryConfig
|
|
2665
|
-
args = get_final_config()
|
|
2666
|
-
# help(query)
|
|
2667
|
-
|
|
2668
|
-
# 准备请求参数
|
|
2669
|
-
request = AutoCommandRequest(
|
|
2670
|
-
user_input=query
|
|
2671
|
-
)
|
|
2672
|
-
|
|
2673
|
-
# 初始化调优器
|
|
2674
|
-
llm = get_single_llm(args.chat_model or args.model,product_mode=args.product_mode)
|
|
2675
|
-
tuner = CommandAutoTuner(llm,
|
|
2676
|
-
args=args,
|
|
2677
|
-
memory_config=MemoryConfig(memory=memory, save_memory_func=save_memory),
|
|
2678
|
-
command_config=CommandConfig(
|
|
2679
|
-
add_files=add_files,
|
|
2680
|
-
remove_files=remove_files,
|
|
2681
|
-
list_files=list_files,
|
|
2682
|
-
conf=configure,
|
|
2683
|
-
revert=revert,
|
|
2684
|
-
commit=commit,
|
|
2685
|
-
help=help,
|
|
2686
|
-
exclude_dirs=exclude_dirs,
|
|
2687
|
-
exclude_files=exclude_files,
|
|
2688
|
-
ask=ask,
|
|
2689
|
-
chat=chat,
|
|
2690
|
-
coding=coding,
|
|
2691
|
-
design=design,
|
|
2692
|
-
summon=summon,
|
|
2693
|
-
lib=lib_command,
|
|
2694
|
-
mcp=mcp,
|
|
2695
|
-
models=manage_models,
|
|
2696
|
-
index_build=index_build,
|
|
2697
|
-
index_query=index_query,
|
|
2698
|
-
execute_shell_command=execute_shell_command,
|
|
2699
|
-
generate_shell_command=generate_shell_command,
|
|
2700
|
-
conf_export=conf_export,
|
|
2701
|
-
conf_import=conf_import,
|
|
2702
|
-
index_export=index_export,
|
|
2703
|
-
index_import=index_import
|
|
2704
|
-
))
|
|
2705
|
-
|
|
2706
|
-
# 生成建议
|
|
2707
|
-
response = tuner.analyze(request)
|
|
2708
|
-
printer = Printer()
|
|
2709
|
-
# 显示建议
|
|
2710
|
-
console = Console()
|
|
2711
|
-
console.print(Panel(
|
|
2712
|
-
Markdown(response.reasoning or ""),
|
|
2713
|
-
title=printer.get_message_from_key_with_format("auto_command_reasoning_title"),
|
|
2714
|
-
border_style="blue",
|
|
2715
|
-
padding=(1, 2)
|
|
2716
|
-
))
|
|
141
|
+
ARGS = None
|
|
2717
142
|
|
|
2718
143
|
|
|
2719
144
|
def main():
|
|
2720
|
-
|
|
2721
|
-
from tokenizers import Tokenizer
|
|
2722
|
-
try:
|
|
2723
|
-
tokenizer_path = pkg_resources.resource_filename(
|
|
2724
|
-
"autocoder", "data/tokenizer.json"
|
|
2725
|
-
)
|
|
2726
|
-
VariableHolder.TOKENIZER_PATH = tokenizer_path
|
|
2727
|
-
VariableHolder.TOKENIZER_MODEL = Tokenizer.from_file(tokenizer_path)
|
|
2728
|
-
except FileNotFoundError:
|
|
2729
|
-
tokenizer_path = None
|
|
145
|
+
load_tokenizer()
|
|
2730
146
|
|
|
2731
147
|
ARGS = parse_arguments()
|
|
2732
148
|
|
|
@@ -2736,10 +152,18 @@ def main():
|
|
|
2736
152
|
if ARGS.pro:
|
|
2737
153
|
ARGS.product_mode = "pro"
|
|
2738
154
|
|
|
2739
|
-
if not ARGS.quick:
|
|
2740
|
-
initialize_system(
|
|
155
|
+
if not ARGS.quick:
|
|
156
|
+
initialize_system(InitializeSystemRequest(
|
|
157
|
+
product_mode=ARGS.product_mode,
|
|
158
|
+
skip_provider_selection=ARGS.skip_provider_selection,
|
|
159
|
+
debug=ARGS.debug,
|
|
160
|
+
quick=ARGS.quick,
|
|
161
|
+
lite=ARGS.lite,
|
|
162
|
+
pro=ARGS.pro
|
|
163
|
+
))
|
|
2741
164
|
|
|
2742
165
|
load_memory()
|
|
166
|
+
memory = get_memory()
|
|
2743
167
|
|
|
2744
168
|
configure(f"product_mode:{ARGS.product_mode}")
|
|
2745
169
|
|
|
@@ -2805,7 +229,7 @@ def main():
|
|
|
2805
229
|
pwd_parts = pwd.split(os.sep)
|
|
2806
230
|
if len(pwd_parts) > 3:
|
|
2807
231
|
pwd = os.sep.join(pwd_parts[-3:])
|
|
2808
|
-
return f"Current Dir: {pwd} \nMode: {MODES[mode]} | Human as Model: {human_as_model} "
|
|
232
|
+
return f"Current Dir: {pwd} \nMode: {MODES[mode]}(ctrl+k) | Human as Model: {human_as_model}(ctrl+n) "
|
|
2809
233
|
|
|
2810
234
|
session = PromptSession(
|
|
2811
235
|
history=InMemoryHistory(),
|