Skip to content

Commit

Permalink
💄 style: add SYSTEM_AGENT env (lobehub#2694)
Browse files Browse the repository at this point in the history
  • Loading branch information
arvinxx committed May 28, 2024
1 parent c84df58 commit 0dfcf8d
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 3 deletions.
2 changes: 2 additions & 0 deletions src/config/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export const getAppConfig = () => {
AGENTS_INDEX_URL: z.string().url(),

DEFAULT_AGENT_CONFIG: z.string(),
SYSTEM_AGENT: z.string().optional(),

PLUGINS_INDEX_URL: z.string().url(),
PLUGIN_SETTINGS: z.string().optional(),
Expand All @@ -44,6 +45,7 @@ export const getAppConfig = () => {
: 'https://chat-agents.lobehub.com',

DEFAULT_AGENT_CONFIG: process.env.DEFAULT_AGENT_CONFIG || '',
SYSTEM_AGENT: process.env.SYSTEM_AGENT,

PLUGINS_INDEX_URL: !!process.env.PLUGINS_INDEX_URL
? process.env.PLUGINS_INDEX_URL
Expand Down
5 changes: 3 additions & 2 deletions src/server/globalConfig/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getAppConfig } from '@/config/app';
import { appEnv, getAppConfig } from '@/config/app';
import { fileEnv } from '@/config/file';
import { langfuseEnv } from '@/config/langfuse';
import { getLLMConfig } from '@/config/llm';
Expand All @@ -9,6 +9,7 @@ import {
TogetherAIProviderCard,
} from '@/config/modelProviders';
import { enableNextAuth } from '@/const/auth';
import { parseSystemAgent } from '@/server/globalConfig/parseSystemAgent';
import { GlobalServerConfig } from '@/types/serverConfig';
import { extractEnabledModels, transformToChatModelCards } from '@/utils/parseModels';

Expand Down Expand Up @@ -51,7 +52,6 @@ export const getServerGlobalConfig = () => {
defaultAgent: {
config: parseAgentConfig(DEFAULT_AGENT_CONFIG),
},

enableUploadFileToServer: !!fileEnv.S3_SECRET_ACCESS_KEY,
enabledAccessCode: ACCESS_CODES?.length > 0,
enabledOAuthSSO: enableNextAuth,
Expand Down Expand Up @@ -114,6 +114,7 @@ export const getServerGlobalConfig = () => {
zeroone: { enabled: ENABLED_ZEROONE },
zhipu: { enabled: ENABLED_ZHIPU },
},
systemAgent: parseSystemAgent(appEnv.SYSTEM_AGENT),
telemetry: {
langfuse: langfuseEnv.ENABLE_LANGFUSE,
},
Expand Down
95 changes: 95 additions & 0 deletions src/server/globalConfig/parseSystemAgent.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { describe, expect, it } from 'vitest';

import { parseSystemAgent } from './parseSystemAgent';

describe('parseSystemAgent', () => {
it('should parse a valid environment variable string correctly', () => {
const envValue = 'topic=openai/gpt-3.5-turbo,translation=anthropic/claude-1';
const expected = {
topic: { provider: 'openai', model: 'gpt-3.5-turbo' },
translation: { provider: 'anthropic', model: 'claude-1' },
};

expect(parseSystemAgent(envValue)).toEqual(expected);
});

it('should handle empty environment variable string', () => {
const envValue = '';
const expected = {};

expect(parseSystemAgent(envValue)).toEqual(expected);
});

it('should ignore unknown keys in environment variable string', () => {
const envValue = 'topic=openai/gpt-3.5-turbo,unknown=test/model';
const expected = {
topic: { provider: 'openai', model: 'gpt-3.5-turbo' },
};

expect(parseSystemAgent(envValue)).toEqual(expected);
});

it('should throw an error for missing model or provider values', () => {
const envValue1 = 'topic=openai,translation=/claude-1';
const envValue2 = 'topic=/gpt-3.5-turbo,translation=anthropic/';

expect(() => parseSystemAgent(envValue1)).toThrowError(/Missing model or provider/);
expect(() => parseSystemAgent(envValue2)).toThrowError(/Missing model or provider/);
});

it('should throw an error for invalid environment variable format', () => {
const envValue = 'topic-openai/gpt-3.5-turbo';

expect(() => parseSystemAgent(envValue)).toThrowError(/Invalid environment variable format/);
});

it('should handle provider or model names with special characters', () => {
const envValue = 'topic=openrouter/mistralai/mistral-7b-instruct:free';
const expected = {
topic: { provider: 'openrouter', model: 'mistralai/mistral-7b-instruct:free' },
};

expect(parseSystemAgent(envValue)).toEqual(expected);
});

it('should handle extra whitespace in environment variable string', () => {
const envValue = ' topic = openai/gpt-3.5-turbo , translation = anthropic/claude-1 ';
const expected = {
topic: { provider: 'openai', model: 'gpt-3.5-turbo' },
translation: { provider: 'anthropic', model: 'claude-1' },
};

expect(parseSystemAgent(envValue)).toEqual(expected);
});

it('should handle full-width comma in environment variable string', () => {
const envValue = 'topic=openai/gpt-3.5-turbo,translation=anthropic/claude-1';
const expected = {
topic: { provider: 'openai', model: 'gpt-3.5-turbo' },
translation: { provider: 'anthropic', model: 'claude-1' },
};

expect(parseSystemAgent(envValue)).toEqual(expected);
});

it('should handle extra whitespace around provider and model names', () => {
const envValue = 'topic= openai / gpt-3.5-turbo ,translation= anthropic / claude-1 ';
const expected = {
topic: { provider: 'openai', model: 'gpt-3.5-turbo' },
translation: { provider: 'anthropic', model: 'claude-1' },
};

expect(parseSystemAgent(envValue)).toEqual(expected);
});

it('should handle an excessively long environment variable string', () => {
const longProviderName = 'a'.repeat(100);
const longModelName = 'b'.repeat(100);
const envValue = `topic=${longProviderName}/${longModelName}`;
const expected = {
topic: { provider: longProviderName, model: longModelName },
};

expect(parseSystemAgent(envValue)).toEqual(expected);
});
});
39 changes: 39 additions & 0 deletions src/server/globalConfig/parseSystemAgent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { DEFAULT_SYSTEM_AGENT_CONFIG } from '@/const/settings';
import { UserSystemAgentConfig } from '@/types/user/settings';

const protectedKeys = Object.keys(DEFAULT_SYSTEM_AGENT_CONFIG);

export const parseSystemAgent = (envString: string = ''): Partial<UserSystemAgentConfig> => {
if (!envString) return {};

const config: Partial<UserSystemAgentConfig> = {};

// 处理全角逗号和多余空格
let envValue = envString.replaceAll(',', ',').trim();

const pairs = envValue.split(',');

for (const pair of pairs) {
const [key, value] = pair.split('=').map((s) => s.trim());

if (key && value) {
const [provider, ...modelParts] = value.split('/');
const model = modelParts.join('/');

if (!provider || !model) {
throw new Error('Missing model or provider value');
}

if (protectedKeys.includes(key)) {
config[key as keyof UserSystemAgentConfig] = {
model: model.trim(),
provider: provider.trim(),
};
}
} else {
throw new Error('Invalid environment variable format');
}
}

return config;
};
2 changes: 2 additions & 0 deletions src/store/user/slices/common/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,9 @@ export const createCommonSlice: StateCreator<
const serverSettings: DeepPartial<UserSettings> = {
defaultAgent: serverConfig.defaultAgent,
languageModel: serverConfig.languageModel,
systemAgent: serverConfig.systemAgent,
};

const defaultSettings = merge(get().defaultSettings, serverSettings);

// merge preference
Expand Down
7 changes: 6 additions & 1 deletion src/types/serverConfig.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { DeepPartial } from 'utility-types';

import { ChatModelCard } from '@/types/llm';
import { UserDefaultAgent, GlobalLLMProviderKey } from '@/types/user/settings';
import {
GlobalLLMProviderKey,
UserDefaultAgent,
UserSystemAgentConfig,
} from '@/types/user/settings';

export interface ServerModelProviderConfig {
enabled?: boolean;
Expand All @@ -21,6 +25,7 @@ export interface GlobalServerConfig {
enabledAccessCode?: boolean;
enabledOAuthSSO?: boolean;
languageModel?: ServerLanguageModel;
systemAgent?: DeepPartial<UserSystemAgentConfig>;
telemetry: {
langfuse?: boolean;
};
Expand Down

0 comments on commit 0dfcf8d

Please sign in to comment.