Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 19 additions & 8 deletions agent-code-review/src/providerDetector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ const DEFAULT_MODELS: Record<string, string> = {

const OLLAMA_DEFAULT_URL = 'http://localhost:11434';

const EMBEDDING_MODEL_PATTERN =
/embed|minilm|mxbai|bge[-_]|gte[-_]|nomic|snowflake-arctic|e5[-_]|clip$/i;

export function pickOllamaChatModel(models: string[]): string | null {
const chatModel = models.find((m) => !EMBEDDING_MODEL_PATTERN.test(m));
return chatModel ?? null;
}

export async function detectProvider(options: DetectOptions = {}): Promise<ProviderConfig | null> {
const env = options.env ?? process.env;
const ollamaBaseUrl = options.ollamaBaseUrl ?? OLLAMA_DEFAULT_URL;
Expand Down Expand Up @@ -69,14 +77,17 @@ export async function detectProvider(options: DetectOptions = {}): Promise<Provi

const ollamaModels = await detectOllama(ollamaBaseUrl);
if (ollamaModels && ollamaModels.length > 0) {
const model = ollamaModels[0];
return {
provider: 'ollama',
model,
baseUrl: ollamaBaseUrl,
autoDetected: true,
detectedAt: new Date().toISOString(),
};
const model = pickOllamaChatModel(ollamaModels);
if (model) {
return {
provider: 'ollama',
model,
baseUrl: ollamaBaseUrl,
autoDetected: true,
detectedAt: new Date().toISOString(),
};
}
return null;
}

if (ollamaModels === null) {
Expand Down
50 changes: 50 additions & 0 deletions agent-code-review/tests/providerDetector.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import os from 'os';
import {
detectProvider,
detectOllama,
pickOllamaChatModel,
loadConfig,
saveConfig,
getDefaultModel,
Expand Down Expand Up @@ -60,6 +61,37 @@ describe('providerDetector', () => {
}
});

it('skips embedding models and picks a chat-capable Ollama model', async () => {
const originalFetch = globalThis.fetch;
globalThis.fetch = vi.fn().mockResolvedValue({
ok: true,
json: async () => ({ models: [{ name: 'nomic-embed-text:latest' }, { name: 'llama3' }] }),
} as any);
try {
const result = await detectProvider({ env: {} });
expect(result).not.toBeNull();
expect(result!.provider).toBe('ollama');
expect(result!.model).toBe('llama3');
expect(result!.baseUrl).toBe('http://localhost:11434');
} finally {
globalThis.fetch = originalFetch;
}
});

it('returns null when Ollama only has embedding models', async () => {
const originalFetch = globalThis.fetch;
globalThis.fetch = vi.fn().mockResolvedValue({
ok: true,
json: async () => ({ models: [{ name: 'nomic-embed-text:latest' }] }),
} as any);
try {
const result = await detectProvider({ env: {} });
expect(result).toBeNull();
} finally {
globalThis.fetch = originalFetch;
}
});

it('returns null when nothing is available', async () => {
const originalFetch = globalThis.fetch;
globalThis.fetch = vi.fn().mockRejectedValue(new Error('Connection refused'));
Expand Down Expand Up @@ -144,6 +176,24 @@ describe('providerDetector', () => {
});
});

describe('pickOllamaChatModel', () => {
it('returns null for an empty list', () => {
expect(pickOllamaChatModel([])).toBeNull();
});

it('skips embedding models and picks the first chat model', () => {
expect(pickOllamaChatModel(['nomic-embed-text:latest', 'llama3'])).toBe('llama3');
});

it('returns null when all models are embeddings', () => {
expect(pickOllamaChatModel(['nomic-embed-text:latest', 'mxbai-embed-large'])).toBeNull();
});

it('returns the first non-embedding model', () => {
expect(pickOllamaChatModel(['qwen2.5-coder:1.5b', 'llama3'])).toBe('qwen2.5-coder:1.5b');
});
});

describe('loadConfig', () => {
let tmpDir: string;

Expand Down
27 changes: 19 additions & 8 deletions agent-doc-generator/src/providerDetector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ const DEFAULT_MODELS: Record<string, string> = {

const OLLAMA_DEFAULT_URL = 'http://localhost:11434';

const EMBEDDING_MODEL_PATTERN =
/embed|minilm|mxbai|bge[-_]|gte[-_]|nomic|snowflake-arctic|e5[-_]|clip$/i;

export function pickOllamaChatModel(models: string[]): string | null {
const chatModel = models.find((m) => !EMBEDDING_MODEL_PATTERN.test(m));
return chatModel ?? null;
}

export async function detectProvider(options: DetectOptions = {}): Promise<ProviderConfig | null> {
const env = options.env ?? process.env;
const ollamaBaseUrl = options.ollamaBaseUrl ?? OLLAMA_DEFAULT_URL;
Expand Down Expand Up @@ -69,14 +77,17 @@ export async function detectProvider(options: DetectOptions = {}): Promise<Provi

const ollamaModels = await detectOllama(ollamaBaseUrl);
if (ollamaModels && ollamaModels.length > 0) {
const model = ollamaModels[0];
return {
provider: 'ollama',
model,
baseUrl: ollamaBaseUrl,
autoDetected: true,
detectedAt: new Date().toISOString(),
};
const model = pickOllamaChatModel(ollamaModels);
if (model) {
return {
provider: 'ollama',
model,
baseUrl: ollamaBaseUrl,
autoDetected: true,
detectedAt: new Date().toISOString(),
};
}
return null;
}

if (ollamaModels === null) {
Expand Down
50 changes: 50 additions & 0 deletions agent-doc-generator/tests/providerDetector.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import os from 'os';
import {
detectProvider,
detectOllama,
pickOllamaChatModel,
loadConfig,
saveConfig,
getDefaultModel,
Expand Down Expand Up @@ -60,6 +61,37 @@ describe('providerDetector', () => {
}
});

it('skips embedding models and picks a chat-capable Ollama model', async () => {
const originalFetch = globalThis.fetch;
globalThis.fetch = vi.fn().mockResolvedValue({
ok: true,
json: async () => ({ models: [{ name: 'nomic-embed-text:latest' }, { name: 'llama3' }] }),
} as any);
try {
const result = await detectProvider({ env: {} });
expect(result).not.toBeNull();
expect(result!.provider).toBe('ollama');
expect(result!.model).toBe('llama3');
expect(result!.baseUrl).toBe('http://localhost:11434');
} finally {
globalThis.fetch = originalFetch;
}
});

it('returns null when Ollama only has embedding models', async () => {
const originalFetch = globalThis.fetch;
globalThis.fetch = vi.fn().mockResolvedValue({
ok: true,
json: async () => ({ models: [{ name: 'nomic-embed-text:latest' }] }),
} as any);
try {
const result = await detectProvider({ env: {} });
expect(result).toBeNull();
} finally {
globalThis.fetch = originalFetch;
}
});

it('returns null when nothing is available', async () => {
const originalFetch = globalThis.fetch;
globalThis.fetch = vi.fn().mockRejectedValue(new Error('Connection refused'));
Expand Down Expand Up @@ -144,6 +176,24 @@ describe('providerDetector', () => {
});
});

describe('pickOllamaChatModel', () => {
it('returns null for an empty list', () => {
expect(pickOllamaChatModel([])).toBeNull();
});

it('skips embedding models and picks the first chat model', () => {
expect(pickOllamaChatModel(['nomic-embed-text:latest', 'llama3'])).toBe('llama3');
});

it('returns null when all models are embeddings', () => {
expect(pickOllamaChatModel(['nomic-embed-text:latest', 'mxbai-embed-large'])).toBeNull();
});

it('returns the first non-embedding model', () => {
expect(pickOllamaChatModel(['qwen2.5-coder:1.5b', 'llama3'])).toBe('qwen2.5-coder:1.5b');
});
});

describe('loadConfig', () => {
let tmpDir: string;

Expand Down
27 changes: 19 additions & 8 deletions agent-refactor/src/providerDetector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ const DEFAULT_MODELS: Record<string, string> = {

const OLLAMA_DEFAULT_URL = 'http://localhost:11434';

const EMBEDDING_MODEL_PATTERN =
/embed|minilm|mxbai|bge[-_]|gte[-_]|nomic|snowflake-arctic|e5[-_]|clip$/i;

export function pickOllamaChatModel(models: string[]): string | null {
const chatModel = models.find((m) => !EMBEDDING_MODEL_PATTERN.test(m));
return chatModel ?? null;
}

export async function detectProvider(options: DetectOptions = {}): Promise<ProviderConfig | null> {
const env = options.env ?? process.env;
const ollamaBaseUrl = options.ollamaBaseUrl ?? OLLAMA_DEFAULT_URL;
Expand Down Expand Up @@ -69,14 +77,17 @@ export async function detectProvider(options: DetectOptions = {}): Promise<Provi

const ollamaModels = await detectOllama(ollamaBaseUrl);
if (ollamaModels && ollamaModels.length > 0) {
const model = ollamaModels[0];
return {
provider: 'ollama',
model,
baseUrl: ollamaBaseUrl,
autoDetected: true,
detectedAt: new Date().toISOString(),
};
const model = pickOllamaChatModel(ollamaModels);
if (model) {
return {
provider: 'ollama',
model,
baseUrl: ollamaBaseUrl,
autoDetected: true,
detectedAt: new Date().toISOString(),
};
}
return null;
}

if (ollamaModels === null) {
Expand Down
50 changes: 50 additions & 0 deletions agent-refactor/tests/providerDetector.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import os from 'os';
import {
detectProvider,
detectOllama,
pickOllamaChatModel,
loadConfig,
saveConfig,
getDefaultModel,
Expand Down Expand Up @@ -60,6 +61,37 @@ describe('providerDetector', () => {
}
});

it('skips embedding models and picks a chat-capable Ollama model', async () => {
const originalFetch = globalThis.fetch;
globalThis.fetch = vi.fn().mockResolvedValue({
ok: true,
json: async () => ({ models: [{ name: 'nomic-embed-text:latest' }, { name: 'llama3' }] }),
} as any);
try {
const result = await detectProvider({ env: {} });
expect(result).not.toBeNull();
expect(result!.provider).toBe('ollama');
expect(result!.model).toBe('llama3');
expect(result!.baseUrl).toBe('http://localhost:11434');
} finally {
globalThis.fetch = originalFetch;
}
});

it('returns null when Ollama only has embedding models', async () => {
const originalFetch = globalThis.fetch;
globalThis.fetch = vi.fn().mockResolvedValue({
ok: true,
json: async () => ({ models: [{ name: 'nomic-embed-text:latest' }] }),
} as any);
try {
const result = await detectProvider({ env: {} });
expect(result).toBeNull();
} finally {
globalThis.fetch = originalFetch;
}
});

it('returns null when nothing is available', async () => {
const originalFetch = globalThis.fetch;
globalThis.fetch = vi.fn().mockRejectedValue(new Error('Connection refused'));
Expand Down Expand Up @@ -144,6 +176,24 @@ describe('providerDetector', () => {
});
});

describe('pickOllamaChatModel', () => {
it('returns null for an empty list', () => {
expect(pickOllamaChatModel([])).toBeNull();
});

it('skips embedding models and picks the first chat model', () => {
expect(pickOllamaChatModel(['nomic-embed-text:latest', 'llama3'])).toBe('llama3');
});

it('returns null when all models are embeddings', () => {
expect(pickOllamaChatModel(['nomic-embed-text:latest', 'mxbai-embed-large'])).toBeNull();
});

it('returns the first non-embedding model', () => {
expect(pickOllamaChatModel(['qwen2.5-coder:1.5b', 'llama3'])).toBe('qwen2.5-coder:1.5b');
});
});

describe('loadConfig', () => {
let tmpDir: string;

Expand Down
27 changes: 19 additions & 8 deletions agent-security-audit/src/providerDetector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ const DEFAULT_MODELS: Record<string, string> = {

const OLLAMA_DEFAULT_URL = 'http://localhost:11434';

const EMBEDDING_MODEL_PATTERN =
/embed|minilm|mxbai|bge[-_]|gte[-_]|nomic|snowflake-arctic|e5[-_]|clip$/i;

export function pickOllamaChatModel(models: string[]): string | null {
const chatModel = models.find((m) => !EMBEDDING_MODEL_PATTERN.test(m));
return chatModel ?? null;
}

export async function detectProvider(options: DetectOptions = {}): Promise<ProviderConfig | null> {
const env = options.env ?? process.env;
const ollamaBaseUrl = options.ollamaBaseUrl ?? OLLAMA_DEFAULT_URL;
Expand Down Expand Up @@ -69,14 +77,17 @@ export async function detectProvider(options: DetectOptions = {}): Promise<Provi

const ollamaModels = await detectOllama(ollamaBaseUrl);
if (ollamaModels && ollamaModels.length > 0) {
const model = ollamaModels[0];
return {
provider: 'ollama',
model,
baseUrl: ollamaBaseUrl,
autoDetected: true,
detectedAt: new Date().toISOString(),
};
const model = pickOllamaChatModel(ollamaModels);
if (model) {
return {
provider: 'ollama',
model,
baseUrl: ollamaBaseUrl,
autoDetected: true,
detectedAt: new Date().toISOString(),
};
}
return null;
}

if (ollamaModels === null) {
Expand Down
Loading
Loading