gitnexus 1.6.5-rc.8 → 1.6.5-rc.9

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.
@@ -30,8 +30,11 @@ const readConfig = () => {
30
30
  const rawDims = process.env.GITNEXUS_EMBEDDING_DIMS;
31
31
  let dimensions;
32
32
  if (rawDims !== undefined) {
33
+ if (!/^\d+$/.test(rawDims)) {
34
+ throw new Error(`GITNEXUS_EMBEDDING_DIMS must be a positive integer, got "${rawDims}"`);
35
+ }
33
36
  const parsed = parseInt(rawDims, 10);
34
- if (Number.isNaN(parsed) || parsed <= 0) {
37
+ if (parsed <= 0) {
35
38
  throw new Error(`GITNEXUS_EMBEDDING_DIMS must be a positive integer, got "${rawDims}"`);
36
39
  }
37
40
  dimensions = parsed;
@@ -73,9 +76,22 @@ const safeUrl = (url) => {
73
76
  * @param model - Model name for the request body
74
77
  * @param apiKey - Bearer token (only used in Authorization header)
75
78
  * @param batchIndex - Logical batch number (for error context)
76
- * @param attempt - Current retry attempt (internal)
79
+ * @param dimensions - Optional output-vector size. When provided, sent as
80
+ * the `dimensions` field in the request body. Endpoints that implement
81
+ * Matryoshka truncation (OpenAI text-embedding-3-*, Cohere embed-v3,
82
+ * Voyage) return a truncated vector at that size; endpoints that do not
83
+ * recognise the field may ignore it or return 400. Leave
84
+ * `GITNEXUS_EMBEDDING_DIMS` unset for strict backends that reject
85
+ * unknown fields.
77
86
  */
78
- const httpEmbedBatch = async (url, batch, model, apiKey, batchIndex = 0) => {
87
+ const httpEmbedBatch = async (url, batch, model, apiKey, batchIndex = 0, dimensions) => {
88
+ const requestBody = {
89
+ input: batch,
90
+ model,
91
+ };
92
+ if (dimensions !== undefined) {
93
+ requestBody.dimensions = dimensions;
94
+ }
79
95
  let resp;
80
96
  try {
81
97
  resp = await resilientFetch(url, {
@@ -85,7 +101,7 @@ const httpEmbedBatch = async (url, batch, model, apiKey, batchIndex = 0) => {
85
101
  'Content-Type': 'application/json',
86
102
  Authorization: `Bearer ${apiKey}`,
87
103
  },
88
- body: JSON.stringify({ input: batch, model }),
104
+ body: JSON.stringify(requestBody),
89
105
  }, {
90
106
  breakerKey: HTTP_BREAKER_KEY,
91
107
  retry: { maxAttempts: HTTP_MAX_RETRIES + 1, baseDelayMs: HTTP_RETRY_BACKOFF_MS },
@@ -130,7 +146,7 @@ export const httpEmbed = async (texts) => {
130
146
  for (let i = 0; i < texts.length; i += HTTP_BATCH_SIZE) {
131
147
  const batch = texts.slice(i, i + HTTP_BATCH_SIZE);
132
148
  const batchIndex = Math.floor(i / HTTP_BATCH_SIZE);
133
- const items = await httpEmbedBatch(url, batch, config.model, config.apiKey, batchIndex);
149
+ const items = await httpEmbedBatch(url, batch, config.model, config.apiKey, batchIndex, config.dimensions);
134
150
  if (items.length !== batch.length) {
135
151
  throw new Error(`Embedding endpoint returned ${items.length} vectors for ${batch.length} texts ` +
136
152
  `(${safeUrl(url)}, batch ${batchIndex})`);
@@ -164,7 +180,7 @@ export const httpEmbedQuery = async (text) => {
164
180
  if (!config)
165
181
  throw new Error('HTTP embedding not configured');
166
182
  const url = `${config.baseUrl}/embeddings`;
167
- const items = await httpEmbedBatch(url, [text], config.model, config.apiKey);
183
+ const items = await httpEmbedBatch(url, [text], config.model, config.apiKey, 0, config.dimensions);
168
184
  if (!items.length) {
169
185
  throw new Error(`Embedding endpoint returned empty response (${safeUrl(url)})`);
170
186
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitnexus",
3
- "version": "1.6.5-rc.8",
3
+ "version": "1.6.5-rc.9",
4
4
  "description": "Graph-powered code intelligence for AI agents. Index any codebase, query via MCP or CLI.",
5
5
  "author": "Abhigyan Patwari",
6
6
  "license": "PolyForm-Noncommercial-1.0.0",