Agent/utils/config.ts
2026-08-06 22:17:39 +08:00

499 lines
14 KiB
TypeScript

// @ts-nocheck
export const CONFIG = {
ZHONGTAI_BASE: 'http://127.0.0.1:8088',
ZHONGTAI_METRICS_PATH: '/metrics',
ZHONGTAI_PROXY_PATH: '/proxy/anthropic-messages',
ZHONGTAI_OMLX_PROXY_PATH: '/proxy/omlx-chat',
MCP_BASE: 'http://127.0.0.1:7777',
MCP_PATH: '/mcp',
HTTP_PATH_PREFIX: '/api/',
OMLX_BASE: 'http://127.0.0.1:8000',
OMLX_CHAT_PATH: '/v1/chat/completions',
SPARKLE_BASE: 'http://127.0.0.1:8317',
SPARKLE_CHAT_PATH: '/v1/chat/completions',
MAX_TURNS: 8,
MAX_SAME_ERROR: 4,
MAX_REPORT_ROUNDS: 10,
REPORT_MAX_TOKENS: 1800,
METRICS_POLL_MS: 1500,
STREAM_RAF: true,
TOKEN_STORAGE_KEY: 'ccsparkle_agent_token',
MODE_STORAGE_KEY: 'ccsparkle_agent_mode',
MODEL_SOURCE_KEY: 'ccsparkle_model_source',
DEFAULT_SOURCE_KEY: 'ccsparkle_default_source',
OLLAMA_CFG_KEY: 'ccsparkle_ollama_cfg',
ANTHROPIC_CFG_KEY: 'ccsparkle_anthropic_cfg',
OMLX_CFG_KEY: 'ccsparkle_omlx_cfg',
SPARKLE_CFG_KEY: 'ccsparkle_sparkle_cfg',
HISTORY_STORAGE_KEY: 'ccsparkle_history',
CONTEXT_THRESHOLD_KEY: 'ccsparkle_context_threshold',
THINKING_ENABLED_KEY: 'ccsparkle_thinking_enabled',
CROSS_MODULE_ENABLED_KEY: 'ccsparkle_cross_module_enabled',
};
export function zhongtaiMetricsUrl() {
return `${CONFIG.ZHONGTAI_BASE}${CONFIG.ZHONGTAI_METRICS_PATH}`;
}
export function zhongtaiProxyUrl() {
return `${CONFIG.ZHONGTAI_BASE}${CONFIG.ZHONGTAI_PROXY_PATH}`;
}
export function zhongtaiOmlxProxyUrl() {
return `${CONFIG.ZHONGTAI_BASE}${CONFIG.ZHONGTAI_OMLX_PROXY_PATH}`;
}
export const DEFAULT_OLLAMA = {
baseUrl: 'http://127.0.0.1:11434',
model: '',
};
export const DEFAULT_ANTHROPIC = {
baseUrl: '',
authToken: '',
protocol: 'anthropic',
preset: 'custom',
fastModel: '',
standardModel: '',
proModel: '',
currentTier: 'fast',
apiVersion: '2023-06-01',
maxTokens: 4096,
presets: {},
};
export const CLOUD_API_PRESETS = [
{
id: 'zhipu_coding_anthropic',
label: '智谱 Coding · Messages',
protocol: 'anthropic',
baseUrl: 'https://open.bigmodel.cn/api/anthropic',
hint: '智谱 Coding Plan 套餐额度,Messages API',
},
{
id: 'zhipu_coding_openai',
label: '智谱 Coding · Chat',
protocol: 'openai',
baseUrl: 'https://open.bigmodel.cn/api/coding/paas/v4',
hint: '智谱 Coding Plan 套餐额度,Chat Completions',
},
{
id: 'zhipu_balance',
label: '智谱 · 账号余额',
protocol: 'openai',
baseUrl: 'https://open.bigmodel.cn/api/paas/v4',
hint: '智谱独立计费,不消耗套餐',
},
{
id: 'bailian_anthropic',
label: '百炼 · Anthropic',
protocol: 'anthropic',
baseUrl: 'https://dashscope.aliyuncs.com/apps/anthropic',
hint: '阿里云百炼(北京),Messages API;Token 填 DashScope API Key',
models: {
fastModel: 'qwen-flash',
standardModel: 'qwen3.7-plus',
proModel: 'qwen3.7-max',
currentTier: 'pro',
},
},
{
id: 'bailian_openai',
label: '百炼 · OpenAI',
protocol: 'openai',
baseUrl: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
hint: '阿里云百炼(北京),Chat Completions;Token 填 DashScope API Key',
models: {
fastModel: 'qwen-flash',
standardModel: 'qwen3.7-plus',
proModel: 'qwen3.7-max',
currentTier: 'pro',
},
},
{
id: 'deepseek_official',
label: 'DeepSeek · 官方',
protocol: 'openai',
baseUrl: 'https://api.deepseek.com/v1',
hint: 'DeepSeek 官方,OpenAI 兼容;Token 填 DeepSeek API Key',
models: {
fastModel: 'deepseek-v4-flash',
standardModel: '',
proModel: 'deepseek-v4-pro',
currentTier: 'pro',
},
},
{
id: 'moonshot_official',
label: 'Moonshot Kimi · 官方按量',
protocol: 'openai',
baseUrl: 'https://api.moonshot.cn/v1',
hint: 'Moonshot 官方按量计费,OpenAI 兼容;Token 填 Moonshot API Key',
models: {
fastModel: 'moonshot-v1-8k',
standardModel: 'moonshot-v1-32k',
proModel: 'moonshot-v1-128k',
currentTier: 'pro',
},
},
{
id: 'kimi_coding_plan',
label: 'Kimi Code Plan · 套餐',
protocol: 'openai',
baseUrl: 'https://api.kimi.com/coding/v1',
hint: 'Kimi Code Plan 套餐(Andante/Moderato/Allegretto/Allegro),OpenAI 兼容;Token 填 Kimi 平台 API Key',
models: {
fastModel: 'kimi-k3',
standardModel: 'kimi-k3',
proModel: 'kimi-k3',
currentTier: 'pro',
},
},
{
id: 'qianfan_openai',
label: '百度千帆 · OpenAI',
protocol: 'openai',
baseUrl: 'https://qianfan.baidubce.com/v2/compatible',
hint: '百度千帆(OpenAI 兼容模式);Token 塺千帆 API Key(用 Bearer 鉴权)',
models: {
fastModel: 'ernie-speed-8k',
standardModel: 'ernie-4.0-8k-latest',
proModel: 'ernie-4.5-8k-latest',
currentTier: 'pro',
},
},
{
id: 'custom',
label: '自定义',
protocol: null,
baseUrl: null,
hint: '自行填写 Base URL 与协议',
},
];
export const DEFAULT_OMLX = {
baseUrl: 'http://127.0.0.1:8000',
apiKey: '',
model: '',
};
export const DEFAULT_SPARKLE = {
baseUrl: 'http://127.0.0.1:8317',
apiKey: '',
model: '',
};
export function mcpUrl() {
return `${CONFIG.MCP_BASE}${CONFIG.MCP_PATH}`;
}
export function httpUrl(toolName) {
return `${CONFIG.MCP_BASE}${CONFIG.HTTP_PATH_PREFIX}${toolName}`;
}
export function loadToken() {
const params = new URLSearchParams(location.search);
const fromUrl = params.get('token');
if (fromUrl) {
localStorage.setItem(CONFIG.TOKEN_STORAGE_KEY, fromUrl);
return fromUrl;
}
const stored = localStorage.getItem(CONFIG.TOKEN_STORAGE_KEY);
if (stored) return stored;
return '';
}
export function loadMode() {
return localStorage.getItem(CONFIG.MODE_STORAGE_KEY) || 'mcp';
}
export function saveMode(mode) {
localStorage.setItem(CONFIG.MODE_STORAGE_KEY, mode);
}
export function loadModelSource() {
const last = localStorage.getItem(CONFIG.MODEL_SOURCE_KEY);
if (last) return last;
return localStorage.getItem(CONFIG.DEFAULT_SOURCE_KEY) || 'ollama';
}
export function saveModelSource(source) {
localStorage.setItem(CONFIG.MODEL_SOURCE_KEY, source);
}
export function loadDefaultSource() {
return localStorage.getItem(CONFIG.DEFAULT_SOURCE_KEY) || 'ollama';
}
export function saveDefaultSource(source) {
localStorage.setItem(CONFIG.DEFAULT_SOURCE_KEY, source);
localStorage.setItem(CONFIG.MODEL_SOURCE_KEY, source);
}
export function loadOllamaConfig() {
try {
const s = localStorage.getItem(CONFIG.OLLAMA_CFG_KEY);
if (s) {
const cfg = { ...DEFAULT_OLLAMA, ...JSON.parse(s) };
if (!String(cfg.baseUrl || '').trim()) cfg.baseUrl = DEFAULT_OLLAMA.baseUrl;
return cfg;
}
} catch (e) {}
return { ...DEFAULT_OLLAMA };
}
export function saveOllamaConfig(cfg) {
localStorage.setItem(CONFIG.OLLAMA_CFG_KEY, JSON.stringify(cfg));
}
export function loadAnthropicConfig() {
try {
const s = localStorage.getItem(CONFIG.ANTHROPIC_CFG_KEY);
if (s) {
const raw = JSON.parse(s);
const cfg = { ...DEFAULT_ANTHROPIC, ...raw };
if (raw.protocol == null) {
const base = (cfg.baseUrl || '').toLowerCase();
if (/\/paas\/v4|\/coding\/paas/.test(base)) {
cfg.protocol = 'openai';
}
}
return cfg;
}
} catch (e) {}
return { ...DEFAULT_ANTHROPIC };
}
export function saveAnthropicConfig(cfg) {
localStorage.setItem(CONFIG.ANTHROPIC_CFG_KEY, JSON.stringify(cfg));
}
export function loadOmlxConfig() {
try {
const s = localStorage.getItem(CONFIG.OMLX_CFG_KEY);
if (s) {
const cfg = { ...DEFAULT_OMLX, ...JSON.parse(s) };
if (!String(cfg.baseUrl || '').trim()) cfg.baseUrl = DEFAULT_OMLX.baseUrl;
return cfg;
}
} catch (e) {}
return { ...DEFAULT_OMLX };
}
export function saveOmlxConfig(cfg) {
localStorage.setItem(CONFIG.OMLX_CFG_KEY, JSON.stringify(cfg));
}
export function loadSparkleConfig() {
try {
const s = localStorage.getItem(CONFIG.SPARKLE_CFG_KEY);
if (s) {
const cfg = { ...DEFAULT_SPARKLE, ...JSON.parse(s) };
if (!String(cfg.baseUrl || '').trim()) cfg.baseUrl = DEFAULT_SPARKLE.baseUrl;
return cfg;
}
} catch (e) {}
return { ...DEFAULT_SPARKLE };
}
export function saveSparkleConfig(cfg) {
localStorage.setItem(CONFIG.SPARKLE_CFG_KEY, JSON.stringify(cfg));
}
export function loadHistory() {
try {
const s = localStorage.getItem(CONFIG.HISTORY_STORAGE_KEY);
return s ? JSON.parse(s) : [];
} catch (e) { return []; }
}
export function saveHistory(history) {
try {
const slim = history
.filter(m => m.role === 'user' || m.role === 'assistant')
.map(m => ({
role: m.role,
content: typeof m.content === 'string' ? m.content.slice(0, 4000) : '',
thinking: typeof m.thinking === 'string' && m.thinking
? m.thinking.slice(0, 8000)
: undefined,
}));
localStorage.setItem(CONFIG.HISTORY_STORAGE_KEY, JSON.stringify(slim));
} catch (e) {}
}
export function clearHistoryStorage() {
localStorage.removeItem(CONFIG.HISTORY_STORAGE_KEY);
}
export function loadThinkingEnabled() {
return localStorage.getItem(CONFIG.THINKING_ENABLED_KEY) === '1';
}
export function saveThinkingEnabled(on) {
localStorage.setItem(CONFIG.THINKING_ENABLED_KEY, on ? '1' : '0');
}
export function loadCrossModuleEnabled() {
return localStorage.getItem(CONFIG.CROSS_MODULE_ENABLED_KEY) === '1';
}
export function saveCrossModuleEnabled(on) {
localStorage.setItem(CONFIG.CROSS_MODULE_ENABLED_KEY, on ? '1' : '0');
}
export function modelThinkingCapability(modelName) {
const m = String(modelName || '');
if (!m) return 'unknown';
const lower = m.toLowerCase();
if (/instruct-2507/i.test(m) && !/thinking/i.test(m)) return 'no';
if (/thinking-2507/i.test(m) || /[/_\-]thinking([/_\-]|$)/i.test(lower)) return 'yes';
if (/qwen3(\.|\d|$)/i.test(m) && !/instruct-2507/i.test(m)) return 'yes';
if (/glm-?(4\.5|4\.6|4\.7|5)/i.test(m) || /deepseek.*reasoner|deepseek-r1|deepseek-v[34]/i.test(lower)) return 'yes';
if (/claude.*(opus|sonnet|4)/i.test(lower)) return 'yes';
if (/qwen2\.5/i.test(m)) return 'no';
return 'unknown';
}
export const THRESHOLD_OPTIONS = [
{ value: 8000, label: '紧凑(8k)— 小 context 模型' },
{ value: 24000, label: '标准(24k)— 32k 模型' },
{ value: 48000, label: '宽松(48k)— 64k+ 模型' },
{ value: 96000, label: '超大(96k)— 128k 模型' },
{ value: 500000, label: '极限(500k)— 长上下文模型' },
{ value: 9999999, label: '关闭(不压缩)' },
];
const DEFAULT_THRESHOLD_BY_SOURCE = {
ollama: 24000,
omlx: 24000,
sparkle: 24000,
anthropic: 96000,
};
export function loadContextThreshold(source) {
const key = `${CONFIG.CONTEXT_THRESHOLD_KEY}_${source || 'ollama'}`;
const v = parseInt(localStorage.getItem(key), 10);
if (v > 0) return v;
return DEFAULT_THRESHOLD_BY_SOURCE[source] || 24000;
}
export function saveContextThreshold(source, v) {
const key = `${CONFIG.CONTEXT_THRESHOLD_KEY}_${source}`;
localStorage.setItem(key, String(v));
}
export function getCurrentModelInfo() {
const source = loadModelSource();
if (source === 'anthropic') {
const cfg = loadAnthropicConfig();
const tierModel = ({
fast: cfg.fastModel,
standard: cfg.standardModel,
pro: cfg.proModel,
})[cfg.currentTier] || cfg.fastModel;
const tierLabel = ({
fast: '快速档',
standard: '平衡档',
pro: '增强档',
})[cfg.currentTier] || '';
return {
source,
sourceLabel: '云端',
model: tierModel,
tier: cfg.currentTier,
tierLabel,
protocol: cfg.protocol === 'openai' ? 'openai' : 'anthropic',
isLocal: false,
};
}
if (source === 'omlx') {
const cfg = loadOmlxConfig();
return {
source,
sourceLabel: '本地',
model: cfg.model,
isLocal: true,
};
}
if (source === 'sparkle') {
const cfg = loadSparkleConfig();
return {
source,
sourceLabel: '本地',
model: cfg.model,
isLocal: true,
};
}
const cfg = loadOllamaConfig();
return {
source,
sourceLabel: '本地',
model: cfg.model,
isLocal: true,
};
}
export function ollamaUrl() {
const cfg = loadOllamaConfig();
const base = String(cfg.baseUrl || DEFAULT_OLLAMA.baseUrl).replace(/\/+$/, '');
return `${base}/api/chat`;
}
export function anthropicUrl() {
const cfg = loadAnthropicConfig();
const base = (cfg.baseUrl || '').replace(/\/+$/, '');
if ((cfg.protocol || 'anthropic') === 'openai') {
return `${base}/chat/completions`;
}
return `${base}/v1/messages`;
}
export function cloudProtocol() {
const cfg = loadAnthropicConfig();
return cfg.protocol === 'openai' ? 'openai' : 'anthropic';
}
export function omlxUrl() {
const cfg = loadOmlxConfig();
const base = String(cfg.baseUrl || DEFAULT_OMLX.baseUrl).replace(/\/+$/, '');
return `${base}${CONFIG.OMLX_CHAT_PATH}`;
}
export function sparkleUrl() {
const cfg = loadSparkleConfig();
const base = String(cfg.baseUrl || DEFAULT_SPARKLE.baseUrl).replace(/\/+$/, '');
return `${base}${CONFIG.SPARKLE_CHAT_PATH}`;
}