moving
Some checks failed
Installer Smoke / installer-smoke (push) Has been cancelled

This commit is contained in:
Oleg Maslov
2026-09-02 10:10:29 +02:00
commit 0c3e2ead3b
3841 changed files with 970576 additions and 0 deletions

View File

@@ -0,0 +1,145 @@
/**
* createEmbeddingProvider tests — ported from
* hive-mind/packages/core/src/mind/embedding-provider.test.ts.
*
* Memory Sync Repair Step 2. Source: hive-mind file at HEAD c363257.
*
* Verbatim port — only the import path is adjusted from
* `./embedding-provider.js` to `../../src/mind/embedding-provider.js`.
*
* NOTE: waggle-os has additional `tests/embedding-provider-quota.test.ts`
* at the top level that exercises tier+quota enforcement (Waggle-only
* feature). That file is NOT a substitute for this port — they cover
* complementary surfaces: this file pins the generic mock fallback,
* dimension respect, deterministic-vector behavior, batch shape, and
* reprobe contract; the top-level file pins tier gating.
*/
import { describe, it, expect } from 'vitest';
import {
createEmbeddingProvider,
capEmbedText,
maxEmbedCharsForModel,
reembedPerText,
} from '../../src/mind/embedding-provider.js';
import type { Embedder } from '../../src/mind/embeddings.js';
describe('createEmbeddingProvider (hive-mind port)', () => {
it('falls back to mock when provider=mock is requested explicitly', async () => {
const provider = await createEmbeddingProvider({ provider: 'mock' });
expect(provider.getActiveProvider()).toBe('mock');
const status = provider.getStatus();
expect(status.activeProvider).toBe('mock');
expect(status.availableProviders).toContain('mock');
expect(status.dimensions).toBe(1024);
expect(status.modelName).toBe('deterministic-mock');
});
it('respects targetDimensions when configured', async () => {
const provider = await createEmbeddingProvider({
provider: 'mock',
targetDimensions: 512,
});
expect(provider.dimensions).toBe(512);
const vec = await provider.embed('hello');
expect(vec).toBeInstanceOf(Float32Array);
expect(vec.length).toBe(512);
});
it('produces deterministic mock vectors for identical inputs', async () => {
const provider = await createEmbeddingProvider({ provider: 'mock' });
const a = await provider.embed('deterministic input');
const b = await provider.embed('deterministic input');
expect(a.length).toBe(1024);
expect(b.length).toBe(1024);
for (let i = 0; i < a.length; i++) {
expect(a[i]).toBe(b[i]);
}
});
it('returns empty array for embedBatch([])', async () => {
const provider = await createEmbeddingProvider({ provider: 'mock' });
const result = await provider.embedBatch([]);
expect(result).toEqual([]);
});
it('batch-embeds multiple inputs to the expected shape', async () => {
const provider = await createEmbeddingProvider({
provider: 'mock',
targetDimensions: 256,
});
const out = await provider.embedBatch(['a', 'b', 'c']);
expect(out).toHaveLength(3);
for (const vec of out) {
expect(vec).toBeInstanceOf(Float32Array);
expect(vec.length).toBe(256);
}
});
it('falls back to mock when an explicit non-mock provider fails to probe', async () => {
// litellm with an obviously-unroutable URL — probe should fail quickly and
// the factory should land on mock.
const provider = await createEmbeddingProvider({
provider: 'litellm',
litellm: { url: 'http://127.0.0.1:1' },
});
expect(provider.getActiveProvider()).toBe('mock');
const status = provider.getStatus();
expect(status.availableProviders).toEqual(['mock']);
});
it('reprobe() refreshes status and keeps mock available when nothing else is', async () => {
const provider = await createEmbeddingProvider({ provider: 'mock' });
const first = provider.getStatus().probeTimestamp;
await new Promise((r) => setTimeout(r, 5));
const second = await provider.reprobe();
expect(second.availableProviders).toContain('mock');
expect(Date.parse(second.probeTimestamp)).toBeGreaterThanOrEqual(Date.parse(first));
});
});
// Reverse-ported from OSS hive-mind (oss-drift triage R5, 2026-06-11).
describe('embedding guards (oversized-frame truncation + skip-not-abort)', () => {
it('capEmbedText truncates only inputs over the limit', () => {
expect(capEmbedText('short', 6000)).toBe('short');
expect(capEmbedText('x'.repeat(6000), 6000)).toHaveLength(6000); // exactly at limit: unchanged
expect(capEmbedText('x'.repeat(20000), 6000)).toHaveLength(6000); // over limit: clamped
});
it('maxEmbedCharsForModel returns 8000 for 8k-named models and 6000 otherwise', () => {
// D1 probe (2026-06-12): the OSS 24k branch was unsafe — '-8k' named
// models can be architecture-capped at 2048 tokens (nomic-bert) and 400
// well below 24k chars, mock-poisoning every long frame. 8k chars ≈ the
// real 2048-token prose budget.
expect(maxEmbedCharsForModel('nomic-embed-text')).toBe(6000);
expect(maxEmbedCharsForModel('voyage-3-lite')).toBe(6000);
expect(maxEmbedCharsForModel('deterministic-mock')).toBe(6000);
expect(maxEmbedCharsForModel('nomic-embed-text-8k')).toBe(8000);
expect(maxEmbedCharsForModel('custom (num_ctx 8192)')).toBe(8000);
});
it('reembedPerText degrades ONLY the failing text, not the whole batch', async () => {
// The regression: the provider used to mock-poison the WHOLE batch when one
// text made the backend throw. Per-text re-embed keeps the good ones real.
const realFirstByte = (t: string): Float32Array => {
const v = new Float32Array(4);
v[0] = t.length; // a "real" marker the mock can't produce for these strings
return v;
};
const embedder: Embedder = {
dimensions: 4,
async embed(t: string) {
if (t === 'POISON') throw new Error('backend rejected this input');
return realFirstByte(t);
},
async embedBatch() {
throw new Error('batch path not used in this test');
},
};
const out = await reembedPerText(embedder, ['alpha', 'POISON', 'betas'], 4);
expect(out).toHaveLength(3);
expect(out[0][0]).toBe(5); // 'alpha' embedded for real
expect(out[2][0]).toBe(5); // 'betas' embedded for real
expect(out[1][0]).not.toBe(6); // 'POISON' degraded to mock, NOT a real length-6 vector
});
});