nc1709 1.15.4__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.
- nc1709/__init__.py +13 -0
- nc1709/agent/__init__.py +36 -0
- nc1709/agent/core.py +505 -0
- nc1709/agent/mcp_bridge.py +245 -0
- nc1709/agent/permissions.py +298 -0
- nc1709/agent/tools/__init__.py +21 -0
- nc1709/agent/tools/base.py +440 -0
- nc1709/agent/tools/bash_tool.py +367 -0
- nc1709/agent/tools/file_tools.py +454 -0
- nc1709/agent/tools/notebook_tools.py +516 -0
- nc1709/agent/tools/search_tools.py +322 -0
- nc1709/agent/tools/task_tool.py +284 -0
- nc1709/agent/tools/web_tools.py +555 -0
- nc1709/agents/__init__.py +17 -0
- nc1709/agents/auto_fix.py +506 -0
- nc1709/agents/test_generator.py +507 -0
- nc1709/checkpoints.py +372 -0
- nc1709/cli.py +3380 -0
- nc1709/cli_ui.py +1080 -0
- nc1709/cognitive/__init__.py +149 -0
- nc1709/cognitive/anticipation.py +594 -0
- nc1709/cognitive/context_engine.py +1046 -0
- nc1709/cognitive/council.py +824 -0
- nc1709/cognitive/learning.py +761 -0
- nc1709/cognitive/router.py +583 -0
- nc1709/cognitive/system.py +519 -0
- nc1709/config.py +155 -0
- nc1709/custom_commands.py +300 -0
- nc1709/executor.py +333 -0
- nc1709/file_controller.py +354 -0
- nc1709/git_integration.py +308 -0
- nc1709/github_integration.py +477 -0
- nc1709/image_input.py +446 -0
- nc1709/linting.py +519 -0
- nc1709/llm_adapter.py +667 -0
- nc1709/logger.py +192 -0
- nc1709/mcp/__init__.py +18 -0
- nc1709/mcp/client.py +370 -0
- nc1709/mcp/manager.py +407 -0
- nc1709/mcp/protocol.py +210 -0
- nc1709/mcp/server.py +473 -0
- nc1709/memory/__init__.py +20 -0
- nc1709/memory/embeddings.py +325 -0
- nc1709/memory/indexer.py +474 -0
- nc1709/memory/sessions.py +432 -0
- nc1709/memory/vector_store.py +451 -0
- nc1709/models/__init__.py +86 -0
- nc1709/models/detector.py +377 -0
- nc1709/models/formats.py +315 -0
- nc1709/models/manager.py +438 -0
- nc1709/models/registry.py +497 -0
- nc1709/performance/__init__.py +343 -0
- nc1709/performance/cache.py +705 -0
- nc1709/performance/pipeline.py +611 -0
- nc1709/performance/tiering.py +543 -0
- nc1709/plan_mode.py +362 -0
- nc1709/plugins/__init__.py +17 -0
- nc1709/plugins/agents/__init__.py +18 -0
- nc1709/plugins/agents/django_agent.py +912 -0
- nc1709/plugins/agents/docker_agent.py +623 -0
- nc1709/plugins/agents/fastapi_agent.py +887 -0
- nc1709/plugins/agents/git_agent.py +731 -0
- nc1709/plugins/agents/nextjs_agent.py +867 -0
- nc1709/plugins/base.py +359 -0
- nc1709/plugins/manager.py +411 -0
- nc1709/plugins/registry.py +337 -0
- nc1709/progress.py +443 -0
- nc1709/prompts/__init__.py +22 -0
- nc1709/prompts/agent_system.py +180 -0
- nc1709/prompts/task_prompts.py +340 -0
- nc1709/prompts/unified_prompt.py +133 -0
- nc1709/reasoning_engine.py +541 -0
- nc1709/remote_client.py +266 -0
- nc1709/shell_completions.py +349 -0
- nc1709/slash_commands.py +649 -0
- nc1709/task_classifier.py +408 -0
- nc1709/version_check.py +177 -0
- nc1709/web/__init__.py +8 -0
- nc1709/web/server.py +950 -0
- nc1709/web/templates/index.html +1127 -0
- nc1709-1.15.4.dist-info/METADATA +858 -0
- nc1709-1.15.4.dist-info/RECORD +86 -0
- nc1709-1.15.4.dist-info/WHEEL +5 -0
- nc1709-1.15.4.dist-info/entry_points.txt +2 -0
- nc1709-1.15.4.dist-info/licenses/LICENSE +9 -0
- nc1709-1.15.4.dist-info/top_level.txt +1 -0
nc1709/mcp/server.py
ADDED
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MCP Server Implementation
|
|
3
|
+
Exposes NC1709 capabilities as an MCP server
|
|
4
|
+
"""
|
|
5
|
+
import asyncio
|
|
6
|
+
import json
|
|
7
|
+
import sys
|
|
8
|
+
from typing import Dict, Any, Optional, List, Callable
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
|
|
11
|
+
from .protocol import (
|
|
12
|
+
MCPMessage, MCPTool, MCPResource, MCPPrompt,
|
|
13
|
+
MCPServerInfo, MCPErrorCode, MCPToolParameter
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class ToolResult:
|
|
19
|
+
"""Result from tool execution"""
|
|
20
|
+
content: List[Dict[str, Any]]
|
|
21
|
+
is_error: bool = False
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class MCPServer:
|
|
25
|
+
"""
|
|
26
|
+
MCP Server for NC1709.
|
|
27
|
+
|
|
28
|
+
Exposes NC1709's capabilities through the Model Context Protocol,
|
|
29
|
+
allowing external AI applications to use NC1709 as a tool provider.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
def __init__(self, name: str = "nc1709", version: str = "1.0.0"):
|
|
33
|
+
"""Initialize the MCP server
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
name: Server name
|
|
37
|
+
version: Server version
|
|
38
|
+
"""
|
|
39
|
+
self.name = name
|
|
40
|
+
self.version = version
|
|
41
|
+
self._tools: Dict[str, MCPTool] = {}
|
|
42
|
+
self._resources: Dict[str, MCPResource] = {}
|
|
43
|
+
self._prompts: Dict[str, MCPPrompt] = {}
|
|
44
|
+
self._request_id = 0
|
|
45
|
+
self._initialized = False
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def server_info(self) -> MCPServerInfo:
|
|
49
|
+
"""Get server information"""
|
|
50
|
+
return MCPServerInfo(
|
|
51
|
+
name=self.name,
|
|
52
|
+
version=self.version,
|
|
53
|
+
capabilities={
|
|
54
|
+
"tools": {"listChanged": True},
|
|
55
|
+
"resources": {"subscribe": False, "listChanged": True},
|
|
56
|
+
"prompts": {"listChanged": True}
|
|
57
|
+
}
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
def register_tool(
|
|
61
|
+
self,
|
|
62
|
+
name: str,
|
|
63
|
+
description: str,
|
|
64
|
+
handler: Callable,
|
|
65
|
+
parameters: Optional[List[MCPToolParameter]] = None
|
|
66
|
+
) -> None:
|
|
67
|
+
"""Register a tool with the server
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
name: Tool name
|
|
71
|
+
description: Tool description
|
|
72
|
+
handler: Function to handle tool calls
|
|
73
|
+
parameters: Tool parameters
|
|
74
|
+
"""
|
|
75
|
+
tool = MCPTool(
|
|
76
|
+
name=name,
|
|
77
|
+
description=description,
|
|
78
|
+
parameters=parameters or [],
|
|
79
|
+
handler=handler
|
|
80
|
+
)
|
|
81
|
+
self._tools[name] = tool
|
|
82
|
+
|
|
83
|
+
def register_resource(
|
|
84
|
+
self,
|
|
85
|
+
uri: str,
|
|
86
|
+
name: str,
|
|
87
|
+
description: str = "",
|
|
88
|
+
mime_type: Optional[str] = None
|
|
89
|
+
) -> None:
|
|
90
|
+
"""Register a resource
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
uri: Resource URI
|
|
94
|
+
name: Resource name
|
|
95
|
+
description: Resource description
|
|
96
|
+
mime_type: MIME type
|
|
97
|
+
"""
|
|
98
|
+
resource = MCPResource(
|
|
99
|
+
uri=uri,
|
|
100
|
+
name=name,
|
|
101
|
+
description=description,
|
|
102
|
+
mimeType=mime_type
|
|
103
|
+
)
|
|
104
|
+
self._resources[uri] = resource
|
|
105
|
+
|
|
106
|
+
def register_prompt(
|
|
107
|
+
self,
|
|
108
|
+
name: str,
|
|
109
|
+
description: str,
|
|
110
|
+
arguments: Optional[List[Dict]] = None
|
|
111
|
+
) -> None:
|
|
112
|
+
"""Register a prompt template
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
name: Prompt name
|
|
116
|
+
description: Prompt description
|
|
117
|
+
arguments: Prompt arguments
|
|
118
|
+
"""
|
|
119
|
+
prompt = MCPPrompt(
|
|
120
|
+
name=name,
|
|
121
|
+
description=description,
|
|
122
|
+
arguments=arguments or []
|
|
123
|
+
)
|
|
124
|
+
self._prompts[name] = prompt
|
|
125
|
+
|
|
126
|
+
async def handle_message(self, message: MCPMessage) -> MCPMessage:
|
|
127
|
+
"""Handle an incoming MCP message
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
message: Incoming message
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
Response message
|
|
134
|
+
"""
|
|
135
|
+
method = message.method
|
|
136
|
+
params = message.params or {}
|
|
137
|
+
msg_id = message.id
|
|
138
|
+
|
|
139
|
+
try:
|
|
140
|
+
if method == "initialize":
|
|
141
|
+
result = self._handle_initialize(params)
|
|
142
|
+
elif method == "tools/list":
|
|
143
|
+
result = self._handle_list_tools()
|
|
144
|
+
elif method == "tools/call":
|
|
145
|
+
result = await self._handle_call_tool(params)
|
|
146
|
+
elif method == "resources/list":
|
|
147
|
+
result = self._handle_list_resources()
|
|
148
|
+
elif method == "resources/read":
|
|
149
|
+
result = await self._handle_read_resource(params)
|
|
150
|
+
elif method == "prompts/list":
|
|
151
|
+
result = self._handle_list_prompts()
|
|
152
|
+
elif method == "prompts/get":
|
|
153
|
+
result = self._handle_get_prompt(params)
|
|
154
|
+
else:
|
|
155
|
+
return MCPMessage.error_response(
|
|
156
|
+
msg_id,
|
|
157
|
+
MCPErrorCode.METHOD_NOT_FOUND,
|
|
158
|
+
f"Unknown method: {method}"
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
return MCPMessage.response(msg_id, result)
|
|
162
|
+
|
|
163
|
+
except Exception as e:
|
|
164
|
+
return MCPMessage.error_response(
|
|
165
|
+
msg_id,
|
|
166
|
+
MCPErrorCode.INTERNAL_ERROR,
|
|
167
|
+
str(e)
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
def _handle_initialize(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
|
171
|
+
"""Handle initialization request"""
|
|
172
|
+
self._initialized = True
|
|
173
|
+
return {
|
|
174
|
+
"protocolVersion": "2024-11-05",
|
|
175
|
+
"serverInfo": self.server_info.to_dict(),
|
|
176
|
+
"capabilities": self.server_info.capabilities
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
def _handle_list_tools(self) -> Dict[str, Any]:
|
|
180
|
+
"""Handle tools/list request"""
|
|
181
|
+
return {
|
|
182
|
+
"tools": [tool.to_dict() for tool in self._tools.values()]
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
async def _handle_call_tool(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
|
186
|
+
"""Handle tools/call request"""
|
|
187
|
+
tool_name = params.get("name")
|
|
188
|
+
arguments = params.get("arguments", {})
|
|
189
|
+
|
|
190
|
+
if tool_name not in self._tools:
|
|
191
|
+
raise ValueError(f"Tool not found: {tool_name}")
|
|
192
|
+
|
|
193
|
+
tool = self._tools[tool_name]
|
|
194
|
+
|
|
195
|
+
if tool.handler is None:
|
|
196
|
+
raise ValueError(f"Tool {tool_name} has no handler")
|
|
197
|
+
|
|
198
|
+
# Call the handler
|
|
199
|
+
if asyncio.iscoroutinefunction(tool.handler):
|
|
200
|
+
result = await tool.handler(**arguments)
|
|
201
|
+
else:
|
|
202
|
+
result = tool.handler(**arguments)
|
|
203
|
+
|
|
204
|
+
# Format result
|
|
205
|
+
if isinstance(result, ToolResult):
|
|
206
|
+
return {
|
|
207
|
+
"content": result.content,
|
|
208
|
+
"isError": result.is_error
|
|
209
|
+
}
|
|
210
|
+
elif isinstance(result, str):
|
|
211
|
+
return {
|
|
212
|
+
"content": [{"type": "text", "text": result}],
|
|
213
|
+
"isError": False
|
|
214
|
+
}
|
|
215
|
+
elif isinstance(result, dict):
|
|
216
|
+
return {
|
|
217
|
+
"content": [{"type": "text", "text": json.dumps(result, indent=2)}],
|
|
218
|
+
"isError": False
|
|
219
|
+
}
|
|
220
|
+
else:
|
|
221
|
+
return {
|
|
222
|
+
"content": [{"type": "text", "text": str(result)}],
|
|
223
|
+
"isError": False
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
def _handle_list_resources(self) -> Dict[str, Any]:
|
|
227
|
+
"""Handle resources/list request"""
|
|
228
|
+
return {
|
|
229
|
+
"resources": [res.to_dict() for res in self._resources.values()]
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
async def _handle_read_resource(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
|
233
|
+
"""Handle resources/read request"""
|
|
234
|
+
uri = params.get("uri")
|
|
235
|
+
|
|
236
|
+
if uri not in self._resources:
|
|
237
|
+
raise ValueError(f"Resource not found: {uri}")
|
|
238
|
+
|
|
239
|
+
# Read resource content based on URI scheme
|
|
240
|
+
resource = self._resources[uri]
|
|
241
|
+
|
|
242
|
+
if uri.startswith("file://"):
|
|
243
|
+
file_path = uri[7:]
|
|
244
|
+
try:
|
|
245
|
+
with open(file_path, 'r') as f:
|
|
246
|
+
content = f.read()
|
|
247
|
+
return {
|
|
248
|
+
"contents": [{
|
|
249
|
+
"uri": uri,
|
|
250
|
+
"mimeType": resource.mimeType or "text/plain",
|
|
251
|
+
"text": content
|
|
252
|
+
}]
|
|
253
|
+
}
|
|
254
|
+
except Exception as e:
|
|
255
|
+
raise ValueError(f"Could not read file: {e}")
|
|
256
|
+
|
|
257
|
+
raise ValueError(f"Unsupported URI scheme: {uri}")
|
|
258
|
+
|
|
259
|
+
def _handle_list_prompts(self) -> Dict[str, Any]:
|
|
260
|
+
"""Handle prompts/list request"""
|
|
261
|
+
return {
|
|
262
|
+
"prompts": [prompt.to_dict() for prompt in self._prompts.values()]
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
def _handle_get_prompt(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
|
266
|
+
"""Handle prompts/get request"""
|
|
267
|
+
name = params.get("name")
|
|
268
|
+
arguments = params.get("arguments", {})
|
|
269
|
+
|
|
270
|
+
if name not in self._prompts:
|
|
271
|
+
raise ValueError(f"Prompt not found: {name}")
|
|
272
|
+
|
|
273
|
+
prompt = self._prompts[name]
|
|
274
|
+
|
|
275
|
+
# Generate prompt messages based on template
|
|
276
|
+
# This is a simple implementation - could be enhanced
|
|
277
|
+
return {
|
|
278
|
+
"description": prompt.description,
|
|
279
|
+
"messages": [{
|
|
280
|
+
"role": "user",
|
|
281
|
+
"content": {
|
|
282
|
+
"type": "text",
|
|
283
|
+
"text": f"Prompt: {name}"
|
|
284
|
+
}
|
|
285
|
+
}]
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
async def run_stdio(self) -> None:
|
|
289
|
+
"""Run the server using stdio transport"""
|
|
290
|
+
reader = asyncio.StreamReader()
|
|
291
|
+
protocol = asyncio.StreamReaderProtocol(reader)
|
|
292
|
+
|
|
293
|
+
await asyncio.get_event_loop().connect_read_pipe(
|
|
294
|
+
lambda: protocol, sys.stdin
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
writer_transport, writer_protocol = await asyncio.get_event_loop().connect_write_pipe(
|
|
298
|
+
asyncio.streams.FlowControlMixin, sys.stdout
|
|
299
|
+
)
|
|
300
|
+
writer = asyncio.StreamWriter(
|
|
301
|
+
writer_transport, writer_protocol, reader, asyncio.get_event_loop()
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
while True:
|
|
305
|
+
try:
|
|
306
|
+
line = await reader.readline()
|
|
307
|
+
if not line:
|
|
308
|
+
break
|
|
309
|
+
|
|
310
|
+
message = MCPMessage.from_json(line.decode())
|
|
311
|
+
response = await self.handle_message(message)
|
|
312
|
+
|
|
313
|
+
writer.write((response.to_json() + "\n").encode())
|
|
314
|
+
await writer.drain()
|
|
315
|
+
|
|
316
|
+
except Exception as e:
|
|
317
|
+
error_response = MCPMessage.error_response(
|
|
318
|
+
None,
|
|
319
|
+
MCPErrorCode.PARSE_ERROR,
|
|
320
|
+
str(e)
|
|
321
|
+
)
|
|
322
|
+
writer.write((error_response.to_json() + "\n").encode())
|
|
323
|
+
await writer.drain()
|
|
324
|
+
|
|
325
|
+
def create_default_tools(self) -> None:
|
|
326
|
+
"""Register default NC1709 tools"""
|
|
327
|
+
|
|
328
|
+
# File read tool
|
|
329
|
+
self.register_tool(
|
|
330
|
+
name="read_file",
|
|
331
|
+
description="Read contents of a file",
|
|
332
|
+
handler=self._tool_read_file,
|
|
333
|
+
parameters=[
|
|
334
|
+
MCPToolParameter(
|
|
335
|
+
name="path",
|
|
336
|
+
type="string",
|
|
337
|
+
description="Path to the file to read",
|
|
338
|
+
required=True
|
|
339
|
+
)
|
|
340
|
+
]
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
# File write tool
|
|
344
|
+
self.register_tool(
|
|
345
|
+
name="write_file",
|
|
346
|
+
description="Write contents to a file",
|
|
347
|
+
handler=self._tool_write_file,
|
|
348
|
+
parameters=[
|
|
349
|
+
MCPToolParameter(
|
|
350
|
+
name="path",
|
|
351
|
+
type="string",
|
|
352
|
+
description="Path to the file to write",
|
|
353
|
+
required=True
|
|
354
|
+
),
|
|
355
|
+
MCPToolParameter(
|
|
356
|
+
name="content",
|
|
357
|
+
type="string",
|
|
358
|
+
description="Content to write",
|
|
359
|
+
required=True
|
|
360
|
+
)
|
|
361
|
+
]
|
|
362
|
+
)
|
|
363
|
+
|
|
364
|
+
# Execute command tool
|
|
365
|
+
self.register_tool(
|
|
366
|
+
name="execute_command",
|
|
367
|
+
description="Execute a shell command",
|
|
368
|
+
handler=self._tool_execute_command,
|
|
369
|
+
parameters=[
|
|
370
|
+
MCPToolParameter(
|
|
371
|
+
name="command",
|
|
372
|
+
type="string",
|
|
373
|
+
description="Command to execute",
|
|
374
|
+
required=True
|
|
375
|
+
)
|
|
376
|
+
]
|
|
377
|
+
)
|
|
378
|
+
|
|
379
|
+
# Search code tool
|
|
380
|
+
self.register_tool(
|
|
381
|
+
name="search_code",
|
|
382
|
+
description="Search for code patterns in the project",
|
|
383
|
+
handler=self._tool_search_code,
|
|
384
|
+
parameters=[
|
|
385
|
+
MCPToolParameter(
|
|
386
|
+
name="query",
|
|
387
|
+
type="string",
|
|
388
|
+
description="Search query",
|
|
389
|
+
required=True
|
|
390
|
+
),
|
|
391
|
+
MCPToolParameter(
|
|
392
|
+
name="file_pattern",
|
|
393
|
+
type="string",
|
|
394
|
+
description="File pattern to search (e.g., *.py)",
|
|
395
|
+
required=False
|
|
396
|
+
)
|
|
397
|
+
]
|
|
398
|
+
)
|
|
399
|
+
|
|
400
|
+
async def _tool_read_file(self, path: str) -> str:
|
|
401
|
+
"""Read file contents"""
|
|
402
|
+
try:
|
|
403
|
+
with open(path, 'r') as f:
|
|
404
|
+
return f.read()
|
|
405
|
+
except Exception as e:
|
|
406
|
+
return ToolResult(
|
|
407
|
+
content=[{"type": "text", "text": f"Error reading file: {e}"}],
|
|
408
|
+
is_error=True
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
async def _tool_write_file(self, path: str, content: str) -> str:
|
|
412
|
+
"""Write file contents"""
|
|
413
|
+
try:
|
|
414
|
+
with open(path, 'w') as f:
|
|
415
|
+
f.write(content)
|
|
416
|
+
return f"Successfully wrote to {path}"
|
|
417
|
+
except Exception as e:
|
|
418
|
+
return ToolResult(
|
|
419
|
+
content=[{"type": "text", "text": f"Error writing file: {e}"}],
|
|
420
|
+
is_error=True
|
|
421
|
+
)
|
|
422
|
+
|
|
423
|
+
async def _tool_execute_command(self, command: str) -> str:
|
|
424
|
+
"""Execute a command"""
|
|
425
|
+
import subprocess
|
|
426
|
+
|
|
427
|
+
# Security check - block dangerous commands
|
|
428
|
+
dangerous = ["rm -rf", "sudo", "mkfs", "dd if=", "> /dev/"]
|
|
429
|
+
for d in dangerous:
|
|
430
|
+
if d in command:
|
|
431
|
+
return ToolResult(
|
|
432
|
+
content=[{"type": "text", "text": f"Command blocked for safety: contains '{d}'"}],
|
|
433
|
+
is_error=True
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
try:
|
|
437
|
+
result = subprocess.run(
|
|
438
|
+
command,
|
|
439
|
+
shell=True,
|
|
440
|
+
capture_output=True,
|
|
441
|
+
text=True,
|
|
442
|
+
timeout=30
|
|
443
|
+
)
|
|
444
|
+
output = result.stdout + result.stderr
|
|
445
|
+
return output if output else "Command completed with no output"
|
|
446
|
+
except subprocess.TimeoutExpired:
|
|
447
|
+
return ToolResult(
|
|
448
|
+
content=[{"type": "text", "text": "Command timed out"}],
|
|
449
|
+
is_error=True
|
|
450
|
+
)
|
|
451
|
+
except Exception as e:
|
|
452
|
+
return ToolResult(
|
|
453
|
+
content=[{"type": "text", "text": f"Error executing command: {e}"}],
|
|
454
|
+
is_error=True
|
|
455
|
+
)
|
|
456
|
+
|
|
457
|
+
async def _tool_search_code(self, query: str, file_pattern: str = "*") -> str:
|
|
458
|
+
"""Search for code"""
|
|
459
|
+
import subprocess
|
|
460
|
+
|
|
461
|
+
try:
|
|
462
|
+
# Use grep for searching
|
|
463
|
+
cmd = f"grep -r -n '{query}' --include='{file_pattern}' ."
|
|
464
|
+
result = subprocess.run(
|
|
465
|
+
cmd,
|
|
466
|
+
shell=True,
|
|
467
|
+
capture_output=True,
|
|
468
|
+
text=True,
|
|
469
|
+
timeout=30
|
|
470
|
+
)
|
|
471
|
+
return result.stdout if result.stdout else "No matches found"
|
|
472
|
+
except Exception as e:
|
|
473
|
+
return f"Search error: {e}"
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""
|
|
2
|
+
NC1709 Memory Module
|
|
3
|
+
Provides long-term memory and semantic search capabilities using vector databases
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from .vector_store import VectorStore, MemoryEntry
|
|
7
|
+
from .embeddings import EmbeddingEngine, CodeChunker
|
|
8
|
+
from .indexer import ProjectIndexer
|
|
9
|
+
from .sessions import SessionManager, Session, Message
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"VectorStore",
|
|
13
|
+
"MemoryEntry",
|
|
14
|
+
"EmbeddingEngine",
|
|
15
|
+
"CodeChunker",
|
|
16
|
+
"ProjectIndexer",
|
|
17
|
+
"SessionManager",
|
|
18
|
+
"Session",
|
|
19
|
+
"Message"
|
|
20
|
+
]
|