release: 0.0.41

- 修复内存泄漏问题,该可能导致内存异常占用
- 支持俄语增加翻译范围
- 修复qwen-3.8-max中断问题(mimo也应该属于同一类问题)
- 修复claude模型可能无法识别图片问题 @GGHansome
- 支持自定义Openai端点 @Sxuan-Coder
- WebSearch 接入百度搜索,DuckDuckGo 作为兜底 @杨超
- 修复一些兼容性问题 @kael-odin
- 修复window上一些表现问题 @philau2512

🔔 如何让AI自动拉模型配置? (以下为提示词,把地址和密钥换为你的)
我的模型配置在 ~/.cursor-local-assistant-v2/config.yaml,我的API地址是:https://xxx 密钥是xxx,帮我拉所有模型配置进去,不要影响已有模型,根据models标准接口拉取。
This commit is contained in:
leookun
2026-07-27 00:55:02 +08:00
parent e401303f64
commit 0f6b0f9484
28 changed files with 808 additions and 441 deletions
+42
View File
@@ -0,0 +1,42 @@
---
name: i18n-requirements
description: Use when adding or changing frontend UI text, locale support, translation JSON, the static i18n scanner, language selection, or native tray labels in this repository; keeps source messages, generated catalogs, translations, and runtime locale registration consistent.
---
# I18n Requirements
## Source Messages
- Treat `zh-CN` as the only source locale.
- Write user-visible frontend text as Chinese source literals in scanned files under `frontend/src/`.
- Do not branch on locale or hard-code English, Japanese, Russian, or other translated UI text in components or state modules.
- Let `frontend/plugins/static-i18n-plugin.js` replace source literals with runtime helpers. Do not hand-write generated message IDs in application code.
- Keep internal matching tokens out of the catalog. Use a regex for Chinese protocol/error matching instead of a user-visible string literal when the text is not intended for display.
- Do not place ordinary user-visible source messages under `frontend/src/i18n/`; the scanner excludes that directory. Native language names in `LOCALE_OPTIONS` are an intentional exception.
## Generated Catalogs
- Treat `frontend/src/i18n/generated/catalog.json` and the source-locale entries as scanner output. Do not manually edit catalog references or message IDs.
- Run `npm run build` from `frontend/` after changing UI text. The build must run with `--scan` and update every locale file.
- Preserve every placeholder exactly across locales, including `{0}`, `{1}`, newlines, and formula fragments such as `${1}`.
- Provide a non-empty translation for every catalog key in every non-source locale. Do not rely on the Chinese fallback for completed locale support.
## Adding A Locale
Update all of these integration points together:
- `SUPPORTED_LOCALES` in `frontend/plugins/static-i18n-plugin.js`.
- `SUPPORTED_LOCALES` and `LOCALE_OPTIONS` in `frontend/src/i18n/config.js`.
- The locale JSON import, `localeMessages`, and primary-language mapping in `frontend/src/i18n/runtime.js`.
- `frontend/src/i18n/locales/<locale>.json` with the complete catalog key set.
- Native tray labels in `internal/app/runner.go`.
## Verification
After the scan build:
1. Confirm `npm run build` succeeds.
2. Confirm every locale JSON has the same keys as `catalog.json`.
3. Confirm non-source locale files contain no empty values.
4. Confirm translated placeholders match the source entry placeholders.
5. Run the build twice when scanner behavior changed and confirm generated files are stable.
@@ -0,0 +1,4 @@
interface:
display_name: "I18n Requirements"
short_description: "Keep UI translations and generated catalogs in sync"
default_prompt: "Use $i18n-requirements to update localized UI text safely."
+1 -1
View File
@@ -8,7 +8,7 @@ info:
description: "Cursor助手" description: "Cursor助手"
copyright: "© 2026, Cursor助手" copyright: "© 2026, Cursor助手"
comments: "Cursor助手" comments: "Cursor助手"
version: "0.0.40" version: "0.0.41"
dev_mode: dev_mode:
root_path: . root_path: .
+2 -2
View File
@@ -17,9 +17,9 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>0.0.40</string> <string>0.0.41</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>0.0.40</string> <string>0.0.41</string>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>
<string>12.0.0</string> <string>12.0.0</string>
<key>LSUIElement</key> <key>LSUIElement</key>
+2 -2
View File
@@ -17,9 +17,9 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>0.0.40</string> <string>0.0.41</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>0.0.40</string> <string>0.0.41</string>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>
<string>12.0.0</string> <string>12.0.0</string>
<key>LSUIElement</key> <key>LSUIElement</key>
+15 -28
View File
@@ -6,7 +6,7 @@
name: "Cursor助手" name: "Cursor助手"
arch: ${GOARCH} arch: ${GOARCH}
platform: "linux" platform: "linux"
version: "0.0.40" version: "0.0.41"
section: "default" section: "default"
priority: "extra" priority: "extra"
maintainer: ${GIT_COMMITTER_NAME} <${GIT_COMMITTER_EMAIL}> maintainer: ${GIT_COMMITTER_NAME} <${GIT_COMMITTER_EMAIL}>
@@ -24,24 +24,24 @@ contents:
- src: "./build/linux/Cursor助手.desktop" - src: "./build/linux/Cursor助手.desktop"
dst: "/usr/share/applications/Cursor助手.desktop" dst: "/usr/share/applications/Cursor助手.desktop"
# Default dependencies for the GTK4 + WebKitGTK 6.0 stack (Ubuntu 24.04+ / Debian 13+) # Default dependencies for Debian 12/Ubuntu 22.04+ with WebKit 4.1
depends: depends:
- libgtk-4-1 - libgtk-3-0
- libwebkitgtk-6.0-4 - libwebkit2gtk-4.1-0
# Distribution-specific overrides for different package formats # Distribution-specific overrides for different package formats and WebKit versions
overrides: overrides:
# RPM packages for Fedora / RHEL / AlmaLinux / Rocky Linux # RPM packages for RHEL/CentOS/AlmaLinux/Rocky Linux (WebKit 4.0)
rpm: rpm:
depends: depends:
- gtk4 - gtk3
- webkitgtk6.0 - webkit2gtk4.1
# Arch Linux packages # Arch Linux packages (WebKit 4.1)
archlinux: archlinux:
depends: depends:
- gtk4 - gtk3
- webkitgtk-6.0 - webkit2gtk-4.1
# scripts section to ensure desktop database is updated after install # scripts section to ensure desktop database is updated after install
scripts: scripts:
@@ -50,26 +50,13 @@ scripts:
# preremove: "./build/linux/nfpm/scripts/preremove.sh" # preremove: "./build/linux/nfpm/scripts/preremove.sh"
# postremove: "./build/linux/nfpm/scripts/postremove.sh" # postremove: "./build/linux/nfpm/scripts/postremove.sh"
# If you build your app with -tags gtk3 (legacy WebKit2GTK 4.1 stack — supported through v3.0.x, removed in v3.1),
# replace the depends/overrides above with these:
#
# depends:
# - libgtk-3-0
# - libwebkit2gtk-4.1-0
# overrides:
# rpm:
# depends:
# - gtk3
# - webkit2gtk4.1
# archlinux:
# depends:
# - gtk3
# - webkit2gtk-4.1
#
# replaces: # replaces:
# - foobar # - foobar
# provides: # provides:
# - bar # - bar
# depends:
# - gtk3
# - libwebkit2gtk
# recommends: # recommends:
# - whatever # - whatever
# suggests: # suggests:
+2 -2
View File
@@ -1,10 +1,10 @@
{ {
"fixed": { "fixed": {
"file_version": "0.0.40" "file_version": "0.0.41"
}, },
"info": { "info": {
"0000": { "0000": {
"ProductVersion": "0.0.40", "ProductVersion": "0.0.41",
"CompanyName": "Cursor助手", "CompanyName": "Cursor助手",
"FileDescription": "Cursor助手", "FileDescription": "Cursor助手",
"LegalCopyright": "© 2026, Cursor助手", "LegalCopyright": "© 2026, Cursor助手",
+12 -37
View File
@@ -14,7 +14,7 @@
!define INFO_PRODUCTNAME "Cursor助手" !define INFO_PRODUCTNAME "Cursor助手"
!endif !endif
!ifndef INFO_PRODUCTVERSION !ifndef INFO_PRODUCTVERSION
!define INFO_PRODUCTVERSION "0.0.40" !define INFO_PRODUCTVERSION "0.0.41"
!endif !endif
!ifndef INFO_COPYRIGHT !ifndef INFO_COPYRIGHT
!define INFO_COPYRIGHT "© 2026, Cursor助手" !define INFO_COPYRIGHT "© 2026, Cursor助手"
@@ -27,16 +27,8 @@
!endif !endif
!define UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINST_KEY_NAME}" !define UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINST_KEY_NAME}"
!ifndef WAILS_INSTALL_SCOPE
!define WAILS_INSTALL_SCOPE "machine"
!endif
!ifndef REQUEST_EXECUTION_LEVEL !ifndef REQUEST_EXECUTION_LEVEL
!if "${WAILS_INSTALL_SCOPE}" == "user" !define REQUEST_EXECUTION_LEVEL "admin"
!define REQUEST_EXECUTION_LEVEL "user"
!else
!define REQUEST_EXECUTION_LEVEL "admin"
!endif
!endif !endif
RequestExecutionLevel "${REQUEST_EXECUTION_LEVEL}" RequestExecutionLevel "${REQUEST_EXECUTION_LEVEL}"
@@ -123,40 +115,23 @@ RequestExecutionLevel "${REQUEST_EXECUTION_LEVEL}"
WriteUninstaller "$INSTDIR\uninstall.exe" WriteUninstaller "$INSTDIR\uninstall.exe"
SetRegView 64 SetRegView 64
!if "${WAILS_INSTALL_SCOPE}" == "user" WriteRegStr HKLM "${UNINST_KEY}" "Publisher" "${INFO_COMPANYNAME}"
WriteRegStr HKCU "${UNINST_KEY}" "Publisher" "${INFO_COMPANYNAME}" WriteRegStr HKLM "${UNINST_KEY}" "DisplayName" "${INFO_PRODUCTNAME}"
WriteRegStr HKCU "${UNINST_KEY}" "DisplayName" "${INFO_PRODUCTNAME}" WriteRegStr HKLM "${UNINST_KEY}" "DisplayVersion" "${INFO_PRODUCTVERSION}"
WriteRegStr HKCU "${UNINST_KEY}" "DisplayVersion" "${INFO_PRODUCTVERSION}" WriteRegStr HKLM "${UNINST_KEY}" "DisplayIcon" "$INSTDIR\${PRODUCT_EXECUTABLE}"
WriteRegStr HKCU "${UNINST_KEY}" "DisplayIcon" "$INSTDIR\${PRODUCT_EXECUTABLE}" WriteRegStr HKLM "${UNINST_KEY}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\""
WriteRegStr HKCU "${UNINST_KEY}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\"" WriteRegStr HKLM "${UNINST_KEY}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S"
WriteRegStr HKCU "${UNINST_KEY}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S"
${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2 ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2
IntFmt $0 "0x%08X" $0 IntFmt $0 "0x%08X" $0
WriteRegDWORD HKCU "${UNINST_KEY}" "EstimatedSize" "$0" WriteRegDWORD HKLM "${UNINST_KEY}" "EstimatedSize" "$0"
!else
WriteRegStr HKLM "${UNINST_KEY}" "Publisher" "${INFO_COMPANYNAME}"
WriteRegStr HKLM "${UNINST_KEY}" "DisplayName" "${INFO_PRODUCTNAME}"
WriteRegStr HKLM "${UNINST_KEY}" "DisplayVersion" "${INFO_PRODUCTVERSION}"
WriteRegStr HKLM "${UNINST_KEY}" "DisplayIcon" "$INSTDIR\${PRODUCT_EXECUTABLE}"
WriteRegStr HKLM "${UNINST_KEY}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\""
WriteRegStr HKLM "${UNINST_KEY}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S"
${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2
IntFmt $0 "0x%08X" $0
WriteRegDWORD HKLM "${UNINST_KEY}" "EstimatedSize" "$0"
!endif
!macroend !macroend
!macro wails.deleteUninstaller !macro wails.deleteUninstaller
Delete "$INSTDIR\uninstall.exe" Delete "$INSTDIR\uninstall.exe"
SetRegView 64 SetRegView 64
!if "${WAILS_INSTALL_SCOPE}" == "user" DeleteRegKey HKLM "${UNINST_KEY}"
DeleteRegKey HKCU "${UNINST_KEY}"
!else
DeleteRegKey HKLM "${UNINST_KEY}"
!endif
!macroend !macroend
!macro wails.setShellContext !macro wails.setShellContext
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3"> <assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<assemblyIdentity type="win32" name="com.cursor.wuxianxubei" version="0.0.40" processorArchitecture="*"/> <assemblyIdentity type="win32" name="com.cursor.wuxianxubei" version="0.0.41" processorArchitecture="*"/>
<dependency> <dependency>
<dependentAssembly> <dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/> <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/>
+2 -2
View File
@@ -5,8 +5,8 @@
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build:dev": "node ./scripts/run-vite-build.mjs --minify false --mode development", "build:dev": "node ./scripts/run-vite-build.mjs --scan --minify false --mode development",
"build": "node ./scripts/run-vite-build.mjs --mode production", "build": "node ./scripts/run-vite-build.mjs --scan --mode production",
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
+25 -16
View File
@@ -11,7 +11,7 @@ import { normalizePath } from "vite";
const traverse = traverseModule.default ?? traverseModule; const traverse = traverseModule.default ?? traverseModule;
const SOURCE_LANGUAGE = "zh-CN"; const SOURCE_LANGUAGE = "zh-CN";
const SUPPORTED_LOCALES = ["zh-CN", "en-US", "ja-JP"]; const SUPPORTED_LOCALES = ["zh-CN", "en-US", "ja-JP", "ru-RU"];
const HAN_REGEX = /\p{Script=Han}/u; const HAN_REGEX = /\p{Script=Han}/u;
const JS_HELPERS = { const JS_HELPERS = {
localized: "__i18nLocalized", localized: "__i18nLocalized",
@@ -490,22 +490,34 @@ function walkTemplateNode(node, visitor) {
} }
} }
function transformVueTemplate(templateCode, filePath, rootDir) { function resolveAbsoluteLoc(sourceCode, sourceOffset, relativeOffset) {
const absoluteOffset = sourceOffset + relativeOffset;
const prefix = sourceCode.slice(0, absoluteOffset);
const lastLineBreak = prefix.lastIndexOf("\n");
return {
line: prefix.split("\n").length,
column: absoluteOffset - lastLineBreak,
};
}
function transformVueTemplate(templateCode, filePath, rootDir, options = {}) {
const ast = parseTemplate(templateCode, { comments: true }); const ast = parseTemplate(templateCode, { comments: true });
const replacements = []; const replacements = [];
const records = []; const records = [];
const sourceCode = options.sourceCode ?? templateCode;
const sourceOffset = options.sourceOffset ?? 0;
const resolveLoc = (node, offset = 0) =>
resolveAbsoluteLoc(sourceCode, sourceOffset, node.loc.start.offset + offset);
walkTemplateNode(ast, (node, parent) => { walkTemplateNode(ast, (node, parent) => {
if (node.type === 2 && containsHan(node.content)) { if (node.type === 2 && containsHan(node.content)) {
const canonical = node.content.trim();
const record = buildMessageRecord( const record = buildMessageRecord(
filePath, filePath,
rootDir, rootDir,
node.content.trim(), canonical,
0, 0,
{ resolveLoc(node, node.content.indexOf(canonical)),
line: node.loc.start.line,
column: node.loc.start.column + 1,
},
); );
const replacement = createTextNodeReplacement(node.loc.source, record); const replacement = createTextNodeReplacement(node.loc.source, record);
if (!replacement) { if (!replacement) {
@@ -527,10 +539,7 @@ function transformVueTemplate(templateCode, filePath, rootDir) {
rootDir, rootDir,
node.value.content, node.value.content,
0, 0,
{ resolveLoc(node),
line: node.loc.start.line,
column: node.loc.start.column + 1,
},
); );
records.push(record); records.push(record);
replacements.push({ replacements.push({
@@ -552,10 +561,7 @@ function transformVueTemplate(templateCode, filePath, rootDir) {
node.content, node.content,
filePath, filePath,
rootDir, rootDir,
{ resolveLoc(node),
line: node.loc.start.line,
column: node.loc.start.column + 1,
},
); );
if (!transformed.changed) { if (!transformed.changed) {
return; return;
@@ -585,7 +591,10 @@ function transformVueSFC(code, filePath, rootDir) {
let changed = false; let changed = false;
if (descriptor.template) { if (descriptor.template) {
const templateResult = transformVueTemplate(descriptor.template.content, filePath, rootDir); const templateResult = transformVueTemplate(descriptor.template.content, filePath, rootDir, {
sourceCode: code,
sourceOffset: descriptor.template.loc.start.offset,
});
records.push(...templateResult.records); records.push(...templateResult.records);
if (templateResult.changed) { if (templateResult.changed) {
changed = true; changed = true;
@@ -273,7 +273,6 @@ const hasHomeAd = computed(() => normalizedHomeAds.value.length > 0);
<div <div
class="flex-1 center-row justify-end shrink-0 gap-2 text-xs text-[#6f6f6f] pr-4 w-[200px]" class="flex-1 center-row justify-end shrink-0 gap-2 text-xs text-[#6f6f6f] pr-4 w-[200px]"
> >
<span>刷新统计</span>
<button <button
type="button" type="button"
class="center-row justify-center h-[24px] w-[24px] rounded-[6px] border border-[#3b3b3b] bg-[#242424] text-[#9d9d9d] transition-colors duration-150 hover:border-[#4c4c4c] hover:text-white disabled:cursor-not-allowed disabled:opacity-60" class="center-row justify-center h-[24px] w-[24px] rounded-[6px] border border-[#3b3b3b] bg-[#242424] text-[#9d9d9d] transition-colors duration-150 hover:border-[#4c4c4c] hover:text-white disabled:cursor-not-allowed disabled:opacity-60"
+2 -1
View File
@@ -2,9 +2,10 @@ export const LOCALE_STORAGE_KEY = "cursor-client:locale:v1";
export const LOCALE_STORAGE_SOURCE_KEY = "cursor-client:locale-source:v1"; export const LOCALE_STORAGE_SOURCE_KEY = "cursor-client:locale-source:v1";
export const SOURCE_LOCALE = "zh-CN"; export const SOURCE_LOCALE = "zh-CN";
export const DEFAULT_LOCALE = "en-US"; export const DEFAULT_LOCALE = "en-US";
export const SUPPORTED_LOCALES = ["zh-CN", "en-US", "ja-JP"]; export const SUPPORTED_LOCALES = ["zh-CN", "en-US", "ja-JP", "ru-RU"];
export const LOCALE_OPTIONS = [ export const LOCALE_OPTIONS = [
{ label: "简体中文", value: "zh-CN" }, { label: "简体中文", value: "zh-CN" },
{ label: "English", value: "en-US" }, { label: "English", value: "en-US" },
{ label: "日本語", value: "ja-JP" }, { label: "日本語", value: "ja-JP" },
{ label: "Русский", value: "ru-RU" },
]; ];
File diff suppressed because it is too large Load Diff
+5
View File
@@ -30,6 +30,7 @@
"26a3855aed1d8d17": "Service not running", "26a3855aed1d8d17": "Service not running",
"281eb6d08c9960d0": "{0} thinking budget token must be a positive integer", "281eb6d08c9960d0": "{0} thinking budget token must be a positive integer",
"28aeffc70ceb4267": "Change the display language for this interface. The setting takes effect immediately and is saved on this device.", "28aeffc70ceb4267": "Change the display language for this interface. The setting takes effect immediately and is saved on this device.",
"2a24519398684ed5": "Visit Homepage",
"2cd0f3be8738a86c": "Cancel", "2cd0f3be8738a86c": "Cancel",
"2d706f7981b45a7b": "Local settings saved", "2d706f7981b45a7b": "Local settings saved",
"2f9daa828907b93f": "Delete", "2f9daa828907b93f": "Delete",
@@ -40,6 +41,7 @@
"3463c5585c246df9": "Total: {0}", "3463c5585c246df9": "Total: {0}",
"3468b57e3edbc599": "Aggregated from turn summaries scanned from the history.", "3468b57e3edbc599": "Aggregated from turn summaries scanned from the history.",
"35076178fe79a210": "Configuration changed. Please test again.", "35076178fe79a210": "Configuration changed. Please test again.",
"358f07b2c1445ab1": "Author's Message",
"36c149a9b3e8dca0": "models configured yet.", "36c149a9b3e8dca0": "models configured yet.",
"37d23612f78a2e63": "Restart Now to Update", "37d23612f78a2e63": "Restart Now to Update",
"392d0dceb45998d3": "Extreme", "392d0dceb45998d3": "Extreme",
@@ -50,6 +52,7 @@
"3d13868593ae4eeb": "Interface Language", "3d13868593ae4eeb": "Interface Language",
"3ea83f9f55062582": "Release date: {0}", "3ea83f9f55062582": "Release date: {0}",
"3edda85621fd03b2": "model adapters", "3edda85621fd03b2": "model adapters",
"3fd47edce45b3603": "Close",
"42aa8e01e98c0d8c": "Total Duration", "42aa8e01e98c0d8c": "Total Duration",
"438bb77c1ecdfab0": "Cache Write: {0} × ${1}/1M = {2}", "438bb77c1ecdfab0": "Cache Write: {0} × ${1}/1M = {2}",
"46056425a48ef05b": "Currently displayed using the reuse rate definition", "46056425a48ef05b": "Currently displayed using the reuse rate definition",
@@ -122,6 +125,7 @@
"91cba5c107a51892": "/ Invalid", "91cba5c107a51892": "/ Invalid",
"92059fe6cd713db4": "The model name actually sent to the server, for example gpt-4.1 or claude-sonnet.", "92059fe6cd713db4": "The model name actually sent to the server, for example gpt-4.1 or claude-sonnet.",
"93e08803675e378b": "Model ID", "93e08803675e378b": "Model ID",
"93faf55cd25c8319": "This software is completely free. If you were charged, you were likely scammed.\nWelcome to visit the author's homepage at https://space.bilibili.com/311706663/upload/video\nto see more updates, sharing guides, and future content.",
"942ff2d88baca0c6": "Checking for updates...", "942ff2d88baca0c6": "Checking for updates...",
"970388573a3c88c9": "Cache Read: {0} × ${1}/1M = {2}", "970388573a3c88c9": "Cache Read: {0} × ${1}/1M = {2}",
"9730c15f3c1963a1": "Max", "9730c15f3c1963a1": "Max",
@@ -148,6 +152,7 @@
"a693d69af48bfe48": "Save and Test", "a693d69af48bfe48": "Save and Test",
"a98585871c5313ff": "Display Name", "a98585871c5313ff": "Display Name",
"aa9e366f68d3d097": "Low", "aa9e366f68d3d097": "Low",
"ab607d54d86dc789": "Author leookun",
"ac217e4d1ca410f1": "New version available", "ac217e4d1ca410f1": "New version available",
"ad79540418be700a": "Open the settings folder, or manage model settings separately", "ad79540418be700a": "Open the settings folder, or manage model settings separately",
"ae5a738238463a92": "Hide API Key", "ae5a738238463a92": "Hide API Key",
+6 -2
View File
@@ -30,6 +30,7 @@
"26a3855aed1d8d17": "サービスは起動していません", "26a3855aed1d8d17": "サービスは起動していません",
"281eb6d08c9960d0": "{0} の思考予算 Token は正の整数である必要があります", "281eb6d08c9960d0": "{0} の思考予算 Token は正の整数である必要があります",
"28aeffc70ceb4267": "この画面の表示言語を切り替えます。設定はすぐに反映され、この端末に保存されます", "28aeffc70ceb4267": "この画面の表示言語を切り替えます。設定はすぐに反映され、この端末に保存されます",
"2a24519398684ed5": "ホームページへ",
"2cd0f3be8738a86c": "キャンセル", "2cd0f3be8738a86c": "キャンセル",
"2d706f7981b45a7b": "ローカル設定を保存しました", "2d706f7981b45a7b": "ローカル設定を保存しました",
"2f9daa828907b93f": "削除", "2f9daa828907b93f": "削除",
@@ -40,6 +41,7 @@
"3463c5585c246df9": "合計:{0}", "3463c5585c246df9": "合計:{0}",
"3468b57e3edbc599": "履歴からスキャンした各ターンの summary を集計しています。", "3468b57e3edbc599": "履歴からスキャンした各ターンの summary を集計しています。",
"35076178fe79a210": "設定が変更されました。再テストしてください", "35076178fe79a210": "設定が変更されました。再テストしてください",
"358f07b2c1445ab1": "著者からのメッセージ",
"36c149a9b3e8dca0": "モデルは設定されていません。", "36c149a9b3e8dca0": "モデルは設定されていません。",
"37d23612f78a2e63": "今すぐ再起動して更新", "37d23612f78a2e63": "今すぐ再起動して更新",
"392d0dceb45998d3": "最高", "392d0dceb45998d3": "最高",
@@ -50,6 +52,7 @@
"3d13868593ae4eeb": "表示言語", "3d13868593ae4eeb": "表示言語",
"3ea83f9f55062582": "公開日時: {0}", "3ea83f9f55062582": "公開日時: {0}",
"3edda85621fd03b2": "件のモデルアダプター", "3edda85621fd03b2": "件のモデルアダプター",
"3fd47edce45b3603": "閉じる",
"42aa8e01e98c0d8c": "総所要時間", "42aa8e01e98c0d8c": "総所要時間",
"438bb77c1ecdfab0": "キャッシュ書き込み:{0} × ${1}/1M = {2}", "438bb77c1ecdfab0": "キャッシュ書き込み:{0} × ${1}/1M = {2}",
"46056425a48ef05b": "現在、再利用率の定義に従って表示されています", "46056425a48ef05b": "現在、再利用率の定義に従って表示されています",
@@ -122,6 +125,7 @@
"91cba5c107a51892": "/ 異常", "91cba5c107a51892": "/ 異常",
"92059fe6cd713db4": "実際にサーバーへ送信されるモデル名です。例: gpt-4.1 または claude-sonnet。", "92059fe6cd713db4": "実際にサーバーへ送信されるモデル名です。例: gpt-4.1 または claude-sonnet。",
"93e08803675e378b": "モデル ID", "93e08803675e378b": "モデル ID",
"93faf55cd25c8319": "このソフトウェアは完全に無料です。もし料金を請求された場合は、詐欺の可能性が高いです。\n著者のホームページ https://space.bilibili.com/311706663/upload/video にアクセスして、更新情報や利用方法などを確認してください。",
"942ff2d88baca0c6": "アップデートを確認中...", "942ff2d88baca0c6": "アップデートを確認中...",
"970388573a3c88c9": "キャッシュ読み取り:{0} × ${1}/1M = {2}", "970388573a3c88c9": "キャッシュ読み取り:{0} × ${1}/1M = {2}",
"9730c15f3c1963a1": "最大", "9730c15f3c1963a1": "最大",
@@ -137,7 +141,7 @@
"9e02529bcaef36c6": "モデルチャネルが重複しています。url、modelID、apiKey、displayName、endpointの組み合わせを確認してください", "9e02529bcaef36c6": "モデルチャネルが重複しています。url、modelID、apiKey、displayName、endpointの組み合わせを確認してください",
"a026f37e613cf48b": "出力 Token", "a026f37e613cf48b": "出力 Token",
"a0d36236c523667c": "{0} のAnthropic思考強度はlow、medium、high、xhigh、maxのみをサポートしています", "a0d36236c523667c": "{0} のAnthropic思考強度はlow、medium、high、xhigh、maxのみをサポートしています",
"a1a038dfa16c3ede": "すでに最新バージョンですv{0})。", "a1a038dfa16c3ede": "すでに最新バージョン(v{0})です。",
"a3030bf8f16dc63c": "保存", "a3030bf8f16dc63c": "保存",
"a325d25c69e7256d": "モデル設定が存在しないため複製できません", "a325d25c69e7256d": "モデル設定が存在しないため複製できません",
"a4dd8bb7e8b6eb31": "API キーを表示", "a4dd8bb7e8b6eb31": "API キーを表示",
@@ -148,6 +152,7 @@
"a693d69af48bfe48": "保存してテスト", "a693d69af48bfe48": "保存してテスト",
"a98585871c5313ff": "表示名", "a98585871c5313ff": "表示名",
"aa9e366f68d3d097": "低", "aa9e366f68d3d097": "低",
"ab607d54d86dc789": "著者 leookun",
"ac217e4d1ca410f1": "新しいバージョンがあります", "ac217e4d1ca410f1": "新しいバージョンがあります",
"ad79540418be700a": "設定フォルダーを開くか、モデル設定を個別に管理できます", "ad79540418be700a": "設定フォルダーを開くか、モデル設定を個別に管理できます",
"ae5a738238463a92": "API キーを隠す", "ae5a738238463a92": "API キーを隠す",
@@ -218,6 +223,5 @@
"f6e1c8b1a6970db5": "現在のアウトバウンドリクエストはシステムプロキシを使用していません", "f6e1c8b1a6970db5": "現在のアウトバウンドリクエストはシステムプロキシを使用していません",
"fac2a67ad87807c4": "OK", "fac2a67ad87807c4": "OK",
"fb7a4c81729ed0ca": "停止中...", "fb7a4c81729ed0ca": "停止中...",
"a1a038dfa16c3ede": "すでに最新バージョン(v{0})です。",
"fec45092945f8790": "ユーザーガイド" "fec45092945f8790": "ユーザーガイド"
} }
+227
View File
@@ -0,0 +1,227 @@
{
"02216368edc68816": "Нет примечаний к выпуску",
"02bc2e95bf49e587": "Пока нет настроенных",
"03b11112dc970014": "Базовый URL",
"047ec6b71d0cec08": "Определяет, будут ли запросы основного маршрута из белого списка проходить через локальный сервис или исходный сервер Cursor",
"04f632dd4f034d5e": "Размер контекстного окна {0} должен быть положительным целым числом",
"051836569928a9f9": "Изменить",
"054d763265603305": "например, 65536 (оставьте пустым для значения по умолчанию)",
"05c8a9238c702efa": "Прямое подключение к Cursor",
"0647728439b5da2e": "Здесь можно настроить режим маршрутизации и каналы моделей. Журналы выполнения находятся в",
"092b520558eff5f2": "Не проверено",
"09ebc2643631ba25": "Оценка стоимости",
"0b0e7478e41fe677": "Текст подсказки {0} не может быть пустым",
"0c3b4cf7aa259edb": "Не удалось выполнить операцию",
"0dde813d719dbd01": "Не удалось открыть домашнюю страницу",
"1117a2f86030d03b": "Чтение и запись кеша включены в статистику Prompt.",
"11afd2a534395b18": "Успешно",
"124be3f86f197802": "Использование токенов",
"13b61c5f697b6700": "Доля попаданий в кеш",
"15d124b200ddabed": "Максимальное число токенов контекста, которое модель может принять за один запрос. Оставьте поле пустым для значения по умолчанию.",
"185aebe19c77425d": "{0} должен быть объектом JSON",
"18b7312022cd1840": "Запустить сервис",
"1af38868896cf53d": "Режим маршрутизации поддерживает только local или upstream",
"1baddde657dd2720": "Исходящие запросы используют системный прокси",
"1bc77f5ab979f4c1": "Добавить настройки модели",
"1e238093b79b3165": "Если оставить пустым, используется 65536",
"21296ab18ad9af25": "Дополнительные параметры JSON",
"24343a2096988d42": "Не удалось открыть",
"253d4a3428c648fb": "Токены записи в кеш: {0}",
"26a3855aed1d8d17": "Сервис не запущен",
"281eb6d08c9960d0": "Бюджет токенов рассуждения {0} должен быть положительным целым числом",
"28aeffc70ceb4267": "Измените язык интерфейса. Настройка применяется сразу и сохраняется на этом устройстве.",
"2a24519398684ed5": "Перейти на домашнюю страницу",
"2cd0f3be8738a86c": "Отмена",
"2d706f7981b45a7b": "Локальные настройки сохранены",
"2f9daa828907b93f": "Удалить",
"30bb57a50caedc38": "например, для ежедневного дополнения кода и ответов на вопросы",
"3275d7e70bbdc3d5": "{1} для {0}",
"32b3c9a50003f77a": "Количество выходных токенов рассчитано приблизительно",
"33d2d273e2bd5f88": "Не удалось открыть руководство пользователя",
"3463c5585c246df9": "Итого: {0}",
"3468b57e3edbc599": "Сводка составлена по данным ходов, найденным в истории.",
"35076178fe79a210": "Конфигурация изменена. Выполните проверку снова.",
"358f07b2c1445ab1": "Сообщение автора",
"36c149a9b3e8dca0": "моделей.",
"37d23612f78a2e63": "Перезапустить и обновить",
"392d0dceb45998d3": "Очень высокая",
"393df9bb13ea4900": "Попадание",
"3af7e5489e61ea51": "Обновление",
"3bf8512aa520ed21": "Режим локального сервиса",
"3c2a9f9901109e75": "Тип {0} поддерживает только OpenAI или Anthropic",
"3d13868593ae4eeb": "Язык интерфейса",
"3ea83f9f55062582": "Дата выпуска: {0}",
"3edda85621fd03b2": "адаптеров моделей",
"3fd47edce45b3603": "Закрыть",
"42aa8e01e98c0d8c": "Общая длительность",
"438bb77c1ecdfab0": "Запись в кеш: {0} × ${1}/1M = {2}",
"46056425a48ef05b": "Сейчас используется расчет по коэффициенту повторного использования",
"468adaa418ee1475": "например, https://api.openai.com/v1",
"472642d58d3d5a6d": "Формула: {0}",
"4923eeb7bd75cccd": "Идентификатор модели {0} не может быть пустым",
"497c85690c4cc0fc": "Нет данных",
"4c0a929bb86ce912": "Сейчас: {0}",
"4d2b6e53be6002e5": "Стратегия статистики кеша: {0} ({1})",
"4d8c1c5b42830791": "Неизвестно",
"4f0982ba1d37e51b": "Исходящие запросы используют прокси из переменных окружения",
"51194c3ad014fb29": "Требуется повторная проверка",
"5205125c0e91d346": "Максимальное число токенов, которое модель Anthropic может сгенерировать за один ответ. Оставьте поле пустым для значения по умолчанию.",
"56627c94a9decee6": "Макс. выходных токенов",
"593a972852ba0004": "Cursor Assistant | Всегда бесплатно | Пользовательский API",
"59a2195a01a8b35b": "{0} должен быть допустимым объектом JSON",
"5aa8f5590c940829": "Ввод без кеша: {0}",
"5beb1206c532729f": "Максимальное число токенов в одном ответе. Оставьте поле пустым для значения по умолчанию.",
"5d1687a4a41883fd": "Остановка...",
"5e709712ce012f5d": "Исходящие запросы используют прокси из переменных окружения: {0}",
"6106f0a12583a334": "Не удалось обновить",
"62873083fcaed27d": "Статистика сеанса",
"6309a3bb5ba4c714": "Не удалось сохранить",
"636e3deffc1e960a": "Модель {0}",
"63d90d977348ab1f": "Дублировать",
"64857b4338678314": "Значение пользовательского заголовка {0} должно быть строкой",
"64d2730f2ae37997": "Исходный ответ",
"65cc5fd2e6ce6e75": "Бэкенд запущен, прокси не запущен",
"66af574b8948fe83": "Ключ API {0} не может быть пустым",
"6744b4c6a9aa0038": "Выключено",
"675109292da4eb36": "Еще не проверено",
"699fe7ade5407687": "Прямой режим",
"6a7b96f399e58138": "например, sk-xxxxxx",
"6aa8f49cc992dfd7": "Проверить",
"6ae23d6d7cb18592": "Ошибка сервиса",
"6d7872164df9b36e": "Обычный ввод: {0} × ${1}/1M = {2}",
"6e584e3d5ce64aa0": "Сохранить настройки",
"6ec87609a8769425": "По умолчанию {0} / С учетом создания {1}",
"72f6c3525c0192a7": "Если включено, создание кеша учитывается в знаменателе",
"737225e2904673fc": "Расчетные выходные токены: {0}",
"7520bd50a5ee5471": "Остановить проверку {0}/{1}",
"753d8bb0da9913ce": "Не удалось дублировать",
"774d6e1b7cb89751": "Стандартный расчет",
"77c9e582e85583af": "Проверка не пройдена",
"7a26bf794e9fb6bf": "Используется только для отображения в интерфейсе и помогает различать модели.",
"7b6187c41e88b70c": "Проверка...",
"7bf8e2c07e084d09": "Редактор модели",
"7df7641e5e741346": "Чтение кеша / (Чтение кеша + Создание кеша + Ввод без кеша)",
"7e9e334aeb0bdc07": "Не удалось выполнить операцию с сервисом",
"7f68ebad19ba6bcd": "Проверить обновления",
"80296f4aa3f4543b": "Чтение/запись кеша",
"81123c56d5d880d0": "Ключ API",
"8139cb3dd11f5a67": "Если включено, объект JSON переопределит итоговые заголовки запроса. При совпадении имен используются значения отсюда; все значения должны быть строками.",
"8672864e90417138": "Максимальная",
"86df7ec743047234": "Сервис запущен",
"87ed126f7bd1121e": "Режим маршрутизации",
"899add6275682210": "Если оставить пустым, используется 200000",
"8a4ef3e48e4e8a5a": "Включено",
"8c0d84831a3c3d5b": "Сейчас используется режим локального сервиса",
"8c1935935600e336": "Проверка модели",
"8cbcf741e727dbf7": "Настройки модели",
"8d1de152be6360ce": "Доля успешных: {0}",
"8e2dc7b0d2e8f6f8": "например, OpenAI - GPT-4.1",
"8f6f8d979c981ced": "Скопировано",
"8f8baf5d18dd0492": "Если включено, объект JSON переопределит тело запроса OpenAI. При совпадении полей используются значения отсюда. OpenAI service_tier поддерживает auto, default, flex, scale и priority; priority можно использовать для сценариев с высоким приоритетом/Fast.",
"8faa670b512b6b9b": "Открыть настройки модели",
"907395551d0f3a93": "Конечная точка OpenAI для {0} поддерживает только /v1/responses, /v1/chat/completions или пользовательский путь, начинающийся с /",
"917b1c1f18d0276b": "Сохранение...",
"9196835e388d2550": "Проверить все",
"91cba5c107a51892": "/ Ошибочные",
"92059fe6cd713db4": "Имя модели, которое фактически отправляется серверу, например gpt-4.1 или claude-sonnet.",
"93e08803675e378b": "Идентификатор модели",
"93faf55cd25c8319": "Это программное обеспечение полностью бесплатно. Если с вас взяли плату, скорее всего, вас обманули.\\nПосетите страницу автора: https://space.bilibili.com/311706663/upload/video\\nТам публикуются обновления, руководства и другие материалы.",
"942ff2d88baca0c6": "Проверка обновлений...",
"970388573a3c88c9": "Чтение кеша: {0} × ${1}/1M = {2}",
"9730c15f3c1963a1": "Макс.",
"986678eccf56dc28": "Состояние сервиса обновляется. Повторите попытку позже.",
"9970736b36ff2b68": "Корневой адрес API сервиса модели, обычно совместимый с OpenAI или Anthropic.",
"9a6e7d6c17471711": "Сейчас используется стандартный расчет доли попаданий",
"9b17fa889b307f7f": "Успешных ходов: {0}",
"9c38b6e9bf94abec": "Включено прямое подключение к Cursor",
"9c41b3a9e12ac994": "Интенсивность рассуждений",
"9d2ca261281a158a": "Позже",
"9d2fb46c0ba890b9": "Пользовательский путь",
"9dc0825fba5422e4": "Загрузка...",
"9e02529bcaef36c6": "Обнаружен повторяющийся канал модели. Проверьте сочетание url, modelID, apiKey, displayName и endpoint",
"a026f37e613cf48b": "Выходные токены",
"a0d36236c523667c": "Интенсивность рассуждений Anthropic для {0} поддерживает только low, medium, high, xhigh и max",
"a1a038dfa16c3ede": "У вас уже установлена последняя версия (v{0}).",
"a3030bf8f16dc63c": "Сохранить",
"a325d25c69e7256d": "Настройки модели не найдены; дублирование невозможно",
"a4dd8bb7e8b6eb31": "Показать ключ API",
"a54d745d9a9249e2": "Если включено, объект JSON переопределит тело запроса Anthropic. При совпадении полей используются значения отсюда.",
"a55a88237df85d98": "Сейчас используется прямой режим",
"a567bdaa11367f26": "Средняя",
"a5f1bd344c92e195": "Ключ API, необходимый для обращения к сервису модели.",
"a693d69af48bfe48": "Сохранить и проверить",
"a98585871c5313ff": "Отображаемое имя",
"aa9e366f68d3d097": "Низкая",
"ab607d54d86dc789": "Автор leookun",
"ac217e4d1ca410f1": "Доступна новая версия",
"ad79540418be700a": "Открыть папку настроек или отдельно управлять настройками моделей",
"ae5a738238463a92": "Скрыть ключ API",
"aed55419ce62f08e": "Переключение...",
"b10041a13f5c55b1": "Вывод модели: {0} × ${1}/1M = {2}",
"b1c27820fec23edb": "Высокая",
"b42049dcf8a05ef7": "Включен режим локального сервиса",
"b5409d4049286061": "Пользовательский путь (введите полный URL запроса)",
"b571037dc396a00c": "Общее число токенов запроса включает Prompt и вывод модели.",
"b765005f69fa971f": "например, gpt-4.1",
"b76a22622020f849": "Выберите конечную точку протокола. Для варианта «Пользовательский путь» укажите полный URL запроса в поле адреса API, включая суффикс /chat/completions или /responses. Тип протокола будет определен автоматически по последнему сегменту.",
"b870928f8f9a24c4": "Конечная точка API",
"b90a8ac9c488ce46": "Выберите язык",
"ba3c66f90fd11725": "Обнаружен системный прокси",
"ba40014ff496f64e": "Тип",
"bb074b86a98f6911": "Контекстное окно",
"bc87a4121a0873b3": "Обновить статистику",
"bd4464ea88d3f24a": "Всего ходов: {0}",
"bddd504af0c92fd0": "Обнаружен системный PAC/автоматический прокси; в текущей версии используется прямое подключение",
"bef280f9eb392495": "Ходы диалога",
"c228558cf257fc49": "Не удалось удалить",
"c3e9c3c60020b8b7": "Выберите режим",
"c5af02060847d167": "Интенсивность для адаптивных рассуждений Anthropic. В запросах всегда используется новый режим thinking.type=adaptive.",
"c69f5bce63b9f14c": "Папка настроек",
"c8c14507b2d37395": "Интенсивность рассуждений",
"c98e118e0a43f078": "Модель",
"c9dd59beefd7144f": "Чтение кеша / (Чтение кеша + Ввод без кеша)",
"ca00a39fcea70dc6": "Запуск...",
"ca1d1059408b3837": "Ошибочных ходов: {0}",
"cd7ca5fb221e1c53": "{0} не может быть пустым",
"ce46f23cea3bf3c5": "Если включено, Cursor подключается напрямую к официальному сервису. Не включайте этот режим.",
"d0325067fed88e5a": "Доля попаданий в кеш: {0}",
"d08fd4224abcd69d": "Не удалось переключить",
"d1bde4a4e057b2c7": "[MainLayout] Не удалось загрузить сведения об авторе",
"d20ab96566d33f25": "Отображаемое имя {0} не может быть пустым",
"d2243e1d44b2a94e": "Изменить настройки модели",
"d3209b935ae86797": "Настройки модели не найдены; удаление невозможно",
"d373809ab86ba93b": "Копировать",
"d3b1da3088ddd334": "Проверка модели не пройдена",
"d53d32f1a1211371": "Пользовательские заголовки JSON",
"d7889896c5b7732a": "Дополнительные параметры Anthropic JSON",
"d7da2aabd35772ec": "например, 200000 (оставьте пустым для значения по умолчанию)",
"d95e5cb6bdcee553": "Учитывать создание кеша",
"da590a8fe3ce4de0": "Выберите значение",
"daede9881787abe7": "Примечания",
"dbb4b5be9b5723dc": "Интенсивность рассуждений {0} поддерживает только low, medium, high, xhigh и max",
"dbee6e7139243362": "Базовый URL {0} не может быть пустым",
"dc82c5e8fb2ab777": "Версия: v{0}",
"de8184da1ef88d03": "Настроено",
"e01c5dae36cf8c35": "Если включено, объект JSON переопределит тело запроса OpenAI. При совпадении полей используются значения отсюда. OpenAI service_tier поддерживает auto, default, flex, scale и priority.",
"e14c41ef2b7253c9": "Всего токенов запроса: {0}",
"e406825e0a72d2c2": "Локальные настройки",
"e552c2accdbf5178": "Добавить модель",
"e6faccfddce722e8": "Токены чтения из кеша: {0}",
"eaffd48cd2ea9f1a": "например, https://api.anthropic.com",
"eb1be07f2ca6e506": "Расчет основан на тарифах Claude Opus 4.7.",
"ec3b17a75db49e24": "{0} т/с | Первый токен {1}",
"ec99e5c45d648fd6": "Не удалось обновить",
"ee95057c6b0335d2": "Исходящие запросы используют системный прокси: {0}",
"f1e0fc261d42fe29": "Примечание, отображаемое при наведении на модель в списке.",
"f363622480699c52": "Интенсивность рассуждений применяется только к моделям с поддержкой reasoning_effort. Чем выше значение, тем обычно стабильнее результат, но ответ может формироваться медленнее.",
"f3a76d896853c1df": "Промах",
"f3fae6cccb9004b1": "Имя пользовательского заголовка не может быть пустым",
"f474a4108aba4c4c": "Остановить сервис",
"f4f0ead1116b5b62": "Включить",
"f56c6c82203b33f6": "Уведомление",
"f61e03f047b786d5": "Максимальное число выходных токенов {0} должно быть положительным целым числом",
"f6e1c8b1a6970db5": "Исходящие запросы не используют системный прокси",
"fac2a67ad87807c4": "ОК",
"fb7a4c81729ed0ca": "Остановка...",
"fec45092945f8790": "Руководство пользователя"
}
+5
View File
@@ -30,6 +30,7 @@
"26a3855aed1d8d17": "服务未启动", "26a3855aed1d8d17": "服务未启动",
"281eb6d08c9960d0": "{0} 的思考预算 Token 必须为正整数", "281eb6d08c9960d0": "{0} 的思考预算 Token 必须为正整数",
"28aeffc70ceb4267": "切换当前界面显示语言,设置会立即生效并保存在本机", "28aeffc70ceb4267": "切换当前界面显示语言,设置会立即生效并保存在本机",
"2a24519398684ed5": "访问主页",
"2cd0f3be8738a86c": "取消", "2cd0f3be8738a86c": "取消",
"2d706f7981b45a7b": "本地配置已保存", "2d706f7981b45a7b": "本地配置已保存",
"2f9daa828907b93f": "删除", "2f9daa828907b93f": "删除",
@@ -40,6 +41,7 @@
"3463c5585c246df9": "合计:{0}", "3463c5585c246df9": "合计:{0}",
"3468b57e3edbc599": "按历史记录里扫描到的回合 summary 汇总。", "3468b57e3edbc599": "按历史记录里扫描到的回合 summary 汇总。",
"35076178fe79a210": "配置已变更,请重新测试", "35076178fe79a210": "配置已变更,请重新测试",
"358f07b2c1445ab1": "作者寄语",
"36c149a9b3e8dca0": "模型。", "36c149a9b3e8dca0": "模型。",
"37d23612f78a2e63": "立即重启更新", "37d23612f78a2e63": "立即重启更新",
"392d0dceb45998d3": "极高", "392d0dceb45998d3": "极高",
@@ -50,6 +52,7 @@
"3d13868593ae4eeb": "界面语言", "3d13868593ae4eeb": "界面语言",
"3ea83f9f55062582": "发布时间:{0}", "3ea83f9f55062582": "发布时间:{0}",
"3edda85621fd03b2": "个模型适配器", "3edda85621fd03b2": "个模型适配器",
"3fd47edce45b3603": "关闭",
"42aa8e01e98c0d8c": "总耗时", "42aa8e01e98c0d8c": "总耗时",
"438bb77c1ecdfab0": "缓存写入:{0} × ${1}/1M = {2}", "438bb77c1ecdfab0": "缓存写入:{0} × ${1}/1M = {2}",
"46056425a48ef05b": "当前按复用率口径显示", "46056425a48ef05b": "当前按复用率口径显示",
@@ -122,6 +125,7 @@
"91cba5c107a51892": "/ 异常", "91cba5c107a51892": "/ 异常",
"92059fe6cd713db4": "请求实际发送给服务端的模型名称,例如 gpt-4.1 或 claude-sonnet。", "92059fe6cd713db4": "请求实际发送给服务端的模型名称,例如 gpt-4.1 或 claude-sonnet。",
"93e08803675e378b": "模型标识", "93e08803675e378b": "模型标识",
"93faf55cd25c8319": "本软件是纯免费软件,如果你被收费,那大概率就是被骗了。\n欢迎点击访问作者主页 https://space.bilibili.com/311706663/upload/video\n查看更多更新动态、使用分享和后续内容。",
"942ff2d88baca0c6": "检查更新中...", "942ff2d88baca0c6": "检查更新中...",
"970388573a3c88c9": "缓存读取:{0} × ${1}/1M = {2}", "970388573a3c88c9": "缓存读取:{0} × ${1}/1M = {2}",
"9730c15f3c1963a1": "最大", "9730c15f3c1963a1": "最大",
@@ -148,6 +152,7 @@
"a693d69af48bfe48": "保存并测试", "a693d69af48bfe48": "保存并测试",
"a98585871c5313ff": "显示名称", "a98585871c5313ff": "显示名称",
"aa9e366f68d3d097": "低", "aa9e366f68d3d097": "低",
"ab607d54d86dc789": "作者 leookun",
"ac217e4d1ca410f1": "发现新版本", "ac217e4d1ca410f1": "发现新版本",
"ad79540418be700a": "打开设置目录,或单独管理模型配置", "ad79540418be700a": "打开设置目录,或单独管理模型配置",
"ae5a738238463a92": "隐藏访问密钥", "ae5a738238463a92": "隐藏访问密钥",
+3
View File
@@ -11,17 +11,20 @@ import {
import zhCNMessages from "@/i18n/locales/zh-CN.json"; import zhCNMessages from "@/i18n/locales/zh-CN.json";
import enUSMessages from "@/i18n/locales/en-US.json"; import enUSMessages from "@/i18n/locales/en-US.json";
import jaJPMessages from "@/i18n/locales/ja-JP.json"; import jaJPMessages from "@/i18n/locales/ja-JP.json";
import ruRUMessages from "@/i18n/locales/ru-RU.json";
const localeMessages = { const localeMessages = {
"zh-CN": zhCNMessages, "zh-CN": zhCNMessages,
"en-US": enUSMessages, "en-US": enUSMessages,
"ja-JP": jaJPMessages, "ja-JP": jaJPMessages,
"ru-RU": ruRUMessages,
}; };
const languageLocaleMap = { const languageLocaleMap = {
zh: "zh-CN", zh: "zh-CN",
en: "en-US", en: "en-US",
ja: "ja-JP", ja: "ja-JP",
ru: "ru-RU",
}; };
function isSupportedLocale(locale) { function isSupportedLocale(locale) {
+5 -19
View File
@@ -16,7 +16,6 @@ import {
import { isWindows } from "@/utils/isWindows"; import { isWindows } from "@/utils/isWindows";
import { computed, onMounted, onUnmounted, ref } from "vue"; import { computed, onMounted, onUnmounted, ref } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import { useLocale } from "@/i18n/runtime";
import Logo from "@/assets/logo.png"; import Logo from "@/assets/logo.png";
const route = useRoute(); const route = useRoute();
@@ -26,28 +25,15 @@ const title = computed(() => route.meta.title ?? "Cursor助手|永久免费|
const directlyClose = computed(() => route.meta.directlyClose === true); const directlyClose = computed(() => route.meta.directlyClose === true);
const showFooter = computed(() => route.path === "/"); const showFooter = computed(() => route.path === "/");
const footerAuthorInfo = ref(null); const footerAuthorInfo = ref(null);
const { locale } = useLocale();
const localizedAuthorInfo = computed(() => { const localizedAuthorInfo = computed(() => {
if (!footerAuthorInfo.value) return null; if (!footerAuthorInfo.value) return null;
if (locale.value === "zh-CN") {
return footerAuthorInfo.value;
}
if (locale.value === "ja-JP") {
return {
buttonText: "著者 leookun",
dialogTitle: "著者からのメッセージ",
dialogContent: "このソフトウェアは完全に無料です。もし料金を請求された場合は、詐欺の可能性が高いです。\n著者のホームページ https://space.bilibili.com/311706663/upload/video にアクセスして、更新情報や利用方法などを確認してください。",
dialogConfirmText: "ホームページへ",
dialogCancelText: "閉じる"
};
}
return { return {
buttonText: "Author leookun", buttonText: "作者 leookun",
dialogTitle: "Author's Message", dialogTitle: "作者寄语",
dialogContent: "This software is completely free. If you were charged, you were likely scammed.\nWelcome to visit the author's homepage at https://space.bilibili.com/311706663/upload/video\nto see more updates, sharing guides, and future content.", dialogContent: "本软件是纯免费软件,如果你被收费,那大概率就是被骗了。\n欢迎点击访问作者主页 https://space.bilibili.com/311706663/upload/video\n查看更多更新动态、使用分享和后续内容。",
dialogConfirmText: "Visit Homepage", dialogConfirmText: "访问主页",
dialogCancelText: "Close" dialogCancelText: "关闭",
}; };
}); });
const usageDocsURL = "https://docs.leokun.cn"; const usageDocsURL = "https://docs.leokun.cn";
+1 -43
View File
@@ -1,7 +1,6 @@
import { computed, reactive, watchSyncEffect } from "vue"; import { computed, reactive, watchSyncEffect } from "vue";
import { Events } from "@wailsio/runtime"; import { Events } from "@wailsio/runtime";
import dayjs from "dayjs"; import dayjs from "dayjs";
import { getLocale } from "@/i18n/runtime";
import { import {
checkForUpdates, checkForUpdates,
getAppVersion, getAppVersion,
@@ -998,43 +997,19 @@ export const appViewState = reactive({
function localizeUpdateMessage(msg) { function localizeUpdateMessage(msg) {
if (!msg) return ""; if (!msg) return "";
if (msg.includes("当前已是最新版本")) { if (/当前已是最新版本/.test(msg)) {
const match = msg.match(/v?([0-9]+\.[0-9]+\.[0-9]+)/); const match = msg.match(/v?([0-9]+\.[0-9]+\.[0-9]+)/);
const version = match ? match[1] : appState.appVersion || "..."; const version = match ? match[1] : appState.appVersion || "...";
const locale = getLocale ? getLocale() : "zh-CN";
if (locale === "en-US") {
return `You are already on the latest version (v${version}).`;
}
if (locale === "ja-JP") {
return `すでに最新バージョン(v${version})です。`;
}
return `当前已是最新版本(v${version})。`; return `当前已是最新版本(v${version})。`;
} }
return msg; return msg;
} }
function localizeReadyContent() { function localizeReadyContent() {
const locale = getLocale ? getLocale() : "zh-CN";
const version = appState.updateVersion || appState.appVersion || "..."; const version = appState.updateVersion || appState.appVersion || "...";
const date = formatReleaseDate(appState.updateReleaseDate); const date = formatReleaseDate(appState.updateReleaseDate);
const notes = appState.updateReleaseNotes || ""; const notes = appState.updateReleaseNotes || "";
if (locale === "en-US") {
return [
`Version: v${version}`,
`Release Date: ${date}`,
"",
notes || "No release notes",
].join("\n");
}
if (locale === "ja-JP") {
return [
`バージョン: v${version}`,
`リリース日: ${date}`,
"",
notes || "リリースノートはありません",
].join("\n");
}
return [ return [
`版本:v${version}`, `版本:v${version}`,
`发布时间:${date}`, `发布时间:${date}`,
@@ -1052,19 +1027,12 @@ export const updateViewState = reactive({
width: `${Math.max(0, Math.min(100, appState.updateProgressPercent || 0))}%`, width: `${Math.max(0, Math.min(100, appState.updateProgressPercent || 0))}%`,
})), })),
promptTitle: computed(() => { promptTitle: computed(() => {
const locale = getLocale ? getLocale() : "zh-CN";
switch (appState.updatePromptKind) { switch (appState.updatePromptKind) {
case "ready": case "ready":
if (locale === "en-US") return "New Version Available";
if (locale === "ja-JP") return "新しいバージョンがあります";
return "发现新版本"; return "发现新版本";
case "error": case "error":
if (locale === "en-US") return "Update Failed";
if (locale === "ja-JP") return "アップデートに失敗しました";
return "更新失败"; return "更新失败";
default: default:
if (locale === "en-US") return "Check for Updates";
if (locale === "ja-JP") return "アップデートを確認";
return "检查更新"; return "检查更新";
} }
}), }),
@@ -1079,25 +1047,15 @@ export const updateViewState = reactive({
} }
}), }),
promptConfirmText: computed(() => { promptConfirmText: computed(() => {
const locale = getLocale ? getLocale() : "zh-CN";
if (appState.updatePromptKind === "ready") { if (appState.updatePromptKind === "ready") {
if (locale === "en-US") return "Restart to Update";
if (locale === "ja-JP") return "再起動して更新";
return "立即重启更新"; return "立即重启更新";
} }
if (locale === "en-US") return "OK";
if (locale === "ja-JP") return "OK";
return "确定"; return "确定";
}), }),
promptCancelText: computed(() => { promptCancelText: computed(() => {
const locale = getLocale ? getLocale() : "zh-CN";
if (appState.updatePromptKind === "ready") { if (appState.updatePromptKind === "ready") {
if (locale === "en-US") return "Later";
if (locale === "ja-JP") return "後で";
return "稍后"; return "稍后";
} }
if (locale === "en-US") return "Cancel";
if (locale === "ja-JP") return "キャンセル";
return "取消"; return "取消";
}), }),
promptShowCancel: computed(() => appState.updatePromptKind === "ready"), promptShowCancel: computed(() => appState.updatePromptKind === "ready"),
-6
View File
@@ -6,7 +6,6 @@ import HomeMetricsCard from "@/components/HomeMetricsCard.vue";
import { useMessage } from "@/composables/useMessage"; import { useMessage } from "@/composables/useMessage";
import { showModal } from "@/composables/useModal"; import { showModal } from "@/composables/useModal";
import { getAdRuntime } from "@/services/clientApi"; import { getAdRuntime } from "@/services/clientApi";
import { useLocale } from "@/i18n/runtime";
import { import {
appState, appState,
appViewState, appViewState,
@@ -43,12 +42,7 @@ function asBoolean(value) {
return value === true || value === "true" || value === 1 || value === "1"; return value === true || value === "true" || value === 1 || value === "1";
} }
const { locale } = useLocale();
const homeAds = computed(() => { const homeAds = computed(() => {
if (locale.value !== "zh-CN") {
return [];
}
const runtime = adRuntime.value && typeof adRuntime.value === "object" ? adRuntime.value : {}; const runtime = adRuntime.value && typeof adRuntime.value === "object" ? adRuntime.value : {};
const slots = Array.isArray(runtime.slots) && runtime.slots.length > 0 ? runtime.slots : [runtime]; const slots = Array.isArray(runtime.slots) && runtime.slots.length > 0 ? runtime.slots : [runtime];
return slots return slots
+11
View File
@@ -294,6 +294,8 @@ func Run(resources EmbeddedResources) error {
statusItem.SetLabel("Status: Running") statusItem.SetLabel("Status: Running")
} else if locale == "ja-JP" { } else if locale == "ja-JP" {
statusItem.SetLabel("状態:実行中") statusItem.SetLabel("状態:実行中")
} else if locale == "ru-RU" {
statusItem.SetLabel("Статус: запущено")
} else { } else {
statusItem.SetLabel("状态:运行中") statusItem.SetLabel("状态:运行中")
} }
@@ -302,6 +304,8 @@ func Run(resources EmbeddedResources) error {
statusItem.SetLabel("Status: Not Started") statusItem.SetLabel("Status: Not Started")
} else if locale == "ja-JP" { } else if locale == "ja-JP" {
statusItem.SetLabel("状態:未起動") statusItem.SetLabel("状態:未起動")
} else if locale == "ru-RU" {
statusItem.SetLabel("Статус: не запущено")
} else { } else {
statusItem.SetLabel("状态:未启动") statusItem.SetLabel("状态:未启动")
} }
@@ -321,6 +325,13 @@ func Run(resources EmbeddedResources) error {
showItem.SetLabel("ウィンドウを表示") showItem.SetLabel("ウィンドウを表示")
hideItem.SetLabel("ウィンドウを非表示") hideItem.SetLabel("ウィンドウを非表示")
quitItem.SetLabel("終了") quitItem.SetLabel("終了")
} else if locale == "ru-RU" {
startItem.SetLabel("Запустить сервис")
stopItem.SetLabel("Остановить сервис")
updateItem.SetLabel("Проверить обновления")
showItem.SetLabel("Показать окно")
hideItem.SetLabel("Скрыть окно")
quitItem.SetLabel("Выход")
} else { } else {
startItem.SetLabel("启动服务") startItem.SetLabel("启动服务")
stopItem.SetLabel("停止服务") stopItem.SetLabel("停止服务")
+1 -1
View File
@@ -249,7 +249,7 @@ func canMergeProviderAssistantToolCalls(last Message, current Message) bool {
if strings.TrimSpace(last.Role) != "assistant" || strings.TrimSpace(current.Role) != "assistant" { if strings.TrimSpace(last.Role) != "assistant" || strings.TrimSpace(current.Role) != "assistant" {
return false return false
} }
if len(last.ToolCalls) == 0 || len(current.ToolCalls) == 0 { if len(current.ToolCalls) == 0 {
return false return false
} }
if strings.TrimSpace(last.ToolCallID) != "" || strings.TrimSpace(last.Name) != "" { if strings.TrimSpace(last.ToolCallID) != "" || strings.TrimSpace(last.Name) != "" {
@@ -0,0 +1,58 @@
package modeladapter
import (
"reflect"
"testing"
)
func TestSanitizeProviderMessagesMergesLegacyAssistantTextAndToolCallTurnsIdempotently(t *testing.T) {
input := []Message{
{
Role: "assistant",
Content: "Now let me pass stream.Mode in service.go.",
ReasoningContent: "I need to update service.go.",
},
{
Role: "assistant",
Content: "",
ReasoningContent: "I need to update service.go.",
ToolCalls: []ToolCallDescriptor{
{
ID: "call_1",
Type: "function",
Function: ToolCallFunctionShape{
Name: "PatchEdit",
Arguments: `{"path":"/workspace/service.go"}`,
},
},
},
},
{
Role: "tool",
Content: `{"success":{"path":"/workspace/service.go"}}`,
ToolCallID: "call_1",
Name: "PatchEdit",
},
}
first := sanitizeProviderMessages(input)
if len(first) != 2 {
t.Fatalf("message count = %d, want 2: %#v", len(first), first)
}
assistant := first[0]
if assistant.Content != input[0].Content {
t.Fatalf("assistant content = %q", assistant.Content)
}
if assistant.ReasoningContent != input[0].ReasoningContent {
t.Fatalf("assistant reasoning = %q, want one copy of %q", assistant.ReasoningContent, input[0].ReasoningContent)
}
if len(assistant.ToolCalls) != 1 || assistant.ToolCalls[0].ID != "call_1" {
t.Fatalf("assistant tool calls = %#v", assistant.ToolCalls)
}
second := sanitizeProviderMessages(first)
if !reflect.DeepEqual(second, first) {
t.Fatalf("sanitizing normalized messages changed them:\nfirst: %#v\nsecond: %#v", first, second)
}
}
+4 -23
View File
@@ -897,8 +897,8 @@ func buildMessagesFromPendingAssistantRaw(raw string) []Message {
reasoningSignature := "" reasoningSignature := ""
pendingToolCalls := make([]ToolCallDescriptor, 0, len(payload.Content)) pendingToolCalls := make([]ToolCallDescriptor, 0, len(payload.Content))
pendingToolResults := make([]Message, 0, len(payload.Content)) pendingToolResults := make([]Message, 0, len(payload.Content))
flushAssistantText := func(forceReasoningOnly bool) { flushAssistantTurn := func() {
if len(textParts) == 0 && (!forceReasoningOnly || len(reasoningParts) == 0) { if len(textParts) == 0 && len(reasoningParts) == 0 && len(pendingToolCalls) == 0 {
return return
} }
messages = append(messages, Message{ messages = append(messages, Message{
@@ -906,23 +906,10 @@ func buildMessagesFromPendingAssistantRaw(raw string) []Message {
Content: formatMessageText(strings.Join(textParts, "")), Content: formatMessageText(strings.Join(textParts, "")),
ReasoningContent: strings.Join(reasoningParts, ""), ReasoningContent: strings.Join(reasoningParts, ""),
ReasoningSignature: reasoningSignature, ReasoningSignature: reasoningSignature,
})
textParts = textParts[:0]
reasoningParts = reasoningParts[:0]
reasoningSignature = ""
}
flushToolCalls := func() {
if len(pendingToolCalls) == 0 {
return
}
messages = append(messages, Message{
Role: "assistant",
Content: "",
ReasoningContent: strings.Join(reasoningParts, ""),
ReasoningSignature: reasoningSignature,
ToolCalls: append([]ToolCallDescriptor(nil), pendingToolCalls...), ToolCalls: append([]ToolCallDescriptor(nil), pendingToolCalls...),
}) })
messages = append(messages, pendingToolResults...) messages = append(messages, pendingToolResults...)
textParts = textParts[:0]
reasoningParts = reasoningParts[:0] reasoningParts = reasoningParts[:0]
reasoningSignature = "" reasoningSignature = ""
pendingToolCalls = pendingToolCalls[:0] pendingToolCalls = pendingToolCalls[:0]
@@ -932,8 +919,6 @@ func buildMessagesFromPendingAssistantRaw(raw string) []Message {
for _, item := range payload.Content { for _, item := range payload.Content {
switch strings.TrimSpace(item.Type) { switch strings.TrimSpace(item.Type) {
case "reasoning": case "reasoning":
flushToolCalls()
flushAssistantText(false)
if item.Text != "" { if item.Text != "" {
reasoningParts = append(reasoningParts, item.Text) reasoningParts = append(reasoningParts, item.Text)
} }
@@ -941,12 +926,10 @@ func buildMessagesFromPendingAssistantRaw(raw string) []Message {
reasoningSignature = strings.TrimSpace(item.Signature) reasoningSignature = strings.TrimSpace(item.Signature)
} }
case "text": case "text":
flushToolCalls()
if item.Text != "" { if item.Text != "" {
textParts = append(textParts, item.Text) textParts = append(textParts, item.Text)
} }
case "tool-call": case "tool-call":
flushAssistantText(false)
pendingToolCalls = append(pendingToolCalls, ToolCallDescriptor{ pendingToolCalls = append(pendingToolCalls, ToolCallDescriptor{
ID: strings.TrimSpace(item.ToolCallID), ID: strings.TrimSpace(item.ToolCallID),
Index: len(pendingToolCalls), Index: len(pendingToolCalls),
@@ -966,9 +949,7 @@ func buildMessagesFromPendingAssistantRaw(raw string) []Message {
} }
} }
} }
flushAssistantText(false) flushAssistantTurn()
flushToolCalls()
flushAssistantText(true)
return messages return messages
} }
@@ -0,0 +1,53 @@
package promptengine
import (
"reflect"
"testing"
)
func TestBuildReplayMessagesFromPendingAssistantOutputsKeepsTextAndToolCallInOneAssistantTurn(t *testing.T) {
raw := `{
"id":"1",
"role":"assistant",
"content":[
{"type":"reasoning","text":"I need to update service.go.","signature":"reasoning-signature"},
{"type":"text","text":"Now let me pass stream.Mode in service.go."},
{"type":"tool-call","toolCallId":"call_1","toolName":"PatchEdit","args":{"path":"/workspace/service.go","old_string":"old","new_string":"new"},"result":{"success":{"path":"/workspace/service.go"}}}
]
}`
first := BuildReplayMessagesFromPendingAssistantOutputs([]string{raw})
if len(first) != 2 {
t.Fatalf("message count = %d, want 2 (assistant tool-call turn plus tool result): %#v", len(first), first)
}
assistant := first[0]
if assistant.Role != "assistant" {
t.Fatalf("assistant role = %q, want assistant", assistant.Role)
}
if assistant.Content != "Now let me pass stream.Mode in service.go." {
t.Fatalf("assistant content = %q", assistant.Content)
}
if assistant.ReasoningContent != "I need to update service.go." {
t.Fatalf("assistant reasoning = %q", assistant.ReasoningContent)
}
if assistant.ReasoningSignature != "reasoning-signature" {
t.Fatalf("assistant reasoning signature = %q", assistant.ReasoningSignature)
}
if len(assistant.ToolCalls) != 1 {
t.Fatalf("assistant tool calls = %d, want 1", len(assistant.ToolCalls))
}
if assistant.ToolCalls[0].ID != "call_1" || assistant.ToolCalls[0].Function.Name != "PatchEdit" {
t.Fatalf("assistant tool call = %#v", assistant.ToolCalls[0])
}
toolResult := first[1]
if toolResult.Role != "tool" || toolResult.ToolCallID != "call_1" || toolResult.Name != "PatchEdit" {
t.Fatalf("tool result = %#v", toolResult)
}
second := BuildReplayMessagesFromPendingAssistantOutputs([]string{raw})
if !reflect.DeepEqual(second, first) {
t.Fatalf("rebuilding the same pending output changed messages:\nfirst: %#v\nsecond: %#v", first, second)
}
}
+10 -5
View File
@@ -1,6 +1,11 @@
QQ10群:1049354347 - 修复内存泄漏问题,该可能导致内存异常占用
---- - 支持俄语增加翻译范围
- 支持 GPT 5.6 - 修复qwen-3.8-max中断问题(mimo也应该属于同一类问题)
- 修复一些bug - 修复claude模型可能无法识别图片问题 @GGHansome
- 支持自定义Openai端点 @Sxuan-Coder
- WebSearch 接入百度搜索,DuckDuckGo 作为兜底 @杨超
- 修复一些兼容性问题 @kael-odin
- 修复window上一些表现问题 @philau2512
🔔 如何让AI自动拉模型配置? (以下为提示词,把地址和密钥换为你的)
我的模型配置在 /.cursor-local-assistant-v2/config.yaml,我的API地址是:https://xxx 密钥是xxx,帮我拉所有模型配置进去,不要影响已有模型,根据models标准接口拉取。