chore: import upstream snapshot with attribution
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
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
This commit is contained in:
@@ -0,0 +1,239 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { clearCache } from '../../src/cache';
|
||||
import { DatabricksMosaicAiChatCompletionProvider } from '../../src/providers/databricks';
|
||||
import { OpenAiChatCompletionProvider } from '../../src/providers/openai/chat';
|
||||
import { mockProcessEnv } from '../util/utils';
|
||||
|
||||
import type { DatabricksMosaicAiProviderOptions } from '../../src/providers/databricks';
|
||||
|
||||
vi.mock('../../src/logger');
|
||||
|
||||
describe('Databricks Foundation Model APIs Provider', () => {
|
||||
const originalEnv = { ...process.env };
|
||||
const workspaceUrl = 'https://test-workspace.cloud.databricks.com';
|
||||
const defaultOptions: DatabricksMosaicAiProviderOptions = {
|
||||
config: {
|
||||
workspaceUrl,
|
||||
},
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
mockProcessEnv({ ...originalEnv }, { clear: true });
|
||||
mockProcessEnv({ DATABRICKS_WORKSPACE_URL: undefined });
|
||||
mockProcessEnv({ DATABRICKS_TOKEN: undefined });
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await clearCache();
|
||||
mockProcessEnv(originalEnv, { clear: true });
|
||||
});
|
||||
|
||||
describe('DatabricksMosaicAiChatCompletionProvider', () => {
|
||||
it('should create provider for a custom deployed endpoint', () => {
|
||||
const provider = new DatabricksMosaicAiChatCompletionProvider(
|
||||
'my-custom-endpoint',
|
||||
defaultOptions,
|
||||
);
|
||||
|
||||
expect(provider).toBeInstanceOf(OpenAiChatCompletionProvider);
|
||||
expect(provider.config.apiBaseUrl).toBe(`${workspaceUrl}/serving-endpoints`);
|
||||
expect(provider.config.apiKeyEnvar).toBe('DATABRICKS_TOKEN');
|
||||
});
|
||||
|
||||
it('should create provider for a pay-per-token endpoint', () => {
|
||||
const options: DatabricksMosaicAiProviderOptions = {
|
||||
config: {
|
||||
workspaceUrl,
|
||||
isPayPerToken: true,
|
||||
},
|
||||
};
|
||||
const provider = new DatabricksMosaicAiChatCompletionProvider(
|
||||
'databricks-meta-llama-3-3-70b-instruct',
|
||||
options,
|
||||
);
|
||||
|
||||
expect(provider).toBeInstanceOf(OpenAiChatCompletionProvider);
|
||||
expect(provider.config.apiBaseUrl).toBe(workspaceUrl);
|
||||
expect(provider.config.apiKeyEnvar).toBe('DATABRICKS_TOKEN');
|
||||
});
|
||||
|
||||
it('should create provider with workspace URL from environment variable', () => {
|
||||
mockProcessEnv({ DATABRICKS_WORKSPACE_URL: workspaceUrl });
|
||||
|
||||
const options: DatabricksMosaicAiProviderOptions = {
|
||||
config: {},
|
||||
};
|
||||
const provider = new DatabricksMosaicAiChatCompletionProvider('my-endpoint', options);
|
||||
|
||||
expect(provider).toBeInstanceOf(OpenAiChatCompletionProvider);
|
||||
expect(provider.config.apiBaseUrl).toBe(`${workspaceUrl}/serving-endpoints`);
|
||||
expect(provider.config.apiKeyEnvar).toBe('DATABRICKS_TOKEN');
|
||||
});
|
||||
|
||||
it('should strip trailing slash from workspace URL', () => {
|
||||
const options: DatabricksMosaicAiProviderOptions = {
|
||||
config: {
|
||||
workspaceUrl: `${workspaceUrl}/`,
|
||||
},
|
||||
};
|
||||
const provider = new DatabricksMosaicAiChatCompletionProvider('my-endpoint', options);
|
||||
|
||||
expect(provider.config.apiBaseUrl).toBe(`${workspaceUrl}/serving-endpoints`);
|
||||
});
|
||||
|
||||
it('should throw error when no workspace URL is provided', () => {
|
||||
const options: DatabricksMosaicAiProviderOptions = {
|
||||
config: {},
|
||||
};
|
||||
expect(() => new DatabricksMosaicAiChatCompletionProvider('my-endpoint', options)).toThrow(
|
||||
'Databricks workspace URL is required. Set it in the config or DATABRICKS_WORKSPACE_URL environment variable.',
|
||||
);
|
||||
});
|
||||
|
||||
it('should pass through environment variables', () => {
|
||||
const options: DatabricksMosaicAiProviderOptions = {
|
||||
config: {
|
||||
workspaceUrl,
|
||||
},
|
||||
env: {
|
||||
DATABRICKS_TOKEN: 'test-token',
|
||||
},
|
||||
};
|
||||
const provider = new DatabricksMosaicAiChatCompletionProvider('my-endpoint', options);
|
||||
|
||||
expect(provider).toBeInstanceOf(OpenAiChatCompletionProvider);
|
||||
// The env is passed to the parent constructor, check it's accessible
|
||||
expect((provider as any).env).toEqual(
|
||||
expect.objectContaining({
|
||||
DATABRICKS_TOKEN: 'test-token',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should pass through OpenAI configuration options', () => {
|
||||
const options: DatabricksMosaicAiProviderOptions = {
|
||||
config: {
|
||||
workspaceUrl,
|
||||
temperature: 0.7,
|
||||
max_tokens: 100,
|
||||
top_p: 0.9,
|
||||
},
|
||||
};
|
||||
const provider = new DatabricksMosaicAiChatCompletionProvider('my-endpoint', options);
|
||||
|
||||
expect(provider).toBeInstanceOf(OpenAiChatCompletionProvider);
|
||||
expect(provider.config.temperature).toBe(0.7);
|
||||
expect(provider.config.max_tokens).toBe(100);
|
||||
expect(provider.config.top_p).toBe(0.9);
|
||||
});
|
||||
|
||||
it('should include usage context as extra body params', () => {
|
||||
const options: DatabricksMosaicAiProviderOptions = {
|
||||
config: {
|
||||
workspaceUrl,
|
||||
usageContext: {
|
||||
project: 'test-project',
|
||||
team: 'engineering',
|
||||
},
|
||||
},
|
||||
};
|
||||
const provider = new DatabricksMosaicAiChatCompletionProvider('my-endpoint', options);
|
||||
|
||||
expect((provider.config as any).extraBodyParams).toEqual({
|
||||
usage_context: {
|
||||
project: 'test-project',
|
||||
team: 'engineering',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should merge usage context with existing extra body params', () => {
|
||||
const options: DatabricksMosaicAiProviderOptions = {
|
||||
config: {
|
||||
workspaceUrl,
|
||||
usageContext: {
|
||||
project: 'test-project',
|
||||
},
|
||||
extraBodyParams: {
|
||||
custom_param: 'value',
|
||||
},
|
||||
},
|
||||
};
|
||||
const provider = new DatabricksMosaicAiChatCompletionProvider('my-endpoint', options);
|
||||
|
||||
expect((provider.config as any).extraBodyParams).toEqual({
|
||||
custom_param: 'value',
|
||||
usage_context: {
|
||||
project: 'test-project',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should pass through AI Gateway config', () => {
|
||||
const options: DatabricksMosaicAiProviderOptions = {
|
||||
config: {
|
||||
workspaceUrl,
|
||||
aiGatewayConfig: {
|
||||
enableSafety: true,
|
||||
piiHandling: 'mask',
|
||||
},
|
||||
},
|
||||
};
|
||||
const provider = new DatabricksMosaicAiChatCompletionProvider('my-endpoint', options);
|
||||
|
||||
expect(provider.config.aiGatewayConfig).toEqual({
|
||||
enableSafety: true,
|
||||
piiHandling: 'mask',
|
||||
});
|
||||
});
|
||||
|
||||
it('should use custom apiKeyEnvar if provided', () => {
|
||||
const options: DatabricksMosaicAiProviderOptions = {
|
||||
config: {
|
||||
workspaceUrl,
|
||||
apiKeyEnvar: 'CUSTOM_DATABRICKS_KEY',
|
||||
},
|
||||
};
|
||||
const provider = new DatabricksMosaicAiChatCompletionProvider('my-endpoint', options);
|
||||
|
||||
expect(provider.config.apiKeyEnvar).toBe('CUSTOM_DATABRICKS_KEY');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getApiUrl method', () => {
|
||||
it('should return custom URL for pay-per-token endpoints', () => {
|
||||
const options: DatabricksMosaicAiProviderOptions = {
|
||||
config: {
|
||||
workspaceUrl,
|
||||
isPayPerToken: true,
|
||||
},
|
||||
};
|
||||
const provider = new DatabricksMosaicAiChatCompletionProvider(
|
||||
'databricks-meta-llama-3-3-70b-instruct',
|
||||
options,
|
||||
);
|
||||
|
||||
// Use type assertion to access protected method
|
||||
const url = (provider as any).getApiUrl();
|
||||
|
||||
expect(url).toBe(
|
||||
`${workspaceUrl}/serving-endpoints/databricks-meta-llama-3-3-70b-instruct/invocations`,
|
||||
);
|
||||
});
|
||||
|
||||
it('should use parent class URL for custom endpoints', () => {
|
||||
const provider = new DatabricksMosaicAiChatCompletionProvider(
|
||||
'my-custom-endpoint',
|
||||
defaultOptions,
|
||||
);
|
||||
|
||||
// Since we're extending OpenAI provider, it should use the OpenAI URL pattern
|
||||
const url = (provider as any).getApiUrl();
|
||||
|
||||
// For custom endpoints, getApiUrl returns the base URL (apiBaseUrl)
|
||||
// The /chat/completions path is added later in the callApi method
|
||||
expect(url).toBe(`${workspaceUrl}/serving-endpoints`);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user