toolplane-python-client 0.1.0__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.
- toolplane/__init__.py +106 -0
- toolplane/common/__init__.py +93 -0
- toolplane/common/base_config.py +129 -0
- toolplane/common/base_connection_manager.py +171 -0
- toolplane/common/base_session_manager.py +321 -0
- toolplane/common/base_tool_manager.py +347 -0
- toolplane/common/constants.py +47 -0
- toolplane/common/utils.py +310 -0
- toolplane/core/__init__.py +67 -0
- toolplane/core/config.py +107 -0
- toolplane/core/connection.py +285 -0
- toolplane/core/errors.py +298 -0
- toolplane/core/machine.py +480 -0
- toolplane/core/request.py +775 -0
- toolplane/core/session.py +332 -0
- toolplane/core/session_context.py +514 -0
- toolplane/core/task.py +130 -0
- toolplane/core/tool.py +329 -0
- toolplane/http_core/__init__.py +37 -0
- toolplane/http_core/http_config.py +97 -0
- toolplane/http_core/http_connection.py +409 -0
- toolplane/http_core/http_machine.py +298 -0
- toolplane/http_core/http_request.py +748 -0
- toolplane/http_core/http_session.py +348 -0
- toolplane/http_core/http_session_context.py +491 -0
- toolplane/http_core/http_task.py +101 -0
- toolplane/http_core/http_tool.py +400 -0
- toolplane/interfaces/__init__.py +27 -0
- toolplane/interfaces/client_interface.py +122 -0
- toolplane/interfaces/connection_interface.py +193 -0
- toolplane/interfaces/event_interface.py +290 -0
- toolplane/interfaces/request_interface.py +439 -0
- toolplane/interfaces/session_interface.py +288 -0
- toolplane/interfaces/tool_interface.py +441 -0
- toolplane/proto/__init__.py +0 -0
- toolplane/proto/service_pb2.py +315 -0
- toolplane/proto/service_pb2_grpc.py +2240 -0
- toolplane/provider_cli.py +268 -0
- toolplane/provider_registry.py +77 -0
- toolplane/provider_runtime.py +302 -0
- toolplane/toolkits/__init__.py +0 -0
- toolplane/toolkits/standalone_tools/__init__.py +0 -0
- toolplane/toolkits/standalone_tools/create_directory.py +94 -0
- toolplane/toolkits/standalone_tools/create_file.py +124 -0
- toolplane/toolkits/standalone_tools/file_search.py +229 -0
- toolplane/toolkits/standalone_tools/grep_search.py +372 -0
- toolplane/toolkits/standalone_tools/launcher.py +146 -0
- toolplane/toolkits/standalone_tools/list_dir.py +395 -0
- toolplane/toolkits/standalone_tools/read_file.py +346 -0
- toolplane/toolkits/standalone_tools/replace_string_in_file.py +407 -0
- toolplane/toolkits/standalone_tools/run_tests.py +66 -0
- toolplane/toolkits/standalone_tools/semantic_search.py +485 -0
- toolplane/toolkits/standalone_tools/standalone_toolkit.py +979 -0
- toolplane/toolkits/standalone_tools/test_failure_analysis.py +618 -0
- toolplane/toolkits/standalone_tools/test_standalone_toolkit.py +517 -0
- toolplane/toolkits/swe/__init__.py +35 -0
- toolplane/toolkits/swe/create_directory.py +15 -0
- toolplane/toolkits/swe/create_file.py +15 -0
- toolplane/toolkits/swe/descriptions.py +273 -0
- toolplane/toolkits/swe/execute_bash.py +93 -0
- toolplane/toolkits/swe/file_editor.py +775 -0
- toolplane/toolkits/swe/file_search.py +16 -0
- toolplane/toolkits/swe/finish.py +50 -0
- toolplane/toolkits/swe/grep_search.py +19 -0
- toolplane/toolkits/swe/list_dir.py +407 -0
- toolplane/toolkits/swe/read_file.py +18 -0
- toolplane/toolkits/swe/replace_string_in_file.py +17 -0
- toolplane/toolkits/swe/search.py +260 -0
- toolplane/toolkits/swe/semantic_search.py +20 -0
- toolplane/toolkits/swe/str_replace_editor.py +647 -0
- toolplane/toolkits/swe/submit.py +29 -0
- toolplane/toolkits/swe/swe_toolkit.py +1296 -0
- toolplane/toolplane_client.py +686 -0
- toolplane/toolplane_http_client.py +681 -0
- toolplane/utils/__init__.py +3 -0
- toolplane/utils/schema.py +146 -0
- toolplane_python_client-0.1.0.dist-info/METADATA +543 -0
- toolplane_python_client-0.1.0.dist-info/RECORD +81 -0
- toolplane_python_client-0.1.0.dist-info/WHEEL +5 -0
- toolplane_python_client-0.1.0.dist-info/entry_points.txt +2 -0
- toolplane_python_client-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,485 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Description: Semantic search for relevant code or documentation using text similarity.
|
|
4
|
+
|
|
5
|
+
This tool performs semantic search across code and documentation files using
|
|
6
|
+
text similarity algorithms to find relevant content based on natural language queries.
|
|
7
|
+
|
|
8
|
+
Parameters:
|
|
9
|
+
query (string, required): The search query in natural language.
|
|
10
|
+
max_results (integer, optional): Maximum number of results to return (default: 10).
|
|
11
|
+
file_types (array, optional): File types to search in (default: common code files).
|
|
12
|
+
similarity_threshold (float, optional): Minimum similarity score to include (default: 0.1).
|
|
13
|
+
context_size (integer, optional): Number of lines of context around matches (default: 3).
|
|
14
|
+
search_path (string, optional): Directory to search in (default: current directory).
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import argparse
|
|
18
|
+
import math
|
|
19
|
+
import os
|
|
20
|
+
import re
|
|
21
|
+
import sys
|
|
22
|
+
from collections import Counter, defaultdict
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
from typing import Any, Dict, List, Set
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def semantic_search(
|
|
28
|
+
query: str,
|
|
29
|
+
max_results: int = 10,
|
|
30
|
+
file_types: List[str] = None,
|
|
31
|
+
similarity_threshold: float = 0.1,
|
|
32
|
+
context_size: int = 3,
|
|
33
|
+
search_path: str = None,
|
|
34
|
+
) -> List[Dict[str, Any]]:
|
|
35
|
+
"""
|
|
36
|
+
Perform semantic search for relevant code or documentation.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
query: The search query in natural language
|
|
40
|
+
max_results: Maximum number of results to return
|
|
41
|
+
file_types: File types to search in
|
|
42
|
+
similarity_threshold: Minimum similarity score to include
|
|
43
|
+
context_size: Number of lines of context around matches
|
|
44
|
+
search_path: Directory to search in
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
List of search results with similarity scores
|
|
48
|
+
"""
|
|
49
|
+
if search_path is None:
|
|
50
|
+
search_path = os.getcwd()
|
|
51
|
+
|
|
52
|
+
if file_types is None:
|
|
53
|
+
file_types = [
|
|
54
|
+
".py",
|
|
55
|
+
".js",
|
|
56
|
+
".ts",
|
|
57
|
+
".jsx",
|
|
58
|
+
".tsx",
|
|
59
|
+
".java",
|
|
60
|
+
".cpp",
|
|
61
|
+
".c",
|
|
62
|
+
".h",
|
|
63
|
+
".cs",
|
|
64
|
+
".php",
|
|
65
|
+
".rb",
|
|
66
|
+
".go",
|
|
67
|
+
".rs",
|
|
68
|
+
".swift",
|
|
69
|
+
".kt",
|
|
70
|
+
".scala",
|
|
71
|
+
".html",
|
|
72
|
+
".css",
|
|
73
|
+
".scss",
|
|
74
|
+
".md",
|
|
75
|
+
".rst",
|
|
76
|
+
".txt",
|
|
77
|
+
".json",
|
|
78
|
+
".yaml",
|
|
79
|
+
".yml",
|
|
80
|
+
".xml",
|
|
81
|
+
".sql",
|
|
82
|
+
".sh",
|
|
83
|
+
".bash",
|
|
84
|
+
".ps1",
|
|
85
|
+
".bat",
|
|
86
|
+
]
|
|
87
|
+
|
|
88
|
+
# Get all files to search
|
|
89
|
+
files_to_search = get_searchable_files(search_path, file_types)
|
|
90
|
+
|
|
91
|
+
# Process query
|
|
92
|
+
query_terms = preprocess_text(query)
|
|
93
|
+
|
|
94
|
+
# Search each file
|
|
95
|
+
results = []
|
|
96
|
+
|
|
97
|
+
for file_path in files_to_search:
|
|
98
|
+
try:
|
|
99
|
+
file_results = search_file(file_path, query_terms, context_size)
|
|
100
|
+
|
|
101
|
+
# Calculate similarity scores
|
|
102
|
+
for result in file_results:
|
|
103
|
+
score = calculate_similarity(query_terms, result["content_tokens"])
|
|
104
|
+
|
|
105
|
+
if score >= similarity_threshold:
|
|
106
|
+
result["similarity_score"] = score
|
|
107
|
+
result["query"] = query
|
|
108
|
+
results.append(result)
|
|
109
|
+
|
|
110
|
+
except Exception as e:
|
|
111
|
+
# Skip files that can't be processed
|
|
112
|
+
continue
|
|
113
|
+
|
|
114
|
+
# Sort by similarity score
|
|
115
|
+
results.sort(key=lambda x: x["similarity_score"], reverse=True)
|
|
116
|
+
|
|
117
|
+
# Return top results
|
|
118
|
+
return results[:max_results]
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def get_searchable_files(search_path: str, file_types: List[str]) -> List[str]:
|
|
122
|
+
"""Get all files that match the specified file types."""
|
|
123
|
+
files = []
|
|
124
|
+
|
|
125
|
+
for root, dirs, filenames in os.walk(search_path):
|
|
126
|
+
# Skip hidden directories
|
|
127
|
+
dirs[:] = [d for d in dirs if not d.startswith(".")]
|
|
128
|
+
|
|
129
|
+
for filename in filenames:
|
|
130
|
+
if filename.startswith("."):
|
|
131
|
+
continue
|
|
132
|
+
|
|
133
|
+
file_path = Path(root) / filename
|
|
134
|
+
|
|
135
|
+
# Check if file type is in our list
|
|
136
|
+
if any(filename.lower().endswith(ext) for ext in file_types):
|
|
137
|
+
files.append(str(file_path.resolve()))
|
|
138
|
+
|
|
139
|
+
return files
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def search_file(
|
|
143
|
+
file_path: str, query_terms: Set[str], context_size: int
|
|
144
|
+
) -> List[Dict[str, Any]]:
|
|
145
|
+
"""Search for relevant content in a single file."""
|
|
146
|
+
try:
|
|
147
|
+
with open(file_path, "r", encoding="utf-8", errors="ignore") as f:
|
|
148
|
+
lines = f.readlines()
|
|
149
|
+
except Exception:
|
|
150
|
+
return []
|
|
151
|
+
|
|
152
|
+
results = []
|
|
153
|
+
|
|
154
|
+
# Search for matches in each line
|
|
155
|
+
for line_num, line in enumerate(lines):
|
|
156
|
+
line_tokens = preprocess_text(line.strip())
|
|
157
|
+
|
|
158
|
+
# Check if line contains any query terms
|
|
159
|
+
if query_terms.intersection(line_tokens):
|
|
160
|
+
# Get context around the match
|
|
161
|
+
start_line = max(0, line_num - context_size)
|
|
162
|
+
end_line = min(len(lines), line_num + context_size + 1)
|
|
163
|
+
|
|
164
|
+
context_lines = []
|
|
165
|
+
for i in range(start_line, end_line):
|
|
166
|
+
context_lines.append(
|
|
167
|
+
{
|
|
168
|
+
"line_number": i + 1,
|
|
169
|
+
"content": lines[i].rstrip("\n\r"),
|
|
170
|
+
"is_match": i == line_num,
|
|
171
|
+
}
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
# Get all tokens from the context
|
|
175
|
+
context_text = " ".join(cl["content"] for cl in context_lines)
|
|
176
|
+
content_tokens = preprocess_text(context_text)
|
|
177
|
+
|
|
178
|
+
result = {
|
|
179
|
+
"file_path": file_path,
|
|
180
|
+
"line_number": line_num + 1,
|
|
181
|
+
"matched_line": line.strip(),
|
|
182
|
+
"context": context_lines,
|
|
183
|
+
"content_tokens": content_tokens,
|
|
184
|
+
"file_type": Path(file_path).suffix.lower(),
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
results.append(result)
|
|
188
|
+
|
|
189
|
+
# Also search in function/class definitions and comments
|
|
190
|
+
function_results = extract_functions_and_classes(
|
|
191
|
+
file_path, lines, query_terms, context_size
|
|
192
|
+
)
|
|
193
|
+
results.extend(function_results)
|
|
194
|
+
|
|
195
|
+
# Remove duplicates based on line number
|
|
196
|
+
seen_lines = set()
|
|
197
|
+
unique_results = []
|
|
198
|
+
for result in results:
|
|
199
|
+
if result["line_number"] not in seen_lines:
|
|
200
|
+
seen_lines.add(result["line_number"])
|
|
201
|
+
unique_results.append(result)
|
|
202
|
+
|
|
203
|
+
return unique_results
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def extract_functions_and_classes(
|
|
207
|
+
file_path: str, lines: List[str], query_terms: Set[str], context_size: int
|
|
208
|
+
) -> List[Dict[str, Any]]:
|
|
209
|
+
"""Extract functions and classes that might be relevant."""
|
|
210
|
+
results = []
|
|
211
|
+
file_ext = Path(file_path).suffix.lower()
|
|
212
|
+
|
|
213
|
+
# Define patterns for different file types
|
|
214
|
+
patterns = {
|
|
215
|
+
".py": [r"^\s*def\s+(\w+)", r"^\s*class\s+(\w+)", r"^\s*async\s+def\s+(\w+)"],
|
|
216
|
+
".js": [
|
|
217
|
+
r"^\s*function\s+(\w+)",
|
|
218
|
+
r"^\s*const\s+(\w+)\s*=\s*\(",
|
|
219
|
+
r"^\s*let\s+(\w+)\s*=\s*\(",
|
|
220
|
+
r"^\s*var\s+(\w+)\s*=\s*\(",
|
|
221
|
+
r"^\s*(\w+)\s*:\s*function",
|
|
222
|
+
r"^\s*class\s+(\w+)",
|
|
223
|
+
],
|
|
224
|
+
".ts": [
|
|
225
|
+
r"^\s*function\s+(\w+)",
|
|
226
|
+
r"^\s*const\s+(\w+)\s*=\s*\(",
|
|
227
|
+
r"^\s*let\s+(\w+)\s*=\s*\(",
|
|
228
|
+
r"^\s*class\s+(\w+)",
|
|
229
|
+
r"^\s*interface\s+(\w+)",
|
|
230
|
+
r"^\s*type\s+(\w+)",
|
|
231
|
+
],
|
|
232
|
+
".java": [
|
|
233
|
+
r"^\s*public\s+.*\s+(\w+)\s*\(",
|
|
234
|
+
r"^\s*private\s+.*\s+(\w+)\s*\(",
|
|
235
|
+
r"^\s*protected\s+.*\s+(\w+)\s*\(",
|
|
236
|
+
r"^\s*class\s+(\w+)",
|
|
237
|
+
r"^\s*interface\s+(\w+)",
|
|
238
|
+
],
|
|
239
|
+
".cpp": [r"^\s*.*\s+(\w+)\s*\(", r"^\s*class\s+(\w+)", r"^\s*struct\s+(\w+)"],
|
|
240
|
+
".c": [r"^\s*.*\s+(\w+)\s*\(", r"^\s*struct\s+(\w+)"],
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if file_ext not in patterns:
|
|
244
|
+
return results
|
|
245
|
+
|
|
246
|
+
for line_num, line in enumerate(lines):
|
|
247
|
+
for pattern in patterns[file_ext]:
|
|
248
|
+
match = re.search(pattern, line)
|
|
249
|
+
if match:
|
|
250
|
+
function_name = match.group(1)
|
|
251
|
+
|
|
252
|
+
# Check if function name or line content matches query
|
|
253
|
+
name_tokens = preprocess_text(function_name)
|
|
254
|
+
line_tokens = preprocess_text(line.strip())
|
|
255
|
+
|
|
256
|
+
if query_terms.intersection(name_tokens) or query_terms.intersection(
|
|
257
|
+
line_tokens
|
|
258
|
+
):
|
|
259
|
+
# Get context around the function
|
|
260
|
+
start_line = max(0, line_num - context_size)
|
|
261
|
+
end_line = min(len(lines), line_num + context_size + 1)
|
|
262
|
+
|
|
263
|
+
context_lines = []
|
|
264
|
+
for i in range(start_line, end_line):
|
|
265
|
+
context_lines.append(
|
|
266
|
+
{
|
|
267
|
+
"line_number": i + 1,
|
|
268
|
+
"content": lines[i].rstrip("\n\r"),
|
|
269
|
+
"is_match": i == line_num,
|
|
270
|
+
}
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
context_text = " ".join(cl["content"] for cl in context_lines)
|
|
274
|
+
content_tokens = preprocess_text(context_text)
|
|
275
|
+
|
|
276
|
+
result = {
|
|
277
|
+
"file_path": file_path,
|
|
278
|
+
"line_number": line_num + 1,
|
|
279
|
+
"matched_line": line.strip(),
|
|
280
|
+
"context": context_lines,
|
|
281
|
+
"content_tokens": content_tokens,
|
|
282
|
+
"file_type": file_ext,
|
|
283
|
+
"match_type": "function_definition",
|
|
284
|
+
"function_name": function_name,
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
results.append(result)
|
|
288
|
+
|
|
289
|
+
return results
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def preprocess_text(text: str) -> Set[str]:
|
|
293
|
+
"""Preprocess text for similarity comparison."""
|
|
294
|
+
# Convert to lowercase
|
|
295
|
+
text = text.lower()
|
|
296
|
+
|
|
297
|
+
# Remove special characters and split into words
|
|
298
|
+
words = re.findall(r"\b\w+\b", text)
|
|
299
|
+
|
|
300
|
+
# Remove common stop words
|
|
301
|
+
stop_words = {
|
|
302
|
+
"the",
|
|
303
|
+
"a",
|
|
304
|
+
"an",
|
|
305
|
+
"and",
|
|
306
|
+
"or",
|
|
307
|
+
"but",
|
|
308
|
+
"in",
|
|
309
|
+
"on",
|
|
310
|
+
"at",
|
|
311
|
+
"to",
|
|
312
|
+
"for",
|
|
313
|
+
"of",
|
|
314
|
+
"with",
|
|
315
|
+
"by",
|
|
316
|
+
"from",
|
|
317
|
+
"is",
|
|
318
|
+
"are",
|
|
319
|
+
"was",
|
|
320
|
+
"were",
|
|
321
|
+
"be",
|
|
322
|
+
"been",
|
|
323
|
+
"have",
|
|
324
|
+
"has",
|
|
325
|
+
"had",
|
|
326
|
+
"do",
|
|
327
|
+
"does",
|
|
328
|
+
"did",
|
|
329
|
+
"will",
|
|
330
|
+
"would",
|
|
331
|
+
"could",
|
|
332
|
+
"should",
|
|
333
|
+
"may",
|
|
334
|
+
"might",
|
|
335
|
+
"can",
|
|
336
|
+
"this",
|
|
337
|
+
"that",
|
|
338
|
+
"these",
|
|
339
|
+
"those",
|
|
340
|
+
"i",
|
|
341
|
+
"you",
|
|
342
|
+
"he",
|
|
343
|
+
"she",
|
|
344
|
+
"it",
|
|
345
|
+
"we",
|
|
346
|
+
"they",
|
|
347
|
+
"me",
|
|
348
|
+
"him",
|
|
349
|
+
"her",
|
|
350
|
+
"us",
|
|
351
|
+
"them",
|
|
352
|
+
"my",
|
|
353
|
+
"your",
|
|
354
|
+
"his",
|
|
355
|
+
"her",
|
|
356
|
+
"its",
|
|
357
|
+
"our",
|
|
358
|
+
"their",
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
# Filter out stop words and short words
|
|
362
|
+
filtered_words = [
|
|
363
|
+
word for word in words if word not in stop_words and len(word) > 2
|
|
364
|
+
]
|
|
365
|
+
|
|
366
|
+
return set(filtered_words)
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
def calculate_similarity(query_terms: Set[str], content_tokens: Set[str]) -> float:
|
|
370
|
+
"""Calculate similarity between query terms and content tokens."""
|
|
371
|
+
if not query_terms or not content_tokens:
|
|
372
|
+
return 0.0
|
|
373
|
+
|
|
374
|
+
# Jaccard similarity: intersection / union
|
|
375
|
+
intersection = len(query_terms.intersection(content_tokens))
|
|
376
|
+
union = len(query_terms.union(content_tokens))
|
|
377
|
+
|
|
378
|
+
if union == 0:
|
|
379
|
+
return 0.0
|
|
380
|
+
|
|
381
|
+
jaccard_score = intersection / union
|
|
382
|
+
|
|
383
|
+
# Boost score if many query terms are present
|
|
384
|
+
query_coverage = intersection / len(query_terms)
|
|
385
|
+
|
|
386
|
+
# Combined score
|
|
387
|
+
similarity_score = (jaccard_score * 0.6) + (query_coverage * 0.4)
|
|
388
|
+
|
|
389
|
+
return similarity_score
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
def main():
|
|
393
|
+
parser = argparse.ArgumentParser(
|
|
394
|
+
description="Semantic search for relevant code or documentation using text similarity."
|
|
395
|
+
)
|
|
396
|
+
parser.add_argument("query", type=str, help="The search query in natural language")
|
|
397
|
+
parser.add_argument(
|
|
398
|
+
"--max_results",
|
|
399
|
+
type=int,
|
|
400
|
+
default=10,
|
|
401
|
+
help="Maximum number of results to return (default: 10)",
|
|
402
|
+
)
|
|
403
|
+
parser.add_argument(
|
|
404
|
+
"--file_types", nargs="+", help="File types to search in (e.g., .py .js .md)"
|
|
405
|
+
)
|
|
406
|
+
parser.add_argument(
|
|
407
|
+
"--similarity_threshold",
|
|
408
|
+
type=float,
|
|
409
|
+
default=0.1,
|
|
410
|
+
help="Minimum similarity score to include (default: 0.1)",
|
|
411
|
+
)
|
|
412
|
+
parser.add_argument(
|
|
413
|
+
"--context_size",
|
|
414
|
+
type=int,
|
|
415
|
+
default=3,
|
|
416
|
+
help="Number of lines of context around matches (default: 3)",
|
|
417
|
+
)
|
|
418
|
+
parser.add_argument(
|
|
419
|
+
"--search_path",
|
|
420
|
+
type=str,
|
|
421
|
+
help="Directory to search in (default: current directory)",
|
|
422
|
+
)
|
|
423
|
+
parser.add_argument(
|
|
424
|
+
"--output_format",
|
|
425
|
+
choices=["default", "json", "compact"],
|
|
426
|
+
default="default",
|
|
427
|
+
help="Output format (default: default)",
|
|
428
|
+
)
|
|
429
|
+
|
|
430
|
+
args = parser.parse_args()
|
|
431
|
+
|
|
432
|
+
results = semantic_search(
|
|
433
|
+
args.query,
|
|
434
|
+
max_results=args.max_results,
|
|
435
|
+
file_types=args.file_types,
|
|
436
|
+
similarity_threshold=args.similarity_threshold,
|
|
437
|
+
context_size=args.context_size,
|
|
438
|
+
search_path=args.search_path,
|
|
439
|
+
)
|
|
440
|
+
|
|
441
|
+
if not results:
|
|
442
|
+
print(f"No results found for query: {args.query}")
|
|
443
|
+
sys.exit(0)
|
|
444
|
+
|
|
445
|
+
if args.output_format == "json":
|
|
446
|
+
import json
|
|
447
|
+
|
|
448
|
+
print(json.dumps(results, indent=2))
|
|
449
|
+
|
|
450
|
+
elif args.output_format == "compact":
|
|
451
|
+
print(f"Found {len(results)} results for: {args.query}")
|
|
452
|
+
print("-" * 60)
|
|
453
|
+
|
|
454
|
+
for i, result in enumerate(results, 1):
|
|
455
|
+
print(
|
|
456
|
+
f"{i}. {result['file_path']}:{result['line_number']} (score: {result['similarity_score']:.3f})"
|
|
457
|
+
)
|
|
458
|
+
print(f" {result['matched_line'][:100]}...")
|
|
459
|
+
print()
|
|
460
|
+
|
|
461
|
+
else: # default format
|
|
462
|
+
print(f"Semantic search results for: {args.query}")
|
|
463
|
+
print(f"Found {len(results)} results")
|
|
464
|
+
print("=" * 80)
|
|
465
|
+
|
|
466
|
+
for i, result in enumerate(results, 1):
|
|
467
|
+
print(f"\nResult {i}: {result['file_path']}:{result['line_number']}")
|
|
468
|
+
print(f"Similarity Score: {result['similarity_score']:.3f}")
|
|
469
|
+
print(f"File Type: {result['file_type']}")
|
|
470
|
+
|
|
471
|
+
if result.get("match_type") == "function_definition":
|
|
472
|
+
print(f"Function: {result.get('function_name', 'unknown')}")
|
|
473
|
+
|
|
474
|
+
print("Context:")
|
|
475
|
+
for context_line in result["context"]:
|
|
476
|
+
marker = ">>>" if context_line["is_match"] else " "
|
|
477
|
+
print(
|
|
478
|
+
f"{marker} {context_line['line_number']:4d}: {context_line['content']}"
|
|
479
|
+
)
|
|
480
|
+
|
|
481
|
+
print("-" * 80)
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
if __name__ == "__main__":
|
|
485
|
+
main()
|