cocoindex-code 0.2.40__tar.gz → 0.2.41__tar.gz
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.
- {cocoindex_code-0.2.40 → cocoindex_code-0.2.41}/PKG-INFO +1 -1
- {cocoindex_code-0.2.40 → cocoindex_code-0.2.41}/src/cocoindex_code/_version.py +2 -2
- {cocoindex_code-0.2.40 → cocoindex_code-0.2.41}/src/cocoindex_code/client.py +18 -8
- {cocoindex_code-0.2.40 → cocoindex_code-0.2.41}/src/cocoindex_code/daemon.py +3 -2
- {cocoindex_code-0.2.40 → cocoindex_code-0.2.41}/src/cocoindex_code/query.py +46 -13
- {cocoindex_code-0.2.40 → cocoindex_code-0.2.41}/.gitignore +0 -0
- {cocoindex_code-0.2.40 → cocoindex_code-0.2.41}/LICENSE +0 -0
- {cocoindex_code-0.2.40 → cocoindex_code-0.2.41}/README.md +0 -0
- {cocoindex_code-0.2.40 → cocoindex_code-0.2.41}/pyproject.toml +0 -0
- {cocoindex_code-0.2.40 → cocoindex_code-0.2.41}/src/cocoindex_code/__init__.py +0 -0
- {cocoindex_code-0.2.40 → cocoindex_code-0.2.41}/src/cocoindex_code/__main__.py +0 -0
- {cocoindex_code-0.2.40 → cocoindex_code-0.2.41}/src/cocoindex_code/_daemon_paths.py +0 -0
- {cocoindex_code-0.2.40 → cocoindex_code-0.2.41}/src/cocoindex_code/chunking.py +0 -0
- {cocoindex_code-0.2.40 → cocoindex_code-0.2.41}/src/cocoindex_code/cli.py +0 -0
- {cocoindex_code-0.2.40 → cocoindex_code-0.2.41}/src/cocoindex_code/embedder_defaults.py +0 -0
- {cocoindex_code-0.2.40 → cocoindex_code-0.2.41}/src/cocoindex_code/embedder_params.py +0 -0
- {cocoindex_code-0.2.40 → cocoindex_code-0.2.41}/src/cocoindex_code/file_walk.py +0 -0
- {cocoindex_code-0.2.40 → cocoindex_code-0.2.41}/src/cocoindex_code/grep.py +0 -0
- {cocoindex_code-0.2.40 → cocoindex_code-0.2.41}/src/cocoindex_code/indexer.py +0 -0
- {cocoindex_code-0.2.40 → cocoindex_code-0.2.41}/src/cocoindex_code/litellm_embedder.py +0 -0
- {cocoindex_code-0.2.40 → cocoindex_code-0.2.41}/src/cocoindex_code/project.py +0 -0
- {cocoindex_code-0.2.40 → cocoindex_code-0.2.41}/src/cocoindex_code/protocol.py +0 -0
- {cocoindex_code-0.2.40 → cocoindex_code-0.2.41}/src/cocoindex_code/schema.py +0 -0
- {cocoindex_code-0.2.40 → cocoindex_code-0.2.41}/src/cocoindex_code/server.py +0 -0
- {cocoindex_code-0.2.40 → cocoindex_code-0.2.41}/src/cocoindex_code/settings.py +0 -0
- {cocoindex_code-0.2.40 → cocoindex_code-0.2.41}/src/cocoindex_code/shared.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cocoindex-code
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.41
|
|
4
4
|
Summary: MCP server for indexing and querying codebases using CocoIndex
|
|
5
5
|
Project-URL: Homepage, https://github.com/cocoindex-io/cocoindex-code
|
|
6
6
|
Project-URL: Repository, https://github.com/cocoindex-io/cocoindex-code
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.2.
|
|
22
|
-
__version_tuple__ = version_tuple = (0, 2,
|
|
21
|
+
__version__ = version = '0.2.41'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 2, 41)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -228,6 +228,19 @@ def _handle_vanished_daemon() -> None:
|
|
|
228
228
|
)
|
|
229
229
|
|
|
230
230
|
|
|
231
|
+
def _daemon_error(resp: ErrorResponse) -> RuntimeError:
|
|
232
|
+
"""Build the exception for an ``ErrorResponse`` from the daemon.
|
|
233
|
+
|
|
234
|
+
The daemon-side traceback is appended when present: without it the caller
|
|
235
|
+
only ever sees the client's own re-raise frames, which says nothing about
|
|
236
|
+
where the failure actually happened (issue #270).
|
|
237
|
+
"""
|
|
238
|
+
detail = f"Daemon error: {resp.message}"
|
|
239
|
+
if resp.traceback:
|
|
240
|
+
detail += f"\n{resp.traceback}"
|
|
241
|
+
return RuntimeError(detail)
|
|
242
|
+
|
|
243
|
+
|
|
231
244
|
class _HandshakeResult(NamedTuple):
|
|
232
245
|
conn: Connection
|
|
233
246
|
resp: HandshakeResponse
|
|
@@ -261,7 +274,7 @@ def _raw_connect_and_handshake() -> _HandshakeResult:
|
|
|
261
274
|
raise DaemonProtocolError(f"Undecodable handshake reply from daemon: {e}") from e
|
|
262
275
|
if isinstance(resp, ErrorResponse):
|
|
263
276
|
conn.close()
|
|
264
|
-
raise
|
|
277
|
+
raise _daemon_error(resp)
|
|
265
278
|
if not isinstance(resp, HandshakeResponse):
|
|
266
279
|
conn.close()
|
|
267
280
|
raise RuntimeError(f"Unexpected handshake response: {type(resp).__name__}")
|
|
@@ -340,7 +353,7 @@ def _send(req: Request) -> Response:
|
|
|
340
353
|
conn.close()
|
|
341
354
|
resp = decode_response(data)
|
|
342
355
|
if isinstance(resp, ErrorResponse):
|
|
343
|
-
raise
|
|
356
|
+
raise _daemon_error(resp)
|
|
344
357
|
return resp
|
|
345
358
|
|
|
346
359
|
|
|
@@ -366,7 +379,7 @@ def index(
|
|
|
366
379
|
raise RuntimeError("Connection to daemon lost during indexing")
|
|
367
380
|
resp = decode_response(data)
|
|
368
381
|
if isinstance(resp, ErrorResponse):
|
|
369
|
-
raise
|
|
382
|
+
raise _daemon_error(resp)
|
|
370
383
|
if isinstance(resp, IndexWaitingNotice):
|
|
371
384
|
if on_waiting is not None:
|
|
372
385
|
on_waiting()
|
|
@@ -419,7 +432,7 @@ def search(
|
|
|
419
432
|
raise RuntimeError("Connection to daemon lost during search")
|
|
420
433
|
resp = decode_response(data)
|
|
421
434
|
if isinstance(resp, ErrorResponse):
|
|
422
|
-
raise
|
|
435
|
+
raise _daemon_error(resp)
|
|
423
436
|
if isinstance(resp, IndexWaitingNotice):
|
|
424
437
|
if on_waiting is not None:
|
|
425
438
|
on_waiting()
|
|
@@ -496,10 +509,7 @@ def doctor(
|
|
|
496
509
|
raise RuntimeError("Connection to daemon lost during doctor checks")
|
|
497
510
|
resp = decode_response(data)
|
|
498
511
|
if isinstance(resp, ErrorResponse):
|
|
499
|
-
|
|
500
|
-
if resp.traceback:
|
|
501
|
-
detail += f"\n{resp.traceback}"
|
|
502
|
-
raise RuntimeError(detail)
|
|
512
|
+
raise _daemon_error(resp)
|
|
503
513
|
if isinstance(resp, DoctorResponse):
|
|
504
514
|
results.append(resp.result)
|
|
505
515
|
if on_result is not None:
|
|
@@ -346,7 +346,8 @@ async def _search_with_wait(
|
|
|
346
346
|
offset=req.offset,
|
|
347
347
|
)
|
|
348
348
|
except Exception as e:
|
|
349
|
-
|
|
349
|
+
logger.exception("Error handling search request")
|
|
350
|
+
yield ErrorResponse(message=str(e), traceback=traceback.format_exc())
|
|
350
351
|
|
|
351
352
|
|
|
352
353
|
async def _handle_doctor(
|
|
@@ -605,7 +606,7 @@ async def _dispatch(
|
|
|
605
606
|
return ErrorResponse(message=f"Unknown request type: {type(req).__name__}")
|
|
606
607
|
except Exception as e:
|
|
607
608
|
logger.exception("Error dispatching request")
|
|
608
|
-
return ErrorResponse(message=str(e))
|
|
609
|
+
return ErrorResponse(message=str(e), traceback=traceback.format_exc())
|
|
609
610
|
|
|
610
611
|
|
|
611
612
|
# ---------------------------------------------------------------------------
|
|
@@ -16,6 +16,33 @@ def _l2_to_score(distance: float) -> float:
|
|
|
16
16
|
return 1.0 - distance * distance / 2.0
|
|
17
17
|
|
|
18
18
|
|
|
19
|
+
def _checked(rows: list[tuple[Any, ...]], query_shape: str) -> list[tuple[Any, ...]]:
|
|
20
|
+
"""Return *rows*, failing loudly if any of them carries a NULL distance.
|
|
21
|
+
|
|
22
|
+
``code_chunks_vec`` is a vec0 virtual table whose ``distance`` is a *hidden*
|
|
23
|
+
column: sqlite-vec populates it only under the KNN query plan and yields
|
|
24
|
+
NULL for it on a plain full scan. A NULL therefore means the plan we asked
|
|
25
|
+
for is not the plan we got, which is a bug worth reporting rather than a
|
|
26
|
+
result worth ranking. Left unchecked, the NULL flows into ``_l2_to_score``
|
|
27
|
+
and surfaces as an unrelated-looking ``TypeError: unsupported operand
|
|
28
|
+
type(s) for *: 'NoneType' and 'NoneType'`` (issue #270).
|
|
29
|
+
|
|
30
|
+
Only KNN queries need this guard: ``_full_scan_query`` computes its own
|
|
31
|
+
``vec_distance_L2(...)``, which works under any plan and raises (never
|
|
32
|
+
returns NULL) on bad input.
|
|
33
|
+
"""
|
|
34
|
+
bad = next((row for row in rows if row[5] is None), None)
|
|
35
|
+
if bad is not None:
|
|
36
|
+
raise RuntimeError(
|
|
37
|
+
f"Vector index returned a row with no distance ({query_shape}, "
|
|
38
|
+
f"file_path={bad[0]!r}) — the sqlite-vec KNN query plan was not "
|
|
39
|
+
"used. Please report this at "
|
|
40
|
+
"https://github.com/cocoindex-io/cocoindex-code/issues along with "
|
|
41
|
+
"the output of `ccc doctor`."
|
|
42
|
+
)
|
|
43
|
+
return rows
|
|
44
|
+
|
|
45
|
+
|
|
19
46
|
def _knn_query(
|
|
20
47
|
conn: sqlite3.Connection,
|
|
21
48
|
embedding_bytes: bytes,
|
|
@@ -24,24 +51,30 @@ def _knn_query(
|
|
|
24
51
|
) -> list[tuple[Any, ...]]:
|
|
25
52
|
"""Run a vec0 KNN query, optionally constrained to a language partition."""
|
|
26
53
|
if language is not None:
|
|
27
|
-
return
|
|
54
|
+
return _checked(
|
|
55
|
+
conn.execute(
|
|
56
|
+
"""
|
|
57
|
+
SELECT file_path, language, content, start_line, end_line, distance
|
|
58
|
+
FROM code_chunks_vec
|
|
59
|
+
WHERE embedding MATCH ? AND k = ? AND language = ?
|
|
60
|
+
ORDER BY distance
|
|
61
|
+
""",
|
|
62
|
+
(embedding_bytes, k, language),
|
|
63
|
+
).fetchall(),
|
|
64
|
+
f"knn language={language!r}",
|
|
65
|
+
)
|
|
66
|
+
return _checked(
|
|
67
|
+
conn.execute(
|
|
28
68
|
"""
|
|
29
69
|
SELECT file_path, language, content, start_line, end_line, distance
|
|
30
70
|
FROM code_chunks_vec
|
|
31
|
-
WHERE embedding MATCH ? AND k = ?
|
|
71
|
+
WHERE embedding MATCH ? AND k = ?
|
|
32
72
|
ORDER BY distance
|
|
33
73
|
""",
|
|
34
|
-
(embedding_bytes, k
|
|
35
|
-
).fetchall()
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
SELECT file_path, language, content, start_line, end_line, distance
|
|
39
|
-
FROM code_chunks_vec
|
|
40
|
-
WHERE embedding MATCH ? AND k = ?
|
|
41
|
-
ORDER BY distance
|
|
42
|
-
""",
|
|
43
|
-
(embedding_bytes, k),
|
|
44
|
-
).fetchall()
|
|
74
|
+
(embedding_bytes, k),
|
|
75
|
+
).fetchall(),
|
|
76
|
+
"knn unfiltered",
|
|
77
|
+
)
|
|
45
78
|
|
|
46
79
|
|
|
47
80
|
def _full_scan_query(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|