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.
Files changed (86) hide show
  1. nc1709/__init__.py +13 -0
  2. nc1709/agent/__init__.py +36 -0
  3. nc1709/agent/core.py +505 -0
  4. nc1709/agent/mcp_bridge.py +245 -0
  5. nc1709/agent/permissions.py +298 -0
  6. nc1709/agent/tools/__init__.py +21 -0
  7. nc1709/agent/tools/base.py +440 -0
  8. nc1709/agent/tools/bash_tool.py +367 -0
  9. nc1709/agent/tools/file_tools.py +454 -0
  10. nc1709/agent/tools/notebook_tools.py +516 -0
  11. nc1709/agent/tools/search_tools.py +322 -0
  12. nc1709/agent/tools/task_tool.py +284 -0
  13. nc1709/agent/tools/web_tools.py +555 -0
  14. nc1709/agents/__init__.py +17 -0
  15. nc1709/agents/auto_fix.py +506 -0
  16. nc1709/agents/test_generator.py +507 -0
  17. nc1709/checkpoints.py +372 -0
  18. nc1709/cli.py +3380 -0
  19. nc1709/cli_ui.py +1080 -0
  20. nc1709/cognitive/__init__.py +149 -0
  21. nc1709/cognitive/anticipation.py +594 -0
  22. nc1709/cognitive/context_engine.py +1046 -0
  23. nc1709/cognitive/council.py +824 -0
  24. nc1709/cognitive/learning.py +761 -0
  25. nc1709/cognitive/router.py +583 -0
  26. nc1709/cognitive/system.py +519 -0
  27. nc1709/config.py +155 -0
  28. nc1709/custom_commands.py +300 -0
  29. nc1709/executor.py +333 -0
  30. nc1709/file_controller.py +354 -0
  31. nc1709/git_integration.py +308 -0
  32. nc1709/github_integration.py +477 -0
  33. nc1709/image_input.py +446 -0
  34. nc1709/linting.py +519 -0
  35. nc1709/llm_adapter.py +667 -0
  36. nc1709/logger.py +192 -0
  37. nc1709/mcp/__init__.py +18 -0
  38. nc1709/mcp/client.py +370 -0
  39. nc1709/mcp/manager.py +407 -0
  40. nc1709/mcp/protocol.py +210 -0
  41. nc1709/mcp/server.py +473 -0
  42. nc1709/memory/__init__.py +20 -0
  43. nc1709/memory/embeddings.py +325 -0
  44. nc1709/memory/indexer.py +474 -0
  45. nc1709/memory/sessions.py +432 -0
  46. nc1709/memory/vector_store.py +451 -0
  47. nc1709/models/__init__.py +86 -0
  48. nc1709/models/detector.py +377 -0
  49. nc1709/models/formats.py +315 -0
  50. nc1709/models/manager.py +438 -0
  51. nc1709/models/registry.py +497 -0
  52. nc1709/performance/__init__.py +343 -0
  53. nc1709/performance/cache.py +705 -0
  54. nc1709/performance/pipeline.py +611 -0
  55. nc1709/performance/tiering.py +543 -0
  56. nc1709/plan_mode.py +362 -0
  57. nc1709/plugins/__init__.py +17 -0
  58. nc1709/plugins/agents/__init__.py +18 -0
  59. nc1709/plugins/agents/django_agent.py +912 -0
  60. nc1709/plugins/agents/docker_agent.py +623 -0
  61. nc1709/plugins/agents/fastapi_agent.py +887 -0
  62. nc1709/plugins/agents/git_agent.py +731 -0
  63. nc1709/plugins/agents/nextjs_agent.py +867 -0
  64. nc1709/plugins/base.py +359 -0
  65. nc1709/plugins/manager.py +411 -0
  66. nc1709/plugins/registry.py +337 -0
  67. nc1709/progress.py +443 -0
  68. nc1709/prompts/__init__.py +22 -0
  69. nc1709/prompts/agent_system.py +180 -0
  70. nc1709/prompts/task_prompts.py +340 -0
  71. nc1709/prompts/unified_prompt.py +133 -0
  72. nc1709/reasoning_engine.py +541 -0
  73. nc1709/remote_client.py +266 -0
  74. nc1709/shell_completions.py +349 -0
  75. nc1709/slash_commands.py +649 -0
  76. nc1709/task_classifier.py +408 -0
  77. nc1709/version_check.py +177 -0
  78. nc1709/web/__init__.py +8 -0
  79. nc1709/web/server.py +950 -0
  80. nc1709/web/templates/index.html +1127 -0
  81. nc1709-1.15.4.dist-info/METADATA +858 -0
  82. nc1709-1.15.4.dist-info/RECORD +86 -0
  83. nc1709-1.15.4.dist-info/WHEEL +5 -0
  84. nc1709-1.15.4.dist-info/entry_points.txt +2 -0
  85. nc1709-1.15.4.dist-info/licenses/LICENSE +9 -0
  86. nc1709-1.15.4.dist-info/top_level.txt +1 -0
