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:
@@ -667,18 +667,31 @@
|
|||||||
"description": "Whether to enable the copilot plugin.\n@default false",
|
"description": "Whether to enable the copilot plugin.\n@default false",
|
||||||
"default": false
|
"default": false
|
||||||
},
|
},
|
||||||
|
"scenarios": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "The models used in the scene for the copilot, will use this config if enabled.\n@default {\"enabled\":false,\"scenarios\":{\"audio\":\"gemini-2.5-flash\",\"chat\":\"claude-sonnet-4@20250514\",\"embedding\":\"gemini-embedding-001\",\"image\":\"gpt-image-1\",\"rerank\":\"gpt-4.1\",\"brainstorm\":\"gpt-4o-2024-08-06\",\"coding\":\"claude-sonnet-4@20250514\",\"quick_decision\":\"gpt-4.1-mini\",\"quick_written\":\"gemini-2.5-flash\",\"summary_inspection\":\"gemini-2.5-flash\"}}",
|
||||||
|
"default": {
|
||||||
|
"enabled": false,
|
||||||
|
"scenarios": {
|
||||||
|
"audio": "gemini-2.5-flash",
|
||||||
|
"chat": "claude-sonnet-4@20250514",
|
||||||
|
"embedding": "gemini-embedding-001",
|
||||||
|
"image": "gpt-image-1",
|
||||||
|
"rerank": "gpt-4.1",
|
||||||
|
"brainstorm": "gpt-4o-2024-08-06",
|
||||||
|
"coding": "claude-sonnet-4@20250514",
|
||||||
|
"quick_decision": "gpt-4.1-mini",
|
||||||
|
"quick_written": "gemini-2.5-flash",
|
||||||
|
"summary_inspection": "gemini-2.5-flash"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"providers.openai": {
|
"providers.openai": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "The config for the openai provider.\n@default {\"apiKey\":\"\",\"baseUrl\":\"\",\"fallback\":{\"text\":\"\",\"structured\":\"\",\"image\":\"\",\"embedding\":\"\"}}\n@link https://github.com/openai/openai-node",
|
"description": "The config for the openai provider.\n@default {\"apiKey\":\"\",\"baseURL\":\"https://api.openai.com/v1\"}\n@link https://github.com/openai/openai-node",
|
||||||
"default": {
|
"default": {
|
||||||
"apiKey": "",
|
"apiKey": "",
|
||||||
"baseUrl": "",
|
"baseURL": "https://api.openai.com/v1"
|
||||||
"fallback": {
|
|
||||||
"text": "",
|
|
||||||
"structured": "",
|
|
||||||
"image": "",
|
|
||||||
"embedding": ""
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"providers.fal": {
|
"providers.fal": {
|
||||||
@@ -690,21 +703,15 @@
|
|||||||
},
|
},
|
||||||
"providers.gemini": {
|
"providers.gemini": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "The config for the gemini provider.\n@default {\"apiKey\":\"\",\"baseUrl\":\"\",\"fallback\":{\"text\":\"\",\"structured\":\"\",\"image\":\"\",\"embedding\":\"\"}}",
|
"description": "The config for the gemini provider.\n@default {\"apiKey\":\"\",\"baseURL\":\"https://generativelanguage.googleapis.com/v1beta\"}",
|
||||||
"default": {
|
"default": {
|
||||||
"apiKey": "",
|
"apiKey": "",
|
||||||
"baseUrl": "",
|
"baseURL": "https://generativelanguage.googleapis.com/v1beta"
|
||||||
"fallback": {
|
|
||||||
"text": "",
|
|
||||||
"structured": "",
|
|
||||||
"image": "",
|
|
||||||
"embedding": ""
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"providers.geminiVertex": {
|
"providers.geminiVertex": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "The config for the google vertex provider.\n@default {\"baseURL\":\"\",\"fallback\":{\"text\":\"\",\"structured\":\"\",\"image\":\"\",\"embedding\":\"\"}}",
|
"description": "The config for the google vertex provider.\n@default {}",
|
||||||
"properties": {
|
"properties": {
|
||||||
"location": {
|
"location": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -735,39 +742,26 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"default": {
|
"default": {}
|
||||||
"baseURL": "",
|
|
||||||
"fallback": {
|
|
||||||
"text": "",
|
|
||||||
"structured": "",
|
|
||||||
"image": "",
|
|
||||||
"embedding": ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"providers.perplexity": {
|
"providers.perplexity": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "The config for the perplexity provider.\n@default {\"apiKey\":\"\",\"fallback\":{\"text\":\"\"}}",
|
"description": "The config for the perplexity provider.\n@default {\"apiKey\":\"\"}",
|
||||||
"default": {
|
"default": {
|
||||||
"apiKey": "",
|
"apiKey": ""
|
||||||
"fallback": {
|
|
||||||
"text": ""
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"providers.anthropic": {
|
"providers.anthropic": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "The config for the anthropic provider.\n@default {\"apiKey\":\"\",\"fallback\":{\"text\":\"\"}}",
|
"description": "The config for the anthropic provider.\n@default {\"apiKey\":\"\",\"baseURL\":\"https://api.anthropic.com/v1\"}",
|
||||||
"default": {
|
"default": {
|
||||||
"apiKey": "",
|
"apiKey": "",
|
||||||
"fallback": {
|
"baseURL": "https://api.anthropic.com/v1"
|
||||||
"text": ""
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"providers.anthropicVertex": {
|
"providers.anthropicVertex": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "The config for the google vertex provider.\n@default {\"baseURL\":\"\",\"fallback\":{\"text\":\"\"}}",
|
"description": "The config for the google vertex provider.\n@default {}",
|
||||||
"properties": {
|
"properties": {
|
||||||
"location": {
|
"location": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -798,12 +792,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"default": {
|
"default": {}
|
||||||
"baseURL": "",
|
|
||||||
"fallback": {
|
|
||||||
"text": ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"providers.morph": {
|
"providers.morph": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { randomUUID } from 'node:crypto';
|
||||||
|
|
||||||
import type { ExecutionContext, TestFn } from 'ava';
|
import type { ExecutionContext, TestFn } from 'ava';
|
||||||
import ava from 'ava';
|
import ava from 'ava';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
@@ -5,6 +7,7 @@ import { z } from 'zod';
|
|||||||
import { ServerFeature, ServerService } from '../core';
|
import { ServerFeature, ServerService } from '../core';
|
||||||
import { AuthService } from '../core/auth';
|
import { AuthService } from '../core/auth';
|
||||||
import { QuotaModule } from '../core/quota';
|
import { QuotaModule } from '../core/quota';
|
||||||
|
import { Models } from '../models';
|
||||||
import { CopilotModule } from '../plugins/copilot';
|
import { CopilotModule } from '../plugins/copilot';
|
||||||
import { prompts, PromptService } from '../plugins/copilot/prompt';
|
import { prompts, PromptService } from '../plugins/copilot/prompt';
|
||||||
import {
|
import {
|
||||||
@@ -30,6 +33,8 @@ import { TestAssets } from './utils/copilot';
|
|||||||
type Tester = {
|
type Tester = {
|
||||||
auth: AuthService;
|
auth: AuthService;
|
||||||
module: TestingModule;
|
module: TestingModule;
|
||||||
|
models: Models;
|
||||||
|
service: ServerService;
|
||||||
prompt: PromptService;
|
prompt: PromptService;
|
||||||
factory: CopilotProviderFactory;
|
factory: CopilotProviderFactory;
|
||||||
workflow: CopilotWorkflowService;
|
workflow: CopilotWorkflowService;
|
||||||
@@ -66,12 +71,15 @@ test.serial.before(async t => {
|
|||||||
isCopilotConfigured = service.features.includes(ServerFeature.Copilot);
|
isCopilotConfigured = service.features.includes(ServerFeature.Copilot);
|
||||||
|
|
||||||
const auth = module.get(AuthService);
|
const auth = module.get(AuthService);
|
||||||
|
const models = module.get(Models);
|
||||||
const prompt = module.get(PromptService);
|
const prompt = module.get(PromptService);
|
||||||
const factory = module.get(CopilotProviderFactory);
|
const factory = module.get(CopilotProviderFactory);
|
||||||
const workflow = module.get(CopilotWorkflowService);
|
const workflow = module.get(CopilotWorkflowService);
|
||||||
|
|
||||||
t.context.module = module;
|
t.context.module = module;
|
||||||
t.context.auth = auth;
|
t.context.auth = auth;
|
||||||
|
t.context.service = service;
|
||||||
|
t.context.models = models;
|
||||||
t.context.prompt = prompt;
|
t.context.prompt = prompt;
|
||||||
t.context.factory = factory;
|
t.context.factory = factory;
|
||||||
t.context.workflow = workflow;
|
t.context.workflow = workflow;
|
||||||
@@ -84,7 +92,7 @@ test.serial.before(async t => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test.serial.before(async t => {
|
test.serial.before(async t => {
|
||||||
const { prompt, executors } = t.context;
|
const { prompt, executors, models, service } = t.context;
|
||||||
|
|
||||||
executors.image.register();
|
executors.image.register();
|
||||||
executors.text.register();
|
executors.text.register();
|
||||||
@@ -98,6 +106,28 @@ test.serial.before(async t => {
|
|||||||
for (const p of prompts) {
|
for (const p of prompts) {
|
||||||
await prompt.set(p.name, p.model, p.messages, p.config);
|
await prompt.set(p.name, p.model, p.messages, p.config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const user = await models.user.create({
|
||||||
|
email: `${randomUUID()}@affine.pro`,
|
||||||
|
});
|
||||||
|
await service.updateConfig(user.id, [
|
||||||
|
{
|
||||||
|
module: 'copilot',
|
||||||
|
key: 'scenarios',
|
||||||
|
value: {
|
||||||
|
enabled: true,
|
||||||
|
scenarios: {
|
||||||
|
image: 'lcm',
|
||||||
|
rerank: 'gpt-4.1-mini',
|
||||||
|
brainstorm: 'gpt-4.1-mini',
|
||||||
|
coding: 'gpt-4.1-mini',
|
||||||
|
quick_decision: 'gpt-4.1-mini',
|
||||||
|
quick_written: 'gpt-4.1-mini',
|
||||||
|
summary_inspection: 'gemini-2.5-flash',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test.after(async t => {
|
test.after(async t => {
|
||||||
@@ -532,7 +562,6 @@ The term **“CRDT”** was first introduced by Marc Shapiro, Nuno Preguiça, Ca
|
|||||||
'Make it shorter',
|
'Make it shorter',
|
||||||
'Section Edit',
|
'Section Edit',
|
||||||
'Chat With AFFiNE AI',
|
'Chat With AFFiNE AI',
|
||||||
'Search With AFFiNE AI',
|
|
||||||
],
|
],
|
||||||
messages: [{ role: 'user' as const, content: TestAssets.SSOT }],
|
messages: [{ role: 'user' as const, content: TestAssets.SSOT }],
|
||||||
verifier: (t: ExecutionContext<Tester>, result: string) => {
|
verifier: (t: ExecutionContext<Tester>, result: string) => {
|
||||||
@@ -655,20 +684,7 @@ The term **“CRDT”** was first introduced by Marc Shapiro, Nuno Preguiça, Ca
|
|||||||
type: 'image' as const,
|
type: 'image' as const,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
promptName: ['debug:action:dalle3'],
|
promptName: ['Generate image'],
|
||||||
messages: [
|
|
||||||
{
|
|
||||||
role: 'user' as const,
|
|
||||||
content: 'Panda',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
verifier: (t: ExecutionContext<Tester>, link: string) => {
|
|
||||||
t.truthy(checkUrl(link), 'should be a valid url');
|
|
||||||
},
|
|
||||||
type: 'image' as const,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
promptName: ['debug:action:gpt-image-1'],
|
|
||||||
messages: [
|
messages: [
|
||||||
{
|
{
|
||||||
role: 'user' as const,
|
role: 'user' as const,
|
||||||
|
|||||||
@@ -211,7 +211,9 @@ test('should be able to manage prompt', async t => {
|
|||||||
'should have two messages'
|
'should have two messages'
|
||||||
);
|
);
|
||||||
|
|
||||||
await prompt.update(promptName, [{ role: 'system', content: 'hello' }]);
|
await prompt.update(promptName, {
|
||||||
|
messages: [{ role: 'system', content: 'hello' }],
|
||||||
|
});
|
||||||
t.is(
|
t.is(
|
||||||
(await prompt.get(promptName))!.finish({}).length,
|
(await prompt.get(promptName))!.finish({}).length,
|
||||||
1,
|
1,
|
||||||
@@ -370,7 +372,7 @@ test('should be able to update chat session prompt', async t => {
|
|||||||
// Update the session
|
// Update the session
|
||||||
const updatedSessionId = await session.update({
|
const updatedSessionId = await session.update({
|
||||||
sessionId,
|
sessionId,
|
||||||
promptName: 'Search With AFFiNE AI',
|
promptName: 'Chat With AFFiNE AI',
|
||||||
userId,
|
userId,
|
||||||
});
|
});
|
||||||
t.is(updatedSessionId, sessionId, 'should update session with same id');
|
t.is(updatedSessionId, sessionId, 'should update session with same id');
|
||||||
@@ -380,7 +382,7 @@ test('should be able to update chat session prompt', async t => {
|
|||||||
t.truthy(updatedSession, 'should retrieve updated session');
|
t.truthy(updatedSession, 'should retrieve updated session');
|
||||||
t.is(
|
t.is(
|
||||||
updatedSession?.config.promptName,
|
updatedSession?.config.promptName,
|
||||||
'Search With AFFiNE AI',
|
'Chat With AFFiNE AI',
|
||||||
'should have updated prompt name'
|
'should have updated prompt name'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ export class ServerService implements OnApplicationBootstrap {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.configFactory.override(overrides);
|
this.configFactory.override(overrides);
|
||||||
this.event.emit('config.changed', { updates: overrides });
|
await this.event.emitAsync('config.changed', { updates: overrides });
|
||||||
this.event.broadcast('config.changed.broadcast', { updates: overrides });
|
this.event.broadcast('config.changed.broadcast', { updates: overrides });
|
||||||
return overrides;
|
return overrides;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import {
|
|||||||
StorageJSONSchema,
|
StorageJSONSchema,
|
||||||
StorageProviderConfig,
|
StorageProviderConfig,
|
||||||
} from '../../base';
|
} from '../../base';
|
||||||
|
import { CopilotPromptScenario } from './prompt/prompts';
|
||||||
import {
|
import {
|
||||||
AnthropicOfficialConfig,
|
AnthropicOfficialConfig,
|
||||||
AnthropicVertexConfig,
|
AnthropicVertexConfig,
|
||||||
@@ -24,6 +25,7 @@ declare global {
|
|||||||
key: string;
|
key: string;
|
||||||
}>;
|
}>;
|
||||||
storage: ConfigItem<StorageProviderConfig>;
|
storage: ConfigItem<StorageProviderConfig>;
|
||||||
|
scenarios: ConfigItem<CopilotPromptScenario>;
|
||||||
providers: {
|
providers: {
|
||||||
openai: ConfigItem<OpenAIConfig>;
|
openai: ConfigItem<OpenAIConfig>;
|
||||||
fal: ConfigItem<FalConfig>;
|
fal: ConfigItem<FalConfig>;
|
||||||
@@ -43,17 +45,29 @@ defineModuleConfig('copilot', {
|
|||||||
desc: 'Whether to enable the copilot plugin.',
|
desc: 'Whether to enable the copilot plugin.',
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
scenarios: {
|
||||||
|
desc: 'The models used in the scene for the copilot, will use this config if enabled.',
|
||||||
|
default: {
|
||||||
|
enabled: false,
|
||||||
|
scenarios: {
|
||||||
|
audio: 'gemini-2.5-flash',
|
||||||
|
chat: 'claude-sonnet-4@20250514',
|
||||||
|
embedding: 'gemini-embedding-001',
|
||||||
|
image: 'gpt-image-1',
|
||||||
|
rerank: 'gpt-4.1',
|
||||||
|
brainstorm: 'gpt-4o-2024-08-06',
|
||||||
|
coding: 'claude-sonnet-4@20250514',
|
||||||
|
quick_decision: 'gpt-4.1-mini',
|
||||||
|
quick_written: 'gemini-2.5-flash',
|
||||||
|
summary_inspection: 'gemini-2.5-flash',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
'providers.openai': {
|
'providers.openai': {
|
||||||
desc: 'The config for the openai provider.',
|
desc: 'The config for the openai provider.',
|
||||||
default: {
|
default: {
|
||||||
apiKey: '',
|
apiKey: '',
|
||||||
baseUrl: '',
|
baseURL: 'https://api.openai.com/v1',
|
||||||
fallback: {
|
|
||||||
text: '',
|
|
||||||
structured: '',
|
|
||||||
image: '',
|
|
||||||
embedding: '',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
link: 'https://github.com/openai/openai-node',
|
link: 'https://github.com/openai/openai-node',
|
||||||
},
|
},
|
||||||
@@ -67,54 +81,30 @@ defineModuleConfig('copilot', {
|
|||||||
desc: 'The config for the gemini provider.',
|
desc: 'The config for the gemini provider.',
|
||||||
default: {
|
default: {
|
||||||
apiKey: '',
|
apiKey: '',
|
||||||
baseUrl: '',
|
baseURL: 'https://generativelanguage.googleapis.com/v1beta',
|
||||||
fallback: {
|
|
||||||
text: '',
|
|
||||||
structured: '',
|
|
||||||
image: '',
|
|
||||||
embedding: '',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'providers.geminiVertex': {
|
'providers.geminiVertex': {
|
||||||
desc: 'The config for the gemini provider in Google Vertex AI.',
|
desc: 'The config for the gemini provider in Google Vertex AI.',
|
||||||
default: {
|
default: {},
|
||||||
baseURL: '',
|
|
||||||
fallback: {
|
|
||||||
text: '',
|
|
||||||
structured: '',
|
|
||||||
image: '',
|
|
||||||
embedding: '',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
schema: VertexSchema,
|
schema: VertexSchema,
|
||||||
},
|
},
|
||||||
'providers.perplexity': {
|
'providers.perplexity': {
|
||||||
desc: 'The config for the perplexity provider.',
|
desc: 'The config for the perplexity provider.',
|
||||||
default: {
|
default: {
|
||||||
apiKey: '',
|
apiKey: '',
|
||||||
fallback: {
|
|
||||||
text: '',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'providers.anthropic': {
|
'providers.anthropic': {
|
||||||
desc: 'The config for the anthropic provider.',
|
desc: 'The config for the anthropic provider.',
|
||||||
default: {
|
default: {
|
||||||
apiKey: '',
|
apiKey: '',
|
||||||
fallback: {
|
baseURL: 'https://api.anthropic.com/v1',
|
||||||
text: '',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'providers.anthropicVertex': {
|
'providers.anthropicVertex': {
|
||||||
desc: 'The config for the anthropic provider in Google Vertex AI.',
|
desc: 'The config for the anthropic provider in Google Vertex AI.',
|
||||||
default: {
|
default: {},
|
||||||
baseURL: '',
|
|
||||||
fallback: {
|
|
||||||
text: '',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
schema: VertexSchema,
|
schema: VertexSchema,
|
||||||
},
|
},
|
||||||
'providers.morph': {
|
'providers.morph': {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Logger } from '@nestjs/common';
|
|||||||
import type { ModuleRef } from '@nestjs/core';
|
import type { ModuleRef } from '@nestjs/core';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
Config,
|
||||||
CopilotPromptNotFound,
|
CopilotPromptNotFound,
|
||||||
CopilotProviderNotSupported,
|
CopilotProviderNotSupported,
|
||||||
} from '../../../base';
|
} from '../../../base';
|
||||||
@@ -28,6 +29,7 @@ class ProductionEmbeddingClient extends EmbeddingClient {
|
|||||||
private readonly logger = new Logger(ProductionEmbeddingClient.name);
|
private readonly logger = new Logger(ProductionEmbeddingClient.name);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
private readonly config: Config,
|
||||||
private readonly providerFactory: CopilotProviderFactory,
|
private readonly providerFactory: CopilotProviderFactory,
|
||||||
private readonly prompt: PromptService
|
private readonly prompt: PromptService
|
||||||
) {
|
) {
|
||||||
@@ -36,7 +38,9 @@ class ProductionEmbeddingClient extends EmbeddingClient {
|
|||||||
|
|
||||||
override async configured(): Promise<boolean> {
|
override async configured(): Promise<boolean> {
|
||||||
const embedding = await this.providerFactory.getProvider({
|
const embedding = await this.providerFactory.getProvider({
|
||||||
modelId: EMBEDDING_MODEL,
|
modelId: this.config.copilot?.scenarios?.enabled
|
||||||
|
? this.config.copilot.scenarios.scenarios?.embedding || EMBEDDING_MODEL
|
||||||
|
: EMBEDDING_MODEL,
|
||||||
outputType: ModelOutputType.Embedding,
|
outputType: ModelOutputType.Embedding,
|
||||||
});
|
});
|
||||||
const result = Boolean(embedding);
|
const result = Boolean(embedding);
|
||||||
@@ -209,12 +213,13 @@ export async function getEmbeddingClient(
|
|||||||
if (EMBEDDING_CLIENT) {
|
if (EMBEDDING_CLIENT) {
|
||||||
return EMBEDDING_CLIENT;
|
return EMBEDDING_CLIENT;
|
||||||
}
|
}
|
||||||
|
const config = moduleRef.get(Config, { strict: false });
|
||||||
const providerFactory = moduleRef.get(CopilotProviderFactory, {
|
const providerFactory = moduleRef.get(CopilotProviderFactory, {
|
||||||
strict: false,
|
strict: false,
|
||||||
});
|
});
|
||||||
const prompt = moduleRef.get(PromptService, { strict: false });
|
const prompt = moduleRef.get(PromptService, { strict: false });
|
||||||
|
|
||||||
const client = new ProductionEmbeddingClient(providerFactory, prompt);
|
const client = new ProductionEmbeddingClient(config, providerFactory, prompt);
|
||||||
if (await client.configured()) {
|
if (await client.configured()) {
|
||||||
EMBEDDING_CLIENT = client;
|
EMBEDDING_CLIENT = client;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,83 @@ type Prompt = Omit<
|
|||||||
config?: PromptConfig;
|
config?: PromptConfig;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const Scenario: Record<string, string[]> = {
|
||||||
|
audio: ['Transcript audio'],
|
||||||
|
brainstorm: [
|
||||||
|
'Brainstorm mindmap',
|
||||||
|
'Create a presentation',
|
||||||
|
'Expand mind map',
|
||||||
|
'workflow:brainstorm:step2',
|
||||||
|
'workflow:presentation:step2',
|
||||||
|
'workflow:presentation:step4',
|
||||||
|
],
|
||||||
|
chat: ['Chat With AFFiNE AI'],
|
||||||
|
coding: [
|
||||||
|
'Apply Updates',
|
||||||
|
'Code Artifact',
|
||||||
|
'Make it real',
|
||||||
|
'Make it real with text',
|
||||||
|
'Section Edit',
|
||||||
|
],
|
||||||
|
// no prompt needed, just a placeholder
|
||||||
|
embedding: [],
|
||||||
|
image: [
|
||||||
|
'Convert to Anime style',
|
||||||
|
'Convert to Clay style',
|
||||||
|
'Convert to Pixel style',
|
||||||
|
'Convert to Sketch style',
|
||||||
|
'Convert to sticker',
|
||||||
|
'Generate image',
|
||||||
|
'Remove background',
|
||||||
|
'Upscale image',
|
||||||
|
],
|
||||||
|
quick_decision: [
|
||||||
|
'Create headings',
|
||||||
|
'Generate a caption',
|
||||||
|
'Translate to',
|
||||||
|
'workflow:brainstorm:step1',
|
||||||
|
'workflow:presentation:step1',
|
||||||
|
'workflow:image-anime:step2',
|
||||||
|
'workflow:image-clay:step2',
|
||||||
|
'workflow:image-pixel:step2',
|
||||||
|
'workflow:image-sketch:step2',
|
||||||
|
],
|
||||||
|
quick_written: [
|
||||||
|
'Brainstorm ideas about this',
|
||||||
|
'Continue writing',
|
||||||
|
'Explain this code',
|
||||||
|
'Fix spelling for it',
|
||||||
|
'Improve writing for it',
|
||||||
|
'Make it longer',
|
||||||
|
'Make it shorter',
|
||||||
|
'Write a blog post about this',
|
||||||
|
'Write a poem about this',
|
||||||
|
'Write an article about this',
|
||||||
|
'Write outline',
|
||||||
|
],
|
||||||
|
rerank: ['Rerank results'],
|
||||||
|
summary_inspection: [
|
||||||
|
'Change tone to',
|
||||||
|
'Check code error',
|
||||||
|
'Conversation Summary',
|
||||||
|
'Explain this',
|
||||||
|
'Explain this image',
|
||||||
|
'Find action for summary',
|
||||||
|
'Find action items from it',
|
||||||
|
'Improve grammar for it',
|
||||||
|
'Summarize the meeting',
|
||||||
|
'Summary',
|
||||||
|
'Summary as title',
|
||||||
|
'Summary the webpage',
|
||||||
|
'Write a twitter about this',
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CopilotPromptScenario = {
|
||||||
|
enabled?: boolean;
|
||||||
|
scenarios?: Partial<Record<keyof typeof Scenario, string>>;
|
||||||
|
};
|
||||||
|
|
||||||
const workflows: Prompt[] = [
|
const workflows: Prompt[] = [
|
||||||
{
|
{
|
||||||
name: 'workflow:presentation',
|
name: 'workflow:presentation',
|
||||||
@@ -1612,31 +1689,6 @@ const imageActions: Prompt[] = [
|
|||||||
model: 'workflowutils/teed',
|
model: 'workflowutils/teed',
|
||||||
messages: [{ role: 'user', content: '{{content}}' }],
|
messages: [{ role: 'user', content: '{{content}}' }],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: 'debug:action:dalle3',
|
|
||||||
action: 'image',
|
|
||||||
model: 'dall-e-3',
|
|
||||||
messages: [
|
|
||||||
{
|
|
||||||
role: 'user',
|
|
||||||
content: '{{content}}',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'debug:action:gpt-image-1',
|
|
||||||
action: 'image',
|
|
||||||
model: 'gpt-image-1',
|
|
||||||
messages: [
|
|
||||||
{
|
|
||||||
role: 'user',
|
|
||||||
content: '{{content}}',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
config: {
|
|
||||||
requireContent: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: 'debug:action:fal-sd15',
|
name: 'debug:action:fal-sd15',
|
||||||
action: 'image',
|
action: 'image',
|
||||||
@@ -1814,6 +1866,65 @@ Now apply the \`updates\` to the \`content\`, following the intent in \`op\`, an
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'Code Artifact',
|
||||||
|
model: 'claude-sonnet-4@20250514',
|
||||||
|
messages: [
|
||||||
|
{
|
||||||
|
role: 'system',
|
||||||
|
content: `
|
||||||
|
When sent new notes, respond ONLY with the contents of the html file.
|
||||||
|
DO NOT INCLUDE ANY OTHER TEXT, EXPLANATIONS, APOLOGIES, OR INTRODUCTORY/CLOSING PHRASES.
|
||||||
|
IF USER DOES NOT SPECIFY A STYLE, FOLLOW THE DEFAULT STYLE.
|
||||||
|
<generate_guide>
|
||||||
|
- The results should be a single HTML file.
|
||||||
|
- Use tailwindcss to style the website
|
||||||
|
- Put any additional CSS styles in a style tag and any JavaScript in a script tag.
|
||||||
|
- Use unpkg or skypack to import any required dependencies.
|
||||||
|
- Use Google fonts to pull in any open source fonts you require.
|
||||||
|
- Use lucide icons for any icons.
|
||||||
|
- If you have any images, load them from Unsplash or use solid colored rectangles.
|
||||||
|
</generate_guide>
|
||||||
|
|
||||||
|
<DO_NOT_USE_COLORS>
|
||||||
|
- DO NOT USE ANY COLORS
|
||||||
|
</DO_NOT_USE_COLORS>
|
||||||
|
<DO_NOT_USE_GRADIENTS>
|
||||||
|
- DO NOT USE ANY GRADIENTS
|
||||||
|
</DO_NOT_USE_GRADIENTS>
|
||||||
|
|
||||||
|
<COLOR_THEME>
|
||||||
|
- --affine-blue-300: #93e2fd
|
||||||
|
- --affine-blue-400: #60cffa
|
||||||
|
- --affine-blue-500: #3ab5f7
|
||||||
|
- --affine-blue-600: #1e96eb
|
||||||
|
- --affine-blue-700: #1e67af
|
||||||
|
- --affine-text-primary-color: #121212
|
||||||
|
- --affine-text-secondary-color: #8e8d91
|
||||||
|
- --affine-text-disable-color: #a9a9ad
|
||||||
|
- --affine-background-overlay-panel-color: #fbfbfc
|
||||||
|
- --affine-background-secondary-color: #f4f4f5
|
||||||
|
- --affine-background-primary-color: #fff
|
||||||
|
</COLOR_THEME>
|
||||||
|
<default_style_guide>
|
||||||
|
- MUST USE White and Blue(#1e96eb) as the primary color
|
||||||
|
- KEEP THE DEFAULT STYLE SIMPLE AND CLEAN
|
||||||
|
- DO NOT USE ANY COMPLEX STYLES
|
||||||
|
- DO NOT USE ANY GRADIENTS
|
||||||
|
- USE LESS SHADOWS
|
||||||
|
- USE RADIUS 4px or 8px for rounded corners
|
||||||
|
- USE 12px or 16px for padding
|
||||||
|
- Use the tailwind color gray, zinc, slate, neutral much more.
|
||||||
|
- Use 0.5px border should be better
|
||||||
|
</default_style_guide>
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
role: 'user',
|
||||||
|
content: '{{content}}',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const CHAT_PROMPT: Omit<Prompt, 'name'> = {
|
const CHAT_PROMPT: Omit<Prompt, 'name'> = {
|
||||||
@@ -1973,84 +2084,6 @@ const chat: Prompt[] = [
|
|||||||
name: 'Chat With AFFiNE AI',
|
name: 'Chat With AFFiNE AI',
|
||||||
...CHAT_PROMPT,
|
...CHAT_PROMPT,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: 'Search With AFFiNE AI',
|
|
||||||
...CHAT_PROMPT,
|
|
||||||
},
|
|
||||||
// use for believer plan
|
|
||||||
{
|
|
||||||
name: 'Chat With AFFiNE AI - Believer',
|
|
||||||
model: 'gpt-o1',
|
|
||||||
messages: [
|
|
||||||
{
|
|
||||||
role: 'system',
|
|
||||||
content:
|
|
||||||
"You are AFFiNE AI, a professional and humorous copilot within AFFiNE. You are powered by latest GPT model from OpenAI and AFFiNE. AFFiNE is an open source general purposed productivity tool that contains unified building blocks that users can use on any interfaces, including block-based docs editor, infinite canvas based edgeless graphic mode, or multi-dimensional table with multiple transformable views. Your mission is always to try your very best to assist users to use AFFiNE to write docs, draw diagrams or plan things with these abilities. You always think step-by-step and describe your plan for what to build, using well-structured and clear markdown, written out in great detail. Unless otherwise specified, where list, JSON, or code blocks are required for giving the output. Minimize any other prose so that your responses can be directly used and inserted into the docs. You are able to access to API of AFFiNE to finish your job. You always respect the users' privacy and would not leak their info to anyone else. AFFiNE is made by Toeverything .Pte .Ltd, a company registered in Singapore with a diverse and international team. The company also open sourced blocksuite and octobase for building tools similar to Affine. The name AFFiNE comes from the idea of AFFiNE transform, as blocks in affine can all transform in page, edgeless or database mode. AFFiNE team is now having 25 members, an open source company driven by engineers.",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const artifactActions: Prompt[] = [
|
|
||||||
{
|
|
||||||
name: 'Code Artifact',
|
|
||||||
model: 'claude-sonnet-4@20250514',
|
|
||||||
messages: [
|
|
||||||
{
|
|
||||||
role: 'system',
|
|
||||||
content: `
|
|
||||||
When sent new notes, respond ONLY with the contents of the html file.
|
|
||||||
DO NOT INCLUDE ANY OTHER TEXT, EXPLANATIONS, APOLOGIES, OR INTRODUCTORY/CLOSING PHRASES.
|
|
||||||
IF USER DOES NOT SPECIFY A STYLE, FOLLOW THE DEFAULT STYLE.
|
|
||||||
<generate_guide>
|
|
||||||
- The results should be a single HTML file.
|
|
||||||
- Use tailwindcss to style the website
|
|
||||||
- Put any additional CSS styles in a style tag and any JavaScript in a script tag.
|
|
||||||
- Use unpkg or skypack to import any required dependencies.
|
|
||||||
- Use Google fonts to pull in any open source fonts you require.
|
|
||||||
- Use lucide icons for any icons.
|
|
||||||
- If you have any images, load them from Unsplash or use solid colored rectangles.
|
|
||||||
</generate_guide>
|
|
||||||
|
|
||||||
<DO_NOT_USE_COLORS>
|
|
||||||
- DO NOT USE ANY COLORS
|
|
||||||
</DO_NOT_USE_COLORS>
|
|
||||||
<DO_NOT_USE_GRADIENTS>
|
|
||||||
- DO NOT USE ANY GRADIENTS
|
|
||||||
</DO_NOT_USE_GRADIENTS>
|
|
||||||
|
|
||||||
<COLOR_THEME>
|
|
||||||
- --affine-blue-300: #93e2fd
|
|
||||||
- --affine-blue-400: #60cffa
|
|
||||||
- --affine-blue-500: #3ab5f7
|
|
||||||
- --affine-blue-600: #1e96eb
|
|
||||||
- --affine-blue-700: #1e67af
|
|
||||||
- --affine-text-primary-color: #121212
|
|
||||||
- --affine-text-secondary-color: #8e8d91
|
|
||||||
- --affine-text-disable-color: #a9a9ad
|
|
||||||
- --affine-background-overlay-panel-color: #fbfbfc
|
|
||||||
- --affine-background-secondary-color: #f4f4f5
|
|
||||||
- --affine-background-primary-color: #fff
|
|
||||||
</COLOR_THEME>
|
|
||||||
<default_style_guide>
|
|
||||||
- MUST USE White and Blue(#1e96eb) as the primary color
|
|
||||||
- KEEP THE DEFAULT STYLE SIMPLE AND CLEAN
|
|
||||||
- DO NOT USE ANY COMPLEX STYLES
|
|
||||||
- DO NOT USE ANY GRADIENTS
|
|
||||||
- USE LESS SHADOWS
|
|
||||||
- USE RADIUS 4px or 8px for rounded corners
|
|
||||||
- USE 12px or 16px for padding
|
|
||||||
- Use the tailwind color gray, zinc, slate, neutral much more.
|
|
||||||
- Use 0.5px border should be better
|
|
||||||
</default_style_guide>
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
role: 'user',
|
|
||||||
content: '{{content}}',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
export const prompts: Prompt[] = [
|
export const prompts: Prompt[] = [
|
||||||
@@ -2059,7 +2092,6 @@ export const prompts: Prompt[] = [
|
|||||||
...modelActions,
|
...modelActions,
|
||||||
...chat,
|
...chat,
|
||||||
...workflows,
|
...workflows,
|
||||||
...artifactActions,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
export async function refreshPrompts(db: PrismaClient) {
|
export async function refreshPrompts(db: PrismaClient) {
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { Injectable, OnApplicationBootstrap } from '@nestjs/common';
|
import { Injectable, Logger, OnApplicationBootstrap } from '@nestjs/common';
|
||||||
import { PrismaClient } from '@prisma/client';
|
import { Transactional } from '@nestjs-cls/transactional';
|
||||||
|
import { Prisma, PrismaClient } from '@prisma/client';
|
||||||
|
|
||||||
|
import { Config, OnEvent } from '../../../base';
|
||||||
import {
|
import {
|
||||||
PromptConfig,
|
PromptConfig,
|
||||||
PromptConfigSchema,
|
PromptConfigSchema,
|
||||||
@@ -8,19 +10,65 @@ import {
|
|||||||
PromptMessageSchema,
|
PromptMessageSchema,
|
||||||
} from '../providers';
|
} from '../providers';
|
||||||
import { ChatPrompt } from './chat-prompt';
|
import { ChatPrompt } from './chat-prompt';
|
||||||
import { refreshPrompts } from './prompts';
|
import {
|
||||||
|
CopilotPromptScenario,
|
||||||
|
prompts,
|
||||||
|
refreshPrompts,
|
||||||
|
Scenario,
|
||||||
|
} from './prompts';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PromptService implements OnApplicationBootstrap {
|
export class PromptService implements OnApplicationBootstrap {
|
||||||
|
private readonly logger = new Logger(PromptService.name);
|
||||||
private readonly cache = new Map<string, ChatPrompt>();
|
private readonly cache = new Map<string, ChatPrompt>();
|
||||||
|
|
||||||
constructor(private readonly db: PrismaClient) {}
|
constructor(
|
||||||
|
private readonly config: Config,
|
||||||
|
private readonly db: PrismaClient
|
||||||
|
) {}
|
||||||
|
|
||||||
async onApplicationBootstrap() {
|
async onApplicationBootstrap() {
|
||||||
this.cache.clear();
|
this.cache.clear();
|
||||||
await refreshPrompts(this.db);
|
await refreshPrompts(this.db);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OnEvent('config.init')
|
||||||
|
async onConfigInit() {
|
||||||
|
await this.setup(this.config.copilot?.scenarios);
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnEvent('config.changed')
|
||||||
|
async onConfigChanged(event: Events['config.changed']) {
|
||||||
|
if ('copilot' in event.updates) {
|
||||||
|
await this.setup(event.updates.copilot?.scenarios);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async setup(scenarios?: CopilotPromptScenario) {
|
||||||
|
if (!!scenarios && scenarios.enabled && scenarios.scenarios) {
|
||||||
|
this.logger.log('Updating prompts based on scenarios...');
|
||||||
|
for (const [scenario, model] of Object.entries(scenarios.scenarios)) {
|
||||||
|
const promptNames = Scenario[scenario];
|
||||||
|
for (const name of promptNames) {
|
||||||
|
const prompt = prompts.find(p => p.name === name);
|
||||||
|
if (prompt && model) {
|
||||||
|
await this.update(
|
||||||
|
prompt.name,
|
||||||
|
{ model, modified: true },
|
||||||
|
{ model: { not: model } }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.logger.log('No scenarios enabled, using default prompts.');
|
||||||
|
const prompts = Object.values(Scenario).flat();
|
||||||
|
for (const prompt of prompts) {
|
||||||
|
await this.update(prompt, { modified: false });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* list prompt names
|
* list prompt names
|
||||||
* @returns prompt names
|
* @returns prompt names
|
||||||
@@ -121,33 +169,46 @@ export class PromptService implements OnApplicationBootstrap {
|
|||||||
.then(ret => ret.id);
|
.then(ret => ret.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional()
|
||||||
async update(
|
async update(
|
||||||
name: string,
|
name: string,
|
||||||
messages: PromptMessage[],
|
data: {
|
||||||
modifyByApi: boolean = false,
|
messages?: PromptMessage[];
|
||||||
config?: PromptConfig
|
model?: string;
|
||||||
|
modified?: boolean;
|
||||||
|
config?: PromptConfig;
|
||||||
|
},
|
||||||
|
where?: Prisma.AiPromptWhereInput
|
||||||
) {
|
) {
|
||||||
const { id } = await this.db.aiPrompt.update({
|
const { config, messages, model, modified } = data;
|
||||||
where: { name },
|
const existing = await this.db.aiPrompt
|
||||||
data: {
|
.count({ where: { ...where, name } })
|
||||||
config: config || undefined,
|
.then(count => count > 0);
|
||||||
updatedAt: new Date(),
|
if (existing) {
|
||||||
modified: modifyByApi,
|
await this.db.aiPrompt.update({
|
||||||
messages: {
|
where: { name },
|
||||||
// cleanup old messages
|
data: {
|
||||||
deleteMany: {},
|
config: config || undefined,
|
||||||
create: messages.map((m, idx) => ({
|
updatedAt: new Date(),
|
||||||
idx,
|
modified,
|
||||||
...m,
|
model,
|
||||||
attachments: m.attachments || undefined,
|
messages: messages
|
||||||
params: m.params || undefined,
|
? {
|
||||||
})),
|
// cleanup old messages
|
||||||
|
deleteMany: {},
|
||||||
|
create: messages.map((m, idx) => ({
|
||||||
|
idx,
|
||||||
|
...m,
|
||||||
|
attachments: m.attachments || undefined,
|
||||||
|
params: m.params || undefined,
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
},
|
},
|
||||||
},
|
});
|
||||||
});
|
|
||||||
|
|
||||||
this.cache.delete(name);
|
this.cache.delete(name);
|
||||||
return id;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async delete(name: string) {
|
async delete(name: string) {
|
||||||
|
|||||||
@@ -2,26 +2,20 @@ import {
|
|||||||
type AnthropicProvider as AnthropicSDKProvider,
|
type AnthropicProvider as AnthropicSDKProvider,
|
||||||
createAnthropic,
|
createAnthropic,
|
||||||
} from '@ai-sdk/anthropic';
|
} from '@ai-sdk/anthropic';
|
||||||
|
import z from 'zod';
|
||||||
|
|
||||||
import {
|
import { CopilotProviderType, ModelInputType, ModelOutputType } from '../types';
|
||||||
CopilotChatOptions,
|
|
||||||
CopilotProviderType,
|
|
||||||
ModelConditions,
|
|
||||||
ModelInputType,
|
|
||||||
ModelOutputType,
|
|
||||||
PromptMessage,
|
|
||||||
StreamObject,
|
|
||||||
} from '../types';
|
|
||||||
import { AnthropicProvider } from './anthropic';
|
import { AnthropicProvider } from './anthropic';
|
||||||
|
|
||||||
export type AnthropicOfficialConfig = {
|
export type AnthropicOfficialConfig = {
|
||||||
apiKey: string;
|
apiKey: string;
|
||||||
baseUrl?: string;
|
baseURL?: string;
|
||||||
fallback?: {
|
|
||||||
text?: string;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ModelListSchema = z.object({
|
||||||
|
data: z.array(z.object({ id: z.string() })),
|
||||||
|
});
|
||||||
|
|
||||||
export class AnthropicOfficialProvider extends AnthropicProvider<AnthropicOfficialConfig> {
|
export class AnthropicOfficialProvider extends AnthropicProvider<AnthropicOfficialConfig> {
|
||||||
override readonly type = CopilotProviderType.Anthropic;
|
override readonly type = CopilotProviderType.Anthropic;
|
||||||
|
|
||||||
@@ -75,34 +69,27 @@ export class AnthropicOfficialProvider extends AnthropicProvider<AnthropicOffici
|
|||||||
super.setup();
|
super.setup();
|
||||||
this.instance = createAnthropic({
|
this.instance = createAnthropic({
|
||||||
apiKey: this.config.apiKey,
|
apiKey: this.config.apiKey,
|
||||||
baseURL: this.config.baseUrl,
|
baseURL: this.config.baseURL,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
override async text(
|
override async refreshOnlineModels() {
|
||||||
cond: ModelConditions,
|
try {
|
||||||
messages: PromptMessage[],
|
const baseUrl = this.config.baseURL || 'https://api.anthropic.com/v1';
|
||||||
options: CopilotChatOptions = {}
|
if (baseUrl && !this.onlineModelList.length) {
|
||||||
): Promise<string> {
|
const { data } = await fetch(`${baseUrl}/models`, {
|
||||||
const fullCond = { ...cond, fallbackModel: this.config.fallback?.text };
|
headers: {
|
||||||
return super.text(fullCond, messages, options);
|
'x-api-key': this.config.apiKey,
|
||||||
}
|
'anthropic-version': '2023-06-01',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
override async *streamText(
|
},
|
||||||
cond: ModelConditions,
|
})
|
||||||
messages: PromptMessage[],
|
.then(r => r.json())
|
||||||
options: CopilotChatOptions = {}
|
.then(r => ModelListSchema.parse(r));
|
||||||
): AsyncIterable<string> {
|
this.onlineModelList = data.map(model => model.id);
|
||||||
const fullCond = { ...cond, fallbackModel: this.config.fallback?.text };
|
}
|
||||||
yield* super.streamText(fullCond, messages, options);
|
} catch (e) {
|
||||||
}
|
this.logger.error('Failed to fetch available models', e);
|
||||||
|
}
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,23 +4,11 @@ import {
|
|||||||
type GoogleVertexAnthropicProviderSettings,
|
type GoogleVertexAnthropicProviderSettings,
|
||||||
} from '@ai-sdk/google-vertex/anthropic';
|
} from '@ai-sdk/google-vertex/anthropic';
|
||||||
|
|
||||||
import {
|
import { CopilotProviderType, ModelInputType, ModelOutputType } from '../types';
|
||||||
CopilotChatOptions,
|
|
||||||
CopilotProviderType,
|
|
||||||
ModelConditions,
|
|
||||||
ModelInputType,
|
|
||||||
ModelOutputType,
|
|
||||||
PromptMessage,
|
|
||||||
StreamObject,
|
|
||||||
} from '../types';
|
|
||||||
import { getGoogleAuth, VertexModelListSchema } from '../utils';
|
import { getGoogleAuth, VertexModelListSchema } from '../utils';
|
||||||
import { AnthropicProvider } from './anthropic';
|
import { AnthropicProvider } from './anthropic';
|
||||||
|
|
||||||
export type AnthropicVertexConfig = GoogleVertexAnthropicProviderSettings & {
|
export type AnthropicVertexConfig = GoogleVertexAnthropicProviderSettings;
|
||||||
fallback?: {
|
|
||||||
text?: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export class AnthropicVertexProvider extends AnthropicProvider<AnthropicVertexConfig> {
|
export class AnthropicVertexProvider extends AnthropicProvider<AnthropicVertexConfig> {
|
||||||
override readonly type = CopilotProviderType.AnthropicVertex;
|
override readonly type = CopilotProviderType.AnthropicVertex;
|
||||||
@@ -76,33 +64,6 @@ export class AnthropicVertexProvider extends AnthropicProvider<AnthropicVertexCo
|
|||||||
this.instance = createVertexAnthropic(this.config);
|
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() {
|
override async refreshOnlineModels() {
|
||||||
try {
|
try {
|
||||||
const { baseUrl, headers } = await getGoogleAuth(
|
const { baseUrl, headers } = await getGoogleAuth(
|
||||||
|
|||||||
@@ -74,6 +74,16 @@ export class FalProvider extends CopilotProvider<FalConfig> {
|
|||||||
override type = CopilotProviderType.FAL;
|
override type = CopilotProviderType.FAL;
|
||||||
|
|
||||||
override readonly models = [
|
override readonly models = [
|
||||||
|
{
|
||||||
|
id: 'lcm',
|
||||||
|
capabilities: [
|
||||||
|
{
|
||||||
|
input: [ModelInputType.Text],
|
||||||
|
output: [ModelOutputType.Image],
|
||||||
|
defaultForOutputType: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
// image to image models
|
// image to image models
|
||||||
{
|
{
|
||||||
id: 'lcm-sd15-i2i',
|
id: 'lcm-sd15-i2i',
|
||||||
|
|||||||
@@ -4,27 +4,12 @@ import {
|
|||||||
} from '@ai-sdk/google';
|
} from '@ai-sdk/google';
|
||||||
import z from 'zod';
|
import z from 'zod';
|
||||||
|
|
||||||
import {
|
import { CopilotProviderType, ModelInputType, ModelOutputType } from '../types';
|
||||||
CopilotChatOptions,
|
|
||||||
CopilotEmbeddingOptions,
|
|
||||||
CopilotProviderType,
|
|
||||||
ModelConditions,
|
|
||||||
ModelInputType,
|
|
||||||
ModelOutputType,
|
|
||||||
PromptMessage,
|
|
||||||
StreamObject,
|
|
||||||
} from '../types';
|
|
||||||
import { GeminiProvider } from './gemini';
|
import { GeminiProvider } from './gemini';
|
||||||
|
|
||||||
export type GeminiGenerativeConfig = {
|
export type GeminiGenerativeConfig = {
|
||||||
apiKey: string;
|
apiKey: string;
|
||||||
baseUrl?: string;
|
baseURL?: string;
|
||||||
fallback?: {
|
|
||||||
text?: string;
|
|
||||||
structured?: string;
|
|
||||||
image?: string;
|
|
||||||
embedding?: string;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const ModelListSchema = z.object({
|
const ModelListSchema = z.object({
|
||||||
@@ -113,65 +98,14 @@ export class GeminiGenerativeProvider extends GeminiProvider<GeminiGenerativeCon
|
|||||||
super.setup();
|
super.setup();
|
||||||
this.instance = createGoogleGenerativeAI({
|
this.instance = createGoogleGenerativeAI({
|
||||||
apiKey: this.config.apiKey,
|
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() {
|
override async refreshOnlineModels() {
|
||||||
try {
|
try {
|
||||||
const baseUrl =
|
const baseUrl =
|
||||||
this.config.baseUrl ||
|
this.config.baseURL ||
|
||||||
'https://generativelanguage.googleapis.com/v1beta';
|
'https://generativelanguage.googleapis.com/v1beta';
|
||||||
if (baseUrl && !this.onlineModelList.length) {
|
if (baseUrl && !this.onlineModelList.length) {
|
||||||
const { models } = await fetch(
|
const { models } = await fetch(
|
||||||
|
|||||||
@@ -4,27 +4,11 @@ import {
|
|||||||
type GoogleVertexProviderSettings,
|
type GoogleVertexProviderSettings,
|
||||||
} from '@ai-sdk/google-vertex';
|
} from '@ai-sdk/google-vertex';
|
||||||
|
|
||||||
import {
|
import { CopilotProviderType, ModelInputType, ModelOutputType } from '../types';
|
||||||
CopilotChatOptions,
|
|
||||||
CopilotEmbeddingOptions,
|
|
||||||
CopilotProviderType,
|
|
||||||
ModelConditions,
|
|
||||||
ModelInputType,
|
|
||||||
ModelOutputType,
|
|
||||||
PromptMessage,
|
|
||||||
StreamObject,
|
|
||||||
} from '../types';
|
|
||||||
import { getGoogleAuth, VertexModelListSchema } from '../utils';
|
import { getGoogleAuth, VertexModelListSchema } from '../utils';
|
||||||
import { GeminiProvider } from './gemini';
|
import { GeminiProvider } from './gemini';
|
||||||
|
|
||||||
export type GeminiVertexConfig = GoogleVertexProviderSettings & {
|
export type GeminiVertexConfig = GoogleVertexProviderSettings;
|
||||||
fallback?: {
|
|
||||||
text?: string;
|
|
||||||
structured?: string;
|
|
||||||
image?: string;
|
|
||||||
embedding?: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export class GeminiVertexProvider extends GeminiProvider<GeminiVertexConfig> {
|
export class GeminiVertexProvider extends GeminiProvider<GeminiVertexConfig> {
|
||||||
override readonly type = CopilotProviderType.GeminiVertex;
|
override readonly type = CopilotProviderType.GeminiVertex;
|
||||||
@@ -90,57 +74,6 @@ export class GeminiVertexProvider extends GeminiProvider<GeminiVertexConfig> {
|
|||||||
this.instance = createVertex(this.config);
|
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() {
|
override async refreshOnlineModels() {
|
||||||
try {
|
try {
|
||||||
const { baseUrl, headers } = await getGoogleAuth(this.config, 'google');
|
const { baseUrl, headers } = await getGoogleAuth(this.config, 'google');
|
||||||
|
|||||||
@@ -45,13 +45,7 @@ export const DEFAULT_DIMENSIONS = 256;
|
|||||||
|
|
||||||
export type OpenAIConfig = {
|
export type OpenAIConfig = {
|
||||||
apiKey: string;
|
apiKey: string;
|
||||||
baseUrl?: string;
|
baseURL?: string;
|
||||||
fallback?: {
|
|
||||||
text?: string;
|
|
||||||
structured?: string;
|
|
||||||
image?: string;
|
|
||||||
embedding?: string;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const ModelListSchema = z.object({
|
const ModelListSchema = z.object({
|
||||||
@@ -249,7 +243,7 @@ export class OpenAIProvider extends CopilotProvider<OpenAIConfig> {
|
|||||||
super.setup();
|
super.setup();
|
||||||
this.#instance = createOpenAI({
|
this.#instance = createOpenAI({
|
||||||
apiKey: this.config.apiKey,
|
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() {
|
override async refreshOnlineModels() {
|
||||||
try {
|
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) {
|
if (baseUrl && !this.onlineModelList.length) {
|
||||||
const { data } = await fetch(`${baseUrl}/models`, {
|
const { data } = await fetch(`${baseUrl}/models`, {
|
||||||
headers: {
|
headers: {
|
||||||
@@ -320,7 +314,6 @@ export class OpenAIProvider extends CopilotProvider<OpenAIConfig> {
|
|||||||
const fullCond = {
|
const fullCond = {
|
||||||
...cond,
|
...cond,
|
||||||
outputType: ModelOutputType.Text,
|
outputType: ModelOutputType.Text,
|
||||||
fallbackModel: this.config.fallback?.text,
|
|
||||||
};
|
};
|
||||||
await this.checkParams({ messages, cond: fullCond, options });
|
await this.checkParams({ messages, cond: fullCond, options });
|
||||||
const model = this.selectModel(fullCond);
|
const model = this.selectModel(fullCond);
|
||||||
@@ -361,7 +354,6 @@ export class OpenAIProvider extends CopilotProvider<OpenAIConfig> {
|
|||||||
const fullCond = {
|
const fullCond = {
|
||||||
...cond,
|
...cond,
|
||||||
outputType: ModelOutputType.Text,
|
outputType: ModelOutputType.Text,
|
||||||
fallbackModel: this.config.fallback?.text,
|
|
||||||
};
|
};
|
||||||
await this.checkParams({ messages, cond: fullCond, options });
|
await this.checkParams({ messages, cond: fullCond, options });
|
||||||
const model = this.selectModel(fullCond);
|
const model = this.selectModel(fullCond);
|
||||||
@@ -407,11 +399,7 @@ export class OpenAIProvider extends CopilotProvider<OpenAIConfig> {
|
|||||||
messages: PromptMessage[],
|
messages: PromptMessage[],
|
||||||
options: CopilotChatOptions = {}
|
options: CopilotChatOptions = {}
|
||||||
): AsyncIterable<StreamObject> {
|
): AsyncIterable<StreamObject> {
|
||||||
const fullCond = {
|
const fullCond = { ...cond, outputType: ModelOutputType.Object };
|
||||||
...cond,
|
|
||||||
outputType: ModelOutputType.Object,
|
|
||||||
fallbackModel: this.config.fallback?.text,
|
|
||||||
};
|
|
||||||
await this.checkParams({ cond: fullCond, messages, options });
|
await this.checkParams({ cond: fullCond, messages, options });
|
||||||
const model = this.selectModel(fullCond);
|
const model = this.selectModel(fullCond);
|
||||||
|
|
||||||
@@ -444,11 +432,7 @@ export class OpenAIProvider extends CopilotProvider<OpenAIConfig> {
|
|||||||
messages: PromptMessage[],
|
messages: PromptMessage[],
|
||||||
options: CopilotStructuredOptions = {}
|
options: CopilotStructuredOptions = {}
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const fullCond = {
|
const fullCond = { ...cond, outputType: ModelOutputType.Structured };
|
||||||
...cond,
|
|
||||||
outputType: ModelOutputType.Structured,
|
|
||||||
fallbackModel: this.config.fallback?.structured,
|
|
||||||
};
|
|
||||||
await this.checkParams({ messages, cond: fullCond, options });
|
await this.checkParams({ messages, cond: fullCond, options });
|
||||||
const model = this.selectModel(fullCond);
|
const model = this.selectModel(fullCond);
|
||||||
|
|
||||||
@@ -488,11 +472,7 @@ export class OpenAIProvider extends CopilotProvider<OpenAIConfig> {
|
|||||||
chunkMessages: PromptMessage[][],
|
chunkMessages: PromptMessage[][],
|
||||||
options: CopilotChatOptions = {}
|
options: CopilotChatOptions = {}
|
||||||
): Promise<number[]> {
|
): Promise<number[]> {
|
||||||
const fullCond = {
|
const fullCond = { ...cond, outputType: ModelOutputType.Text };
|
||||||
...cond,
|
|
||||||
outputType: ModelOutputType.Text,
|
|
||||||
fallbackModel: this.config.fallback?.text,
|
|
||||||
};
|
|
||||||
await this.checkParams({ messages: [], cond: fullCond, options });
|
await this.checkParams({ messages: [], cond: fullCond, options });
|
||||||
const model = this.selectModel(fullCond);
|
const model = this.selectModel(fullCond);
|
||||||
// get the log probability of "yes"/"no"
|
// 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, {
|
const res = await fetch(url, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { Authorization: `Bearer ${this.config.apiKey}` },
|
headers: { Authorization: `Bearer ${this.config.apiKey}` },
|
||||||
@@ -637,11 +617,7 @@ export class OpenAIProvider extends CopilotProvider<OpenAIConfig> {
|
|||||||
messages: PromptMessage[],
|
messages: PromptMessage[],
|
||||||
options: CopilotImageOptions = {}
|
options: CopilotImageOptions = {}
|
||||||
) {
|
) {
|
||||||
const fullCond = {
|
const fullCond = { ...cond, outputType: ModelOutputType.Image };
|
||||||
...cond,
|
|
||||||
outputType: ModelOutputType.Image,
|
|
||||||
fallbackModel: this.config.fallback?.image,
|
|
||||||
};
|
|
||||||
await this.checkParams({ messages, cond: fullCond, options });
|
await this.checkParams({ messages, cond: fullCond, options });
|
||||||
const model = this.selectModel(fullCond);
|
const model = this.selectModel(fullCond);
|
||||||
|
|
||||||
@@ -691,11 +667,7 @@ export class OpenAIProvider extends CopilotProvider<OpenAIConfig> {
|
|||||||
options: CopilotEmbeddingOptions = { dimensions: DEFAULT_DIMENSIONS }
|
options: CopilotEmbeddingOptions = { dimensions: DEFAULT_DIMENSIONS }
|
||||||
): Promise<number[][]> {
|
): Promise<number[][]> {
|
||||||
messages = Array.isArray(messages) ? messages : [messages];
|
messages = Array.isArray(messages) ? messages : [messages];
|
||||||
const fullCond = {
|
const fullCond = { ...cond, outputType: ModelOutputType.Embedding };
|
||||||
...cond,
|
|
||||||
outputType: ModelOutputType.Embedding,
|
|
||||||
fallbackModel: this.config.fallback?.embedding,
|
|
||||||
};
|
|
||||||
await this.checkParams({ embeddings: messages, cond: fullCond, options });
|
await this.checkParams({ embeddings: messages, cond: fullCond, options });
|
||||||
const model = this.selectModel(fullCond);
|
const model = this.selectModel(fullCond);
|
||||||
|
|
||||||
|
|||||||
@@ -20,9 +20,6 @@ import { chatToGPTMessage, CitationParser } from './utils';
|
|||||||
export type PerplexityConfig = {
|
export type PerplexityConfig = {
|
||||||
apiKey: string;
|
apiKey: string;
|
||||||
endpoint?: string;
|
endpoint?: string;
|
||||||
fallback?: {
|
|
||||||
text?: string;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const PerplexityErrorSchema = z.union([
|
const PerplexityErrorSchema = z.union([
|
||||||
@@ -112,11 +109,7 @@ export class PerplexityProvider extends CopilotProvider<PerplexityConfig> {
|
|||||||
messages: PromptMessage[],
|
messages: PromptMessage[],
|
||||||
options: CopilotChatOptions = {}
|
options: CopilotChatOptions = {}
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const fullCond = {
|
const fullCond = { ...cond, outputType: ModelOutputType.Text };
|
||||||
...cond,
|
|
||||||
outputType: ModelOutputType.Text,
|
|
||||||
fallbackModel: this.config.fallback?.text,
|
|
||||||
};
|
|
||||||
await this.checkParams({ cond: fullCond, messages, options });
|
await this.checkParams({ cond: fullCond, messages, options });
|
||||||
const model = this.selectModel(fullCond);
|
const model = this.selectModel(fullCond);
|
||||||
|
|
||||||
@@ -156,11 +149,7 @@ export class PerplexityProvider extends CopilotProvider<PerplexityConfig> {
|
|||||||
messages: PromptMessage[],
|
messages: PromptMessage[],
|
||||||
options: CopilotChatOptions = {}
|
options: CopilotChatOptions = {}
|
||||||
): AsyncIterable<string> {
|
): AsyncIterable<string> {
|
||||||
const fullCond = {
|
const fullCond = { ...cond, outputType: ModelOutputType.Text };
|
||||||
...cond,
|
|
||||||
outputType: ModelOutputType.Text,
|
|
||||||
fallbackModel: this.config.fallback?.text,
|
|
||||||
};
|
|
||||||
await this.checkParams({ cond: fullCond, messages, options });
|
await this.checkParams({ cond: fullCond, messages, options });
|
||||||
const model = this.selectModel(fullCond);
|
const model = this.selectModel(fullCond);
|
||||||
|
|
||||||
|
|||||||
@@ -104,22 +104,12 @@ export abstract class CopilotProvider<C = any> {
|
|||||||
|
|
||||||
if (modelId) {
|
if (modelId) {
|
||||||
const hasOnlineModel = this.onlineModelList.includes(modelId);
|
const hasOnlineModel = this.onlineModelList.includes(modelId);
|
||||||
const hasFallbackModel = cond.fallbackModel
|
|
||||||
? this.onlineModelList.includes(cond.fallbackModel)
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
const model = this.models.find(
|
const model = this.models.find(
|
||||||
m => m.id === modelId && m.capabilities.some(matcher)
|
m => m.id === modelId && m.capabilities.some(matcher)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (model) {
|
if (model) return 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;
|
|
||||||
}
|
|
||||||
// allow online model without capabilities check
|
// allow online model without capabilities check
|
||||||
if (hasOnlineModel) return { id: modelId, capabilities: [] };
|
if (hasOnlineModel) return { id: modelId, capabilities: [] };
|
||||||
return undefined;
|
return undefined;
|
||||||
|
|||||||
@@ -248,5 +248,4 @@ export type ModelConditions = {
|
|||||||
|
|
||||||
export type ModelFullConditions = ModelConditions & {
|
export type ModelFullConditions = ModelConditions & {
|
||||||
outputType?: ModelOutputType;
|
outputType?: ModelOutputType;
|
||||||
fallbackModel?: string;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -907,7 +907,7 @@ export class PromptsManagementResolver {
|
|||||||
@Args('messages', { type: () => [CopilotPromptMessageType] })
|
@Args('messages', { type: () => [CopilotPromptMessageType] })
|
||||||
messages: CopilotPromptMessageType[]
|
messages: CopilotPromptMessageType[]
|
||||||
) {
|
) {
|
||||||
await this.promptService.update(name, messages, true);
|
await this.promptService.update(name, { messages, modified: true });
|
||||||
return this.promptService.get(name);
|
return this.promptService.get(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,10 @@
|
|||||||
"type": "Boolean",
|
"type": "Boolean",
|
||||||
"desc": "Whether to enable the copilot plugin."
|
"desc": "Whether to enable the copilot plugin."
|
||||||
},
|
},
|
||||||
|
"scenarios": {
|
||||||
|
"type": "Object",
|
||||||
|
"desc": "The models used in the scene for the copilot, will use this config if enabled."
|
||||||
|
},
|
||||||
"providers.openai": {
|
"providers.openai": {
|
||||||
"type": "Object",
|
"type": "Object",
|
||||||
"desc": "The config for the openai provider.",
|
"desc": "The config for the openai provider.",
|
||||||
|
|||||||
@@ -142,6 +142,7 @@ export const KNOWN_CONFIG_GROUPS = [
|
|||||||
module: 'copilot',
|
module: 'copilot',
|
||||||
fields: [
|
fields: [
|
||||||
'enabled',
|
'enabled',
|
||||||
|
'scenarios',
|
||||||
'providers.openai',
|
'providers.openai',
|
||||||
'providers.gemini',
|
'providers.gemini',
|
||||||
'providers.perplexity',
|
'providers.perplexity',
|
||||||
|
|||||||
@@ -17,5 +17,4 @@ enum class Prompt(val value: String) {
|
|||||||
MakeItShorter("Make it shorter"),
|
MakeItShorter("Make it shorter"),
|
||||||
ContinueWriting("Continue writing"),
|
ContinueWriting("Continue writing"),
|
||||||
ChatWithAFFiNEAI("Chat With AFFiNE AI"),
|
ChatWithAFFiNEAI("Chat With AFFiNE AI"),
|
||||||
SearchWithAFFiNEAI("Search With AFFiNE AI"),
|
|
||||||
}
|
}
|
||||||
@@ -25,5 +25,4 @@ public enum PromptName: String, Codable {
|
|||||||
case makeItShorter = "Make it shorter"
|
case makeItShorter = "Make it shorter"
|
||||||
case continueWriting = "Continue writing"
|
case continueWriting = "Continue writing"
|
||||||
case chatWithAffineAI = "Chat With AFFiNE AI"
|
case chatWithAffineAI = "Chat With AFFiNE AI"
|
||||||
case searchWithAffineAI = "Search With AFFiNE AI"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
export const promptKeys = [
|
export const promptKeys = [
|
||||||
// text actions
|
// text actions
|
||||||
'Chat With AFFiNE AI',
|
'Chat With AFFiNE AI',
|
||||||
'Search With AFFiNE AI',
|
|
||||||
'Summary',
|
'Summary',
|
||||||
'Summary as title',
|
'Summary as title',
|
||||||
'Generate a caption',
|
'Generate a caption',
|
||||||
|
|||||||
Reference in New Issue
Block a user