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
|
@@ -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
|
+
]
|