feat: adapt cloudflare worker ai (#14732)

#### PR Dependency Tree


* **PR #14732** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Cloudflare Workers AI added as a Copilot provider (configurable in
admin settings).
  * Gemini 3.1 Flash Lite Preview model made available.

* **Behavior Changes**
* Reranking now uses a different default model identifier (affects
relevancy scores).

* **Tests**
* Rerank tests adjusted to focus on the updated model and expected
results.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
DarkSky
2026-03-27 02:15:49 +08:00
committed by GitHub
parent 5b05c5a1b2
commit a41c5e4366
18 changed files with 502 additions and 30 deletions
@@ -964,11 +964,11 @@ test(
'The stock market is experiencing significant fluctuations.',
];
const provider = (await factory.getProviderByModel('gpt-5.2'))!;
const provider = (await factory.getProviderByModel('gpt-4o-mini'))!;
t.assert(provider, 'should have provider for rerank');
const scores = await provider.rerank(
{ modelId: 'gpt-5.2' },
{ modelId: 'gpt-4o-mini' },
{
query,
candidates: embeddings.map((text, index) => ({
@@ -990,8 +990,8 @@ test(
t.log('Rerank scores:', scores);
t.is(
scores.filter(s => s > 0.5).length,
5,
'should have 5 related chunks'
4,
'should have 4 related chunks'
);
});
}
@@ -3,6 +3,7 @@ import test from 'ava';
import type { NativeLlmRerankRequest } from '../../native';
import { ProviderMiddlewareConfig } from '../../plugins/copilot/config';
import { CloudflareWorkersAIProvider } from '../../plugins/copilot/providers/cloudflare';
import {
normalizeOpenAIOptionsForModel,
OpenAIProvider,
@@ -53,7 +54,7 @@ class TestOpenAIProvider extends CopilotProvider<{ apiKey: string }> {
class NativeRerankProtocolProvider extends OpenAIProvider {
override readonly models = [
{
id: 'gpt-5.2',
id: 'gpt-4o-mini',
capabilities: [
{
input: [ModelInputType.Text],
@@ -77,6 +78,19 @@ class NativeRerankProtocolProvider extends OpenAIProvider {
}
}
class NativeCloudflareRerankProtocolProvider extends CloudflareWorkersAIProvider {
override get config() {
return {
apiToken: 'test-key',
accountId: 'account-1',
};
}
override configured() {
return true;
}
}
function createProvider(profileMiddleware?: ProviderMiddlewareConfig) {
const provider = new TestOpenAIProvider();
(provider as any).AFFiNEConfig = {
@@ -170,14 +184,14 @@ test('OpenAI rerank should always use chat-completions native protocol', async t
) => {
capturedProtocol = protocol;
capturedRequest = JSON.parse(requestJson) as NativeLlmRerankRequest;
return JSON.stringify({ model: 'gpt-5.2', scores: [0.9, 0.1] });
return JSON.stringify({ model: 'gpt-4o-mini', scores: [0.9, 0.1] });
};
t.teardown(() => {
(serverNativeModule as any).llmRerankDispatch = original;
});
const scores = await provider.rerank(
{ modelId: 'gpt-5.2' },
{ modelId: 'gpt-4o-mini' },
{
query: 'programming',
candidates: [
@@ -190,7 +204,7 @@ test('OpenAI rerank should always use chat-completions native protocol', async t
t.deepEqual(scores, [0.9, 0.1]);
t.is(capturedProtocol, 'openai_chat');
t.deepEqual(capturedRequest, {
model: 'gpt-5.2',
model: 'gpt-4o-mini',
query: 'programming',
candidates: [
{ id: 'react', text: 'React is a UI library.' },
@@ -198,3 +212,63 @@ test('OpenAI rerank should always use chat-completions native protocol', async t
],
});
});
test('Cloudflare rerank should keep native protocol details behind provider', async t => {
const provider = new NativeCloudflareRerankProtocolProvider();
let capturedProtocol: string | undefined;
let capturedRequest: NativeLlmRerankRequest | undefined;
let capturedBackendConfig: Record<string, unknown> | undefined;
const original = (serverNativeModule as any).llmRerankDispatch;
(serverNativeModule as any).llmRerankDispatch = (
protocol: string,
backendConfigJson: string,
requestJson: string
) => {
capturedProtocol = protocol;
capturedBackendConfig = JSON.parse(backendConfigJson) as Record<
string,
unknown
>;
capturedRequest = JSON.parse(requestJson) as NativeLlmRerankRequest;
return JSON.stringify({
model: '@cf/qwen/qwen3-30b-a3b-fp8',
scores: [0.9, 0.1],
});
};
t.teardown(() => {
(serverNativeModule as any).llmRerankDispatch = original;
});
for (const modelId of [
'@cf/qwen/qwen3-30b-a3b-fp8',
'@cf/baai/bge-reranker-base',
]) {
const scores = await provider.rerank(
{ modelId },
{
query: 'programming',
candidates: [
{ id: 'react', text: 'React is a UI library.' },
{ id: 'weather', text: 'The weather is sunny today.' },
],
}
);
t.deepEqual(scores, [0.9, 0.1]);
t.is(capturedProtocol, 'openai_chat');
t.deepEqual(capturedBackendConfig, {
base_url: 'https://api.cloudflare.com/client/v4/accounts/account-1/ai',
auth_token: 'test-key',
request_layer: 'cloudflare_workers_ai',
});
t.deepEqual(capturedRequest, {
model: modelId,
query: 'programming',
candidates: [
{ id: 'react', text: 'React is a UI library.' },
{ id: 'weather', text: 'The weather is sunny today.' },
],
});
}
});