siada-cli 0.0.1__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.
- agent_config.yaml +34 -0
- siada/__init__.py +13 -0
- siada/agent_hub/__init__.py +10 -0
- siada/agent_hub/coder/bug_fix_agent.py +398 -0
- siada/agent_hub/coder/code_gen_agent.py +235 -0
- siada/agent_hub/coder/fe_gen_agent.py +37 -0
- siada/agent_hub/coder/issue_review_agent.py +68 -0
- siada/agent_hub/coder/prompt/__init__.py +0 -0
- siada/agent_hub/coder/prompt/base/__init__.py +0 -0
- siada/agent_hub/coder/prompt/base/capabilities.py +18 -0
- siada/agent_hub/coder/prompt/base/non_interactive.py +14 -0
- siada/agent_hub/coder/prompt/base/prompt_builder.py +33 -0
- siada/agent_hub/coder/prompt/base/rules.py +40 -0
- siada/agent_hub/coder/prompt/base/tool_use.py +14 -0
- siada/agent_hub/coder/prompt/bug_prompt/bug_fix_prompt.py +51 -0
- siada/agent_hub/coder/prompt/bug_prompt/rules.py +53 -0
- siada/agent_hub/coder/prompt/code_gen_prompt.py +45 -0
- siada/agent_hub/coder/prompt/fe_gen_prompt.py +45 -0
- siada/agent_hub/coder/prompt/issue_review_prompt.py +121 -0
- siada/agent_hub/coder/tracing/__init__.py +22 -0
- siada/agent_hub/coder/tracing/logger_tracing_processor.py +458 -0
- siada/agent_hub/hooks/__init__.py +0 -0
- siada/agent_hub/hooks/io_hooks.py +30 -0
- siada/agent_hub/siada_agent.py +214 -0
- siada/config/__init__.py +0 -0
- siada/config/config_loader.py +67 -0
- siada/entrypoint/__init__.py +3 -0
- siada/entrypoint/args_parser/__init__.py +0 -0
- siada/entrypoint/args_parser/args.py +195 -0
- siada/entrypoint/interaction/__init__.py +0 -0
- siada/entrypoint/interaction/base_turn.py +107 -0
- siada/entrypoint/interaction/config.py +30 -0
- siada/entrypoint/interaction/controller.py +122 -0
- siada/entrypoint/interaction/nointeractive_controller.py +27 -0
- siada/entrypoint/interaction/turn/interface.py +116 -0
- siada/entrypoint/interaction/turn/models.py +34 -0
- siada/entrypoint/interaction/turn/run_turn.py +641 -0
- siada/entrypoint/interaction/turn_factory.py +35 -0
- siada/entrypoint/interaction/turn_models.py +28 -0
- siada/entrypoint/siadahub.py +413 -0
- siada/foundation/__init__.py +0 -0
- siada/foundation/code_agent_context.py +48 -0
- siada/foundation/config.py +59 -0
- siada/foundation/constants.py +2 -0
- siada/foundation/context.py +76 -0
- siada/foundation/logging.py +341 -0
- siada/foundation/tools/__init__.py +0 -0
- siada/foundation/tools/get_git_diff.py +105 -0
- siada/io/__init__.py +0 -0
- siada/io/banner.py +148 -0
- siada/io/color_settings.py +207 -0
- siada/io/color_utils.py +16 -0
- siada/io/components/__init__.py +0 -0
- siada/io/components/mdstream.py +204 -0
- siada/io/console_printer.py +68 -0
- siada/io/io.py +661 -0
- siada/io/key_bindings.py +129 -0
- siada/io/notification_command.py +40 -0
- siada/io/test_banner.py +64 -0
- siada/models/__init__.py +0 -0
- siada/models/agent.py +47 -0
- siada/models/coder/__init__.py +0 -0
- siada/models/converter.py +27 -0
- siada/models/model_base_config.py +121 -0
- siada/models/model_run_config.py +153 -0
- siada/provider/__init__.py +0 -0
- siada/provider/client_factory.py +112 -0
- siada/provider/llm_client.py +11 -0
- siada/provider/openrouter/__init__.py +0 -0
- siada/provider/openrouter/coverter.py +17 -0
- siada/provider/openrouter/openroute_provider.py +33 -0
- siada/provider/provider_factory.py +53 -0
- siada/queries/tree-sitter-language-pack/README.md +7 -0
- siada/queries/tree-sitter-language-pack/arduino-tags.scm +5 -0
- siada/queries/tree-sitter-language-pack/c-tags.scm +9 -0
- siada/queries/tree-sitter-language-pack/chatito-tags.scm +16 -0
- siada/queries/tree-sitter-language-pack/commonlisp-tags.scm +122 -0
- siada/queries/tree-sitter-language-pack/cpp-tags.scm +15 -0
- siada/queries/tree-sitter-language-pack/csharp-tags.scm +26 -0
- siada/queries/tree-sitter-language-pack/d-tags.scm +26 -0
- siada/queries/tree-sitter-language-pack/dart-tags.scm +92 -0
- siada/queries/tree-sitter-language-pack/elisp-tags.scm +5 -0
- siada/queries/tree-sitter-language-pack/elixir-tags.scm +54 -0
- siada/queries/tree-sitter-language-pack/elm-tags.scm +19 -0
- siada/queries/tree-sitter-language-pack/gleam-tags.scm +41 -0
- siada/queries/tree-sitter-language-pack/go-tags.scm +42 -0
- siada/queries/tree-sitter-language-pack/java-tags.scm +20 -0
- siada/queries/tree-sitter-language-pack/javascript-tags.scm +88 -0
- siada/queries/tree-sitter-language-pack/lua-tags.scm +34 -0
- siada/queries/tree-sitter-language-pack/ocaml-tags.scm +115 -0
- siada/queries/tree-sitter-language-pack/ocaml_interface-tags.scm +98 -0
- siada/queries/tree-sitter-language-pack/pony-tags.scm +39 -0
- siada/queries/tree-sitter-language-pack/properties-tags.scm +5 -0
- siada/queries/tree-sitter-language-pack/python-tags.scm +14 -0
- siada/queries/tree-sitter-language-pack/r-tags.scm +21 -0
- siada/queries/tree-sitter-language-pack/racket-tags.scm +12 -0
- siada/queries/tree-sitter-language-pack/ruby-tags.scm +64 -0
- siada/queries/tree-sitter-language-pack/rust-tags.scm +60 -0
- siada/queries/tree-sitter-language-pack/solidity-tags.scm +43 -0
- siada/queries/tree-sitter-language-pack/swift-tags.scm +51 -0
- siada/queries/tree-sitter-language-pack/udev-tags.scm +20 -0
- siada/queries/tree-sitter-languages/README.md +23 -0
- siada/queries/tree-sitter-languages/c-tags.scm +9 -0
- siada/queries/tree-sitter-languages/c_sharp-tags.scm +46 -0
- siada/queries/tree-sitter-languages/cpp-tags.scm +15 -0
- siada/queries/tree-sitter-languages/dart-tags.scm +91 -0
- siada/queries/tree-sitter-languages/elisp-tags.scm +8 -0
- siada/queries/tree-sitter-languages/elixir-tags.scm +54 -0
- siada/queries/tree-sitter-languages/elm-tags.scm +19 -0
- siada/queries/tree-sitter-languages/go-tags.scm +30 -0
- siada/queries/tree-sitter-languages/hcl-tags.scm +77 -0
- siada/queries/tree-sitter-languages/java-tags.scm +20 -0
- siada/queries/tree-sitter-languages/javascript-tags.scm +88 -0
- siada/queries/tree-sitter-languages/kotlin-tags.scm +27 -0
- siada/queries/tree-sitter-languages/ocaml-tags.scm +115 -0
- siada/queries/tree-sitter-languages/ocaml_interface-tags.scm +98 -0
- siada/queries/tree-sitter-languages/php-tags.scm +26 -0
- siada/queries/tree-sitter-languages/python-tags.scm +12 -0
- siada/queries/tree-sitter-languages/ql-tags.scm +26 -0
- siada/queries/tree-sitter-languages/ruby-tags.scm +64 -0
- siada/queries/tree-sitter-languages/rust-tags.scm +60 -0
- siada/queries/tree-sitter-languages/scala-tags.scm +65 -0
- siada/queries/tree-sitter-languages/typescript-tags.scm +41 -0
- siada/services/__init__.py +30 -0
- siada/services/at_file_recommendation_design_document.md +1213 -0
- siada/services/code_context_manager.py +136 -0
- siada/services/enhanced_fix_result_check.py +546 -0
- siada/services/execution_trace_collector.py +207 -0
- siada/services/file_recommendation/__init__.py +136 -0
- siada/services/file_recommendation/core/__init__.py +17 -0
- siada/services/file_recommendation/core/completion_engine.py +351 -0
- siada/services/file_recommendation/core/config.py +62 -0
- siada/services/file_recommendation/core/file_discovery.py +353 -0
- siada/services/file_recommendation/core/suggestion.py +110 -0
- siada/services/file_recommendation/utils/__init__.py +22 -0
- siada/services/file_recommendation/utils/path_utils.py +138 -0
- siada/services/file_recommendation/utils/text_utils.py +253 -0
- siada/services/fix_result_check.py +377 -0
- siada/services/handle_at_command/README.md +247 -0
- siada/services/handle_at_command/__init__.py +115 -0
- siada/services/handle_at_command/exceptions.py +46 -0
- siada/services/handle_at_command/models.py +92 -0
- siada/services/handle_at_command/parser.py +189 -0
- siada/services/handle_at_command/processor.py +321 -0
- siada/services/handle_at_command/resolver.py +318 -0
- siada/services/handle_at_command/utils.py +345 -0
- siada/services/model_info_service.py +103 -0
- siada/services/siada_runner.py +170 -0
- siada/session/__init__.py +29 -0
- siada/session/session_manager.py +66 -0
- siada/session/session_models.py +43 -0
- siada/support/__init__.py +0 -0
- siada/support/completer.py +204 -0
- siada/support/editor.py +146 -0
- siada/support/envprocessor.py +54 -0
- siada/support/repo.py +51 -0
- siada/support/slash_commands.py +410 -0
- siada/support/spinner.py +320 -0
- siada/tools/__init__.py +0 -0
- siada/tools/ast/README.md +345 -0
- siada/tools/ast/ast_tool.py +341 -0
- siada/tools/ast/models.py +11 -0
- siada/tools/coder/__init__.py +0 -0
- siada/tools/coder/ask_followup_question.py +70 -0
- siada/tools/coder/cmd_runner.py +132 -0
- siada/tools/coder/file_operator.py +284 -0
- siada/tools/coder/file_search/README.md +223 -0
- siada/tools/coder/file_search/__init__.py +10 -0
- siada/tools/coder/file_search/bin/rg-linux-arm64 +0 -0
- siada/tools/coder/file_search/bin/rg-linux-x64 +0 -0
- siada/tools/coder/file_search/bin/rg-macos-arm64 +0 -0
- siada/tools/coder/file_search/bin/rg-macos-x64 +0 -0
- siada/tools/coder/file_search/bin/rg.exe +0 -0
- siada/tools/coder/file_search/search.py +437 -0
- siada/tools/coder/file_search/setup_package.py +150 -0
- siada/tools/coder/file_search/test_search.py +142 -0
- siada/tools/coder/files.py +147 -0
- siada/tools/coder/fix_attempt_completion.py +58 -0
- siada/tools/coder/issue_review_completion.py +29 -0
- siada/tools/coder/observation/__init__.py +0 -0
- siada/tools/coder/observation/error.py +22 -0
- siada/tools/coder/observation/file_observation.py +216 -0
- siada/tools/coder/observation/observation.py +71 -0
- siada/tools/coder/repo_map/__init__.py +157 -0
- siada/tools/coder/repo_map/dump.py +29 -0
- siada/tools/coder/repo_map/io.py +226 -0
- siada/tools/coder/repo_map/repo_map.py +881 -0
- siada/tools/coder/repo_map/special.py +203 -0
- siada/tools/coder/repo_map/token_counter.py +154 -0
- siada/tools/coder/repo_map/waiting.py +221 -0
- siada/tools/coder/reproduce_completion.py +39 -0
- siada/tools/coder/run_cmd.py +60 -0
- siada/tools/coder/test_completion.py +25 -0
- siada/tools/coder/tool_docs.py +44 -0
- siada/tools/compression_tool.py +200 -0
- siada/tools/read_many_files/README.md +220 -0
- siada/tools/read_many_files/__init__.py +25 -0
- siada/tools/read_many_files/file_processor.py +486 -0
- siada/tools/read_many_files/filters.py +326 -0
- siada/tools/read_many_files/formatters.py +204 -0
- siada/tools/read_many_files/models.py +189 -0
- siada/tools/read_many_files_tool.py +233 -0
- siada/tools/tool_call_format/__init__.py +55 -0
- siada/tools/tool_call_format/file_to_language.py +231 -0
- siada/tools/tool_call_format/formatter_factory.py +80 -0
- siada/tools/tool_call_format/formatters.py +282 -0
- siada/tools/tool_call_format/tool_call_formatter.py +54 -0
- siada/tools/web/__init__.py +0 -0
- siada/tools/web/web_crawl.py +208 -0
- siada/utils.py +194 -0
- siada_cli-0.0.1.dist-info/LICENSE +201 -0
- siada_cli-0.0.1.dist-info/METADATA +457 -0
- siada_cli-0.0.1.dist-info/RECORD +215 -0
- siada_cli-0.0.1.dist-info/WHEEL +4 -0
- siada_cli-0.0.1.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
from typing import Any, Dict, List, Optional
|
|
7
|
+
|
|
8
|
+
from agents.tracing import TracingProcessor, Trace, Span
|
|
9
|
+
from openai.types.responses import ResponseFunctionToolCall
|
|
10
|
+
|
|
11
|
+
@dataclass
|
|
12
|
+
class ModelCall:
|
|
13
|
+
"""模型调用记录"""
|
|
14
|
+
call_id: int
|
|
15
|
+
model: str
|
|
16
|
+
input_messages: List[Dict[str, Any]]
|
|
17
|
+
output_messages: List[Dict[str, Any]]
|
|
18
|
+
usage: Optional[Dict[str, Any]] = None
|
|
19
|
+
timestamp: datetime = field(default_factory=datetime.now)
|
|
20
|
+
duration_ms: Optional[float] = None
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class ToolCall:
|
|
25
|
+
"""工具调用记录"""
|
|
26
|
+
call_id: int
|
|
27
|
+
tool_name: str
|
|
28
|
+
input_args: Any
|
|
29
|
+
output_result: Any
|
|
30
|
+
timestamp: datetime = field(default_factory=datetime.now)
|
|
31
|
+
duration_ms: Optional[float] = None
|
|
32
|
+
success: bool = True
|
|
33
|
+
error_message: Optional[str] = None
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclass
|
|
37
|
+
class ExecutionTrace:
|
|
38
|
+
trace_id: str
|
|
39
|
+
workflow_name: str
|
|
40
|
+
start_time: datetime
|
|
41
|
+
end_time: Optional[datetime] = None
|
|
42
|
+
model_calls: List[ModelCall] = field(default_factory=list)
|
|
43
|
+
tool_calls: List[ToolCall] = field(default_factory=list)
|
|
44
|
+
total_tokens: int = 0
|
|
45
|
+
total_input_tokens: int = 0
|
|
46
|
+
total_output_tokens: int = 0
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def duration_seconds(self) -> float:
|
|
50
|
+
if self.end_time:
|
|
51
|
+
return (self.end_time - self.start_time).total_seconds()
|
|
52
|
+
return 0.0
|
|
53
|
+
|
|
54
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
55
|
+
return {
|
|
56
|
+
"trace_id": self.trace_id,
|
|
57
|
+
"workflow_name": self.workflow_name,
|
|
58
|
+
"start_time": self.start_time.isoformat(),
|
|
59
|
+
"end_time": self.end_time.isoformat() if self.end_time else None,
|
|
60
|
+
"duration_seconds": self.duration_seconds,
|
|
61
|
+
"model_calls": [
|
|
62
|
+
{
|
|
63
|
+
"call_id": call.call_id,
|
|
64
|
+
"model": call.model,
|
|
65
|
+
"input_messages": call.input_messages,
|
|
66
|
+
"output_messages": call.output_messages,
|
|
67
|
+
"usage": call.usage,
|
|
68
|
+
"timestamp": call.timestamp.isoformat(),
|
|
69
|
+
"duration_ms": call.duration_ms
|
|
70
|
+
}
|
|
71
|
+
for call in self.model_calls
|
|
72
|
+
],
|
|
73
|
+
"tool_calls": [
|
|
74
|
+
{
|
|
75
|
+
"call_id": call.call_id,
|
|
76
|
+
"tool_name": call.tool_name,
|
|
77
|
+
"input_args": call.input_args,
|
|
78
|
+
"output_result": call.output_result,
|
|
79
|
+
"timestamp": call.timestamp.isoformat(),
|
|
80
|
+
"duration_ms": call.duration_ms,
|
|
81
|
+
"success": call.success,
|
|
82
|
+
"error_message": call.error_message
|
|
83
|
+
}
|
|
84
|
+
for call in self.tool_calls
|
|
85
|
+
],
|
|
86
|
+
"statistics": {
|
|
87
|
+
"total_model_calls": len(self.model_calls),
|
|
88
|
+
"total_tool_calls": len(self.tool_calls),
|
|
89
|
+
"total_tokens": self.total_tokens,
|
|
90
|
+
"total_input_tokens": self.total_input_tokens,
|
|
91
|
+
"total_output_tokens": self.total_output_tokens
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class ExecutionTraceCollector(TracingProcessor):
|
|
97
|
+
"""
|
|
98
|
+
Collect the execution traces of Agents (MODEL CALL and TOOL CALL).
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
def __init__(self):
|
|
102
|
+
self.traces: Dict[str, ExecutionTrace] = {}
|
|
103
|
+
self.active_spans: Dict[str, Dict[str, Any]] = {} # span_id -> span_info
|
|
104
|
+
|
|
105
|
+
def get_trace(self, trace_id: str) -> Optional[ExecutionTrace]:
|
|
106
|
+
return self.traces.get(trace_id)
|
|
107
|
+
|
|
108
|
+
def get_latest_trace(self) -> Optional[ExecutionTrace]:
|
|
109
|
+
if not self.traces:
|
|
110
|
+
return None
|
|
111
|
+
return max(self.traces.values(), key=lambda t: t.start_time)
|
|
112
|
+
|
|
113
|
+
def clear_traces(self) -> None:
|
|
114
|
+
self.traces.clear()
|
|
115
|
+
self.active_spans.clear()
|
|
116
|
+
|
|
117
|
+
def on_trace_start(self, trace: Trace) -> None:
|
|
118
|
+
execution_trace = ExecutionTrace(
|
|
119
|
+
trace_id=trace.trace_id,
|
|
120
|
+
workflow_name=trace.name or "unknown",
|
|
121
|
+
start_time=datetime.now()
|
|
122
|
+
)
|
|
123
|
+
self.traces[trace.trace_id] = execution_trace
|
|
124
|
+
|
|
125
|
+
def on_trace_end(self, trace: Trace) -> None:
|
|
126
|
+
if trace.trace_id in self.traces:
|
|
127
|
+
self.traces[trace.trace_id].end_time = datetime.now()
|
|
128
|
+
|
|
129
|
+
def on_span_start(self, span: Span) -> None:
|
|
130
|
+
span_info = {
|
|
131
|
+
"span_id": span.span_id,
|
|
132
|
+
"trace_id": span.trace_id,
|
|
133
|
+
"type": span.span_data.type,
|
|
134
|
+
"start_time": datetime.now()
|
|
135
|
+
}
|
|
136
|
+
self.active_spans[span.span_id] = span_info
|
|
137
|
+
|
|
138
|
+
def on_span_end(self, span: Span) -> None:
|
|
139
|
+
span_info = self.active_spans.get(span.span_id)
|
|
140
|
+
if not span_info:
|
|
141
|
+
return
|
|
142
|
+
|
|
143
|
+
trace = self.traces.get(span.trace_id)
|
|
144
|
+
if not trace:
|
|
145
|
+
return
|
|
146
|
+
|
|
147
|
+
duration_ms = None
|
|
148
|
+
if span_info.get("start_time"):
|
|
149
|
+
duration = datetime.now() - span_info["start_time"]
|
|
150
|
+
duration_ms = duration.total_seconds() * 1000
|
|
151
|
+
|
|
152
|
+
span_type = span.span_data.type
|
|
153
|
+
|
|
154
|
+
if span_type == "generation":
|
|
155
|
+
self._handle_model_call(span, trace, duration_ms)
|
|
156
|
+
elif span_type == "function":
|
|
157
|
+
self._handle_tool_call(span, trace, duration_ms)
|
|
158
|
+
|
|
159
|
+
self.active_spans.pop(span.span_id, None)
|
|
160
|
+
|
|
161
|
+
def _handle_model_call(self, span: Span, trace: ExecutionTrace, duration_ms: Optional[float]) -> None:
|
|
162
|
+
data = span.span_data
|
|
163
|
+
|
|
164
|
+
model_call = ModelCall(
|
|
165
|
+
call_id=len(trace.model_calls) + 1,
|
|
166
|
+
model=data.model or "unknown",
|
|
167
|
+
input_messages=data.input or [],
|
|
168
|
+
output_messages=data.output or [],
|
|
169
|
+
usage=data.usage,
|
|
170
|
+
duration_ms=duration_ms
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
trace.model_calls.append(model_call)
|
|
174
|
+
|
|
175
|
+
if data.usage:
|
|
176
|
+
trace.total_input_tokens += data.usage.get('input_tokens', 0)
|
|
177
|
+
trace.total_output_tokens += data.usage.get('output_tokens', 0)
|
|
178
|
+
trace.total_tokens += data.usage.get('total_tokens', 0)
|
|
179
|
+
|
|
180
|
+
def _handle_tool_call(self, span: Span, trace: ExecutionTrace, duration_ms: Optional[float]) -> None:
|
|
181
|
+
data = span.span_data
|
|
182
|
+
|
|
183
|
+
success = True
|
|
184
|
+
error_message = None
|
|
185
|
+
|
|
186
|
+
if data.output and isinstance(data.output, str):
|
|
187
|
+
if "error" in data.output.lower() or "exception" in data.output.lower():
|
|
188
|
+
success = False
|
|
189
|
+
error_message = data.output
|
|
190
|
+
|
|
191
|
+
tool_call = ToolCall(
|
|
192
|
+
call_id=len(trace.tool_calls) + 1,
|
|
193
|
+
tool_name=data.name or "unknown",
|
|
194
|
+
input_args=data.input,
|
|
195
|
+
output_result=data.output,
|
|
196
|
+
duration_ms=duration_ms,
|
|
197
|
+
success=success,
|
|
198
|
+
error_message=error_message
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
trace.tool_calls.append(tool_call)
|
|
202
|
+
|
|
203
|
+
def shutdown(self) -> None:
|
|
204
|
+
pass
|
|
205
|
+
|
|
206
|
+
def force_flush(self) -> None:
|
|
207
|
+
pass
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"""
|
|
2
|
+
File Recommendation Service - @ 文件推荐功能
|
|
3
|
+
|
|
4
|
+
This package provides intelligent file path auto-completion for @ commands.
|
|
5
|
+
When users type @ followed by text, the system provides real-time file and directory suggestions.
|
|
6
|
+
|
|
7
|
+
Main Components:
|
|
8
|
+
- FileRecommendationEngine: Main engine that coordinates all components
|
|
9
|
+
- CompletionEngine: Core completion logic
|
|
10
|
+
- FileDiscoveryService: File discovery and filtering
|
|
11
|
+
- Suggestion data structures and utilities
|
|
12
|
+
|
|
13
|
+
Usage:
|
|
14
|
+
from siada.services.file_recommendation import FileRecommendationEngine
|
|
15
|
+
|
|
16
|
+
engine = FileRecommendationEngine(
|
|
17
|
+
current_directory=os.getcwd(),
|
|
18
|
+
config=CompletionConfig()
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
if engine.should_show_suggestions("@src/main"):
|
|
22
|
+
suggestions = engine.get_suggestions("@src/main")
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from .core.completion_engine import CompletionEngine
|
|
26
|
+
from .core.file_discovery import FileDiscoveryService
|
|
27
|
+
from .core.suggestion import Suggestion
|
|
28
|
+
from .core.config import CompletionConfig, FilterOptions, DEFAULT_COMPLETION_CONFIG
|
|
29
|
+
from .utils.path_utils import escape_path, unescape_path
|
|
30
|
+
from .utils.text_utils import (
|
|
31
|
+
is_completion_active,
|
|
32
|
+
parse_at_command_path,
|
|
33
|
+
to_code_points,
|
|
34
|
+
cp_len,
|
|
35
|
+
cp_slice
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
__all__ = [
|
|
39
|
+
# Main classes
|
|
40
|
+
'CompletionEngine',
|
|
41
|
+
'FileDiscoveryService',
|
|
42
|
+
'FileRecommendationEngine',
|
|
43
|
+
|
|
44
|
+
# Data structures
|
|
45
|
+
'Suggestion',
|
|
46
|
+
'CompletionConfig',
|
|
47
|
+
'FilterOptions',
|
|
48
|
+
'DEFAULT_COMPLETION_CONFIG',
|
|
49
|
+
|
|
50
|
+
# Utilities
|
|
51
|
+
'escape_path',
|
|
52
|
+
'unescape_path',
|
|
53
|
+
'is_completion_active',
|
|
54
|
+
'parse_at_command_path',
|
|
55
|
+
'to_code_points',
|
|
56
|
+
'cp_len',
|
|
57
|
+
'cp_slice'
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
# Version information
|
|
61
|
+
__version__ = '1.0.0'
|
|
62
|
+
__author__ = 'Siada Team'
|
|
63
|
+
__description__ = 'Intelligent file path auto-completion for @ commands'
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class FileRecommendationEngine:
|
|
67
|
+
"""
|
|
68
|
+
Main file recommendation engine
|
|
69
|
+
|
|
70
|
+
This is the primary interface for the file recommendation functionality.
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
def __init__(self, current_directory: str = None, config: CompletionConfig = None):
|
|
74
|
+
"""
|
|
75
|
+
Initialize the file recommendation engine
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
current_directory: Current working directory (default: current working directory)
|
|
79
|
+
config: Completion configuration (default: DEFAULT_COMPLETION_CONFIG)
|
|
80
|
+
"""
|
|
81
|
+
import os
|
|
82
|
+
|
|
83
|
+
self.current_directory = current_directory or os.getcwd()
|
|
84
|
+
self.config = config or DEFAULT_COMPLETION_CONFIG
|
|
85
|
+
|
|
86
|
+
# Initialize components
|
|
87
|
+
self.file_discovery = FileDiscoveryService(self.current_directory)
|
|
88
|
+
self.completion_engine = CompletionEngine(
|
|
89
|
+
search_directories=[self.current_directory],
|
|
90
|
+
config=self.config
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
def should_show_suggestions(self, text: str, cursor_row: int = 0, cursor_col: int = None) -> bool:
|
|
94
|
+
"""
|
|
95
|
+
Check if file suggestions should be shown
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
text: Input text
|
|
99
|
+
cursor_row: Cursor row position (default: 0)
|
|
100
|
+
cursor_col: Cursor column position (default: end of text)
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
bool: True if suggestions should be shown
|
|
104
|
+
"""
|
|
105
|
+
# Use the completion engine's logic for determining when to show suggestions
|
|
106
|
+
return self.completion_engine.should_show_suggestions(text)
|
|
107
|
+
|
|
108
|
+
async def get_suggestions(self, text: str) -> list[Suggestion]:
|
|
109
|
+
"""
|
|
110
|
+
Get file suggestions for the given text
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
text: Input text containing @ command
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
List of file suggestions
|
|
117
|
+
"""
|
|
118
|
+
return await self.completion_engine.get_suggestions(text)
|
|
119
|
+
|
|
120
|
+
def get_suggestions_sync(self, text: str) -> list[Suggestion]:
|
|
121
|
+
"""
|
|
122
|
+
Synchronous version of get_suggestions
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
text: Input text containing @ command
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
List of file suggestions
|
|
129
|
+
"""
|
|
130
|
+
import asyncio
|
|
131
|
+
try:
|
|
132
|
+
loop = asyncio.get_event_loop()
|
|
133
|
+
return loop.run_until_complete(self.get_suggestions(text))
|
|
134
|
+
except RuntimeError:
|
|
135
|
+
# No event loop running, create a new one
|
|
136
|
+
return asyncio.run(self.get_suggestions(text))
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Core components for file recommendation functionality.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from .completion_engine import CompletionEngine
|
|
6
|
+
from .file_discovery import FileDiscoveryService
|
|
7
|
+
from .suggestion import Suggestion
|
|
8
|
+
from .config import CompletionConfig, FilterOptions, DEFAULT_COMPLETION_CONFIG
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
'CompletionEngine',
|
|
12
|
+
'FileDiscoveryService',
|
|
13
|
+
'Suggestion',
|
|
14
|
+
'CompletionConfig',
|
|
15
|
+
'FilterOptions',
|
|
16
|
+
'DEFAULT_COMPLETION_CONFIG'
|
|
17
|
+
]
|