0d3cb498a3
CI / Shell Format Check (push) Has been cancelled
CI / Check Ruby (3.4) (push) Has been cancelled
CI / CI Config (push) Has been cancelled
CI / Test on Node ${{ matrix.node }} and ${{ matrix.os }}${{ matrix.shard && format(' (shard {0}/3)', matrix.shard) || '' }} (push) Has been cancelled
CI / Build on Node ${{ matrix.node }} (push) Has been cancelled
CI / Style Check (push) Has been cancelled
CI / Generate Assets (push) Has been cancelled
CI / Check Python (3.14) (push) Has been cancelled
CI / Check Python (3.9) (push) Has been cancelled
CI / Build Docs (push) Has been cancelled
CI / Code Scan Action (push) Has been cancelled
CI / Site tests (push) Has been cancelled
CI / webui tests (push) Has been cancelled
CI / Run Integration Tests (push) Has been cancelled
CI / Run Smoke Tests (push) Has been cancelled
CI / Go Tests (push) Has been cancelled
CI / Share Test (push) Has been cancelled
CI / Redteam (Production API) (push) Has been cancelled
CI / Redteam (Staging API) (push) Has been cancelled
CI / GitHub Actions Lint (push) Has been cancelled
CI / Check Ruby (3.0) (push) Has been cancelled
release-please / release-please (push) Has been cancelled
release-please / build (push) Has been cancelled
release-please / publish-npm (push) Has been cancelled
release-please / publish-npm-backfill (push) Has been cancelled
release-please / docker (push) Has been cancelled
release-please / publish-code-scan-action (push) Has been cancelled
release-please / attest-code-scan-action (push) Has been cancelled
Deploy local.promptfoo.app / Deploy to Cloudflare Pages (push) Has been cancelled
Test and Publish Multi-arch Docker Image / test (push) Has been cancelled
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-amd64 platform:linux/amd64 runner:ubuntu-latest]) (push) Has been cancelled
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-arm64 platform:linux/arm64 runner:ubuntu-24.04-arm]) (push) Has been cancelled
Test and Publish Multi-arch Docker Image / merge-docker-digests (push) Has been cancelled
Test and Publish Multi-arch Docker Image / Attest Multi-arch Image (push) Has been cancelled
Validate Renovate Config / Validate Renovate Configuration (push) Has been cancelled
762 lines
22 KiB
TypeScript
762 lines
22 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
import { fetchWithCache } from '../../src/cache';
|
|
import {
|
|
OllamaChatProvider,
|
|
OllamaCompletionProvider,
|
|
OllamaEmbeddingProvider,
|
|
} from '../../src/providers/ollama';
|
|
|
|
import type { CallApiContextParams } from '../../src/types/index';
|
|
|
|
vi.mock('../../src/cache');
|
|
|
|
describe('OllamaCompletionProvider', () => {
|
|
beforeEach(() => {
|
|
vi.resetAllMocks();
|
|
});
|
|
|
|
it('should construct with model name and options', () => {
|
|
const provider = new OllamaCompletionProvider('llama3.3', {
|
|
id: 'custom-id',
|
|
config: { temperature: 0.7 },
|
|
});
|
|
expect(provider.modelName).toBe('llama3.3');
|
|
expect(provider.config.temperature).toBe(0.7);
|
|
expect(provider.id()).toBe('custom-id');
|
|
});
|
|
|
|
it('should call API and return response', async () => {
|
|
const mockResponse = {
|
|
data: '{"response":"test response","done":true}\n',
|
|
cached: false,
|
|
status: 200,
|
|
statusText: 'OK',
|
|
headers: {},
|
|
};
|
|
|
|
vi.mocked(fetchWithCache).mockResolvedValue(mockResponse);
|
|
|
|
const provider = new OllamaCompletionProvider('llama3.3');
|
|
const result = await provider.callApi('test prompt');
|
|
|
|
expect(result).toEqual({
|
|
output: 'test response',
|
|
});
|
|
});
|
|
|
|
it('should handle multiple response chunks', async () => {
|
|
const mockResponse = {
|
|
data: '{"response":"test response","done":false}\n{"response":" more","done":true}\n',
|
|
cached: false,
|
|
status: 200,
|
|
statusText: 'OK',
|
|
headers: {},
|
|
};
|
|
|
|
vi.mocked(fetchWithCache).mockResolvedValue(mockResponse);
|
|
|
|
const provider = new OllamaCompletionProvider('llama3.3');
|
|
const result = await provider.callApi('test prompt');
|
|
|
|
expect(result).toEqual({
|
|
output: 'test response more',
|
|
});
|
|
});
|
|
|
|
it('should handle API errors', async () => {
|
|
vi.mocked(fetchWithCache).mockRejectedValue(new Error('API error'));
|
|
|
|
const provider = new OllamaCompletionProvider('llama3.3');
|
|
const result = await provider.callApi('test prompt');
|
|
|
|
expect(result.error).toContain('API call error: Error: API error');
|
|
});
|
|
|
|
it('should handle API response with error field', async () => {
|
|
const mockResponse = {
|
|
data: { error: 'some error occurred' },
|
|
cached: false,
|
|
status: 200,
|
|
statusText: 'OK',
|
|
headers: {},
|
|
};
|
|
|
|
vi.mocked(fetchWithCache).mockResolvedValue(mockResponse);
|
|
|
|
const provider = new OllamaCompletionProvider('llama3.3');
|
|
const result = await provider.callApi('test prompt');
|
|
|
|
expect(result.error).toBe('Ollama error: some error occurred');
|
|
});
|
|
|
|
it('should handle invalid JSON response', async () => {
|
|
const mockResponse = {
|
|
data: 'invalid json',
|
|
cached: false,
|
|
status: 200,
|
|
statusText: 'OK',
|
|
headers: {},
|
|
};
|
|
|
|
vi.mocked(fetchWithCache).mockResolvedValue(mockResponse);
|
|
|
|
const provider = new OllamaCompletionProvider('llama3.3');
|
|
const result = await provider.callApi('test prompt');
|
|
|
|
expect(result.error).toContain('Ollama API response error:');
|
|
});
|
|
|
|
it('should use default id when not provided', () => {
|
|
const provider = new OllamaCompletionProvider('llama3.3');
|
|
expect(provider.id()).toBe('ollama:completion:llama3.3');
|
|
});
|
|
|
|
it('should handle toString method', () => {
|
|
const provider = new OllamaCompletionProvider('llama3.3');
|
|
expect(provider.toString()).toBe('[Ollama Completion Provider llama3.3]');
|
|
});
|
|
|
|
it('should extract token usage from response', async () => {
|
|
const mockResponse = {
|
|
data: '{"response":"test response","done":false,"prompt_eval_count":26}\n{"response":" more","done":true,"prompt_eval_count":26,"eval_count":259}\n',
|
|
cached: false,
|
|
status: 200,
|
|
statusText: 'OK',
|
|
headers: {},
|
|
};
|
|
|
|
vi.mocked(fetchWithCache).mockResolvedValue(mockResponse);
|
|
|
|
const provider = new OllamaCompletionProvider('llama3.3');
|
|
const result = await provider.callApi('test prompt');
|
|
|
|
expect(result).toEqual({
|
|
output: 'test response more',
|
|
tokenUsage: {
|
|
prompt: 26,
|
|
completion: 259,
|
|
total: 285,
|
|
},
|
|
});
|
|
});
|
|
|
|
it('should handle missing token usage gracefully', async () => {
|
|
const mockResponse = {
|
|
data: '{"response":"test response","done":true}\n',
|
|
cached: false,
|
|
status: 200,
|
|
statusText: 'OK',
|
|
headers: {},
|
|
};
|
|
|
|
vi.mocked(fetchWithCache).mockResolvedValue(mockResponse);
|
|
|
|
const provider = new OllamaCompletionProvider('llama3.3');
|
|
const result = await provider.callApi('test prompt');
|
|
|
|
expect(result).toEqual({
|
|
output: 'test response',
|
|
});
|
|
});
|
|
|
|
it('should handle partial token usage (only prompt_eval_count)', async () => {
|
|
const mockResponse = {
|
|
data: '{"response":"test response","done":true,"prompt_eval_count":26}\n',
|
|
cached: false,
|
|
status: 200,
|
|
statusText: 'OK',
|
|
headers: {},
|
|
};
|
|
|
|
vi.mocked(fetchWithCache).mockResolvedValue(mockResponse);
|
|
|
|
const provider = new OllamaCompletionProvider('llama3.3');
|
|
const result = await provider.callApi('test prompt');
|
|
|
|
expect(result).toEqual({
|
|
output: 'test response',
|
|
tokenUsage: {
|
|
prompt: 26,
|
|
completion: 0,
|
|
total: 26,
|
|
},
|
|
});
|
|
});
|
|
|
|
it('should handle partial token usage (only eval_count)', async () => {
|
|
const mockResponse = {
|
|
data: '{"response":"test response","done":true,"eval_count":259}\n',
|
|
cached: false,
|
|
status: 200,
|
|
statusText: 'OK',
|
|
headers: {},
|
|
};
|
|
|
|
vi.mocked(fetchWithCache).mockResolvedValue(mockResponse);
|
|
|
|
const provider = new OllamaCompletionProvider('llama3.3');
|
|
const result = await provider.callApi('test prompt');
|
|
|
|
expect(result).toEqual({
|
|
output: 'test response',
|
|
tokenUsage: {
|
|
prompt: 0,
|
|
completion: 259,
|
|
total: 259,
|
|
},
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('OllamaChatProvider', () => {
|
|
beforeEach(() => {
|
|
vi.resetAllMocks();
|
|
});
|
|
|
|
it('should construct with model name and options', () => {
|
|
const provider = new OllamaChatProvider('llama3.3', {
|
|
id: 'custom-id',
|
|
config: { temperature: 0.7 },
|
|
});
|
|
expect(provider.modelName).toBe('llama3.3');
|
|
expect(provider.config.temperature).toBe(0.7);
|
|
expect(provider.id()).toBe('custom-id');
|
|
});
|
|
|
|
it('should call chat API and return response', async () => {
|
|
const mockResponse = {
|
|
data: '{"message":{"role":"assistant","content":"test response","images":null},"done":true}\n',
|
|
cached: false,
|
|
status: 200,
|
|
statusText: 'OK',
|
|
headers: {},
|
|
};
|
|
|
|
vi.mocked(fetchWithCache).mockResolvedValue(mockResponse);
|
|
|
|
const provider = new OllamaChatProvider('llama3.3');
|
|
const result = await provider.callApi('test prompt');
|
|
|
|
expect(result).toEqual({
|
|
output: 'test response',
|
|
});
|
|
});
|
|
|
|
it('should handle multiple chat response chunks', async () => {
|
|
const mockResponse = {
|
|
data: '{"message":{"role":"assistant","content":"test response","images":null},"done":false}\n{"message":{"role":"assistant","content":" more","images":null},"done":true}\n',
|
|
cached: false,
|
|
status: 200,
|
|
statusText: 'OK',
|
|
headers: {},
|
|
};
|
|
|
|
vi.mocked(fetchWithCache).mockResolvedValue(mockResponse);
|
|
|
|
const provider = new OllamaChatProvider('llama3.3');
|
|
const result = await provider.callApi('test prompt');
|
|
|
|
expect(result).toEqual({
|
|
output: 'test response more',
|
|
});
|
|
});
|
|
|
|
it('should handle chat API errors', async () => {
|
|
vi.mocked(fetchWithCache).mockRejectedValue(new Error('API error'));
|
|
|
|
const provider = new OllamaChatProvider('llama3.3');
|
|
const result = await provider.callApi('test prompt');
|
|
|
|
expect(result.error).toContain('API call error: Error: API error');
|
|
});
|
|
|
|
it('should handle chat API response with error field', async () => {
|
|
const mockResponse = {
|
|
data: { error: 'chat error occurred' },
|
|
cached: false,
|
|
status: 200,
|
|
statusText: 'OK',
|
|
headers: {},
|
|
};
|
|
|
|
vi.mocked(fetchWithCache).mockResolvedValue(mockResponse);
|
|
|
|
const provider = new OllamaChatProvider('llama3.3');
|
|
const result = await provider.callApi('test prompt');
|
|
|
|
expect(result.error).toBe('Ollama error: chat error occurred');
|
|
});
|
|
|
|
it('should handle invalid JSON response', async () => {
|
|
const mockResponse = {
|
|
data: 'invalid json',
|
|
cached: false,
|
|
status: 200,
|
|
statusText: 'OK',
|
|
headers: {},
|
|
};
|
|
|
|
vi.mocked(fetchWithCache).mockResolvedValue(mockResponse);
|
|
|
|
const provider = new OllamaChatProvider('llama3.3');
|
|
const result = await provider.callApi('test prompt');
|
|
|
|
expect(result.error).toContain('Ollama API response error:');
|
|
});
|
|
|
|
it('should use default id when not provided', () => {
|
|
const provider = new OllamaChatProvider('llama3.3');
|
|
expect(provider.id()).toBe('ollama:chat:llama3.3');
|
|
});
|
|
|
|
it('should handle toString method', () => {
|
|
const provider = new OllamaChatProvider('llama3.3');
|
|
expect(provider.toString()).toBe('[Ollama Chat Provider llama3.3]');
|
|
});
|
|
|
|
it('should handle think configuration when it is not provided', async () => {
|
|
const provider = new OllamaCompletionProvider('llama3.3');
|
|
const mockResponse = {
|
|
data: '',
|
|
cached: false,
|
|
status: 200,
|
|
statusText: 'OK',
|
|
headers: {},
|
|
};
|
|
|
|
vi.mocked(fetchWithCache).mockResolvedValue(mockResponse);
|
|
|
|
await provider.callApi('test prompt');
|
|
|
|
expect(vi.mocked(fetchWithCache).mock.calls[0]).toBeDefined();
|
|
const call = vi.mocked(fetchWithCache).mock.calls[0] as any;
|
|
expect(JSON.parse(call[1].body).think).toBeFalsy();
|
|
});
|
|
|
|
it('should handle think configuration when it is false', async () => {
|
|
const provider = new OllamaCompletionProvider('llama3.3', {
|
|
config: {
|
|
think: false,
|
|
},
|
|
});
|
|
const mockResponse = {
|
|
data: '',
|
|
cached: false,
|
|
status: 200,
|
|
statusText: 'OK',
|
|
headers: {},
|
|
};
|
|
|
|
vi.mocked(fetchWithCache).mockResolvedValue(mockResponse);
|
|
|
|
await provider.callApi('test prompt');
|
|
|
|
expect(vi.mocked(fetchWithCache).mock.calls[0]).toBeDefined();
|
|
const call = vi.mocked(fetchWithCache).mock.calls[0] as any;
|
|
expect(JSON.parse(call[1].body).think).toBeFalsy();
|
|
});
|
|
|
|
it('should handle think configuration when it is true', async () => {
|
|
const provider = new OllamaCompletionProvider('llama3.3', {
|
|
config: {
|
|
think: true,
|
|
},
|
|
});
|
|
const mockResponse = {
|
|
data: '',
|
|
cached: false,
|
|
status: 200,
|
|
statusText: 'OK',
|
|
headers: {},
|
|
};
|
|
|
|
vi.mocked(fetchWithCache).mockResolvedValue(mockResponse);
|
|
|
|
await provider.callApi('test prompt');
|
|
|
|
expect(vi.mocked(fetchWithCache).mock.calls[0]).toBeDefined();
|
|
const call = vi.mocked(fetchWithCache).mock.calls[0] as any;
|
|
expect(JSON.parse(call[1].body).think).toBeTruthy();
|
|
});
|
|
|
|
it('should handle tools configuration', async () => {
|
|
const provider = new OllamaChatProvider('llama3.3', {
|
|
config: {
|
|
tools: [{ name: 'test-tool' }],
|
|
},
|
|
});
|
|
const mockResponse = {
|
|
data: '{"message":{"role":"assistant","content":"test response","images":null},"done":true}\n',
|
|
cached: false,
|
|
status: 200,
|
|
statusText: 'OK',
|
|
headers: {},
|
|
};
|
|
|
|
vi.mocked(fetchWithCache).mockResolvedValue(mockResponse);
|
|
|
|
const context: CallApiContextParams = {
|
|
prompt: { raw: 'test prompt', label: 'test' },
|
|
vars: { test: 'value' },
|
|
debug: true,
|
|
};
|
|
|
|
await provider.callApi('test prompt', context);
|
|
|
|
expect(vi.mocked(fetchWithCache).mock.calls[0]).toBeDefined();
|
|
const call = vi.mocked(fetchWithCache).mock.calls[0] as any;
|
|
expect(JSON.parse(call[1].body)).toMatchObject({
|
|
tools: [{ name: 'test-tool' }],
|
|
});
|
|
expect(call[4]).toBe(true);
|
|
});
|
|
|
|
it('should handle context bustCache parameter', async () => {
|
|
const provider = new OllamaChatProvider('llama3.3');
|
|
const mockResponse = {
|
|
data: '{"message":{"role":"assistant","content":"test response","images":null},"done":true}\n',
|
|
cached: false,
|
|
status: 200,
|
|
statusText: 'OK',
|
|
headers: {},
|
|
};
|
|
|
|
vi.mocked(fetchWithCache).mockResolvedValue(mockResponse);
|
|
|
|
const context: CallApiContextParams = {
|
|
prompt: { raw: 'test prompt', label: 'test' },
|
|
vars: {},
|
|
bustCache: true,
|
|
};
|
|
|
|
await provider.callApi('test prompt', context);
|
|
|
|
expect(vi.mocked(fetchWithCache).mock.calls[0]).toBeDefined();
|
|
const call = vi.mocked(fetchWithCache).mock.calls[0] as any;
|
|
expect(call[4]).toBe(true);
|
|
});
|
|
|
|
it('should extract token usage from chat response', async () => {
|
|
const mockResponse = {
|
|
data: '{"message":{"role":"assistant","content":"test response","images":null},"done":false,"prompt_eval_count":26}\n{"message":{"role":"assistant","content":" more","images":null},"done":true,"prompt_eval_count":26,"eval_count":259}\n',
|
|
cached: false,
|
|
status: 200,
|
|
statusText: 'OK',
|
|
headers: {},
|
|
};
|
|
|
|
vi.mocked(fetchWithCache).mockResolvedValue(mockResponse);
|
|
|
|
const provider = new OllamaChatProvider('llama3.3');
|
|
const result = await provider.callApi('test prompt');
|
|
|
|
expect(result).toEqual({
|
|
output: 'test response more',
|
|
tokenUsage: {
|
|
prompt: 26,
|
|
completion: 259,
|
|
total: 285,
|
|
},
|
|
});
|
|
});
|
|
|
|
it('should handle missing token usage gracefully in chat', async () => {
|
|
const mockResponse = {
|
|
data: '{"message":{"role":"assistant","content":"test response","images":null},"done":true}\n',
|
|
cached: false,
|
|
status: 200,
|
|
statusText: 'OK',
|
|
headers: {},
|
|
};
|
|
|
|
vi.mocked(fetchWithCache).mockResolvedValue(mockResponse);
|
|
|
|
const provider = new OllamaChatProvider('llama3.3');
|
|
const result = await provider.callApi('test prompt');
|
|
|
|
expect(result).toEqual({
|
|
output: 'test response',
|
|
});
|
|
});
|
|
|
|
it('should handle partial token usage in chat (only prompt_eval_count)', async () => {
|
|
const mockResponse = {
|
|
data: '{"message":{"role":"assistant","content":"test response","images":null},"done":true,"prompt_eval_count":26}\n',
|
|
cached: false,
|
|
status: 200,
|
|
statusText: 'OK',
|
|
headers: {},
|
|
};
|
|
|
|
vi.mocked(fetchWithCache).mockResolvedValue(mockResponse);
|
|
|
|
const provider = new OllamaChatProvider('llama3.3');
|
|
const result = await provider.callApi('test prompt');
|
|
|
|
expect(result).toEqual({
|
|
output: 'test response',
|
|
tokenUsage: {
|
|
prompt: 26,
|
|
completion: 0,
|
|
total: 26,
|
|
},
|
|
});
|
|
});
|
|
|
|
it('should handle partial token usage in chat (only eval_count)', async () => {
|
|
const mockResponse = {
|
|
data: '{"message":{"role":"assistant","content":"test response","images":null},"done":true,"eval_count":259}\n',
|
|
cached: false,
|
|
status: 200,
|
|
statusText: 'OK',
|
|
headers: {},
|
|
};
|
|
|
|
vi.mocked(fetchWithCache).mockResolvedValue(mockResponse);
|
|
|
|
const provider = new OllamaChatProvider('llama3.3');
|
|
const result = await provider.callApi('test prompt');
|
|
|
|
expect(result).toEqual({
|
|
output: 'test response',
|
|
tokenUsage: {
|
|
prompt: 0,
|
|
completion: 259,
|
|
total: 259,
|
|
},
|
|
});
|
|
});
|
|
|
|
it('should handle tool calls in response', async () => {
|
|
const mockResponse = {
|
|
data: '{"message":{"role":"assistant","content":"","images":null,"tool_calls":[{"function":{"name":"get_weather","arguments":"{\\"location\\":\\"Amsterdam\\",\\"unit\\":\\"celsius\\"}"}}]},"done":true}\n',
|
|
cached: false,
|
|
status: 200,
|
|
statusText: 'OK',
|
|
headers: {},
|
|
};
|
|
|
|
vi.mocked(fetchWithCache).mockResolvedValue(mockResponse);
|
|
|
|
const provider = new OllamaChatProvider('llama3.3', {
|
|
config: {
|
|
tools: [
|
|
{
|
|
type: 'function',
|
|
function: {
|
|
name: 'get_weather',
|
|
description: 'Get current weather for a location',
|
|
parameters: {
|
|
type: 'object',
|
|
properties: {
|
|
location: {
|
|
type: 'string',
|
|
description: 'City and state, e.g. San Francisco, CA',
|
|
},
|
|
unit: {
|
|
type: 'string',
|
|
enum: ['celsius', 'fahrenheit'],
|
|
},
|
|
},
|
|
required: ['location'],
|
|
},
|
|
},
|
|
},
|
|
],
|
|
},
|
|
});
|
|
|
|
const result = await provider.callApi('What is the weather in Amsterdam?');
|
|
|
|
expect(result.output).toEqual([
|
|
{
|
|
function: {
|
|
name: 'get_weather',
|
|
arguments: '{"location":"Amsterdam","unit":"celsius"}',
|
|
},
|
|
},
|
|
]);
|
|
});
|
|
|
|
it('should handle tool calls with content in response', async () => {
|
|
const mockResponse = {
|
|
data: '{"message":{"role":"assistant","content":"Let me check the weather for you.","images":null,"tool_calls":[{"function":{"name":"get_weather","arguments":"{\\"location\\":\\"Amsterdam\\",\\"unit\\":\\"celsius\\"}"}}]},"done":true}\n',
|
|
cached: false,
|
|
status: 200,
|
|
statusText: 'OK',
|
|
headers: {},
|
|
};
|
|
|
|
vi.mocked(fetchWithCache).mockResolvedValue(mockResponse);
|
|
|
|
const provider = new OllamaChatProvider('llama3.3', {
|
|
config: {
|
|
tools: [
|
|
{
|
|
type: 'function',
|
|
function: {
|
|
name: 'get_weather',
|
|
description: 'Get current weather for a location',
|
|
parameters: {
|
|
type: 'object',
|
|
properties: {
|
|
location: {
|
|
type: 'string',
|
|
description: 'City and state, e.g. San Francisco, CA',
|
|
},
|
|
unit: {
|
|
type: 'string',
|
|
enum: ['celsius', 'fahrenheit'],
|
|
},
|
|
},
|
|
required: ['location'],
|
|
},
|
|
},
|
|
},
|
|
],
|
|
},
|
|
});
|
|
|
|
const result = await provider.callApi('What is the weather in Amsterdam?');
|
|
|
|
expect(result.output).toEqual({
|
|
content: 'Let me check the weather for you.',
|
|
tool_calls: [
|
|
{
|
|
function: {
|
|
name: 'get_weather',
|
|
arguments: '{"location":"Amsterdam","unit":"celsius"}',
|
|
},
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('should handle multiple tool calls in response', async () => {
|
|
const mockResponse = {
|
|
data: '{"message":{"role":"assistant","content":"","images":null,"tool_calls":[{"function":{"name":"get_weather","arguments":"{\\"location\\":\\"Amsterdam\\",\\"unit\\":\\"celsius\\"}"}},{"function":{"name":"get_weather","arguments":"{\\"location\\":\\"Paris\\",\\"unit\\":\\"celsius\\"}"}}]},"done":true}\n',
|
|
cached: false,
|
|
status: 200,
|
|
statusText: 'OK',
|
|
headers: {},
|
|
};
|
|
|
|
vi.mocked(fetchWithCache).mockResolvedValue(mockResponse);
|
|
|
|
const provider = new OllamaChatProvider('llama3.3', {
|
|
config: {
|
|
tools: [
|
|
{
|
|
type: 'function',
|
|
function: {
|
|
name: 'get_weather',
|
|
description: 'Get current weather for a location',
|
|
parameters: {
|
|
type: 'object',
|
|
properties: {
|
|
location: {
|
|
type: 'string',
|
|
description: 'City and state, e.g. San Francisco, CA',
|
|
},
|
|
unit: {
|
|
type: 'string',
|
|
enum: ['celsius', 'fahrenheit'],
|
|
},
|
|
},
|
|
required: ['location'],
|
|
},
|
|
},
|
|
},
|
|
],
|
|
},
|
|
});
|
|
|
|
const result = await provider.callApi('Compare weather in Amsterdam and Paris');
|
|
|
|
expect(result.output).toEqual([
|
|
{
|
|
function: {
|
|
name: 'get_weather',
|
|
arguments: '{"location":"Amsterdam","unit":"celsius"}',
|
|
},
|
|
},
|
|
{
|
|
function: {
|
|
name: 'get_weather',
|
|
arguments: '{"location":"Paris","unit":"celsius"}',
|
|
},
|
|
},
|
|
]);
|
|
});
|
|
});
|
|
|
|
describe('OllamaEmbeddingProvider', () => {
|
|
beforeEach(() => {
|
|
vi.resetAllMocks();
|
|
});
|
|
|
|
it('should call embeddings API and return response', async () => {
|
|
const mockResponse = {
|
|
data: {
|
|
embedding: [0.1, 0.2, 0.3],
|
|
},
|
|
cached: false,
|
|
status: 200,
|
|
statusText: 'OK',
|
|
headers: {},
|
|
};
|
|
|
|
vi.mocked(fetchWithCache).mockResolvedValue(mockResponse);
|
|
|
|
const provider = new OllamaEmbeddingProvider('llama3.3');
|
|
const result = await provider.callEmbeddingApi('test text');
|
|
|
|
expect(result).toEqual({
|
|
embedding: [0.1, 0.2, 0.3],
|
|
});
|
|
});
|
|
|
|
it('should handle embeddings API errors', async () => {
|
|
vi.mocked(fetchWithCache).mockRejectedValue(new Error('API error'));
|
|
|
|
const provider = new OllamaEmbeddingProvider('llama3.3');
|
|
const result = await provider.callEmbeddingApi('test text');
|
|
|
|
expect(result.error).toBe('API call error: Error: API error');
|
|
});
|
|
|
|
it('should handle missing embedding in response', async () => {
|
|
const mockResponse = {
|
|
data: {},
|
|
cached: false,
|
|
status: 200,
|
|
statusText: 'OK',
|
|
headers: {},
|
|
};
|
|
|
|
vi.mocked(fetchWithCache).mockResolvedValue(mockResponse);
|
|
|
|
const provider = new OllamaEmbeddingProvider('llama3.3');
|
|
const result = await provider.callEmbeddingApi('test text');
|
|
|
|
expect(result.error).toContain('No embedding found in Ollama embeddings API response');
|
|
});
|
|
|
|
it('should handle invalid JSON response', async () => {
|
|
const mockResponse = {
|
|
data: 'invalid json',
|
|
cached: false,
|
|
status: 200,
|
|
statusText: 'OK',
|
|
headers: {},
|
|
};
|
|
|
|
vi.mocked(fetchWithCache).mockResolvedValue(mockResponse);
|
|
|
|
const provider = new OllamaEmbeddingProvider('llama3.3');
|
|
const result = await provider.callEmbeddingApi('test text');
|
|
|
|
expect(result.error).toContain('API response error:');
|
|
});
|
|
});
|