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

Files changed (85) hide show
  1. auto_coder-0.1.399.dist-info/METADATA +396 -0
  2. {auto_coder-0.1.397.dist-info → auto_coder-0.1.399.dist-info}/RECORD +81 -28
  3. {auto_coder-0.1.397.dist-info → auto_coder-0.1.399.dist-info}/WHEEL +1 -1
  4. {auto_coder-0.1.397.dist-info → auto_coder-0.1.399.dist-info}/entry_points.txt +2 -0
  5. autocoder/agent/base_agentic/base_agent.py +2 -2
  6. autocoder/agent/base_agentic/tools/replace_in_file_tool_resolver.py +1 -1
  7. autocoder/agent/entry_command_agent/__init__.py +29 -0
  8. autocoder/agent/entry_command_agent/auto_tool.py +61 -0
  9. autocoder/agent/entry_command_agent/chat.py +475 -0
  10. autocoder/agent/entry_command_agent/designer.py +53 -0
  11. autocoder/agent/entry_command_agent/generate_command.py +50 -0
  12. autocoder/agent/entry_command_agent/project_reader.py +58 -0
  13. autocoder/agent/entry_command_agent/voice2text.py +71 -0
  14. autocoder/auto_coder.py +23 -548
  15. autocoder/auto_coder_rag.py +1 -0
  16. autocoder/auto_coder_runner.py +510 -8
  17. autocoder/chat/rules_command.py +1 -1
  18. autocoder/chat_auto_coder.py +8 -0
  19. autocoder/common/ac_style_command_parser/__init__.py +15 -0
  20. autocoder/common/ac_style_command_parser/example.py +7 -0
  21. autocoder/{command_parser.py → common/ac_style_command_parser/parser.py} +1 -33
  22. autocoder/common/ac_style_command_parser/test_parser.py +516 -0
  23. autocoder/common/command_completer_v2.py +1 -1
  24. autocoder/common/command_file_manager/examples.py +22 -8
  25. autocoder/common/command_file_manager/manager.py +37 -6
  26. autocoder/common/conversations/__init__.py +84 -39
  27. autocoder/common/conversations/backup/__init__.py +14 -0
  28. autocoder/common/conversations/backup/backup_manager.py +564 -0
  29. autocoder/common/conversations/backup/restore_manager.py +546 -0
  30. autocoder/common/conversations/cache/__init__.py +16 -0
  31. autocoder/common/conversations/cache/base_cache.py +89 -0
  32. autocoder/common/conversations/cache/cache_manager.py +368 -0
  33. autocoder/common/conversations/cache/memory_cache.py +224 -0
  34. autocoder/common/conversations/config.py +195 -0
  35. autocoder/common/conversations/exceptions.py +72 -0
  36. autocoder/common/conversations/file_locker.py +145 -0
  37. autocoder/common/conversations/get_conversation_manager.py +143 -0
  38. autocoder/common/conversations/manager.py +1028 -0
  39. autocoder/common/conversations/models.py +154 -0
  40. autocoder/common/conversations/search/__init__.py +15 -0
  41. autocoder/common/conversations/search/filter_manager.py +431 -0
  42. autocoder/common/conversations/search/text_searcher.py +366 -0
  43. autocoder/common/conversations/storage/__init__.py +16 -0
  44. autocoder/common/conversations/storage/base_storage.py +82 -0
  45. autocoder/common/conversations/storage/file_storage.py +267 -0
  46. autocoder/common/conversations/storage/index_manager.py +406 -0
  47. autocoder/common/v2/agent/agentic_edit.py +131 -18
  48. autocoder/common/v2/agent/agentic_edit_types.py +10 -0
  49. autocoder/common/v2/code_auto_generate_editblock.py +10 -2
  50. autocoder/dispacher/__init__.py +10 -0
  51. autocoder/rags.py +73 -50
  52. autocoder/run_context.py +1 -0
  53. autocoder/sdk/__init__.py +188 -0
  54. autocoder/sdk/cli/__init__.py +15 -0
  55. autocoder/sdk/cli/__main__.py +26 -0
  56. autocoder/sdk/cli/completion_wrapper.py +38 -0
  57. autocoder/sdk/cli/formatters.py +211 -0
  58. autocoder/sdk/cli/handlers.py +174 -0
  59. autocoder/sdk/cli/install_completion.py +301 -0
  60. autocoder/sdk/cli/main.py +284 -0
  61. autocoder/sdk/cli/options.py +72 -0
  62. autocoder/sdk/constants.py +102 -0
  63. autocoder/sdk/core/__init__.py +20 -0
  64. autocoder/sdk/core/auto_coder_core.py +867 -0
  65. autocoder/sdk/core/bridge.py +497 -0
  66. autocoder/sdk/example.py +0 -0
  67. autocoder/sdk/exceptions.py +72 -0
  68. autocoder/sdk/models/__init__.py +19 -0
  69. autocoder/sdk/models/messages.py +209 -0
  70. autocoder/sdk/models/options.py +194 -0
  71. autocoder/sdk/models/responses.py +311 -0
  72. autocoder/sdk/session/__init__.py +32 -0
  73. autocoder/sdk/session/session.py +106 -0
  74. autocoder/sdk/session/session_manager.py +56 -0
  75. autocoder/sdk/utils/__init__.py +24 -0
  76. autocoder/sdk/utils/formatters.py +216 -0
  77. autocoder/sdk/utils/io_utils.py +302 -0
  78. autocoder/sdk/utils/validators.py +287 -0
  79. autocoder/version.py +2 -1
  80. auto_coder-0.1.397.dist-info/METADATA +0 -111
  81. autocoder/common/conversations/compatibility.py +0 -303
  82. autocoder/common/conversations/conversation_manager.py +0 -502
  83. autocoder/common/conversations/example.py +0 -152
  84. {auto_coder-0.1.397.dist-info → auto_coder-0.1.399.dist-info/licenses}/LICENSE +0 -0
  85. {auto_coder-0.1.397.dist-info → auto_coder-0.1.399.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,516 @@
1
+
2
+ import pytest
3
+ from typing import Dict, List, Any
4
+
5
+ # 导入被测模块
6
+ from .parser import (
7
+ CommandParser,
8
+ parse_query,
9
+ has_command,
10
+ get_command_args,
11
+ get_command_kwargs
12
+ )
13
+
14
+
15
+ class TestCommandParser:
16
+ """CommandParser类的单元测试"""
17
+
18
+ @pytest.fixture
19
+ def parser(self):
20
+ """提供CommandParser实例"""
21
+ return CommandParser()
22
+
23
+ def test_init(self, parser):
24
+ """测试CommandParser初始化"""
25
+ assert parser is not None
26
+ assert hasattr(parser, 'command_pattern')
27
+ assert hasattr(parser, 'key_value_pattern')
28
+ assert hasattr(parser, 'path_pattern')
29
+
30
+ def test_empty_query(self, parser):
31
+ """测试空查询字符串"""
32
+ assert parser.parse("") == {}
33
+ assert parser.parse(" ") == {}
34
+ assert parser.parse(None) == {}
35
+
36
+ def test_single_command_no_args(self, parser):
37
+ """测试单个命令无参数"""
38
+ result = parser.parse("/help")
39
+ expected = {
40
+ "help": {
41
+ "args": [],
42
+ "kwargs": {}
43
+ }
44
+ }
45
+ assert result == expected
46
+
47
+ def test_single_command_with_args(self, parser):
48
+ """测试单个命令带位置参数"""
49
+ result = parser.parse("/add file1.txt file2.py")
50
+ expected = {
51
+ "add": {
52
+ "args": ["file1.txt", "file2.py"],
53
+ "kwargs": {}
54
+ }
55
+ }
56
+ assert result == expected
57
+
58
+ def test_single_command_with_kwargs(self, parser):
59
+ """测试单个命令带键值对参数"""
60
+ result = parser.parse("/config model=gpt-4 temperature=0.7")
61
+ expected = {
62
+ "config": {
63
+ "args": [],
64
+ "kwargs": {
65
+ "model": "gpt-4",
66
+ "temperature": "0.7"
67
+ }
68
+ }
69
+ }
70
+ assert result == expected
71
+
72
+ def test_single_command_mixed_params(self, parser):
73
+ """测试单个命令混合参数"""
74
+ result = parser.parse("/deploy myapp env=prod version=1.0")
75
+ expected = {
76
+ "deploy": {
77
+ "args": ["myapp"],
78
+ "kwargs": {
79
+ "env": "prod",
80
+ "version": "1.0"
81
+ }
82
+ }
83
+ }
84
+ assert result == expected
85
+
86
+ def test_quoted_args_double_quotes(self, parser):
87
+ """测试双引号参数"""
88
+ result = parser.parse('/say "hello world" "this is a test"')
89
+ expected = {
90
+ "say": {
91
+ "args": ["hello world", "this is a test"],
92
+ "kwargs": {}
93
+ }
94
+ }
95
+ assert result == expected
96
+
97
+ def test_quoted_args_single_quotes(self, parser):
98
+ """测试单引号参数"""
99
+ result = parser.parse("/say 'hello world' 'this is a test'")
100
+ expected = {
101
+ "say": {
102
+ "args": ["hello world", "this is a test"],
103
+ "kwargs": {}
104
+ }
105
+ }
106
+ assert result == expected
107
+
108
+ def test_quoted_kwargs(self, parser):
109
+ """测试带引号的键值对参数"""
110
+ result = parser.parse('/config message="hello world" path=\'/tmp/test dir\'')
111
+ expected = {
112
+ "config": {
113
+ "args": [],
114
+ "kwargs": {
115
+ "message": "hello world",
116
+ "path": "/tmp/test dir"
117
+ }
118
+ }
119
+ }
120
+ assert result == expected
121
+
122
+ def test_multiple_commands(self, parser):
123
+ """测试多个命令"""
124
+ result = parser.parse("/add file1.txt /remove file2.txt")
125
+ expected = {
126
+ "add": {
127
+ "args": ["file1.txt"],
128
+ "kwargs": {}
129
+ },
130
+ "remove": {
131
+ "args": ["file2.txt"],
132
+ "kwargs": {}
133
+ }
134
+ }
135
+ assert result == expected
136
+
137
+ def test_multiple_commands_with_mixed_params(self, parser):
138
+ """测试多个命令带混合参数"""
139
+ result = parser.parse("/deploy app1 env=prod /config model=gpt-4 /status")
140
+ expected = {
141
+ "deploy": {
142
+ "args": ["app1"],
143
+ "kwargs": {"env": "prod"}
144
+ },
145
+ "config": {
146
+ "args": [],
147
+ "kwargs": {"model": "gpt-4"}
148
+ },
149
+ "status": {
150
+ "args": [],
151
+ "kwargs": {}
152
+ }
153
+ }
154
+ assert result == expected
155
+
156
+ def test_path_not_recognized_as_command(self, parser):
157
+ """测试路径不被识别为命令"""
158
+ result = parser.parse("/add /path/to/file.txt /config model=gpt-4")
159
+ expected = {
160
+ "add": {
161
+ "args": ["/path/to/file.txt"],
162
+ "kwargs": {}
163
+ },
164
+ "config": {
165
+ "args": [],
166
+ "kwargs": {"model": "gpt-4"}
167
+ }
168
+ }
169
+ assert result == expected
170
+
171
+ def test_complex_path_handling(self, parser):
172
+ """测试复杂路径处理"""
173
+ result = parser.parse("/analyze /home/user/project/src/main.py /output /tmp/results")
174
+ expected = {
175
+ "analyze": {
176
+ "args": ["/home/user/project/src/main.py"],
177
+ "kwargs": {}
178
+ },
179
+ "output": {
180
+ "args": ["/tmp/results"],
181
+ "kwargs": {}
182
+ }
183
+ }
184
+ assert result == expected
185
+
186
+ def test_command_with_dots_not_recognized(self, parser):
187
+ """测试带点的字符串不被识别为命令"""
188
+ result = parser.parse("check /config.json /setup.py")
189
+ # 不以/开头,所以没有命令被识别
190
+ assert result == {}
191
+
192
+ def test_parse_command_existing(self, parser):
193
+ """测试解析特定存在的命令"""
194
+ query = "/add file1.txt /remove file2.txt mode=force"
195
+ result = parser.parse_command(query, "remove")
196
+ expected = {
197
+ "args": ["file2.txt"],
198
+ "kwargs": {"mode": "force"}
199
+ }
200
+ assert result == expected
201
+
202
+ def test_parse_command_nonexistent(self, parser):
203
+ """测试解析不存在的命令"""
204
+ query = "/add file1.txt /remove file2.txt"
205
+ result = parser.parse_command(query, "deploy")
206
+ assert result is None
207
+
208
+ def test_edge_case_empty_kwargs_value(self, parser):
209
+ """测试空的键值对值"""
210
+ result = parser.parse("/config key1= key2=value")
211
+ expected = {
212
+ "config": {
213
+ "args": [],
214
+ "kwargs": {
215
+ "key1": "",
216
+ "key2": "value"
217
+ }
218
+ }
219
+ }
220
+ assert result == expected
221
+
222
+ def test_edge_case_special_characters_in_values(self, parser):
223
+ """测试值中包含特殊字符"""
224
+ result = parser.parse("/config url=https://api.example.com/v1 pattern='*.py'")
225
+ expected = {
226
+ "config": {
227
+ "args": [],
228
+ "kwargs": {
229
+ "url": "https://api.example.com/v1",
230
+ "pattern": "*.py"
231
+ }
232
+ }
233
+ }
234
+ assert result == expected
235
+
236
+ def test_command_at_end_of_string(self, parser):
237
+ """测试字符串末尾的命令"""
238
+ result = parser.parse("some text /help")
239
+ expected = {
240
+ "help": {
241
+ "args": [],
242
+ "kwargs": {}
243
+ }
244
+ }
245
+ assert result == expected
246
+
247
+
248
+ class TestConvenienceFunctions:
249
+ """测试便捷函数"""
250
+
251
+ def test_parse_query_function(self):
252
+ """测试parse_query函数"""
253
+ result = parse_query("/add file1.txt mode=fast")
254
+ expected = {
255
+ "add": {
256
+ "args": ["file1.txt"],
257
+ "kwargs": {"mode": "fast"}
258
+ }
259
+ }
260
+ assert result == expected
261
+
262
+ def test_has_command_true(self):
263
+ """测试has_command函数 - 命令存在"""
264
+ assert has_command("/add file1.txt /remove file2.txt", "add") == True
265
+ assert has_command("/add file1.txt /remove file2.txt", "remove") == True
266
+
267
+ def test_has_command_false(self):
268
+ """测试has_command函数 - 命令不存在"""
269
+ assert has_command("/add file1.txt /remove file2.txt", "deploy") == False
270
+ assert has_command("no commands here", "add") == False
271
+ assert has_command("", "add") == False
272
+
273
+ def test_get_command_args_existing(self):
274
+ """测试get_command_args函数 - 命令存在"""
275
+ query = "/add file1.txt file2.py /remove file3.txt"
276
+ assert get_command_args(query, "add") == ["file1.txt", "file2.py"]
277
+ assert get_command_args(query, "remove") == ["file3.txt"]
278
+
279
+ def test_get_command_args_nonexistent(self):
280
+ """测试get_command_args函数 - 命令不存在"""
281
+ query = "/add file1.txt file2.py"
282
+ assert get_command_args(query, "remove") == []
283
+ assert get_command_args("", "add") == []
284
+
285
+ def test_get_command_kwargs_existing(self):
286
+ """测试get_command_kwargs函数 - 命令存在"""
287
+ query = "/config model=gpt-4 temp=0.7 /deploy env=prod"
288
+ assert get_command_kwargs(query, "config") == {"model": "gpt-4", "temp": "0.7"}
289
+ assert get_command_kwargs(query, "deploy") == {"env": "prod"}
290
+
291
+ def test_get_command_kwargs_nonexistent(self):
292
+ """测试get_command_kwargs函数 - 命令不存在"""
293
+ query = "/config model=gpt-4"
294
+ assert get_command_kwargs(query, "deploy") == {}
295
+ assert get_command_kwargs("", "config") == {}
296
+
297
+
298
+ class TestComplexScenarios:
299
+ """测试复杂场景"""
300
+
301
+ def test_real_world_scenario_1(self):
302
+ """测试真实场景1:文件操作命令"""
303
+ query = '/add "src/main.py" "tests/test_main.py" /config model="gpt-4" temperature=0.7 /deploy env=production version="1.2.3"'
304
+ result = parse_query(query)
305
+
306
+ expected = {
307
+ "add": {
308
+ "args": ["src/main.py", "tests/test_main.py"],
309
+ "kwargs": {}
310
+ },
311
+ "config": {
312
+ "args": [],
313
+ "kwargs": {
314
+ "model": "gpt-4",
315
+ "temperature": "0.7"
316
+ }
317
+ },
318
+ "deploy": {
319
+ "args": [],
320
+ "kwargs": {
321
+ "env": "production",
322
+ "version": "1.2.3"
323
+ }
324
+ }
325
+ }
326
+ assert result == expected
327
+
328
+ def test_real_world_scenario_2(self):
329
+ """测试真实场景2:包含路径的复杂命令"""
330
+ query = "/analyze /home/user/project/src /output /tmp/analysis.json format=json verbose=true"
331
+ result = parse_query(query)
332
+
333
+ expected = {
334
+ "analyze": {
335
+ "args": ["/home/user/project/src"],
336
+ "kwargs": {}
337
+ },
338
+ "output": {
339
+ "args": ["/tmp/analysis.json"],
340
+ "kwargs": {
341
+ "format": "json",
342
+ "verbose": "true"
343
+ }
344
+ }
345
+ }
346
+ assert result == expected
347
+
348
+ def test_real_world_scenario_3(self):
349
+ """测试真实场景3:混合引号和特殊字符"""
350
+ query = """/search pattern="*.py" path='/home/user/My Documents/project' /filter exclude="__pycache__" """
351
+ result = parse_query(query)
352
+
353
+ expected = {
354
+ "search": {
355
+ "args": [],
356
+ "kwargs": {
357
+ "pattern": "*.py",
358
+ "path": "/home/user/My Documents/project"
359
+ }
360
+ },
361
+ "filter": {
362
+ "args": [],
363
+ "kwargs": {
364
+ "exclude": "__pycache__"
365
+ }
366
+ }
367
+ }
368
+ assert result == expected
369
+
370
+ def test_edge_case_consecutive_commands(self):
371
+ """测试连续命令"""
372
+ query = "/start /stop /restart mode=fast"
373
+ result = parse_query(query)
374
+
375
+ expected = {
376
+ "start": {
377
+ "args": [],
378
+ "kwargs": {}
379
+ },
380
+ "stop": {
381
+ "args": [],
382
+ "kwargs": {}
383
+ },
384
+ "restart": {
385
+ "args": [],
386
+ "kwargs": {"mode": "fast"}
387
+ }
388
+ }
389
+ assert result == expected
390
+
391
+ def test_edge_case_command_with_numbers_and_underscores(self):
392
+ """测试包含数字和下划线的命令"""
393
+ query = "/test_case_1 /deploy_v2 app_name=test123"
394
+ result = parse_query(query)
395
+
396
+ expected = {
397
+ "test_case_1": {
398
+ "args": [],
399
+ "kwargs": {}
400
+ },
401
+ "deploy_v2": {
402
+ "args": [],
403
+ "kwargs": {"app_name": "test123"}
404
+ }
405
+ }
406
+ assert result == expected
407
+
408
+
409
+ class TestErrorHandling:
410
+ """测试错误处理和边界情况"""
411
+
412
+ def test_malformed_quotes(self):
413
+ """测试格式错误的引号"""
414
+ # 这些应该仍能部分解析,不会抛出异常
415
+ parser = CommandParser()
416
+
417
+ # 未闭合的引号 - 应该被当作普通参数处理
418
+ result = parser.parse('/test "unclosed quote arg')
419
+ assert "test" in result
420
+
421
+ # 混合引号
422
+ result = parser.parse('/test "mixed\' quotes"')
423
+ assert "test" in result
424
+
425
+ def test_special_characters_in_commands(self):
426
+ """测试命令中的特殊字符"""
427
+ parser = CommandParser()
428
+
429
+ # 命令名只能包含单词字符,所以这些不会被识别为命令
430
+ result = parser.parse("/test-command /test.command")
431
+ assert result == {}
432
+
433
+ def test_whitespace_handling(self):
434
+ """测试空白字符处理"""
435
+ parser = CommandParser()
436
+
437
+ query = " /add file1.txt file2.py key=value "
438
+ result = parser.parse(query)
439
+
440
+ expected = {
441
+ "add": {
442
+ "args": ["file1.txt", "file2.py"],
443
+ "kwargs": {"key": "value"}
444
+ }
445
+ }
446
+ assert result == expected
447
+
448
+ def test_unicode_characters(self):
449
+ """测试Unicode字符"""
450
+ parser = CommandParser()
451
+
452
+ query = '/test "中文参数" key="中文值"'
453
+ result = parser.parse(query)
454
+
455
+ expected = {
456
+ "test": {
457
+ "args": ["中文参数"],
458
+ "kwargs": {"key": "中文值"}
459
+ }
460
+ }
461
+ assert result == expected
462
+
463
+ def test__command_with_path(self, parser):
464
+ """测试单个命令混合参数"""
465
+ result = parser.parse('/command "tdd/hello.md" name="威廉"')
466
+ expected = {
467
+ "command": {
468
+ "args": ["tdd/hello.md"],
469
+ "kwargs": {
470
+ "name": "威廉"
471
+ }
472
+ }
473
+ }
474
+ assert result == expected
475
+
476
+
477
+ # 参数化测试用例
478
+ @pytest.mark.parametrize("query,expected_commands", [
479
+ ("/help", ["help"]),
480
+ ("/add /remove", ["add", "remove"]),
481
+ ("/config model=gpt-4", ["config"]),
482
+ ("no commands", []),
483
+ ("/start /stop /restart", ["start", "stop", "restart"]),
484
+ ])
485
+ def test_command_detection_parametrized(query, expected_commands):
486
+ """参数化测试命令检测"""
487
+ result = parse_query(query)
488
+ actual_commands = list(result.keys())
489
+ assert actual_commands == expected_commands
490
+
491
+
492
+ @pytest.mark.parametrize("query,command,expected_args", [
493
+ ("/add file1 file2", "add", ["file1", "file2"]),
494
+ ("/remove", "remove", []),
495
+ ("/test arg1 'arg with spaces'", "test", ["arg1", "arg with spaces"]),
496
+ ("", "any", []),
497
+ ])
498
+ def test_get_args_parametrized(query, command, expected_args):
499
+ """参数化测试获取参数"""
500
+ assert get_command_args(query, command) == expected_args
501
+
502
+
503
+ @pytest.mark.parametrize("query,command,expected_kwargs", [
504
+ ("/config model=gpt-4 temp=0.7", "config", {"model": "gpt-4", "temp": "0.7"}),
505
+ ("/deploy", "deploy", {}),
506
+ ("/test key='value with spaces'", "test", {"key": "value with spaces"}),
507
+ ("", "any", {}),
508
+ ])
509
+ def test_get_kwargs_parametrized(query, command, expected_kwargs):
510
+ """参数化测试获取键值对参数"""
511
+ assert get_command_kwargs(query, command) == expected_kwargs
512
+
513
+
514
+ if __name__ == "__main__":
515
+ # 可以直接运行此文件进行测试
516
+ pytest.main([__file__, "-v"])
@@ -22,7 +22,7 @@ COMMAND_HIERARCHY = {
22
22
  "/mcp": {"/add": {}, "/remove": {}, "/list": {}, "/list_running": {}, "/refresh": {}, "/info": {}},
23
23
  "/lib": {"/add": {}, "/remove": {}, "/list": {}, "/set-proxy": {}, "/refresh": {}, "/get": {}},
24
24
  "/models": {"/chat": {}, "/add": {}, "/add_model": {}, "/remove": {}, "/list": {}, "/speed": {}, "/speed-test": {}, "/input_price": {}, "/output_price": {}, "/activate": {}},
25
- "/auto": {},
25
+ "/auto": {"/new": {}, "/id": {}, "/list": {}},
26
26
  "/shell": {"/chat": {}},
27
27
  "/active_context": {"/list": {}, "/run": {}},
28
28
  "/index": {"/query": {}, "/build": {}, "/export": {}, "/import": {}},
@@ -9,7 +9,7 @@ import sys
9
9
  import json
10
10
  from typing import Dict, Set, List
11
11
 
12
- from autocoder.common.command_manager import (
12
+ from autocoder.common.command_file_manager import (
13
13
  CommandManager, CommandFile, JinjaVariable, CommandFileAnalysisResult
14
14
  )
15
15
 
@@ -122,16 +122,30 @@ def get_all_variables_example(manager: CommandManager):
122
122
  print()
123
123
 
124
124
 
125
- def main():
126
- """主函数"""
127
- # 设置测试环境
125
+ def initialization_examples():
126
+ """初始化示例"""
127
+ print("\n=== CommandManager 初始化示例 ===")
128
+
129
+ # 方式1: 使用默认目录(工作目录下的.autocodercommands目录)
130
+ print("方式1: 使用默认目录")
131
+ default_manager = CommandManager()
132
+ print(f"默认命令目录: {default_manager.commands_dir}")
133
+
134
+ # 方式2: 指定自定义目录
135
+ print("\n方式2: 指定自定义目录")
128
136
  test_dir = setup_test_environment()
129
- print(f"测试目录: {test_dir}")
137
+ custom_manager = CommandManager(test_dir)
138
+ print(f"自定义命令目录: {custom_manager.commands_dir}")
130
139
 
131
- # 创建命令管理器
132
- manager = CommandManager(test_dir)
140
+ return custom_manager
141
+
142
+
143
+ def main():
144
+ """主函数"""
145
+ # 展示初始化示例
146
+ manager = initialization_examples()
133
147
 
134
- # 运行示例
148
+ # 运行其他示例
135
149
  list_command_files_example(manager)
136
150
  read_command_file_example(manager)
137
151
  analyze_command_file_example(manager)
@@ -5,8 +5,9 @@
5
5
  """
6
6
 
7
7
  import os
8
- import logging
9
- from typing import Dict, List, Optional, Set, Tuple
8
+ from loguru import logger
9
+ from typing import Dict, List, Optional, Set, Tuple, Any
10
+ from byzerllm.utils import format_str_jinja2
10
11
 
11
12
  from autocoder.common.command_file_manager.models import (
12
13
  CommandFile, JinjaVariable, CommandFileAnalysisResult, ListCommandsResult
@@ -16,19 +17,19 @@ from autocoder.common.command_file_manager.utils import (
16
17
  analyze_command_file, is_command_file
17
18
  )
18
19
 
19
- logger = logging.getLogger(__name__)
20
-
21
20
 
22
21
  class CommandManager:
23
22
  """命令管理器,提供高层次的API接口"""
24
23
 
25
- def __init__(self, commands_dir: str):
24
+ def __init__(self, commands_dir: Optional[str] = None):
26
25
  """
27
26
  初始化命令管理器
28
27
 
29
28
  Args:
30
- commands_dir: 命令文件目录路径
29
+ commands_dir: 命令文件目录路径,如果为None则默认使用工作目录下的.autocodercommands目录
31
30
  """
31
+ if commands_dir is None:
32
+ commands_dir = os.path.join(os.getcwd(), ".autocodercommands")
32
33
  self.commands_dir = os.path.abspath(commands_dir)
33
34
 
34
35
  # 确保目录存在
@@ -97,6 +98,36 @@ class CommandManager:
97
98
  logger.error(f"读取命令文件时出错: {str(e)}")
98
99
  return None
99
100
 
101
+ def read_command_file_with_render(self, file_name: str, render_variables: Dict[str, Any] = {}) -> Optional[str]:
102
+ """
103
+ 读取指定的命令文件并使用 Jinja2 进行渲染
104
+
105
+ Args:
106
+ file_name: 命令文件名或相对路径
107
+ render_variables: 用于 Jinja2 渲染的变量字典,如果为 None 则使用空字典
108
+
109
+ Returns:
110
+ Optional[str]: 渲染后的文件内容,如果文件不存在或渲染失败则返回None
111
+ """
112
+ if render_variables is None:
113
+ render_variables = {}
114
+
115
+ # 首先读取命令文件
116
+ command_file = self.read_command_file(file_name)
117
+ if command_file is None:
118
+ return None
119
+
120
+ try:
121
+ # 使用 format_str_jinja2 进行渲染
122
+ rendered_content = format_str_jinja2(command_file.content, **render_variables)
123
+
124
+ logger.info(f"成功渲染命令文件: {file_name}, 使用变量: {render_variables}")
125
+ return rendered_content
126
+
127
+ except Exception as e:
128
+ logger.error(f"渲染命令文件时出错: {file_name}, 错误: {str(e)}")
129
+ return None
130
+
100
131
  def analyze_command_file(self, file_name: str) -> Optional[CommandFileAnalysisResult]:
101
132
  """
102
133
  分析指定的命令文件,提取其中的Jinja2变量