@@ -0,0 +1,451 @@
1
+ """
2
+ Vector Store for NC1709
3
+ Manages persistent vector storage using ChromaDB
4
+ """
5
+ import json
6
+ import uuid
7
+ from dataclasses import dataclass, field, asdict
8
+ from datetime import datetime
9
+ from pathlib import Path
10
+ from typing import List, Dict, Any, Optional, Union
11
+
12
+ # Lazy import ChromaDB
13
+ _chroma_client = None
14
+
15
+
16
+ def get_chroma_client(persist_directory: str):
17
+ """Get or create ChromaDB client
18
+
19
+ Args:
20
+ persist_directory: Directory for persistent storage
21
+
22
+ Returns:
23
+ ChromaDB client
24
+ """
25
+ global _chroma_client
26
+
27
+ if _chroma_client is None:
28
+ try:
29
+ import chromadb
30
+ from chromadb.config import Settings
31
+
32
+ settings = Settings(
33
+ chroma_db_impl="duckdb+parquet",
34
+ persist_directory=persist_directory,
35
+ anonymized_telemetry=False
36
+ )
37
+ _chroma_client = chromadb.Client(settings)
38
+ print(f"ChromaDB initialized at: {persist_directory}")
39
+ except ImportError:
40
+ raise ImportError(
41
+ "chromadb is required for vector storage. "
42
+ "Install with: pip install chromadb"
43
+ )
44
+
45
+ return _chroma_client
46
+
47
+
48
+ @dataclass
49
+ class MemoryEntry:
50
+ """Represents a single memory entry in the vector store"""
51
+ id: str
52
+ content: str
53
+ embedding: Optional[List[float]] = None
54
+ metadata: Dict[str, Any] = field(default_factory=dict)
55
+ entry_type: str = "general" # general, code, conversation, document
56
+ created_at: str = field(default_factory=lambda: datetime.now().isoformat())
57
+ updated_at: str = field(default_factory=lambda: datetime.now().isoformat())
58
+
59
+ def to_dict(self) -> Dict[str, Any]:
60
+ """Convert to dictionary"""
61
+ return asdict(self)
62
+
63
+ @classmethod
64
+ def from_dict(cls, data: Dict[str, Any]) -> "MemoryEntry":
65
+ """Create from dictionary"""
66
+ return cls(**data)
67
+
68
+ @classmethod
69
+ def create(
70
+ cls,
71
+ content: str,
72
+ entry_type: str = "general",
73
+ metadata: Optional[Dict[str, Any]] = None,
74
+ embedding: Optional[List[float]] = None
75
+ ) -> "MemoryEntry":
76
+ """Create a new memory entry with auto-generated ID
77
+
78
+ Args:
79
+ content: The content to store
80
+ entry_type: Type of entry
81
+ metadata: Additional metadata
82
+ embedding: Pre-computed embedding
83
+
84
+ Returns:
85
+ New MemoryEntry instance
86
+ """
87
+ return cls(
88
+ id=str(uuid.uuid4()),
89
+ content=content,
90
+ embedding=embedding,
91
+ metadata=metadata or {},
92
+ entry_type=entry_type
93
+ )
94
+
95
+
96
+ class VectorStore:
97
+ """Vector store for semantic search and memory"""
98
+
99
+ # Collection names
100
+ COLLECTIONS = {
101
+ "code": "nc1709_code",
102
+ "conversations": "nc1709_conversations",
103
+ "documents": "nc1709_documents",
104
+ "general": "nc1709_general"
105
+ }
106
+
107
+ def __init__(
108
+ self,
109
+ persist_directory: Optional[str] = None,
110
+ embedding_engine: Optional[Any] = None
111
+ ):
112
+ """Initialize the vector store
113
+
114
+ Args:
115
+ persist_directory: Directory for ChromaDB storage
116
+ embedding_engine: EmbeddingEngine instance for generating embeddings
117
+ """
118
+ if persist_directory is None:
119
+ persist_directory = str(Path.home() / ".nc1709" / "memory" / "vectors")
120
+
121
+ self.persist_directory = Path(persist_directory)
122
+ self.persist_directory.mkdir(parents=True, exist_ok=True)
123
+
124
+ self._client = None
125
+ self._collections = {}
126
+ self._embedding_engine = embedding_engine
127
+
128
+ @property
129
+ def client(self):
130
+ """Lazy load ChromaDB client"""
131
+ if self._client is None:
132
+ self._client = get_chroma_client(str(self.persist_directory))
133
+ return self._client
134
+
135
+ @property
136
+ def embedding_engine(self):
137
+ """Get or create embedding engine"""
138
+ if self._embedding_engine is None:
139
+ from .embeddings import EmbeddingEngine
140
+ self._embedding_engine = EmbeddingEngine()
141
+ return self._embedding_engine
142
+
143
+ def _get_collection(self, collection_type: str = "general"):
144
+ """Get or create a collection
145
+
146
+ Args:
147
+ collection_type: Type of collection (code, conversations, documents, general)
148
+
149
+ Returns:
150
+ ChromaDB collection
151
+ """
152
+ if collection_type not in self._collections:
153
+ collection_name = self.COLLECTIONS.get(collection_type, self.COLLECTIONS["general"])
154
+ self._collections[collection_type] = self.client.get_or_create_collection(
155
+ name=collection_name,
156
+ metadata={"hnsw:space": "cosine"} # Use cosine similarity
157
+ )
158
+ return self._collections[collection_type]
159
+
160
+ def add(
161
+ self,
162
+ content: str,
163
+ entry_type: str = "general",
164
+ metadata: Optional[Dict[str, Any]] = None,
165
+ embedding: Optional[List[float]] = None,
166
+ entry_id: Optional[str] = None
167
+ ) -> MemoryEntry:
168
+ """Add a new entry to the vector store
169
+
170
+ Args:
171
+ content: Content to store
172
+ entry_type: Type of entry (code, conversation, document, general)
173
+ metadata: Additional metadata
174
+ embedding: Pre-computed embedding (will generate if None)
175
+ entry_id: Custom ID (will generate if None)
176
+
177
+ Returns:
178
+ Created MemoryEntry
179
+ """
180
+ # Generate embedding if not provided
181
+ if embedding is None:
182
+ embedding = self.embedding_engine.embed(content)
183
+
184
+ # Create entry
185
+ entry = MemoryEntry(
186
+ id=entry_id or str(uuid.uuid4()),
187
+ content=content,
188
+ embedding=embedding,
189
+ metadata=metadata or {},
190
+ entry_type=entry_type
191
+ )
192
+
193
+ # Get appropriate collection
194
+ collection = self._get_collection(entry_type)
195
+
196
+ # Prepare metadata for ChromaDB (must be flat)
197
+ chroma_metadata = self._flatten_metadata(entry.metadata)
198
+ chroma_metadata["entry_type"] = entry_type
199
+ chroma_metadata["created_at"] = entry.created_at
200
+ chroma_metadata["updated_at"] = entry.updated_at
201
+
202
+ # Add to collection
203
+ collection.add(
204
+ ids=[entry.id],
205
+ embeddings=[embedding],
206
+ documents=[content],
207
+ metadatas=[chroma_metadata]
208
+ )
209
+
210
+ return entry
211
+
212
+ def add_batch(
213
+ self,
214
+ entries: List[Dict[str, Any]],
215
+ entry_type: str = "general",
216
+ show_progress: bool = False
217
+ ) -> List[MemoryEntry]:
218
+ """Add multiple entries at once
219
+
220
+ Args:
221
+ entries: List of dicts with 'content' and optional 'metadata'
222
+ entry_type: Type for all entries
223
+ show_progress: Show progress bar
224
+
225
+ Returns:
226
+ List of created MemoryEntry objects
227
+ """
228
+ if not entries:
229
+ return []
230
+
231
+ # Extract contents
232
+ contents = [e["content"] for e in entries]
233
+
234
+ # Generate embeddings in batch
235
+ embeddings = self.embedding_engine.embed_batch(
236
+ contents,
237
+ show_progress=show_progress
238
+ )
239
+
240
+ # Create entries
241
+ memory_entries = []
242
+ ids = []
243
+ documents = []
244
+ all_embeddings = []
245
+ metadatas = []
246
+
247
+ for i, entry_data in enumerate(entries):
248
+ entry = MemoryEntry(
249
+ id=entry_data.get("id", str(uuid.uuid4())),
250
+ content=entry_data["content"],
251
+ embedding=embeddings[i],
252
+ metadata=entry_data.get("metadata", {}),
253
+ entry_type=entry_type
254
+ )
255
+ memory_entries.append(entry)
256
+
257
+ ids.append(entry.id)
258
+ documents.append(entry.content)
259
+ all_embeddings.append(embeddings[i])
260
+
261
+ meta = self._flatten_metadata(entry.metadata)
262
+ meta["entry_type"] = entry_type
263
+ meta["created_at"] = entry.created_at
264
+ metadatas.append(meta)
265
+
266
+ # Add to collection
267
+ collection = self._get_collection(entry_type)
268
+ collection.add(
269
+ ids=ids,
270
+ embeddings=all_embeddings,
271
+ documents=documents,
272
+ metadatas=metadatas
273
+ )
274
+
275
+ return memory_entries
276
+
277
+ def search(
278
+ self,
279
+ query: str,
280
+ entry_type: Optional[str] = None,
281
+ n_results: int = 5,
282
+ min_similarity: float = 0.0,
283
+ filter_metadata: Optional[Dict[str, Any]] = None
284
+ ) -> List[Dict[str, Any]]:
285
+ """Search for similar entries
286
+
287
+ Args:
288
+ query: Search query
289
+ entry_type: Type of entries to search (None for all)
290
+ n_results: Maximum number of results
291
+ min_similarity: Minimum similarity score (0-1)
292
+ filter_metadata: Metadata filters
293
+
294
+ Returns:
295
+ List of results with content, metadata, and similarity score
296
+ """
297
+ # Generate query embedding
298
+ query_embedding = self.embedding_engine.embed(query)
299
+
300
+ # Determine which collections to search
301
+ if entry_type:
302
+ collections = [self._get_collection(entry_type)]
303
+ else:
304
+ collections = [self._get_collection(t) for t in self.COLLECTIONS.keys()]
305
+
306
+ all_results = []
307
+
308
+ for collection in collections:
309
+ try:
310
+ # Build where clause for filtering
311
+ where = filter_metadata if filter_metadata else None
312
+
313
+ results = collection.query(
314
+ query_embeddings=[query_embedding],
315
+ n_results=n_results,
316
+ where=where,
317
+ include=["documents", "metadatas", "distances"]
318
+ )
319
+
320
+ # Process results
321
+ if results and results["ids"] and results["ids"][0]:
322
+ for i, doc_id in enumerate(results["ids"][0]):
323
+ # Convert distance to similarity (cosine distance to similarity)
324
+ distance = results["distances"][0][i] if results["distances"] else 0
325
+ similarity = 1 - distance # For cosine distance
326
+
327
+ if similarity >= min_similarity:
328
+ all_results.append({
329
+ "id": doc_id,
330
+ "content": results["documents"][0][i],
331
+ "metadata": results["metadatas"][0][i] if results["metadatas"] else {},
332
+ "similarity": similarity
333
+ })
334
+ except Exception as e:
335
+ print(f"Warning: Search error in collection: {e}")
336
+ continue
337
+
338
+ # Sort by similarity and limit
339
+ all_results.sort(key=lambda x: x["similarity"], reverse=True)
340
+ return all_results[:n_results]
341
+
342
+ def get(self, entry_id: str, entry_type: str = "general") -> Optional[Dict[str, Any]]:
343
+ """Get a specific entry by ID
344
+
345
+ Args:
346
+ entry_id: Entry ID
347
+ entry_type: Type of entry
348
+
349
+ Returns:
350
+ Entry dict or None if not found
351
+ """
352
+ collection = self._get_collection(entry_type)
353
+
354
+ try:
355
+ result = collection.get(
356
+ ids=[entry_id],
357
+ include=["documents", "metadatas", "embeddings"]
358
+ )
359
+
360
+ if result and result["ids"]:
361
+ return {
362
+ "id": result["ids"][0],
363
+ "content": result["documents"][0] if result["documents"] else "",
364
+ "metadata": result["metadatas"][0] if result["metadatas"] else {},
365
+ "embedding": result["embeddings"][0] if result["embeddings"] else None
366
+ }
367
+ except Exception:
368
+ pass
369
+
370
+ return None
371
+
372
+ def delete(self, entry_id: str, entry_type: str = "general") -> bool:
373
+ """Delete an entry
374
+
375
+ Args:
376
+ entry_id: Entry ID
377
+ entry_type: Type of entry
378
+
379
+ Returns:
380
+ True if deleted
381
+ """
382
+ collection = self._get_collection(entry_type)
383
+
384
+ try:
385
+ collection.delete(ids=[entry_id])
386
+ return True
387
+ except Exception:
388
+ return False
389
+
390
+ def clear(self, entry_type: Optional[str] = None):
391
+ """Clear entries from the store
392
+
393
+ Args:
394
+ entry_type: Type to clear (None for all)
395
+ """
396
+ if entry_type:
397
+ collection_name = self.COLLECTIONS.get(entry_type)
398
+ if collection_name:
399
+ try:
400
+ self.client.delete_collection(collection_name)
401
+ self._collections.pop(entry_type, None)
402
+ except Exception:
403
+ pass
404
+ else:
405
+ for ctype in list(self.COLLECTIONS.keys()):
406
+ self.clear(ctype)
407
+
408
+ def count(self, entry_type: Optional[str] = None) -> int:
409
+ """Count entries
410
+
411
+ Args:
412
+ entry_type: Type to count (None for all)
413
+
414
+ Returns:
415
+ Number of entries
416
+ """
417
+ if entry_type:
418
+ collection = self._get_collection(entry_type)
419
+ return collection.count()
420
+ else:
421
+ total = 0
422
+ for ctype in self.COLLECTIONS.keys():
423
+ try:
424
+ total += self._get_collection(ctype).count()
425
+ except Exception:
426
+ pass
427
+ return total
428
+
429
+ def persist(self):
430
+ """Persist the database to disk"""
431
+ if self._client:
432
+ self._client.persist()
433
+
434
+ def _flatten_metadata(self, metadata: Dict[str, Any]) -> Dict[str, Union[str, int, float, bool]]:
435
+ """Flatten nested metadata for ChromaDB
436
+
437
+ Args:
438
+ metadata: Potentially nested metadata dict
439
+
440
+ Returns:
441
+ Flattened dict with string/number/bool values only
442
+ """
443
+ flat = {}
444
+ for key, value in metadata.items():
445
+ if isinstance(value, (str, int, float, bool)):
446
+ flat[key] = value
447
+ elif isinstance(value, (list, dict)):
448
+ flat[key] = json.dumps(value)
449
+ else:
450
+ flat[key] = str(value)
451
+ return flat
@@ -0,0 +1,86 @@
1
+ """
2
+ NC1709 Model Registry System
3
+
4
+ Centralized model management that makes adding new models a single config change.
5
+
6
+ Usage:
7
+ from nc1709.models import ModelManager, get_model_spec, KNOWN_MODELS
8
+
9
+ # Get a model spec
10
+ spec = get_model_spec("qwen2.5-coder:32b")
11
+ print(f"Context: {spec.context_window}")
12
+
13
+ # Use the manager
14
+ manager = ModelManager(config)
15
+ spec = manager.get_model_for_task("coding")
16
+ prompt = manager.format_prompt(messages, spec.ollama_name)
17
+
18
+ # Set a model for a task
19
+ manager.set_model_for_task("coding", "new-model:70b")
20
+ """
21
+
22
+ # Registry
23
+ from .registry import (
24
+ # Classes
25
+ ModelSpec,
26
+ PromptFormat,
27
+ ModelCapability,
28
+ # Data
29
+ KNOWN_MODELS,
30
+ # Functions
31
+ get_model_spec,
32
+ get_all_models,
33
+ get_models_with_capability,
34
+ get_best_model_for_task,
35
+ register_model,
36
+ unregister_model,
37
+ create_model_spec,
38
+ )
39
+
40
+ # Formats
41
+ from .formats import (
42
+ Message,
43
+ PromptFormatter,
44
+ get_format_info,
45
+ )
46
+
47
+ # Detector
48
+ from .detector import (
49
+ ModelDetector,
50
+ auto_detect_model,
51
+ )
52
+
53
+ # Manager
54
+ from .manager import (
55
+ ModelManager,
56
+ print_model_info,
57
+ print_all_models,
58
+ print_task_assignments,
59
+ )
60
+
61
+ __all__ = [
62
+ # Registry
63
+ "ModelSpec",
64
+ "PromptFormat",
65
+ "ModelCapability",
66
+ "KNOWN_MODELS",
67
+ "get_model_spec",
68
+ "get_all_models",
69
+ "get_models_with_capability",
70
+ "get_best_model_for_task",
71
+ "register_model",
72
+ "unregister_model",
73
+ "create_model_spec",
74
+ # Formats
75
+ "Message",
76
+ "PromptFormatter",
77
+ "get_format_info",
78
+ # Detector
79
+ "ModelDetector",
80
+ "auto_detect_model",
81
+ # Manager
82
+ "ModelManager",
83
+ "print_model_info",
84
+ "print_all_models",
85
+ "print_task_assignments",
86
+ ]