Forge
csharp72c0d4fb
1using System.Buffers.Binary;
2using Microsoft.Data.Sqlite;
3
4namespace HybridCodebaseIndex.Core;
5
6internal static class SqliteVecInterop
7{
8 internal static bool TryEnableAndLoad(SqliteConnection conn, IndexSettings settings, string indexDirectory, out string? error)
9 {
10 error = null;
11
12 var raw = (settings.SqliteVecExtensionPath ?? "").Trim();
13 if (raw.Length == 0)
14 return false;
15
16 var extPath = ResolveExtensionPath(raw, indexDirectory);
17 if (extPath is null)
18 return false;
19
20 try
21 {
22 conn.EnableExtensions(true);
23 conn.LoadExtension(extPath);
24 return true;
25 }
26 catch (Exception ex)
27 {
28 error = ex.GetType().Name + ": " + ex.Message;
29 return false;
30 }
31 finally
32 {
33 try { conn.EnableExtensions(false); } catch { /* ignore */ }
34 }
35 }
36
37 /// <summary>
38 /// Absolute path as-is if it exists; otherwise relative to index directory, then to <see cref="AppContext.BaseDirectory"/> (published MCP host).
39 /// </summary>
40 private static string? ResolveExtensionPath(string raw, string indexDirectory)
41 {
42 if (Path.IsPathRooted(raw))
43 return File.Exists(raw) ? raw : null;
44
45 var inIndex = Path.Combine(indexDirectory, raw);
46 if (File.Exists(inIndex))
47 return inIndex;
48
49 var inBase = Path.Combine(AppContext.BaseDirectory, raw);
50 return File.Exists(inBase) ? inBase : null;
51 }
52
53 internal static bool TryEnsureVecChunksTable(SqliteConnection conn, int dim, out string? error)
54 {
55 error = null;
56 try
57 {
58 using var cmd = conn.CreateCommand();
59 cmd.CommandText = $"CREATE VIRTUAL TABLE IF NOT EXISTS vec_chunks USING vec0(embedding float[{dim}] distance_metric=cosine);";
60 cmd.ExecuteNonQuery();
61 return true;
62 }
63 catch (Exception ex)
64 {
65 error = ex.GetType().Name + ": " + ex.Message;
66 return false;
67 }
68 }
69
70 internal static bool TryUpsertVector(SqliteConnection conn, long chunkRowId, float[] v, out string? error)
71 {
72 error = null;
73 try
74 {
75 var blob = SerializeF32(v);
76 using var cmd = conn.CreateCommand();
77 cmd.CommandText = "INSERT OR REPLACE INTO vec_chunks(rowid, embedding) VALUES($id, $emb);";
78 cmd.Parameters.AddWithValue("$id", chunkRowId);
79 cmd.Parameters.AddWithValue("$emb", blob);
80 cmd.ExecuteNonQuery();
81 return true;
82 }
83 catch (Exception ex)
84 {
85 error = ex.GetType().Name + ": " + ex.Message;
86 return false;
87 }
88 }
89
90 internal static List<(long chunkRowId, double sim)> QueryTopK(SqliteConnection conn, float[] qv, int k)
91 {
92 // cosine distance: 0 = identical, 1 = orthogonal, 2 = opposite (depending on implementation)
93 // Similarity proxy for fusion: sim = 1 - distance, clamped.
94 var blob = SerializeF32(qv);
95
96 using var cmd = conn.CreateCommand();
97 cmd.CommandText = """
98 SELECT rowid, distance
99 FROM vec_chunks
100 WHERE embedding MATCH $q
101 ORDER BY distance
102 LIMIT $k;
103 """;
104 cmd.Parameters.AddWithValue("$q", blob);
105 cmd.Parameters.AddWithValue("$k", k);
106
107 var list = new List<(long chunkRowId, double sim)>(capacity: k);
108 using var r = cmd.ExecuteReader();
109 while (r.Read())
110 {
111 var id = r.GetInt64(0);
112 var dist = r.GetDouble(1);
113 var sim = Math.Clamp(1.0 - dist, -1.0, 1.0);
114 list.Add((id, sim));
115 }
116 return list;
117 }
118
119 private static byte[] SerializeF32(float[] v)
120 {
121 var blob = new byte[v.Length * 4];
122 for (var i = 0; i < v.Length; i++)
123 BinaryPrimitives.WriteSingleLittleEndian(blob.AsSpan(i * 4, 4), v[i]);
124 return blob;
125 }
126}
127
128
View only · write via MCP/CIDE