auto-coder 0.1.268__py3-none-any.whl → 0.1.269__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.

@@ -1,73 +1,53 @@
1
- from itertools import product
2
- from prompt_toolkit.formatted_text import HTML
3
- from prompt_toolkit.shortcuts import radiolist_dialog
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 autocoder.utils import operate_config_api
49
- from autocoder.agent.auto_guess_query import AutoGuessQuery
50
- from autocoder.common.mcp_server import get_mcp_server, McpRequest, McpInstallRequest, McpRemoveRequest, McpListRequest, McpListRunningRequest, McpRefreshRequest
51
- import byzerllm
52
- from byzerllm.utils import format_str_jinja2
53
- from autocoder.common.memory_manager import get_global_memory_file_paths
54
- from autocoder import models as models_module
55
- import shlex
56
- from autocoder.utils.llms import get_single_llm
57
- import pkg_resources
58
- from autocoder.common.printer import Printer
59
- from autocoder.utils.thread_utils import run_in_thread,run_in_raw_thread
60
- from autocoder.common.command_completer import CommandCompleter,FileSystemModel as CCFileSystemModel,MemoryConfig as CCMemoryModel
61
- from autocoder.common.conf_validator import ConfigValidator
62
-
63
- class SymbolItem(BaseModel):
64
- symbol_name: str
65
- symbol_type: SymbolType
66
- file_name: str
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
- import argparse
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
- from autocoder.rag.variable_holder import VariableHolder
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(ARGS)
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(),