mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-09 05:05:52 +08:00
feat(server): scenario mapping (#13404)
fix AI-404 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Introduced scenario-based configuration for copilot, allowing default model assignments for various AI use cases. * Added a new image generation model to the available options. * **Improvements** * Refined copilot provider settings by removing deprecated fallback options and standardizing base URL configuration. * Enhanced prompt management to support scenario-driven updates and improved configuration handling. * Updated admin and settings interfaces to support new scenario configurations. * **Bug Fixes** * Removed deprecated or unused prompts and related references across platforms for consistency. * **Other** * Improved test coverage and updated test assets to reflect prompt and scenario changes. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -2,26 +2,20 @@ import {
|
||||
type AnthropicProvider as AnthropicSDKProvider,
|
||||
createAnthropic,
|
||||
} from '@ai-sdk/anthropic';
|
||||
import z from 'zod';
|
||||
|
||||
import {
|
||||
CopilotChatOptions,
|
||||
CopilotProviderType,
|
||||
ModelConditions,
|
||||
ModelInputType,
|
||||
ModelOutputType,
|
||||
PromptMessage,
|
||||
StreamObject,
|
||||
} from '../types';
|
||||
import { CopilotProviderType, ModelInputType, ModelOutputType } from '../types';
|
||||
import { AnthropicProvider } from './anthropic';
|
||||
|
||||
export type AnthropicOfficialConfig = {
|
||||
apiKey: string;
|
||||
baseUrl?: string;
|
||||
fallback?: {
|
||||
text?: string;
|
||||
};
|
||||
baseURL?: string;
|
||||
};
|
||||
|
||||
const ModelListSchema = z.object({
|
||||
data: z.array(z.object({ id: z.string() })),
|
||||
});
|
||||
|
||||
export class AnthropicOfficialProvider extends AnthropicProvider<AnthropicOfficialConfig> {
|
||||
override readonly type = CopilotProviderType.Anthropic;
|
||||
|
||||
@@ -75,34 +69,27 @@ export class AnthropicOfficialProvider extends AnthropicProvider<AnthropicOffici
|
||||
super.setup();
|
||||
this.instance = createAnthropic({
|
||||
apiKey: this.config.apiKey,
|
||||
baseURL: this.config.baseUrl,
|
||||
baseURL: this.config.baseURL,
|
||||
});
|
||||
}
|
||||
|
||||
override async text(
|
||||
cond: ModelConditions,
|
||||
messages: PromptMessage[],
|
||||
options: CopilotChatOptions = {}
|
||||
): Promise<string> {
|
||||
const fullCond = { ...cond, fallbackModel: this.config.fallback?.text };
|
||||
return super.text(fullCond, messages, options);
|
||||
}
|
||||
|
||||
override async *streamText(
|
||||
cond: ModelConditions,
|
||||
messages: PromptMessage[],
|
||||
options: CopilotChatOptions = {}
|
||||
): AsyncIterable<string> {
|
||||
const fullCond = { ...cond, fallbackModel: this.config.fallback?.text };
|
||||
yield* super.streamText(fullCond, messages, options);
|
||||
}
|
||||
|
||||
override async *streamObject(
|
||||
cond: ModelConditions,
|
||||
messages: PromptMessage[],
|
||||
options: CopilotChatOptions = {}
|
||||
): AsyncIterable<StreamObject> {
|
||||
const fullCond = { ...cond, fallbackModel: this.config.fallback?.text };
|
||||
yield* super.streamObject(fullCond, messages, options);
|
||||
override async refreshOnlineModels() {
|
||||
try {
|
||||
const baseUrl = this.config.baseURL || 'https://api.anthropic.com/v1';
|
||||
if (baseUrl && !this.onlineModelList.length) {
|
||||
const { data } = await fetch(`${baseUrl}/models`, {
|
||||
headers: {
|
||||
'x-api-key': this.config.apiKey,
|
||||
'anthropic-version': '2023-06-01',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(r => ModelListSchema.parse(r));
|
||||
this.onlineModelList = data.map(model => model.id);
|
||||
}
|
||||
} catch (e) {
|
||||
this.logger.error('Failed to fetch available models', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,23 +4,11 @@ import {
|
||||
type GoogleVertexAnthropicProviderSettings,
|
||||
} from '@ai-sdk/google-vertex/anthropic';
|
||||
|
||||
import {
|
||||
CopilotChatOptions,
|
||||
CopilotProviderType,
|
||||
ModelConditions,
|
||||
ModelInputType,
|
||||
ModelOutputType,
|
||||
PromptMessage,
|
||||
StreamObject,
|
||||
} from '../types';
|
||||
import { CopilotProviderType, ModelInputType, ModelOutputType } from '../types';
|
||||
import { getGoogleAuth, VertexModelListSchema } from '../utils';
|
||||
import { AnthropicProvider } from './anthropic';
|
||||
|
||||
export type AnthropicVertexConfig = GoogleVertexAnthropicProviderSettings & {
|
||||
fallback?: {
|
||||
text?: string;
|
||||
};
|
||||
};
|
||||
export type AnthropicVertexConfig = GoogleVertexAnthropicProviderSettings;
|
||||
|
||||
export class AnthropicVertexProvider extends AnthropicProvider<AnthropicVertexConfig> {
|
||||
override readonly type = CopilotProviderType.AnthropicVertex;
|
||||
@@ -76,33 +64,6 @@ export class AnthropicVertexProvider extends AnthropicProvider<AnthropicVertexCo
|
||||
this.instance = createVertexAnthropic(this.config);
|
||||
}
|
||||
|
||||
override async text(
|
||||
cond: ModelConditions,
|
||||
messages: PromptMessage[],
|
||||
options: CopilotChatOptions = {}
|
||||
): Promise<string> {
|
||||
const fullCond = { ...cond, fallbackModel: this.config.fallback?.text };
|
||||
return super.text(fullCond, messages, options);
|
||||
}
|
||||
|
||||
override async *streamText(
|
||||
cond: ModelConditions,
|
||||
messages: PromptMessage[],
|
||||
options: CopilotChatOptions = {}
|
||||
): AsyncIterable<string> {
|
||||
const fullCond = { ...cond, fallbackModel: this.config.fallback?.text };
|
||||
yield* super.streamText(fullCond, messages, options);
|
||||
}
|
||||
|
||||
override async *streamObject(
|
||||
cond: ModelConditions,
|
||||
messages: PromptMessage[],
|
||||
options: CopilotChatOptions = {}
|
||||
): AsyncIterable<StreamObject> {
|
||||
const fullCond = { ...cond, fallbackModel: this.config.fallback?.text };
|
||||
yield* super.streamObject(fullCond, messages, options);
|
||||
}
|
||||
|
||||
override async refreshOnlineModels() {
|
||||
try {
|
||||
const { baseUrl, headers } = await getGoogleAuth(
|
||||
|
||||
@@ -74,6 +74,16 @@ export class FalProvider extends CopilotProvider<FalConfig> {
|
||||
override type = CopilotProviderType.FAL;
|
||||
|
||||
override readonly models = [
|
||||
{
|
||||
id: 'lcm',
|
||||
capabilities: [
|
||||
{
|
||||
input: [ModelInputType.Text],
|
||||
output: [ModelOutputType.Image],
|
||||
defaultForOutputType: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
// image to image models
|
||||
{
|
||||
id: 'lcm-sd15-i2i',
|
||||
|
||||
@@ -4,27 +4,12 @@ import {
|
||||
} from '@ai-sdk/google';
|
||||
import z from 'zod';
|
||||
|
||||
import {
|
||||
CopilotChatOptions,
|
||||
CopilotEmbeddingOptions,
|
||||
CopilotProviderType,
|
||||
ModelConditions,
|
||||
ModelInputType,
|
||||
ModelOutputType,
|
||||
PromptMessage,
|
||||
StreamObject,
|
||||
} from '../types';
|
||||
import { CopilotProviderType, ModelInputType, ModelOutputType } from '../types';
|
||||
import { GeminiProvider } from './gemini';
|
||||
|
||||
export type GeminiGenerativeConfig = {
|
||||
apiKey: string;
|
||||
baseUrl?: string;
|
||||
fallback?: {
|
||||
text?: string;
|
||||
structured?: string;
|
||||
image?: string;
|
||||
embedding?: string;
|
||||
};
|
||||
baseURL?: string;
|
||||
};
|
||||
|
||||
const ModelListSchema = z.object({
|
||||
@@ -113,65 +98,14 @@ export class GeminiGenerativeProvider extends GeminiProvider<GeminiGenerativeCon
|
||||
super.setup();
|
||||
this.instance = createGoogleGenerativeAI({
|
||||
apiKey: this.config.apiKey,
|
||||
baseURL: this.config.baseUrl,
|
||||
baseURL: this.config.baseURL,
|
||||
});
|
||||
}
|
||||
|
||||
override async text(
|
||||
cond: ModelConditions,
|
||||
messages: PromptMessage[],
|
||||
options: CopilotChatOptions = {}
|
||||
): Promise<string> {
|
||||
const fullCond = { ...cond, fallbackModel: this.config.fallback?.text };
|
||||
return super.text(fullCond, messages, options);
|
||||
}
|
||||
|
||||
override async structure(
|
||||
cond: ModelConditions,
|
||||
messages: PromptMessage[],
|
||||
options?: CopilotChatOptions
|
||||
): Promise<string> {
|
||||
const fullCond = {
|
||||
...cond,
|
||||
fallbackModel: this.config.fallback?.structured,
|
||||
};
|
||||
return super.structure(fullCond, messages, options);
|
||||
}
|
||||
|
||||
override async *streamText(
|
||||
cond: ModelConditions,
|
||||
messages: PromptMessage[],
|
||||
options: CopilotChatOptions = {}
|
||||
): AsyncIterable<string> {
|
||||
const fullCond = { ...cond, fallbackModel: this.config.fallback?.text };
|
||||
yield* super.streamText(fullCond, messages, options);
|
||||
}
|
||||
|
||||
override async *streamObject(
|
||||
cond: ModelConditions,
|
||||
messages: PromptMessage[],
|
||||
options: CopilotChatOptions = {}
|
||||
): AsyncIterable<StreamObject> {
|
||||
const fullCond = { ...cond, fallbackModel: this.config.fallback?.text };
|
||||
yield* super.streamObject(fullCond, messages, options);
|
||||
}
|
||||
|
||||
override async embedding(
|
||||
cond: ModelConditions,
|
||||
messages: string | string[],
|
||||
options?: CopilotEmbeddingOptions
|
||||
): Promise<number[][]> {
|
||||
const fullCond = {
|
||||
...cond,
|
||||
fallbackModel: this.config.fallback?.embedding,
|
||||
};
|
||||
return super.embedding(fullCond, messages, options);
|
||||
}
|
||||
|
||||
override async refreshOnlineModels() {
|
||||
try {
|
||||
const baseUrl =
|
||||
this.config.baseUrl ||
|
||||
this.config.baseURL ||
|
||||
'https://generativelanguage.googleapis.com/v1beta';
|
||||
if (baseUrl && !this.onlineModelList.length) {
|
||||
const { models } = await fetch(
|
||||
|
||||
@@ -4,27 +4,11 @@ import {
|
||||
type GoogleVertexProviderSettings,
|
||||
} from '@ai-sdk/google-vertex';
|
||||
|
||||
import {
|
||||
CopilotChatOptions,
|
||||
CopilotEmbeddingOptions,
|
||||
CopilotProviderType,
|
||||
ModelConditions,
|
||||
ModelInputType,
|
||||
ModelOutputType,
|
||||
PromptMessage,
|
||||
StreamObject,
|
||||
} from '../types';
|
||||
import { CopilotProviderType, ModelInputType, ModelOutputType } from '../types';
|
||||
import { getGoogleAuth, VertexModelListSchema } from '../utils';
|
||||
import { GeminiProvider } from './gemini';
|
||||
|
||||
export type GeminiVertexConfig = GoogleVertexProviderSettings & {
|
||||
fallback?: {
|
||||
text?: string;
|
||||
structured?: string;
|
||||
image?: string;
|
||||
embedding?: string;
|
||||
};
|
||||
};
|
||||
export type GeminiVertexConfig = GoogleVertexProviderSettings;
|
||||
|
||||
export class GeminiVertexProvider extends GeminiProvider<GeminiVertexConfig> {
|
||||
override readonly type = CopilotProviderType.GeminiVertex;
|
||||
@@ -90,57 +74,6 @@ export class GeminiVertexProvider extends GeminiProvider<GeminiVertexConfig> {
|
||||
this.instance = createVertex(this.config);
|
||||
}
|
||||
|
||||
override async text(
|
||||
cond: ModelConditions,
|
||||
messages: PromptMessage[],
|
||||
options: CopilotChatOptions = {}
|
||||
): Promise<string> {
|
||||
const fullCond = { ...cond, fallbackModel: this.config.fallback?.text };
|
||||
return super.text(fullCond, messages, options);
|
||||
}
|
||||
|
||||
override async structure(
|
||||
cond: ModelConditions,
|
||||
messages: PromptMessage[],
|
||||
options?: CopilotChatOptions
|
||||
): Promise<string> {
|
||||
const fullCond = {
|
||||
...cond,
|
||||
fallbackModel: this.config.fallback?.structured,
|
||||
};
|
||||
return super.structure(fullCond, messages, options);
|
||||
}
|
||||
|
||||
override async *streamText(
|
||||
cond: ModelConditions,
|
||||
messages: PromptMessage[],
|
||||
options: CopilotChatOptions = {}
|
||||
): AsyncIterable<string> {
|
||||
const fullCond = { ...cond, fallbackModel: this.config.fallback?.text };
|
||||
yield* super.streamText(fullCond, messages, options);
|
||||
}
|
||||
|
||||
override async *streamObject(
|
||||
cond: ModelConditions,
|
||||
messages: PromptMessage[],
|
||||
options: CopilotChatOptions = {}
|
||||
): AsyncIterable<StreamObject> {
|
||||
const fullCond = { ...cond, fallbackModel: this.config.fallback?.text };
|
||||
yield* super.streamObject(fullCond, messages, options);
|
||||
}
|
||||
|
||||
override async embedding(
|
||||
cond: ModelConditions,
|
||||
messages: string | string[],
|
||||
options?: CopilotEmbeddingOptions
|
||||
): Promise<number[][]> {
|
||||
const fullCond = {
|
||||
...cond,
|
||||
fallbackModel: this.config.fallback?.embedding,
|
||||
};
|
||||
return super.embedding(fullCond, messages, options);
|
||||
}
|
||||
|
||||
override async refreshOnlineModels() {
|
||||
try {
|
||||
const { baseUrl, headers } = await getGoogleAuth(this.config, 'google');
|
||||
|
||||
@@ -45,13 +45,7 @@ export const DEFAULT_DIMENSIONS = 256;
|
||||
|
||||
export type OpenAIConfig = {
|
||||
apiKey: string;
|
||||
baseUrl?: string;
|
||||
fallback?: {
|
||||
text?: string;
|
||||
structured?: string;
|
||||
image?: string;
|
||||
embedding?: string;
|
||||
};
|
||||
baseURL?: string;
|
||||
};
|
||||
|
||||
const ModelListSchema = z.object({
|
||||
@@ -249,7 +243,7 @@ export class OpenAIProvider extends CopilotProvider<OpenAIConfig> {
|
||||
super.setup();
|
||||
this.#instance = createOpenAI({
|
||||
apiKey: this.config.apiKey,
|
||||
baseURL: this.config.baseUrl,
|
||||
baseURL: this.config.baseURL,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -283,7 +277,7 @@ export class OpenAIProvider extends CopilotProvider<OpenAIConfig> {
|
||||
|
||||
override async refreshOnlineModels() {
|
||||
try {
|
||||
const baseUrl = this.config.baseUrl || 'https://api.openai.com/v1';
|
||||
const baseUrl = this.config.baseURL || 'https://api.openai.com/v1';
|
||||
if (baseUrl && !this.onlineModelList.length) {
|
||||
const { data } = await fetch(`${baseUrl}/models`, {
|
||||
headers: {
|
||||
@@ -320,7 +314,6 @@ export class OpenAIProvider extends CopilotProvider<OpenAIConfig> {
|
||||
const fullCond = {
|
||||
...cond,
|
||||
outputType: ModelOutputType.Text,
|
||||
fallbackModel: this.config.fallback?.text,
|
||||
};
|
||||
await this.checkParams({ messages, cond: fullCond, options });
|
||||
const model = this.selectModel(fullCond);
|
||||
@@ -361,7 +354,6 @@ export class OpenAIProvider extends CopilotProvider<OpenAIConfig> {
|
||||
const fullCond = {
|
||||
...cond,
|
||||
outputType: ModelOutputType.Text,
|
||||
fallbackModel: this.config.fallback?.text,
|
||||
};
|
||||
await this.checkParams({ messages, cond: fullCond, options });
|
||||
const model = this.selectModel(fullCond);
|
||||
@@ -407,11 +399,7 @@ export class OpenAIProvider extends CopilotProvider<OpenAIConfig> {
|
||||
messages: PromptMessage[],
|
||||
options: CopilotChatOptions = {}
|
||||
): AsyncIterable<StreamObject> {
|
||||
const fullCond = {
|
||||
...cond,
|
||||
outputType: ModelOutputType.Object,
|
||||
fallbackModel: this.config.fallback?.text,
|
||||
};
|
||||
const fullCond = { ...cond, outputType: ModelOutputType.Object };
|
||||
await this.checkParams({ cond: fullCond, messages, options });
|
||||
const model = this.selectModel(fullCond);
|
||||
|
||||
@@ -444,11 +432,7 @@ export class OpenAIProvider extends CopilotProvider<OpenAIConfig> {
|
||||
messages: PromptMessage[],
|
||||
options: CopilotStructuredOptions = {}
|
||||
): Promise<string> {
|
||||
const fullCond = {
|
||||
...cond,
|
||||
outputType: ModelOutputType.Structured,
|
||||
fallbackModel: this.config.fallback?.structured,
|
||||
};
|
||||
const fullCond = { ...cond, outputType: ModelOutputType.Structured };
|
||||
await this.checkParams({ messages, cond: fullCond, options });
|
||||
const model = this.selectModel(fullCond);
|
||||
|
||||
@@ -488,11 +472,7 @@ export class OpenAIProvider extends CopilotProvider<OpenAIConfig> {
|
||||
chunkMessages: PromptMessage[][],
|
||||
options: CopilotChatOptions = {}
|
||||
): Promise<number[]> {
|
||||
const fullCond = {
|
||||
...cond,
|
||||
outputType: ModelOutputType.Text,
|
||||
fallbackModel: this.config.fallback?.text,
|
||||
};
|
||||
const fullCond = { ...cond, outputType: ModelOutputType.Text };
|
||||
await this.checkParams({ messages: [], cond: fullCond, options });
|
||||
const model = this.selectModel(fullCond);
|
||||
// get the log probability of "yes"/"no"
|
||||
@@ -605,7 +585,7 @@ export class OpenAIProvider extends CopilotProvider<OpenAIConfig> {
|
||||
);
|
||||
}
|
||||
|
||||
const url = `${this.config.baseUrl || 'https://api.openai.com'}/v1/images/edits`;
|
||||
const url = `${this.config.baseURL || 'https://api.openai.com/v1'}/images/edits`;
|
||||
const res = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: { Authorization: `Bearer ${this.config.apiKey}` },
|
||||
@@ -637,11 +617,7 @@ export class OpenAIProvider extends CopilotProvider<OpenAIConfig> {
|
||||
messages: PromptMessage[],
|
||||
options: CopilotImageOptions = {}
|
||||
) {
|
||||
const fullCond = {
|
||||
...cond,
|
||||
outputType: ModelOutputType.Image,
|
||||
fallbackModel: this.config.fallback?.image,
|
||||
};
|
||||
const fullCond = { ...cond, outputType: ModelOutputType.Image };
|
||||
await this.checkParams({ messages, cond: fullCond, options });
|
||||
const model = this.selectModel(fullCond);
|
||||
|
||||
@@ -691,11 +667,7 @@ export class OpenAIProvider extends CopilotProvider<OpenAIConfig> {
|
||||
options: CopilotEmbeddingOptions = { dimensions: DEFAULT_DIMENSIONS }
|
||||
): Promise<number[][]> {
|
||||
messages = Array.isArray(messages) ? messages : [messages];
|
||||
const fullCond = {
|
||||
...cond,
|
||||
outputType: ModelOutputType.Embedding,
|
||||
fallbackModel: this.config.fallback?.embedding,
|
||||
};
|
||||
const fullCond = { ...cond, outputType: ModelOutputType.Embedding };
|
||||
await this.checkParams({ embeddings: messages, cond: fullCond, options });
|
||||
const model = this.selectModel(fullCond);
|
||||
|
||||
|
||||
@@ -20,9 +20,6 @@ import { chatToGPTMessage, CitationParser } from './utils';
|
||||
export type PerplexityConfig = {
|
||||
apiKey: string;
|
||||
endpoint?: string;
|
||||
fallback?: {
|
||||
text?: string;
|
||||
};
|
||||
};
|
||||
|
||||
const PerplexityErrorSchema = z.union([
|
||||
@@ -112,11 +109,7 @@ export class PerplexityProvider extends CopilotProvider<PerplexityConfig> {
|
||||
messages: PromptMessage[],
|
||||
options: CopilotChatOptions = {}
|
||||
): Promise<string> {
|
||||
const fullCond = {
|
||||
...cond,
|
||||
outputType: ModelOutputType.Text,
|
||||
fallbackModel: this.config.fallback?.text,
|
||||
};
|
||||
const fullCond = { ...cond, outputType: ModelOutputType.Text };
|
||||
await this.checkParams({ cond: fullCond, messages, options });
|
||||
const model = this.selectModel(fullCond);
|
||||
|
||||
@@ -156,11 +149,7 @@ export class PerplexityProvider extends CopilotProvider<PerplexityConfig> {
|
||||
messages: PromptMessage[],
|
||||
options: CopilotChatOptions = {}
|
||||
): AsyncIterable<string> {
|
||||
const fullCond = {
|
||||
...cond,
|
||||
outputType: ModelOutputType.Text,
|
||||
fallbackModel: this.config.fallback?.text,
|
||||
};
|
||||
const fullCond = { ...cond, outputType: ModelOutputType.Text };
|
||||
await this.checkParams({ cond: fullCond, messages, options });
|
||||
const model = this.selectModel(fullCond);
|
||||
|
||||
|
||||
@@ -104,22 +104,12 @@ export abstract class CopilotProvider<C = any> {
|
||||
|
||||
if (modelId) {
|
||||
const hasOnlineModel = this.onlineModelList.includes(modelId);
|
||||
const hasFallbackModel = cond.fallbackModel
|
||||
? this.onlineModelList.includes(cond.fallbackModel)
|
||||
: undefined;
|
||||
|
||||
const model = this.models.find(
|
||||
m => m.id === modelId && m.capabilities.some(matcher)
|
||||
);
|
||||
|
||||
if (model) {
|
||||
// return fallback model if current model is not alive
|
||||
if (!hasOnlineModel && hasFallbackModel) {
|
||||
// oxlint-disable-next-line typescript-eslint(no-non-null-assertion)
|
||||
return { id: cond.fallbackModel!, capabilities: [] };
|
||||
}
|
||||
return model;
|
||||
}
|
||||
if (model) return model;
|
||||
// allow online model without capabilities check
|
||||
if (hasOnlineModel) return { id: modelId, capabilities: [] };
|
||||
return undefined;
|
||||
|
||||
@@ -248,5 +248,4 @@ export type ModelConditions = {
|
||||
|
||||
export type ModelFullConditions = ModelConditions & {
|
||||
outputType?: ModelOutputType;
|
||||
fallbackModel?: string;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user