refactor: reorganize imports and update type references across services
- Updated import paths for types and utilities in config-service, menu-service, script-execution-service, script-store-service, and window-service to reflect new structure. - Moved utility functions like debounce and cloneDeep to shared utilities. - Created new runtime and script types files to centralize type definitions. - Removed deprecated task-types and locale messages files. - Updated constants to use shared definitions and added new placeholders for providers. - Enhanced provider type information with additional placeholders for different languages.
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
require("electron");
|
require("electron");
|
||||||
require("./main-BynUR3CU.js");
|
require("./main-TNsjwKgR.js");
|
||||||
require("electron-squirrel-startup");
|
require("electron-squirrel-startup");
|
||||||
require("electron-log");
|
require("electron-log");
|
||||||
require("bytenode");
|
require("bytenode");
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
const electron = require("electron");
|
const electron = require("electron");
|
||||||
var IPC_EVENTS = /* @__PURE__ */ ((IPC_EVENTS2) => {
|
var IPC_EVENTS = /* @__PURE__ */ ((IPC_EVENTS2) => {
|
||||||
|
IPC_EVENTS2["HOST_API_FETCH"] = "hostapi:fetch";
|
||||||
IPC_EVENTS2["EXTERNAL_OPEN"] = "external-open";
|
IPC_EVENTS2["EXTERNAL_OPEN"] = "external-open";
|
||||||
IPC_EVENTS2["APP_SET_FRAMELESS"] = "app:set-frameless";
|
IPC_EVENTS2["APP_SET_FRAMELESS"] = "app:set-frameless";
|
||||||
IPC_EVENTS2["APP_LOAD_PAGE"] = "app:load-page";
|
IPC_EVENTS2["APP_LOAD_PAGE"] = "app:load-page";
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { ConfigKeys, IConfig } from '@runtime/lib/types';
|
import type { ConfigKeys, IConfig } from '@electron/types/runtime';
|
||||||
import configManager from '@electron/service/config-service';
|
import configManager from '@electron/service/config-service';
|
||||||
import type { HostApiResult } from '@src/types/runtime';
|
import type { HostApiResult } from '@src/types/runtime';
|
||||||
import type { HostApiContext } from '../context';
|
import type { HostApiContext } from '../context';
|
||||||
|
|||||||
99
electron/locales/messages.ts
Normal file
99
electron/locales/messages.ts
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
export type RuntimeMessageTree = {
|
||||||
|
[key: string]: string | number | RuntimeMessageTree;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const runtimeLocaleMessages: Record<'en' | 'zh' | 'th', RuntimeMessageTree> = {
|
||||||
|
en: {
|
||||||
|
settings: {
|
||||||
|
title: 'Settings',
|
||||||
|
},
|
||||||
|
menu: {
|
||||||
|
conversation: {
|
||||||
|
newConversation: 'New Conversation',
|
||||||
|
sortBy: 'Sort By',
|
||||||
|
sortByCreateTime: 'Sort by Creation Time',
|
||||||
|
sortByUpdateTime: 'Sort by Update Time',
|
||||||
|
sortByName: 'Sort by Name',
|
||||||
|
sortByModel: 'Sort by Model',
|
||||||
|
sortAscending: 'Ascending',
|
||||||
|
sortDescending: 'Descending',
|
||||||
|
pinConversation: 'Pin Conversation',
|
||||||
|
renameConversation: 'Rename Conversation',
|
||||||
|
delConversation: 'Delete Conversation',
|
||||||
|
batchOperations: 'Batch Operations',
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
copyMessage: 'Copy Message',
|
||||||
|
deleteMessage: 'Delete Message',
|
||||||
|
selectMessage: 'Select Message',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tray: {
|
||||||
|
tooltip: 'ZN-AI',
|
||||||
|
showWindow: 'Show Window',
|
||||||
|
exit: 'Exit',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
zh: {
|
||||||
|
settings: {
|
||||||
|
title: '设置',
|
||||||
|
},
|
||||||
|
menu: {
|
||||||
|
conversation: {
|
||||||
|
newConversation: '新建对话',
|
||||||
|
sortBy: '排序方式',
|
||||||
|
sortByCreateTime: '按创建时间排序',
|
||||||
|
sortByUpdateTime: '按更新时间排序',
|
||||||
|
sortByName: '按名称排序',
|
||||||
|
sortByModel: '按模型排序',
|
||||||
|
sortAscending: '递增',
|
||||||
|
sortDescending: '递减',
|
||||||
|
pinConversation: '置顶对话',
|
||||||
|
renameConversation: '重命名对话',
|
||||||
|
delConversation: '删除对话',
|
||||||
|
batchOperations: '批量操作',
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
copyMessage: '复制消息',
|
||||||
|
deleteMessage: '删除消息',
|
||||||
|
selectMessage: '选择消息',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tray: {
|
||||||
|
tooltip: 'ZN-AI',
|
||||||
|
showWindow: '显示窗口',
|
||||||
|
exit: '退出',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
th: {
|
||||||
|
settings: {
|
||||||
|
title: 'ตั้งค่า',
|
||||||
|
},
|
||||||
|
menu: {
|
||||||
|
conversation: {
|
||||||
|
newConversation: 'การสนทนาใหม่',
|
||||||
|
sortBy: 'จัดเรียงตาม',
|
||||||
|
sortByCreateTime: 'จัดเรียงตามเวลาสร้าง',
|
||||||
|
sortByUpdateTime: 'จัดเรียงตามเวลาอัปเดต',
|
||||||
|
sortByName: 'จัดเรียงตามชื่อ',
|
||||||
|
sortByModel: 'จัดเรียงตามโมเดล',
|
||||||
|
sortAscending: 'เรียงจากน้อยไปมาก',
|
||||||
|
sortDescending: 'เรียงจากมากไปน้อย',
|
||||||
|
pinConversation: 'ปักหมุดการสนทนา',
|
||||||
|
renameConversation: 'เปลี่ยนชื่อการสนทนา',
|
||||||
|
delConversation: 'ลบการสนทนา',
|
||||||
|
batchOperations: 'ดำเนินการแบบกลุ่ม',
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
copyMessage: 'คัดลอกข้อความ',
|
||||||
|
deleteMessage: 'ลบข้อความ',
|
||||||
|
selectMessage: 'เลือกข้อความ',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tray: {
|
||||||
|
tooltip: 'ZN-AI',
|
||||||
|
showWindow: 'แสดงหน้าต่าง',
|
||||||
|
exit: 'ออก',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { app, BrowserWindow, ipcMain } from 'electron'
|
import { app, BrowserWindow, ipcMain } from 'electron'
|
||||||
import { CONFIG_KEYS } from '@runtime/lib/constants'
|
import { CONFIG_KEYS, IPC_EVENTS } from '@runtime/lib/constants'
|
||||||
import { setupMainWindow } from './wins';
|
import { setupMainWindow } from './wins';
|
||||||
import started from 'electron-squirrel-startup'
|
import started from 'electron-squirrel-startup'
|
||||||
import configManager from '@electron/service/config-service'
|
import configManager from '@electron/service/config-service'
|
||||||
@@ -75,7 +75,7 @@ async function requestUpstreamHostApi(path: string, method: string, headers: Rec
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ipcMain.handle('hostapi:fetch', async (_event, { path, method, headers, body }) => {
|
ipcMain.handle(IPC_EVENTS.HOST_API_FETCH, async (_event, { path, method, headers, body }) => {
|
||||||
const normalizedMethod = method || 'GET';
|
const normalizedMethod = method || 'GET';
|
||||||
|
|
||||||
// 1. 优先本地处理 Host API 路由(逐步对齐 ClawX)
|
// 1. 优先本地处理 Host API 路由(逐步对齐 ClawX)
|
||||||
@@ -92,7 +92,7 @@ ipcMain.handle('hostapi:fetch', async (_event, { path, method, headers, body })
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Gateway RPC IPC handler
|
// Gateway RPC IPC handler
|
||||||
ipcMain.handle('gateway:rpc', async (_event, method: string, params: any) => {
|
ipcMain.handle(IPC_EVENTS.GATEWAY_RPC, async (_event, method: string, params: any) => {
|
||||||
return gatewayManager.rpc(method, params);
|
return gatewayManager.rpc(method, params);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { BrowserWindow, ipcMain } from 'electron'
|
import { BrowserWindow, ipcMain } from 'electron'
|
||||||
import type { ConfigKeys, IConfig } from '@runtime/lib/types'
|
|
||||||
import { CONFIG_KEYS, IPC_EVENTS } from '@runtime/lib/constants'
|
import { CONFIG_KEYS, IPC_EVENTS } from '@runtime/lib/constants'
|
||||||
import { debounce } from '@runtime/lib/utils'
|
|
||||||
|
|
||||||
import logManager from '@electron/service/logger'
|
import logManager from '@electron/service/logger'
|
||||||
|
import type { ConfigKeys, IConfig } from '@electron/types/runtime'
|
||||||
import { getUserDataDir } from '@electron/utils/paths'
|
import { getUserDataDir } from '@electron/utils/paths'
|
||||||
|
import { debounce } from '@electron/utils/shared'
|
||||||
|
|
||||||
type AppConfig = IConfig & {
|
type AppConfig = IConfig & {
|
||||||
[CONFIG_KEYS.GATEWAY_AUTO_START]: boolean;
|
[CONFIG_KEYS.GATEWAY_AUTO_START]: boolean;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { ipcMain, Menu, type MenuItemConstructorOptions } from 'electron';
|
import { ipcMain, Menu, type MenuItemConstructorOptions } from 'electron';
|
||||||
import { CONFIG_KEYS, IPC_EVENTS } from '@runtime/lib/constants';
|
import { CONFIG_KEYS, IPC_EVENTS } from '@runtime/lib/constants';
|
||||||
import { cloneDeep } from '@runtime/lib/utils';
|
|
||||||
import { createTranslator } from '@electron/utils'
|
import { createTranslator } from '@electron/utils'
|
||||||
|
import { cloneDeep } from '@electron/utils/shared';
|
||||||
import logManager from '@electron/service/logger'
|
import logManager from '@electron/service/logger'
|
||||||
import configManager from '@electron/service/config-service'
|
import configManager from '@electron/service/config-service'
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import {
|
|||||||
getScriptPathById,
|
getScriptPathById,
|
||||||
updateLastRun,
|
updateLastRun,
|
||||||
} from '@electron/service/script-store-service';
|
} from '@electron/service/script-store-service';
|
||||||
import type { ScriptExecutionResult } from '@runtime/lib/script-types';
|
import type { ScriptExecutionResult } from '../../types/script-types';
|
||||||
|
|
||||||
const executor = new executeScriptService();
|
const executor = new executeScriptService();
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import type {
|
|||||||
ScriptMetaItem,
|
ScriptMetaItem,
|
||||||
ScriptsMeta,
|
ScriptsMeta,
|
||||||
ScriptSaveInput,
|
ScriptSaveInput,
|
||||||
} from '@runtime/lib/script-types';
|
} from '../../types/script-types';
|
||||||
|
|
||||||
const META_FILENAME = 'scripts.meta.json';
|
const META_FILENAME = 'scripts.meta.json';
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { WindowNames } from '@runtime/lib/types'
|
import type { WindowNames } from '@electron/types/runtime'
|
||||||
|
|
||||||
import { CONFIG_KEYS, IPC_EVENTS, WINDOW_NAMES } from '@runtime/lib/constants'
|
import { CONFIG_KEYS, IPC_EVENTS, WINDOW_NAMES } from '@runtime/lib/constants'
|
||||||
import { app, BrowserWindow, BrowserWindowConstructorOptions, ipcMain, IpcMainInvokeEvent, type IpcMainEvent } from 'electron'
|
import { app, BrowserWindow, BrowserWindowConstructorOptions, ipcMain, IpcMainInvokeEvent, type IpcMainEvent } from 'electron'
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { Task } from './task-types';
|
import type { Task } from '@src/lib/task-types';
|
||||||
import { CONFIG_KEYS, WINDOW_NAMES } from './constants';
|
import { CONFIG_KEYS, WINDOW_NAMES } from '@runtime/lib/constants';
|
||||||
|
|
||||||
export type ThemeMode = 'dark' | 'light' | 'system';
|
export type ThemeMode = 'dark' | 'light' | 'system';
|
||||||
export type WindowNames = `${WINDOW_NAMES}`;
|
export type WindowNames = `${WINDOW_NAMES}`;
|
||||||
@@ -8,7 +8,7 @@ export type ConfigKeys = `${CONFIG_KEYS}`;
|
|||||||
export interface IConfig {
|
export interface IConfig {
|
||||||
[CONFIG_KEYS.THEME_MODE]: ThemeMode;
|
[CONFIG_KEYS.THEME_MODE]: ThemeMode;
|
||||||
[CONFIG_KEYS.PRIMARY_COLOR]: string;
|
[CONFIG_KEYS.PRIMARY_COLOR]: string;
|
||||||
[CONFIG_KEYS.LANGUAGE]: 'zh' | 'en';
|
[CONFIG_KEYS.LANGUAGE]: 'zh' | 'en' | 'th';
|
||||||
[CONFIG_KEYS.FONT_SIZE]: number;
|
[CONFIG_KEYS.FONT_SIZE]: number;
|
||||||
[CONFIG_KEYS.MINIMIZE_TO_TRAY]: boolean;
|
[CONFIG_KEYS.MINIMIZE_TO_TRAY]: boolean;
|
||||||
[CONFIG_KEYS.LAUNCH_AT_STARTUP]: boolean;
|
[CONFIG_KEYS.LAUNCH_AT_STARTUP]: boolean;
|
||||||
@@ -3,7 +3,7 @@ import logManager from '@electron/service/logger'
|
|||||||
import configManager from '@electron/service/config-service'
|
import configManager from '@electron/service/config-service'
|
||||||
import path from 'node:path'
|
import path from 'node:path'
|
||||||
import { app } from 'electron'
|
import { app } from 'electron'
|
||||||
import { runtimeLocaleMessages, type RuntimeMessageTree } from '@runtime/locales/messages'
|
import { runtimeLocaleMessages, type RuntimeMessageTree } from '@electron/locales/messages'
|
||||||
|
|
||||||
const messages: Record<string, RuntimeMessageTree> = runtimeLocaleMessages
|
const messages: Record<string, RuntimeMessageTree> = runtimeLocaleMessages
|
||||||
|
|
||||||
|
|||||||
11
global.d.ts
vendored
11
global.d.ts
vendored
@@ -1,8 +1,9 @@
|
|||||||
import { IPC_EVENTS } from '@runtime/lib/constants'
|
import { CONFIG_KEYS, IPC_EVENTS } from '@runtime/lib/constants'
|
||||||
import type { ConfigKeys } from '@runtime/lib/types'
|
import type { AutomationScript, ScriptSaveInput, ScriptExecutionResult } from '@src/lib/script-types'
|
||||||
import type { AutomationScript, ScriptSaveInput, ScriptExecutionResult } from '@runtime/lib/script-types'
|
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
type ConfigKeys = `${CONFIG_KEYS}`
|
||||||
|
|
||||||
// 定义每个通道的参数和返回值类型
|
// 定义每个通道的参数和返回值类型
|
||||||
interface IPCTypings {
|
interface IPCTypings {
|
||||||
// 同步通信
|
// 同步通信
|
||||||
@@ -42,6 +43,10 @@ declare global {
|
|||||||
params: [event: any]
|
params: [event: any]
|
||||||
return: void
|
return: void
|
||||||
}
|
}
|
||||||
|
[IPC_EVENTS.HOST_API_FETCH]: {
|
||||||
|
params: [request: { path: string; method?: string; headers?: Record<string, string>; body?: unknown }]
|
||||||
|
return: Promise<unknown>
|
||||||
|
}
|
||||||
|
|
||||||
// 任务事件
|
// 任务事件
|
||||||
[IPC_EVENTS.TASK_PROGRESS]: { params: [payload: any]; return: void; }
|
[IPC_EVENTS.TASK_PROGRESS]: { params: [payload: any]; return: void; }
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
export enum IPC_EVENTS {
|
export enum IPC_EVENTS {
|
||||||
|
HOST_API_FETCH = 'hostapi:fetch',
|
||||||
EXTERNAL_OPEN = 'external-open',
|
EXTERNAL_OPEN = 'external-open',
|
||||||
APP_SET_FRAMELESS = 'app:set-frameless',
|
APP_SET_FRAMELESS = 'app:set-frameless',
|
||||||
APP_LOAD_PAGE = 'app:load-page',
|
APP_LOAD_PAGE = 'app:load-page',
|
||||||
@@ -120,3 +121,7 @@ export enum MESSAGE_ITEM_MENU_IDS {
|
|||||||
DELETE = 'delete',
|
DELETE = 'delete',
|
||||||
SELECT = 'select',
|
SELECT = 'select',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const DEFAULT_THEME_MODE = 'system' as const;
|
||||||
|
|
||||||
|
export const DEFAULT_LANGUAGE = 'zh' as const;
|
||||||
|
|||||||
@@ -2,9 +2,13 @@ import {
|
|||||||
DEFAULT_AGENT_ID,
|
DEFAULT_AGENT_ID,
|
||||||
DEFAULT_CHANNEL_ACCOUNT_ID,
|
DEFAULT_CHANNEL_ACCOUNT_ID,
|
||||||
DEFAULT_MAIN_SESSION_SUFFIX,
|
DEFAULT_MAIN_SESSION_SUFFIX,
|
||||||
|
buildAgentSessionKey,
|
||||||
|
buildMainSessionKey,
|
||||||
buildChannelAccountOwnerKey,
|
buildChannelAccountOwnerKey,
|
||||||
|
normalizeAgentId,
|
||||||
normalizeChannelAccountId,
|
normalizeChannelAccountId,
|
||||||
normalizeChannelType,
|
normalizeChannelType,
|
||||||
|
normalizeSessionSuffix,
|
||||||
parseChannelAccountOwnerKey,
|
parseChannelAccountOwnerKey,
|
||||||
resolveChannelAccountOwner,
|
resolveChannelAccountOwner,
|
||||||
type AgentSummary,
|
type AgentSummary,
|
||||||
@@ -29,27 +33,6 @@ export interface ParsedSessionKey {
|
|||||||
isAgentSession: boolean;
|
isAgentSession: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function normalizeAgentId(value: string | null | undefined): string {
|
|
||||||
const normalized = String(value ?? '').trim().toLowerCase();
|
|
||||||
return normalized || DEFAULT_AGENT_ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function normalizeSessionSuffix(value: string | null | undefined): string {
|
|
||||||
const normalized = String(value ?? '').trim().toLowerCase();
|
|
||||||
return normalized || DEFAULT_MAIN_SESSION_SUFFIX;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function buildAgentSessionKey(agentId: string, sessionId: string): string {
|
|
||||||
return `agent:${normalizeAgentId(agentId)}:${normalizeSessionSuffix(sessionId)}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function buildMainSessionKey(
|
|
||||||
agentId: string,
|
|
||||||
sessionId = DEFAULT_MAIN_SESSION_SUFFIX,
|
|
||||||
): string {
|
|
||||||
return buildAgentSessionKey(agentId, sessionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function parseSessionKey(sessionKey: string): ParsedSessionKey {
|
export function parseSessionKey(sessionKey: string): ParsedSessionKey {
|
||||||
const trimmed = String(sessionKey ?? '').trim();
|
const trimmed = String(sessionKey ?? '').trim();
|
||||||
|
|
||||||
@@ -97,9 +80,13 @@ export {
|
|||||||
DEFAULT_AGENT_ID,
|
DEFAULT_AGENT_ID,
|
||||||
DEFAULT_CHANNEL_ACCOUNT_ID,
|
DEFAULT_CHANNEL_ACCOUNT_ID,
|
||||||
DEFAULT_MAIN_SESSION_SUFFIX,
|
DEFAULT_MAIN_SESSION_SUFFIX,
|
||||||
|
buildAgentSessionKey,
|
||||||
|
buildMainSessionKey,
|
||||||
buildChannelAccountOwnerKey,
|
buildChannelAccountOwnerKey,
|
||||||
|
normalizeAgentId,
|
||||||
normalizeChannelAccountId,
|
normalizeChannelAccountId,
|
||||||
normalizeChannelType,
|
normalizeChannelType,
|
||||||
|
normalizeSessionSuffix,
|
||||||
parseChannelAccountOwnerKey,
|
parseChannelAccountOwnerKey,
|
||||||
resolveChannelAccountOwner,
|
resolveChannelAccountOwner,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -58,6 +58,8 @@ export interface ProviderTypeInfo {
|
|||||||
name: string;
|
name: string;
|
||||||
icon: string;
|
icon: string;
|
||||||
placeholder: string;
|
placeholder: string;
|
||||||
|
placeholderZh?: string;
|
||||||
|
placeholderTh?: string;
|
||||||
model?: string;
|
model?: string;
|
||||||
requiresApiKey: boolean;
|
requiresApiKey: boolean;
|
||||||
defaultBaseUrl?: string;
|
defaultBaseUrl?: string;
|
||||||
@@ -124,7 +126,7 @@ export const PROVIDER_TYPE_INFO: ProviderTypeInfo[] = [
|
|||||||
{
|
{
|
||||||
id: 'anthropic',
|
id: 'anthropic',
|
||||||
name: 'Anthropic',
|
name: 'Anthropic',
|
||||||
icon: 'A',
|
icon: '🤖',
|
||||||
placeholder: 'sk-ant-api03-...',
|
placeholder: 'sk-ant-api03-...',
|
||||||
model: 'Claude',
|
model: 'Claude',
|
||||||
requiresApiKey: true,
|
requiresApiKey: true,
|
||||||
@@ -133,7 +135,7 @@ export const PROVIDER_TYPE_INFO: ProviderTypeInfo[] = [
|
|||||||
{
|
{
|
||||||
id: 'openai',
|
id: 'openai',
|
||||||
name: 'OpenAI',
|
name: 'OpenAI',
|
||||||
icon: 'O',
|
icon: '💚',
|
||||||
placeholder: 'sk-proj-...',
|
placeholder: 'sk-proj-...',
|
||||||
model: 'GPT',
|
model: 'GPT',
|
||||||
requiresApiKey: true,
|
requiresApiKey: true,
|
||||||
@@ -148,7 +150,7 @@ export const PROVIDER_TYPE_INFO: ProviderTypeInfo[] = [
|
|||||||
{
|
{
|
||||||
id: 'google',
|
id: 'google',
|
||||||
name: 'Google',
|
name: 'Google',
|
||||||
icon: 'G',
|
icon: '🔷',
|
||||||
placeholder: 'AIza...',
|
placeholder: 'AIza...',
|
||||||
model: 'Gemini',
|
model: 'Gemini',
|
||||||
requiresApiKey: true,
|
requiresApiKey: true,
|
||||||
@@ -163,7 +165,7 @@ export const PROVIDER_TYPE_INFO: ProviderTypeInfo[] = [
|
|||||||
{
|
{
|
||||||
id: 'openrouter',
|
id: 'openrouter',
|
||||||
name: 'OpenRouter',
|
name: 'OpenRouter',
|
||||||
icon: 'R',
|
icon: '🌐',
|
||||||
placeholder: 'sk-or-v1-...',
|
placeholder: 'sk-or-v1-...',
|
||||||
model: 'Multi-Model',
|
model: 'Multi-Model',
|
||||||
requiresApiKey: true,
|
requiresApiKey: true,
|
||||||
@@ -175,7 +177,7 @@ export const PROVIDER_TYPE_INFO: ProviderTypeInfo[] = [
|
|||||||
{
|
{
|
||||||
id: 'minimax-portal-cn',
|
id: 'minimax-portal-cn',
|
||||||
name: 'MiniMax (CN)',
|
name: 'MiniMax (CN)',
|
||||||
icon: 'M',
|
icon: '☁️',
|
||||||
placeholder: 'sk-...',
|
placeholder: 'sk-...',
|
||||||
model: 'MiniMax',
|
model: 'MiniMax',
|
||||||
requiresApiKey: false,
|
requiresApiKey: false,
|
||||||
@@ -192,7 +194,7 @@ export const PROVIDER_TYPE_INFO: ProviderTypeInfo[] = [
|
|||||||
{
|
{
|
||||||
id: 'moonshot',
|
id: 'moonshot',
|
||||||
name: 'Moonshot (CN)',
|
name: 'Moonshot (CN)',
|
||||||
icon: 'K',
|
icon: '🌙',
|
||||||
placeholder: 'sk-...',
|
placeholder: 'sk-...',
|
||||||
model: 'Kimi',
|
model: 'Kimi',
|
||||||
requiresApiKey: true,
|
requiresApiKey: true,
|
||||||
@@ -203,7 +205,7 @@ export const PROVIDER_TYPE_INFO: ProviderTypeInfo[] = [
|
|||||||
{
|
{
|
||||||
id: 'siliconflow',
|
id: 'siliconflow',
|
||||||
name: 'SiliconFlow (CN)',
|
name: 'SiliconFlow (CN)',
|
||||||
icon: 'S',
|
icon: '🌊',
|
||||||
placeholder: 'sk-...',
|
placeholder: 'sk-...',
|
||||||
model: 'Multi-Model',
|
model: 'Multi-Model',
|
||||||
requiresApiKey: true,
|
requiresApiKey: true,
|
||||||
@@ -217,7 +219,7 @@ export const PROVIDER_TYPE_INFO: ProviderTypeInfo[] = [
|
|||||||
{
|
{
|
||||||
id: 'deepseek',
|
id: 'deepseek',
|
||||||
name: 'DeepSeek',
|
name: 'DeepSeek',
|
||||||
icon: 'D',
|
icon: '🐋',
|
||||||
placeholder: 'sk-...',
|
placeholder: 'sk-...',
|
||||||
model: 'DeepSeek',
|
model: 'DeepSeek',
|
||||||
requiresApiKey: true,
|
requiresApiKey: true,
|
||||||
@@ -231,7 +233,7 @@ export const PROVIDER_TYPE_INFO: ProviderTypeInfo[] = [
|
|||||||
{
|
{
|
||||||
id: 'minimax-portal',
|
id: 'minimax-portal',
|
||||||
name: 'MiniMax (Global)',
|
name: 'MiniMax (Global)',
|
||||||
icon: 'M',
|
icon: '☁️',
|
||||||
placeholder: 'sk-...',
|
placeholder: 'sk-...',
|
||||||
model: 'MiniMax',
|
model: 'MiniMax',
|
||||||
requiresApiKey: false,
|
requiresApiKey: false,
|
||||||
@@ -248,7 +250,7 @@ export const PROVIDER_TYPE_INFO: ProviderTypeInfo[] = [
|
|||||||
{
|
{
|
||||||
id: 'modelstudio',
|
id: 'modelstudio',
|
||||||
name: 'Model Studio',
|
name: 'Model Studio',
|
||||||
icon: 'Q',
|
icon: '☁️',
|
||||||
placeholder: 'sk-...',
|
placeholder: 'sk-...',
|
||||||
model: 'Qwen',
|
model: 'Qwen',
|
||||||
requiresApiKey: true,
|
requiresApiKey: true,
|
||||||
@@ -264,7 +266,7 @@ export const PROVIDER_TYPE_INFO: ProviderTypeInfo[] = [
|
|||||||
{
|
{
|
||||||
id: 'ark',
|
id: 'ark',
|
||||||
name: 'ByteDance Ark',
|
name: 'ByteDance Ark',
|
||||||
icon: 'B',
|
icon: 'A',
|
||||||
placeholder: 'your-ark-api-key',
|
placeholder: 'your-ark-api-key',
|
||||||
model: 'Doubao',
|
model: 'Doubao',
|
||||||
requiresApiKey: true,
|
requiresApiKey: true,
|
||||||
@@ -280,8 +282,10 @@ export const PROVIDER_TYPE_INFO: ProviderTypeInfo[] = [
|
|||||||
{
|
{
|
||||||
id: 'ollama',
|
id: 'ollama',
|
||||||
name: 'Ollama',
|
name: 'Ollama',
|
||||||
icon: 'L',
|
icon: '🦙',
|
||||||
placeholder: 'Not required',
|
placeholder: 'Not required',
|
||||||
|
placeholderZh: '无需填写',
|
||||||
|
placeholderTh: 'ไม่ต้องกรอก',
|
||||||
requiresApiKey: false,
|
requiresApiKey: false,
|
||||||
defaultBaseUrl: 'http://localhost:11434/v1',
|
defaultBaseUrl: 'http://localhost:11434/v1',
|
||||||
showBaseUrl: true,
|
showBaseUrl: true,
|
||||||
@@ -291,8 +295,10 @@ export const PROVIDER_TYPE_INFO: ProviderTypeInfo[] = [
|
|||||||
{
|
{
|
||||||
id: 'custom',
|
id: 'custom',
|
||||||
name: 'Custom',
|
name: 'Custom',
|
||||||
icon: 'C',
|
icon: '⚙️',
|
||||||
placeholder: 'API key...',
|
placeholder: 'API key...',
|
||||||
|
placeholderZh: 'API Key...',
|
||||||
|
placeholderTh: 'API Key...',
|
||||||
requiresApiKey: true,
|
requiresApiKey: true,
|
||||||
showBaseUrl: true,
|
showBaseUrl: true,
|
||||||
showModelId: true,
|
showModelId: true,
|
||||||
@@ -329,6 +335,22 @@ export function getProviderDocsUrl(
|
|||||||
return provider.docsUrl;
|
return provider.docsUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getProviderPlaceholder(
|
||||||
|
provider: Pick<ProviderTypeInfo, 'placeholder' | 'placeholderZh' | 'placeholderTh'> | undefined,
|
||||||
|
language: string,
|
||||||
|
): string | undefined {
|
||||||
|
if (!provider?.placeholder) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (language.startsWith('zh') && provider.placeholderZh) {
|
||||||
|
return provider.placeholderZh;
|
||||||
|
}
|
||||||
|
if (language.startsWith('th') && provider.placeholderTh) {
|
||||||
|
return provider.placeholderTh;
|
||||||
|
}
|
||||||
|
return provider.placeholder;
|
||||||
|
}
|
||||||
|
|
||||||
export function shouldShowProviderModelId(
|
export function shouldShowProviderModelId(
|
||||||
provider: Pick<ProviderTypeInfo, 'showModelId' | 'showModelIdInDevModeOnly'> | undefined,
|
provider: Pick<ProviderTypeInfo, 'showModelId' | 'showModelIdInDevModeOnly'> | undefined,
|
||||||
devModeUnlocked: boolean,
|
devModeUnlocked: boolean,
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
export type SubTaskStatus = 'pending' | 'running' | 'success' | 'failed';
|
|
||||||
|
|
||||||
export interface SubTask {
|
|
||||||
id: string;
|
|
||||||
taskId: string;
|
|
||||||
scriptId: string;
|
|
||||||
name: string;
|
|
||||||
status: SubTaskStatus;
|
|
||||||
progress: number;
|
|
||||||
message: string;
|
|
||||||
stdoutTail: string;
|
|
||||||
stderrTail: string;
|
|
||||||
error?: string;
|
|
||||||
startedAt: string;
|
|
||||||
completedAt?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type TaskStatus = 'pending' | 'running' | 'success' | 'partial_failed' | 'failed';
|
|
||||||
|
|
||||||
export interface Task {
|
|
||||||
id: string;
|
|
||||||
title: string;
|
|
||||||
operation: 'open' | 'close';
|
|
||||||
roomType: string;
|
|
||||||
dateRange: [string, string];
|
|
||||||
status: TaskStatus;
|
|
||||||
subTasks: SubTask[];
|
|
||||||
roomList: any[];
|
|
||||||
createdAt: string;
|
|
||||||
updatedAt: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TaskProgressPayload {
|
|
||||||
taskId: string;
|
|
||||||
subTaskId: string;
|
|
||||||
progress?: number;
|
|
||||||
message?: string;
|
|
||||||
stdoutTail?: string;
|
|
||||||
stderrTail?: string;
|
|
||||||
}
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
export type RuntimeMessageTree = {
|
|
||||||
[key: string]: string | number | RuntimeMessageTree;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const runtimeLocaleMessages: Record<'en' | 'zh' | 'th', RuntimeMessageTree> = {
|
|
||||||
en: {
|
|
||||||
settings: {
|
|
||||||
title: 'Settings',
|
|
||||||
},
|
|
||||||
menu: {
|
|
||||||
conversation: {
|
|
||||||
newConversation: 'New Conversation',
|
|
||||||
sortBy: 'Sort By',
|
|
||||||
sortByCreateTime: 'Sort by Creation Time',
|
|
||||||
sortByUpdateTime: 'Sort by Update Time',
|
|
||||||
sortByName: 'Sort by Name',
|
|
||||||
sortByModel: 'Sort by Model',
|
|
||||||
sortAscending: 'Ascending',
|
|
||||||
sortDescending: 'Descending',
|
|
||||||
pinConversation: 'Pin Conversation',
|
|
||||||
renameConversation: 'Rename Conversation',
|
|
||||||
delConversation: 'Delete Conversation',
|
|
||||||
batchOperations: 'Batch Operations',
|
|
||||||
},
|
|
||||||
message: {
|
|
||||||
copyMessage: 'Copy Message',
|
|
||||||
deleteMessage: 'Delete Message',
|
|
||||||
selectMessage: 'Select Message',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tray: {
|
|
||||||
tooltip: 'ZN-AI',
|
|
||||||
showWindow: 'Show Window',
|
|
||||||
exit: 'Exit',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
zh: {
|
|
||||||
settings: {
|
|
||||||
title: '\u8bbe\u7f6e',
|
|
||||||
},
|
|
||||||
menu: {
|
|
||||||
conversation: {
|
|
||||||
newConversation: '\u65b0\u5efa\u5bf9\u8bdd',
|
|
||||||
sortBy: '\u6392\u5e8f\u65b9\u5f0f',
|
|
||||||
sortByCreateTime: '\u6309\u521b\u5efa\u65f6\u95f4\u6392\u5e8f',
|
|
||||||
sortByUpdateTime: '\u6309\u66f4\u65b0\u65f6\u95f4\u6392\u5e8f',
|
|
||||||
sortByName: '\u6309\u540d\u79f0\u6392\u5e8f',
|
|
||||||
sortByModel: '\u6309\u6a21\u578b\u6392\u5e8f',
|
|
||||||
sortAscending: '\u9012\u589e',
|
|
||||||
sortDescending: '\u9012\u51cf',
|
|
||||||
pinConversation: '\u7f6e\u9876\u5bf9\u8bdd',
|
|
||||||
renameConversation: '\u91cd\u547d\u540d\u5bf9\u8bdd',
|
|
||||||
delConversation: '\u5220\u9664\u5bf9\u8bdd',
|
|
||||||
batchOperations: '\u6279\u91cf\u64cd\u4f5c',
|
|
||||||
},
|
|
||||||
message: {
|
|
||||||
copyMessage: '\u590d\u5236\u6d88\u606f',
|
|
||||||
deleteMessage: '\u5220\u9664\u6d88\u606f',
|
|
||||||
selectMessage: '\u9009\u62e9\u6d88\u606f',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tray: {
|
|
||||||
tooltip: 'ZN-AI',
|
|
||||||
showWindow: '\u663e\u793a\u7a97\u53e3',
|
|
||||||
exit: '\u9000\u51fa',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
th: {
|
|
||||||
settings: {
|
|
||||||
title: '\u0e15\u0e31\u0e49\u0e07\u0e04\u0e48\u0e32',
|
|
||||||
},
|
|
||||||
menu: {
|
|
||||||
conversation: {
|
|
||||||
newConversation: '\u0e01\u0e32\u0e23\u0e2a\u0e19\u0e17\u0e19\u0e32\u0e43\u0e2b\u0e21\u0e48',
|
|
||||||
sortBy: '\u0e08\u0e31\u0e14\u0e40\u0e23\u0e35\u0e22\u0e07\u0e15\u0e32\u0e21',
|
|
||||||
sortByCreateTime: '\u0e08\u0e31\u0e14\u0e40\u0e23\u0e35\u0e22\u0e07\u0e15\u0e32\u0e21\u0e40\u0e27\u0e25\u0e32\u0e2a\u0e23\u0e49\u0e32\u0e07',
|
|
||||||
sortByUpdateTime: '\u0e08\u0e31\u0e14\u0e40\u0e23\u0e35\u0e22\u0e07\u0e15\u0e32\u0e21\u0e40\u0e27\u0e25\u0e32\u0e2d\u0e31\u0e1b\u0e40\u0e14\u0e15',
|
|
||||||
sortByName: '\u0e08\u0e31\u0e14\u0e40\u0e23\u0e35\u0e22\u0e07\u0e15\u0e32\u0e21\u0e0a\u0e37\u0e48\u0e2d',
|
|
||||||
sortByModel: '\u0e08\u0e31\u0e14\u0e40\u0e23\u0e35\u0e22\u0e07\u0e15\u0e32\u0e21\u0e42\u0e21\u0e40\u0e14\u0e25',
|
|
||||||
sortAscending: '\u0e40\u0e23\u0e35\u0e22\u0e07\u0e08\u0e32\u0e01\u0e19\u0e49\u0e2d\u0e22\u0e44\u0e1b\u0e21\u0e32\u0e01',
|
|
||||||
sortDescending: '\u0e40\u0e23\u0e35\u0e22\u0e07\u0e08\u0e32\u0e01\u0e21\u0e32\u0e01\u0e44\u0e1b\u0e19\u0e49\u0e2d\u0e22',
|
|
||||||
pinConversation: '\u0e1b\u0e31\u0e01\u0e2b\u0e21\u0e38\u0e14\u0e01\u0e32\u0e23\u0e2a\u0e19\u0e17\u0e19\u0e32',
|
|
||||||
renameConversation: '\u0e40\u0e1b\u0e25\u0e35\u0e48\u0e22\u0e19\u0e0a\u0e37\u0e48\u0e2d\u0e01\u0e32\u0e23\u0e2a\u0e19\u0e17\u0e19\u0e32',
|
|
||||||
delConversation: '\u0e25\u0e1a\u0e01\u0e32\u0e23\u0e2a\u0e19\u0e17\u0e19\u0e32',
|
|
||||||
batchOperations: '\u0e14\u0e33\u0e40\u0e19\u0e34\u0e19\u0e01\u0e32\u0e23\u0e41\u0e1a\u0e1a\u0e01\u0e25\u0e38\u0e48\u0e21',
|
|
||||||
},
|
|
||||||
message: {
|
|
||||||
copyMessage: '\u0e04\u0e31\u0e14\u0e25\u0e2d\u0e01\u0e02\u0e49\u0e2d\u0e04\u0e27\u0e32\u0e21',
|
|
||||||
deleteMessage: '\u0e25\u0e1a\u0e02\u0e49\u0e2d\u0e04\u0e27\u0e32\u0e21',
|
|
||||||
selectMessage: '\u0e40\u0e25\u0e37\u0e2d\u0e01\u0e02\u0e49\u0e2d\u0e04\u0e27\u0e32\u0e21',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tray: {
|
|
||||||
tooltip: 'ZN-AI',
|
|
||||||
showWindow: '\u0e41\u0e2a\u0e14\u0e07\u0e2b\u0e19\u0e49\u0e32\u0e15\u0e48\u0e32\u0e07',
|
|
||||||
exit: '\u0e2d\u0e2d\u0e01',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -1,30 +1,7 @@
|
|||||||
import { CONFIG_KEYS as RUNTIME_CONFIG_KEYS } from '../types/runtime';
|
export {
|
||||||
|
CONFIG_KEYS,
|
||||||
export const IPC_EVENTS = {
|
DEFAULT_LANGUAGE,
|
||||||
HOST_API_FETCH: 'hostapi:fetch',
|
DEFAULT_THEME_MODE,
|
||||||
GATEWAY_RPC: 'gateway:rpc',
|
IPC_EVENTS,
|
||||||
GATEWAY_EVENT: 'gateway:event',
|
WINDOW_NAMES,
|
||||||
GET_CONFIG: 'get-config',
|
} from '../../runtime-shared/lib/constants';
|
||||||
SET_CONFIG: 'set-config',
|
|
||||||
GET_THEME_MODE: 'get-theme-mode',
|
|
||||||
SET_THEME_MODE: 'set-theme-mode',
|
|
||||||
THEME_MODE_UPDATED: 'theme-mode-updated',
|
|
||||||
TASK_PROGRESS: 'task:progress',
|
|
||||||
TASK_STARTED: 'task:started',
|
|
||||||
TASK_COMPLETED: 'task:completed',
|
|
||||||
OPEN_CHANNEL: 'open-channel',
|
|
||||||
EXECUTE_SCRIPT: 'execute-script',
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
export const CONFIG_KEYS = RUNTIME_CONFIG_KEYS;
|
|
||||||
|
|
||||||
export const WINDOW_NAMES = {
|
|
||||||
MAIN: 'main',
|
|
||||||
SETTING: 'setting',
|
|
||||||
DIALOG: 'dialog',
|
|
||||||
LOADING: 'loading',
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
export const DEFAULT_THEME_MODE = 'system' as const;
|
|
||||||
|
|
||||||
export const DEFAULT_LANGUAGE = 'zh' as const;
|
|
||||||
|
|||||||
@@ -1,261 +1 @@
|
|||||||
import type { LanguageCode } from '../types/runtime';
|
export * from '../../runtime-shared/lib/providers';
|
||||||
|
|
||||||
export const PROVIDER_TYPES = [
|
|
||||||
'anthropic',
|
|
||||||
'openai',
|
|
||||||
'google',
|
|
||||||
'openrouter',
|
|
||||||
'ark',
|
|
||||||
'moonshot',
|
|
||||||
'siliconflow',
|
|
||||||
'deepseek',
|
|
||||||
'minimax-portal',
|
|
||||||
'minimax-portal-cn',
|
|
||||||
'modelstudio',
|
|
||||||
'ollama',
|
|
||||||
'custom',
|
|
||||||
] as const;
|
|
||||||
export type ProviderType = (typeof PROVIDER_TYPES)[number];
|
|
||||||
|
|
||||||
export const BUILTIN_PROVIDER_TYPES = [
|
|
||||||
'anthropic',
|
|
||||||
'openai',
|
|
||||||
'google',
|
|
||||||
'openrouter',
|
|
||||||
'ark',
|
|
||||||
'moonshot',
|
|
||||||
'siliconflow',
|
|
||||||
'deepseek',
|
|
||||||
'minimax-portal',
|
|
||||||
'minimax-portal-cn',
|
|
||||||
'modelstudio',
|
|
||||||
'ollama',
|
|
||||||
] as const;
|
|
||||||
|
|
||||||
export const OLLAMA_PLACEHOLDER_API_KEY = 'ollama-local';
|
|
||||||
|
|
||||||
export interface ProviderConfig {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
type: ProviderType;
|
|
||||||
baseUrl?: string;
|
|
||||||
apiProtocol?: 'openai-completions' | 'openai-responses' | 'anthropic-messages';
|
|
||||||
headers?: Record<string, string>;
|
|
||||||
model?: string;
|
|
||||||
fallbackModels?: string[];
|
|
||||||
fallbackProviderIds?: string[];
|
|
||||||
enabled: boolean;
|
|
||||||
createdAt: string;
|
|
||||||
updatedAt: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ProviderWithKeyInfo extends ProviderConfig {
|
|
||||||
hasKey: boolean;
|
|
||||||
keyMasked: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ProviderTypeInfo {
|
|
||||||
id: ProviderType;
|
|
||||||
name: string;
|
|
||||||
icon: string;
|
|
||||||
placeholder: string;
|
|
||||||
placeholderZh?: string;
|
|
||||||
placeholderTh?: string;
|
|
||||||
model?: string;
|
|
||||||
requiresApiKey: boolean;
|
|
||||||
defaultBaseUrl?: string;
|
|
||||||
showBaseUrl?: boolean;
|
|
||||||
showModelId?: boolean;
|
|
||||||
showModelIdInDevModeOnly?: boolean;
|
|
||||||
modelIdPlaceholder?: string;
|
|
||||||
defaultModelId?: string;
|
|
||||||
isOAuth?: boolean;
|
|
||||||
supportsApiKey?: boolean;
|
|
||||||
apiKeyUrl?: string;
|
|
||||||
docsUrl?: string;
|
|
||||||
docsUrlZh?: string;
|
|
||||||
codePlanPresetBaseUrl?: string;
|
|
||||||
codePlanPresetModelId?: string;
|
|
||||||
codePlanDocsUrl?: string;
|
|
||||||
hidden?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ProviderAuthMode =
|
|
||||||
| 'api_key'
|
|
||||||
| 'oauth_device'
|
|
||||||
| 'oauth_browser'
|
|
||||||
| 'local';
|
|
||||||
|
|
||||||
export type ProviderVendorCategory =
|
|
||||||
| 'official'
|
|
||||||
| 'compatible'
|
|
||||||
| 'local'
|
|
||||||
| 'custom';
|
|
||||||
|
|
||||||
export interface ProviderVendorInfo extends ProviderTypeInfo {
|
|
||||||
category: ProviderVendorCategory;
|
|
||||||
envVar?: string;
|
|
||||||
supportedAuthModes: ProviderAuthMode[];
|
|
||||||
defaultAuthMode: ProviderAuthMode;
|
|
||||||
supportsMultipleAccounts: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ProviderAccount {
|
|
||||||
id: string;
|
|
||||||
vendorId: ProviderType;
|
|
||||||
label: string;
|
|
||||||
authMode: ProviderAuthMode;
|
|
||||||
baseUrl?: string;
|
|
||||||
apiProtocol?: 'openai-completions' | 'openai-responses' | 'anthropic-messages';
|
|
||||||
headers?: Record<string, string>;
|
|
||||||
model?: string;
|
|
||||||
fallbackModels?: string[];
|
|
||||||
fallbackAccountIds?: string[];
|
|
||||||
enabled: boolean;
|
|
||||||
isDefault: boolean;
|
|
||||||
metadata?: {
|
|
||||||
region?: string;
|
|
||||||
email?: string;
|
|
||||||
resourceUrl?: string;
|
|
||||||
customModels?: string[];
|
|
||||||
};
|
|
||||||
createdAt: string;
|
|
||||||
updatedAt: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const PROVIDER_TYPE_INFO: ProviderTypeInfo[] = [
|
|
||||||
{
|
|
||||||
id: 'anthropic',
|
|
||||||
name: 'Anthropic',
|
|
||||||
icon: '🤖',
|
|
||||||
placeholder: 'sk-ant-api03-...',
|
|
||||||
model: 'Claude',
|
|
||||||
requiresApiKey: true,
|
|
||||||
docsUrl: 'https://platform.claude.com/docs/en/api/overview',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'openai',
|
|
||||||
name: 'OpenAI',
|
|
||||||
icon: '💚',
|
|
||||||
placeholder: 'sk-proj-...',
|
|
||||||
model: 'GPT',
|
|
||||||
requiresApiKey: true,
|
|
||||||
isOAuth: true,
|
|
||||||
supportsApiKey: true,
|
|
||||||
defaultModelId: 'gpt-5.4',
|
|
||||||
showModelId: true,
|
|
||||||
showModelIdInDevModeOnly: true,
|
|
||||||
modelIdPlaceholder: 'gpt-5.4',
|
|
||||||
apiKeyUrl: 'https://platform.openai.com/api-keys',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'google',
|
|
||||||
name: 'Google',
|
|
||||||
icon: '🔷',
|
|
||||||
placeholder: 'AIza...',
|
|
||||||
model: 'Gemini',
|
|
||||||
requiresApiKey: true,
|
|
||||||
isOAuth: true,
|
|
||||||
supportsApiKey: true,
|
|
||||||
defaultModelId: 'gemini-3-pro-preview',
|
|
||||||
showModelId: true,
|
|
||||||
showModelIdInDevModeOnly: true,
|
|
||||||
modelIdPlaceholder: 'gemini-3-pro-preview',
|
|
||||||
apiKeyUrl: 'https://aistudio.google.com/app/apikey',
|
|
||||||
},
|
|
||||||
{ id: 'openrouter', name: 'OpenRouter', icon: '🌐', placeholder: 'sk-or-v1-...', model: 'Multi-Model', requiresApiKey: true, showModelId: true, modelIdPlaceholder: 'openai/gpt-5.4', defaultModelId: 'openai/gpt-5.4', docsUrl: 'https://openrouter.ai/models' },
|
|
||||||
{ id: 'minimax-portal-cn', name: 'MiniMax (CN)', icon: '☁️', placeholder: 'sk-...', model: 'MiniMax', requiresApiKey: false, isOAuth: true, supportsApiKey: true, defaultBaseUrl: 'https://api.minimaxi.com/v1', apiProtocol: 'openai-completions', defaultModelId: 'MiniMax-M2.7', showModelId: true, showModelIdInDevModeOnly: true, modelIdPlaceholder: 'MiniMax-M2.7', apiKeyUrl: 'https://platform.minimaxi.com/' },
|
|
||||||
{ id: 'moonshot', name: 'Moonshot (CN)', icon: '🌙', placeholder: 'sk-...', model: 'Kimi', requiresApiKey: true, defaultBaseUrl: 'https://api.moonshot.cn/v1', defaultModelId: 'kimi-k2.5', docsUrl: 'https://platform.moonshot.cn/' },
|
|
||||||
{ id: 'siliconflow', name: 'SiliconFlow (CN)', icon: '🌊', placeholder: 'sk-...', model: 'Multi-Model', requiresApiKey: true, defaultBaseUrl: 'https://api.siliconflow.cn/v1', showModelId: true, showModelIdInDevModeOnly: true, modelIdPlaceholder: 'deepseek-ai/DeepSeek-V3', defaultModelId: 'deepseek-ai/DeepSeek-V3', docsUrl: 'https://docs.siliconflow.cn/cn/userguide/introduction' },
|
|
||||||
{ id: 'deepseek', name: 'DeepSeek', icon: '🐋', placeholder: 'sk-...', model: 'DeepSeek', requiresApiKey: true, defaultBaseUrl: 'https://api.deepseek.com/v1', showModelId: true, modelIdPlaceholder: 'deepseek-chat', defaultModelId: 'deepseek-chat', apiKeyUrl: 'https://platform.deepseek.com/api_keys', docsUrl: 'https://api-docs.deepseek.com/' },
|
|
||||||
{ id: 'minimax-portal', name: 'MiniMax (Global)', icon: '☁️', placeholder: 'sk-...', model: 'MiniMax', requiresApiKey: false, isOAuth: true, supportsApiKey: true, defaultBaseUrl: 'https://api.minimax.io/v1', apiProtocol: 'openai-completions', defaultModelId: 'MiniMax-M2.7', showModelId: true, showModelIdInDevModeOnly: true, modelIdPlaceholder: 'MiniMax-M2.7', apiKeyUrl: 'https://platform.minimax.io' },
|
|
||||||
{ id: 'modelstudio', name: 'Model Studio', icon: '☁️', placeholder: 'sk-...', model: 'Qwen', requiresApiKey: true, defaultBaseUrl: 'https://coding.dashscope.aliyuncs.com/v1', showBaseUrl: true, defaultModelId: 'qwen3.5-plus', showModelId: true, showModelIdInDevModeOnly: true, modelIdPlaceholder: 'qwen3.5-plus', apiKeyUrl: 'https://bailian.console.aliyun.com/', hidden: true },
|
|
||||||
{ id: 'ark', name: 'ByteDance Ark', icon: 'A', placeholder: 'your-ark-api-key', model: 'Doubao', requiresApiKey: true, defaultBaseUrl: 'https://ark.cn-beijing.volces.com/api/v3', showBaseUrl: true, showModelId: true, modelIdPlaceholder: 'ep-20260228000000-xxxxx', docsUrl: 'https://www.volcengine.com/', codePlanPresetBaseUrl: 'https://ark.cn-beijing.volces.com/api/coding/v3', codePlanPresetModelId: 'ark-code-latest', codePlanDocsUrl: 'https://www.volcengine.com/docs/82379/1928261?lang=zh' },
|
|
||||||
{ id: 'ollama', name: 'Ollama', icon: '🦙', placeholder: 'Not required', placeholderZh: '无需填写', placeholderTh: 'ไม่ต้องกรอก', requiresApiKey: false, defaultBaseUrl: 'http://localhost:11434/v1', showBaseUrl: true, showModelId: true, modelIdPlaceholder: 'qwen3:latest' },
|
|
||||||
{
|
|
||||||
id: 'custom',
|
|
||||||
name: 'Custom',
|
|
||||||
icon: '⚙️',
|
|
||||||
placeholder: 'API key...',
|
|
||||||
placeholderZh: 'API Key...',
|
|
||||||
placeholderTh: 'API Key...',
|
|
||||||
requiresApiKey: true,
|
|
||||||
showBaseUrl: true,
|
|
||||||
showModelId: true,
|
|
||||||
modelIdPlaceholder: 'your-provider/model-id',
|
|
||||||
docsUrl: 'https://icnnp7d0dymg.feishu.cn/wiki/BmiLwGBcEiloZDkdYnGc8RWnn6d#Ee1ldfvKJoVGvfxc32mcILwenth',
|
|
||||||
docsUrlZh: 'https://icnnp7d0dymg.feishu.cn/wiki/BmiLwGBcEiloZDkdYnGc8RWnn6d#IWQCdfe5fobGU3xf3UGcgbLynGh',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export function getProviderIconUrl(_type: ProviderType | string): string | undefined {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function shouldInvertInDark(_type: ProviderType | string): boolean {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const SETUP_PROVIDERS = PROVIDER_TYPE_INFO;
|
|
||||||
|
|
||||||
export function getProviderTypeInfo(type: ProviderType): ProviderTypeInfo | undefined {
|
|
||||||
return PROVIDER_TYPE_INFO.find((providerType) => providerType.id === type);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getProviderDocsUrl(
|
|
||||||
provider: Pick<ProviderTypeInfo, 'docsUrl' | 'docsUrlZh'> | undefined,
|
|
||||||
language: string | LanguageCode,
|
|
||||||
): string | undefined {
|
|
||||||
if (!provider?.docsUrl) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
if (language.startsWith('zh') && provider.docsUrlZh) {
|
|
||||||
return provider.docsUrlZh;
|
|
||||||
}
|
|
||||||
return provider.docsUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getProviderPlaceholder(
|
|
||||||
provider: Pick<ProviderTypeInfo, 'placeholder' | 'placeholderZh' | 'placeholderTh'> | undefined,
|
|
||||||
language: string | LanguageCode,
|
|
||||||
): string | undefined {
|
|
||||||
if (!provider?.placeholder) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
if (language.startsWith('zh') && provider.placeholderZh) {
|
|
||||||
return provider.placeholderZh;
|
|
||||||
}
|
|
||||||
if (language.startsWith('th') && provider.placeholderTh) {
|
|
||||||
return provider.placeholderTh;
|
|
||||||
}
|
|
||||||
return provider.placeholder;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function shouldShowProviderModelId(
|
|
||||||
provider: Pick<ProviderTypeInfo, 'showModelId' | 'showModelIdInDevModeOnly'> | undefined,
|
|
||||||
devModeUnlocked: boolean,
|
|
||||||
): boolean {
|
|
||||||
if (!provider?.showModelId) return false;
|
|
||||||
if (provider.showModelIdInDevModeOnly && !devModeUnlocked) return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function resolveProviderModelForSave(
|
|
||||||
provider: Pick<ProviderTypeInfo, 'defaultModelId' | 'showModelId' | 'showModelIdInDevModeOnly'> | undefined,
|
|
||||||
modelId: string,
|
|
||||||
devModeUnlocked: boolean,
|
|
||||||
): string | undefined {
|
|
||||||
if (!shouldShowProviderModelId(provider, devModeUnlocked)) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
const trimmedModelId = modelId.trim();
|
|
||||||
return trimmedModelId || provider?.defaultModelId || undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function resolveProviderApiKeyForSave(type: ProviderType | string, apiKey: string): string | undefined {
|
|
||||||
const trimmed = apiKey.trim();
|
|
||||||
if (type === 'ollama') {
|
|
||||||
return trimmed || OLLAMA_PLACEHOLDER_API_KEY;
|
|
||||||
}
|
|
||||||
return trimmed || undefined;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,173 +1 @@
|
|||||||
export interface AttachedFileMeta {
|
export * from '../../runtime-shared/shared/chat-model';
|
||||||
fileName: string;
|
|
||||||
mimeType: string;
|
|
||||||
fileSize: number;
|
|
||||||
preview: string | null;
|
|
||||||
filePath?: string;
|
|
||||||
source?: 'user-upload' | 'tool-result' | 'message-ref';
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ContentBlockSource {
|
|
||||||
type: string;
|
|
||||||
media_type?: string;
|
|
||||||
data?: string;
|
|
||||||
url?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ContentBlock {
|
|
||||||
type: 'text' | 'image' | 'thinking' | 'tool_use' | 'tool_result' | 'toolCall' | 'toolResult';
|
|
||||||
text?: string;
|
|
||||||
thinking?: string;
|
|
||||||
source?: ContentBlockSource;
|
|
||||||
data?: string;
|
|
||||||
mimeType?: string;
|
|
||||||
id?: string;
|
|
||||||
name?: string;
|
|
||||||
input?: unknown;
|
|
||||||
arguments?: unknown;
|
|
||||||
content?: string | ContentBlock[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export type RawMessageRole = 'user' | 'assistant' | 'system' | 'toolresult' | 'tool_result';
|
|
||||||
|
|
||||||
export interface RawMessage {
|
|
||||||
role: RawMessageRole;
|
|
||||||
content: string | ContentBlock[];
|
|
||||||
timestamp?: number;
|
|
||||||
id?: string;
|
|
||||||
toolCallId?: string;
|
|
||||||
toolName?: string;
|
|
||||||
details?: unknown;
|
|
||||||
isError?: boolean;
|
|
||||||
question?: string[];
|
|
||||||
toolCall?: Record<string, unknown> | null;
|
|
||||||
_attachedFiles?: AttachedFileMeta[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ToolStatus {
|
|
||||||
id?: string;
|
|
||||||
toolCallId?: string;
|
|
||||||
name: string;
|
|
||||||
status: 'running' | 'completed' | 'error';
|
|
||||||
durationMs?: number;
|
|
||||||
summary?: string;
|
|
||||||
updatedAt: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ChatSession {
|
|
||||||
key: string;
|
|
||||||
label?: string;
|
|
||||||
displayName?: string;
|
|
||||||
thinkingLevel?: string;
|
|
||||||
model?: string;
|
|
||||||
updatedAt?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function extractText(message?: RawMessage | null): string {
|
|
||||||
if (!message) return '';
|
|
||||||
|
|
||||||
if (typeof message.content === 'string') {
|
|
||||||
return message.content;
|
|
||||||
}
|
|
||||||
|
|
||||||
return message.content
|
|
||||||
.filter((block) => block.type === 'text' && typeof block.text === 'string')
|
|
||||||
.map((block) => block.text ?? '')
|
|
||||||
.join('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
export function extractThinking(message?: RawMessage | null): string | null {
|
|
||||||
if (!message || !Array.isArray(message.content)) return null;
|
|
||||||
|
|
||||||
const thinkingBlock = message.content.find((block) => block.type === 'thinking');
|
|
||||||
return thinkingBlock?.thinking ?? null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function extractImages(message?: RawMessage | null): Array<{ url?: string; data?: string; mimeType: string }> {
|
|
||||||
if (!message || !Array.isArray(message.content)) return [];
|
|
||||||
|
|
||||||
const images: Array<{ url?: string; data?: string; mimeType: string }> = [];
|
|
||||||
|
|
||||||
for (const block of message.content) {
|
|
||||||
if (block.type === 'image') {
|
|
||||||
if (block.source?.type === 'base64' && block.source.data) {
|
|
||||||
images.push({
|
|
||||||
data: block.source.data,
|
|
||||||
mimeType: block.source.media_type || 'image/jpeg',
|
|
||||||
});
|
|
||||||
} else if (block.source?.type === 'url' && block.source.url) {
|
|
||||||
images.push({
|
|
||||||
url: block.source.url,
|
|
||||||
mimeType: block.source.media_type || 'image/jpeg',
|
|
||||||
});
|
|
||||||
} else if (block.data) {
|
|
||||||
images.push({
|
|
||||||
data: block.data,
|
|
||||||
mimeType: block.mimeType || 'image/jpeg',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((block.type === 'tool_result' || block.type === 'toolResult') && Array.isArray(block.content)) {
|
|
||||||
images.push(...extractImages({ role: 'toolresult', content: block.content }));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return images;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function extractToolUse(message?: RawMessage | null): Array<{ id?: string; name: string; input?: unknown }> {
|
|
||||||
if (!message || !Array.isArray(message.content)) return [];
|
|
||||||
|
|
||||||
return message.content
|
|
||||||
.filter((block) => block.type === 'tool_use' || block.type === 'toolCall')
|
|
||||||
.map((block) => ({
|
|
||||||
id: block.id,
|
|
||||||
name: block.name || block.id || 'tool',
|
|
||||||
input: block.input ?? block.arguments,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
export function formatTimestamp(ts?: number): string {
|
|
||||||
if (!ts) return '';
|
|
||||||
|
|
||||||
const ms = ts < 1e12 ? ts * 1000 : ts;
|
|
||||||
return new Date(ms).toLocaleString();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isToolResultRole(role?: string): boolean {
|
|
||||||
if (!role) return false;
|
|
||||||
|
|
||||||
const normalized = role.toLowerCase();
|
|
||||||
return normalized === 'toolresult' || normalized === 'tool_result';
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isToolOnlyMessage(message?: RawMessage): boolean {
|
|
||||||
if (!message) return false;
|
|
||||||
if (isToolResultRole(message.role)) return true;
|
|
||||||
if (!Array.isArray(message.content)) return false;
|
|
||||||
|
|
||||||
const hasToolBlock = message.content.some((block) =>
|
|
||||||
['tool_use', 'tool_result', 'toolCall', 'toolResult'].includes(block.type),
|
|
||||||
);
|
|
||||||
const hasTextBlock = message.content.some((block) => block.type === 'text' && block.text?.trim());
|
|
||||||
const hasImageBlock = message.content.some((block) => block.type === 'image');
|
|
||||||
|
|
||||||
return hasToolBlock && !hasTextBlock && !hasImageBlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isInternalMessage(message: { role?: string; content?: unknown }): boolean {
|
|
||||||
if (message.role === 'system') return true;
|
|
||||||
|
|
||||||
if (message.role === 'assistant') {
|
|
||||||
const text = typeof message.content === 'string'
|
|
||||||
? message.content
|
|
||||||
: extractText(message as RawMessage);
|
|
||||||
|
|
||||||
if (/^(HEARTBEAT_OK|NO_REPLY)\s*$/.test(text)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import type { Task } from '../lib/task-types';
|
import type { Task } from '../lib/task-types';
|
||||||
import type { RawMessage } from '../shared/chat-model';
|
import type { RawMessage } from '../shared/chat-model';
|
||||||
|
import { CONFIG_KEYS } from '../../runtime-shared/lib/constants';
|
||||||
|
|
||||||
export type RuntimeRefreshTopic =
|
export type RuntimeRefreshTopic =
|
||||||
| 'providers'
|
| 'providers'
|
||||||
@@ -20,21 +21,6 @@ export type IpcArgs = readonly unknown[];
|
|||||||
|
|
||||||
export type IpcListener = (...args: unknown[]) => void;
|
export type IpcListener = (...args: unknown[]) => void;
|
||||||
|
|
||||||
export const CONFIG_KEYS = {
|
|
||||||
THEME_MODE: 'themeMode',
|
|
||||||
PRIMARY_COLOR: 'primaryColor',
|
|
||||||
LANGUAGE: 'language',
|
|
||||||
FONT_SIZE: 'fontSize',
|
|
||||||
MINIMIZE_TO_TRAY: 'minimizeToTray',
|
|
||||||
LAUNCH_AT_STARTUP: 'launchAtStartup',
|
|
||||||
PROVIDER: 'provider',
|
|
||||||
DEFAULT_MODEL: 'defaultModel',
|
|
||||||
GATEWAY_AUTO_START: 'gatewayAutoStart',
|
|
||||||
SELECTED_CHANNELS: 'selectedChannels',
|
|
||||||
IMAGE_CACHE: 'imageCache',
|
|
||||||
TASK_LIST: 'taskList',
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
export type ConfigKey = (typeof CONFIG_KEYS)[keyof typeof CONFIG_KEYS];
|
export type ConfigKey = (typeof CONFIG_KEYS)[keyof typeof CONFIG_KEYS];
|
||||||
|
|
||||||
export type ConfigValueKey = keyof ConfigValueMap;
|
export type ConfigValueKey = keyof ConfigValueMap;
|
||||||
|
|||||||
Reference in New Issue
Block a user