Rename product to Lingma Proxy

This commit is contained in:
lutc5
2026-05-06 15:03:04 +08:00
parent 7eb68f8bdc
commit 1c349227a3
22 changed files with 227 additions and 160 deletions

View File

@@ -60,14 +60,14 @@ jobs:
- name: Build CLI - name: Build CLI
run: | run: |
mkdir -p dist mkdir -p dist
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -trimpath -ldflags "-s -w" -o dist/lingma-ipc-proxy ./cmd/lingma-ipc-proxy CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -trimpath -ldflags "-s -w" -o dist/lingma-proxy ./cmd/lingma-ipc-proxy
tar -C dist -czf "lingma-ipc-proxy_${RELEASE_TAG}_darwin_arm64.tar.gz" lingma-ipc-proxy tar -C dist -czf "lingma-proxy_${RELEASE_TAG}_darwin_arm64.tar.gz" lingma-proxy
- name: Upload artifact - name: Upload artifact
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: cli-macos name: cli-macos
path: lingma-ipc-proxy_${{ env.RELEASE_TAG }}_darwin_arm64.tar.gz path: lingma-proxy_${{ env.RELEASE_TAG }}_darwin_arm64.tar.gz
build-cli-windows: build-cli-windows:
name: Build CLI Windows name: Build CLI Windows
@@ -86,14 +86,14 @@ jobs:
shell: pwsh shell: pwsh
run: | run: |
.\scripts\build.ps1 -Clean .\scripts\build.ps1 -Clean
$asset = "lingma-ipc-proxy_${env:RELEASE_TAG}_windows_amd64.zip" $asset = "lingma-proxy_${env:RELEASE_TAG}_windows_amd64.zip"
Compress-Archive -Path .\dist\lingma-ipc-proxy.exe -DestinationPath $asset -Force Compress-Archive -Path .\dist\lingma-proxy.exe -DestinationPath $asset -Force
- name: Upload artifact - name: Upload artifact
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: cli-windows name: cli-windows
path: lingma-ipc-proxy_${{ env.RELEASE_TAG }}_windows_amd64.zip path: lingma-proxy_${{ env.RELEASE_TAG }}_windows_amd64.zip
build-desktop-macos: build-desktop-macos:
name: Build Desktop macOS name: Build Desktop macOS
@@ -130,17 +130,17 @@ jobs:
run: | run: |
APP_PATH="$(find desktop/build/bin -maxdepth 1 -name '*.app' -print -quit)" APP_PATH="$(find desktop/build/bin -maxdepth 1 -name '*.app' -print -quit)"
test -n "$APP_PATH" test -n "$APP_PATH"
test "$(basename "$APP_PATH")" = "Lingma IPC Proxy.app" test "$(basename "$APP_PATH")" = "Lingma Proxy.app"
ditto -c -k --sequesterRsrc --keepParent "$APP_PATH" "lingma-ipc-proxy-desktop_${RELEASE_TAG}_darwin_arm64.zip" ditto -c -k --sequesterRsrc --keepParent "$APP_PATH" "lingma-proxy-desktop_${RELEASE_TAG}_darwin_arm64.zip"
DMG_ROOT="$(mktemp -d)" DMG_ROOT="$(mktemp -d)"
cp -R "$APP_PATH" "$DMG_ROOT/" cp -R "$APP_PATH" "$DMG_ROOT/"
ln -s /Applications "$DMG_ROOT/Applications" ln -s /Applications "$DMG_ROOT/Applications"
hdiutil create \ hdiutil create \
-volname "Lingma IPC Proxy" \ -volname "Lingma Proxy" \
-srcfolder "$DMG_ROOT" \ -srcfolder "$DMG_ROOT" \
-ov \ -ov \
-format UDZO \ -format UDZO \
"lingma-ipc-proxy-desktop_${RELEASE_TAG}_darwin_arm64.dmg" "lingma-proxy-desktop_${RELEASE_TAG}_darwin_arm64.dmg"
rm -rf "$DMG_ROOT" rm -rf "$DMG_ROOT"
- name: Upload artifact - name: Upload artifact
@@ -148,8 +148,8 @@ jobs:
with: with:
name: desktop-macos name: desktop-macos
path: | path: |
lingma-ipc-proxy-desktop_${{ env.RELEASE_TAG }}_darwin_arm64.zip lingma-proxy-desktop_${{ env.RELEASE_TAG }}_darwin_arm64.zip
lingma-ipc-proxy-desktop_${{ env.RELEASE_TAG }}_darwin_arm64.dmg lingma-proxy-desktop_${{ env.RELEASE_TAG }}_darwin_arm64.dmg
build-desktop-windows: build-desktop-windows:
name: Build Desktop Windows name: Build Desktop Windows
@@ -191,14 +191,14 @@ jobs:
$exe = Get-ChildItem .\desktop\build\bin -Filter *.exe | Select-Object -First 1 $exe = Get-ChildItem .\desktop\build\bin -Filter *.exe | Select-Object -First 1
if (-not $exe) { throw "Desktop exe was not produced" } if (-not $exe) { throw "Desktop exe was not produced" }
if ($exe.Name -ne "LingmaProxy.exe") { throw "Unexpected desktop exe name: $($exe.Name)" } if ($exe.Name -ne "LingmaProxy.exe") { throw "Unexpected desktop exe name: $($exe.Name)" }
$asset = "lingma-ipc-proxy-desktop_${env:RELEASE_TAG}_windows_amd64.zip" $asset = "lingma-proxy-desktop_${env:RELEASE_TAG}_windows_amd64.zip"
Compress-Archive -Path $exe.FullName -DestinationPath $asset -Force Compress-Archive -Path $exe.FullName -DestinationPath $asset -Force
- name: Upload artifact - name: Upload artifact
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: desktop-windows name: desktop-windows
path: lingma-ipc-proxy-desktop_${{ env.RELEASE_TAG }}_windows_amd64.zip path: lingma-proxy-desktop_${{ env.RELEASE_TAG }}_windows_amd64.zip
publish: publish:
name: Publish Release name: Publish Release
@@ -218,7 +218,7 @@ jobs:
- name: Generate checksums - name: Generate checksums
run: | run: |
cd artifacts cd artifacts
sha256sum * > "lingma-ipc-proxy_${RELEASE_TAG}_sha256.txt" sha256sum * > "lingma-proxy_${RELEASE_TAG}_sha256.txt"
- name: Create or update release - name: Create or update release
uses: softprops/action-gh-release@v2 uses: softprops/action-gh-release@v2

View File

@@ -2,7 +2,10 @@
## Unreleased ## Unreleased
- Nothing yet. - Renamed user-facing product, desktop app, release assets, and documentation from Lingma IPC Proxy to Lingma Proxy.
- Clarified that Remote API mode is the recommended default and that only IPC plugin mode is based on the `coolxll/lingma-ipc-proxy` protocol discovery.
- Added `lingma-proxy.json` and `~/.config/lingma-proxy/config.json` config lookup/write paths while keeping legacy `lingma-ipc-proxy` config fallback.
- Added a desktop top-bar force quit button that stops the proxy and exits the app on macOS and Windows.
## v1.4.6 - 2026-05-06 ## v1.4.6 - 2026-05-06

View File

@@ -2,14 +2,14 @@
[English](./README.md) | [简体中文](./README.zh-CN.md) [English](./README.md) | [简体中文](./README.zh-CN.md)
Lingma Proxy exposes Tongyi Lingma as standard **OpenAI-compatible** and **Anthropic-compatible** HTTP APIs. It can use either the local IDE plugin IPC channel or an experimental remote API backend, and ships as both a CLI proxy service and a cross-platform desktop app for macOS and Windows. Lingma Proxy exposes Tongyi Lingma as standard **OpenAI-compatible** and **Anthropic-compatible** HTTP APIs. It can use either the recommended Remote API backend or the local IDE plugin IPC channel, and ships as both a CLI proxy service and a cross-platform desktop app for macOS and Windows.
The project is designed for tools such as Claude Code, Cline, Continue, OpenCode, custom agents, and any client that can talk to OpenAI or Anthropic style APIs. The project is designed for tools such as Claude Code, Cline, Continue, OpenCode, custom agents, and any client that can talk to OpenAI or Anthropic style APIs.
The proxy now supports two backend modes: The proxy now supports two backend modes:
- **Remote API mode (default, experimental)**: imports the local Lingma login cache or an explicit credential file and calls Lingma remote APIs directly. This feels more like an official API, does not depend on an IDE IPC session, and is currently the recommended mode for Claude Code / Hermes style agents. - **Remote API mode (default, recommended)**: imports the local Lingma login cache or an explicit credential file and calls Lingma remote APIs directly. This behaves closest to a normal hosted API, avoids IDE/plugin session and environment limits, and is currently the best mode for Claude Code / Hermes style agents.
- **IPC plugin mode**: connects to the local Lingma IDE plugin over WebSocket / Named Pipe. This keeps behavior closest to the IDE plugin and is useful as a compatibility fallback. - **IPC plugin mode**: connects to the local Lingma IDE plugin over WebSocket / Named Pipe. This keeps behavior closest to the IDE plugin, but it can inherit IDE session lifetime, local plugin state, and environment constraints, so it is mainly a compatibility fallback.
## Current Version ## Current Version
@@ -21,22 +21,22 @@ Release builds are produced by GitHub Actions for:
| Asset | Platform | Purpose | | Asset | Platform | Purpose |
| --- | --- | --- | | --- | --- | --- |
| `lingma-ipc-proxy_<tag>_darwin_arm64.tar.gz` | macOS | CLI proxy | | `lingma-proxy_<tag>_darwin_arm64.tar.gz` | macOS | CLI proxy |
| `lingma-ipc-proxy_<tag>_windows_amd64.zip` | Windows | CLI proxy | | `lingma-proxy_<tag>_windows_amd64.zip` | Windows | CLI proxy |
| `lingma-ipc-proxy-desktop_<tag>_darwin_arm64.dmg` | macOS Apple Silicon | Drag-to-install desktop app | | `lingma-proxy-desktop_<tag>_darwin_arm64.dmg` | macOS Apple Silicon | Drag-to-install desktop app |
| `lingma-ipc-proxy-desktop_<tag>_darwin_arm64.zip` | macOS Apple Silicon | Raw `.app` archive | | `lingma-proxy-desktop_<tag>_darwin_arm64.zip` | macOS Apple Silicon | Raw `.app` archive |
| `lingma-ipc-proxy-desktop_<tag>_windows_amd64.zip` | Windows | Desktop app | | `lingma-proxy-desktop_<tag>_windows_amd64.zip` | Windows | Desktop app |
| `lingma-ipc-proxy_<tag>_sha256.txt` | all | Checksums | | `lingma-proxy_<tag>_sha256.txt` | all | Checksums |
### Which Package Should I Download? ### Which Package Should I Download?
| Your system | Recommended asset | Notes | | Your system | Recommended asset | Notes |
| --- | --- | --- | | --- | --- | --- |
| macOS on Apple Silicon (M1/M2/M3/M4) | `lingma-ipc-proxy-desktop_<tag>_darwin_arm64.dmg` | Open the DMG and drag `Lingma IPC Proxy.app` to `Applications`. | | macOS on Apple Silicon (M1/M2/M3/M4) | `lingma-proxy-desktop_<tag>_darwin_arm64.dmg` | Open the DMG and drag `Lingma Proxy.app` to `Applications`. |
| macOS on Apple Silicon, portable archive | `lingma-ipc-proxy-desktop_<tag>_darwin_arm64.zip` | Same app, but packaged as a zip instead of a drag-to-install DMG. | | macOS on Apple Silicon, portable archive | `lingma-proxy-desktop_<tag>_darwin_arm64.zip` | Same app, but packaged as a zip instead of a drag-to-install DMG. |
| Windows x64 / x86_64 / AMD64 | `lingma-ipc-proxy-desktop_<tag>_windows_amd64.zip` | This is the correct package for normal 64-bit Windows PCs, including Intel and AMD CPUs. | | Windows x64 / x86_64 / AMD64 | `lingma-proxy-desktop_<tag>_windows_amd64.zip` | This is the correct package for normal 64-bit Windows PCs, including Intel and AMD CPUs. |
| macOS CLI only | `lingma-ipc-proxy_<tag>_darwin_arm64.tar.gz` | Terminal-only proxy binary. | | macOS CLI only | `lingma-proxy_<tag>_darwin_arm64.tar.gz` | Terminal-only proxy binary. |
| Windows CLI only | `lingma-ipc-proxy_<tag>_windows_amd64.zip` | Terminal-only proxy binary for 64-bit Windows. | | Windows CLI only | `lingma-proxy_<tag>_windows_amd64.zip` | Terminal-only proxy binary for 64-bit Windows. |
There is currently no separate `windows_arm64` package. On a normal x64 Windows machine, choose `windows_amd64`. There is currently no separate `windows_arm64` package. On a normal x64 Windows machine, choose `windows_amd64`.
@@ -165,18 +165,18 @@ flowchart LR
If auto detection fails, set the path manually in the desktop Settings page or pass CLI flags: If auto detection fails, set the path manually in the desktop Settings page or pass CLI flags:
```bash ```bash
lingma-ipc-proxy --transport websocket --ws-url ws://127.0.0.1:36510 --port 8095 lingma-proxy --transport websocket --ws-url ws://127.0.0.1:36510 --port 8095
lingma-ipc-proxy --transport pipe --pipe '\\.\pipe\lingma-ipc' lingma-proxy --transport pipe --pipe '\\.\pipe\lingma-ipc'
``` ```
## Backend Modes ## Backend Modes
### Remote API Mode (Default, Experimental) ### Remote API Mode (Default, Recommended)
Remote mode calls Lingma's remote API directly: Remote mode calls Lingma's remote API directly:
```bash ```bash
lingma-ipc-proxy --backend remote --port 8095 lingma-proxy --backend remote --port 8095
``` ```
By default it reads the local Lingma login cache in read-only mode: By default it reads the local Lingma login cache in read-only mode:
@@ -193,10 +193,10 @@ XDG config/state Lingma cache paths when present
You can also pass an explicit credential file: You can also pass an explicit credential file:
```bash ```bash
lingma-ipc-proxy \ lingma-proxy \
--backend remote \ --backend remote \
--remote-base-url https://lingma.alibabacloud.com \ --remote-base-url https://lingma.alibabacloud.com \
--remote-auth-file ~/.config/lingma-ipc-proxy/credentials.json --remote-auth-file ~/.config/lingma-proxy/credentials.json
``` ```
Credential file format: Credential file format:
@@ -216,6 +216,7 @@ Credential file format:
Notes: Notes:
- Remote API mode is the recommended default for day-to-day agent usage. It bypasses the IDE/plugin IPC runtime, so it is less affected by plugin session state, IDE working directory, or local extension environment limitations.
- Remote mode does not write or migrate login state. It only reads the local Lingma cache or the credential file you provide. - Remote mode does not write or migrate login state. It only reads the local Lingma cache or the credential file you provide.
- If your Lingma plugin uses a dedicated domain, remote mode first uses `--remote-base-url`, `LINGMA_REMOTE_BASE_URL`, or the JSON config field. If those are empty, it scans Lingma's local logs on macOS, Windows, and Linux for endpoint hints such as `endpoint config:` and marketplace service URLs. - If your Lingma plugin uses a dedicated domain, remote mode first uses `--remote-base-url`, `LINGMA_REMOTE_BASE_URL`, or the JSON config field. If those are empty, it scans Lingma's local logs on macOS, Windows, and Linux for endpoint hints such as `endpoint config:` and marketplace service URLs.
- The desktop Settings page shows the resolved remote domain and detection source without exposing tokens. - The desktop Settings page shows the resolved remote domain and detection source without exposing tokens.
@@ -228,10 +229,10 @@ Notes:
IPC mode talks to the local Lingma IDE plugin: IPC mode talks to the local Lingma IDE plugin:
```bash ```bash
lingma-ipc-proxy --backend ipc --transport auto --port 8095 lingma-proxy --backend ipc --transport auto --port 8095
``` ```
Use this when VS Code / the Lingma plugin is already running, when you want plugin session behavior, or when you want the model list exposed by the local plugin. Use this when VS Code / the Lingma plugin is already running, when you want plugin session behavior, or when you want the exact model list exposed by the local plugin. Compared with Remote API mode, IPC mode is more coupled to the IDE/plugin process and can be affected by that process's session, current project, and local environment.
## Quick Start ## Quick Start
@@ -239,25 +240,25 @@ Use this when VS Code / the Lingma plugin is already running, when you want plug
1. Install VS Code and the Tongyi Lingma extension. 1. Install VS Code and the Tongyi Lingma extension.
2. Log in to Tongyi Lingma and verify the Lingma panel can chat normally. 2. Log in to Tongyi Lingma and verify the Lingma panel can chat normally.
3. Download the desktop asset from [Releases](https://github.com/Lutiancheng1/lingma-ipc-proxy/releases). 3. Download the desktop asset from [Releases](https://github.com/Lutiancheng1/lingma-proxy/releases).
4. Start `Lingma IPC Proxy`. 4. Start `Lingma Proxy`.
5. Click `探测模型` after the proxy is running. 5. Click `探测模型` after the proxy is running.
6. Configure clients to use `http://127.0.0.1:8095`. 6. Configure clients to use `http://127.0.0.1:8095`.
### CLI ### CLI
```bash ```bash
git clone https://github.com/Lutiancheng1/lingma-ipc-proxy.git git clone https://github.com/Lutiancheng1/lingma-proxy.git
cd lingma-ipc-proxy cd lingma-proxy
go build -o ./dist/lingma-ipc-proxy ./cmd/lingma-ipc-proxy go build -o ./dist/lingma-proxy ./cmd/lingma-ipc-proxy
./dist/lingma-ipc-proxy --host 127.0.0.1 --port 8095 --session-mode auto ./dist/lingma-proxy --host 127.0.0.1 --port 8095 --session-mode auto
``` ```
Windows: Windows:
```powershell ```powershell
.\scripts\build.ps1 .\scripts\build.ps1
.\dist\lingma-ipc-proxy.exe --host 127.0.0.1 --port 8095 --session-mode auto .\dist\lingma-proxy.exe --host 127.0.0.1 --port 8095 --session-mode auto
``` ```
## Client Configuration ## Client Configuration
@@ -335,7 +336,8 @@ Remote mode enables timeout fallback by default. On timeout, upstream 5xx/429, o
Default config file: Default config file:
```text ```text
./lingma-ipc-proxy.json ./lingma-proxy.json
./lingma-ipc-proxy.json # legacy fallback
``` ```
Example: Example:
@@ -387,7 +389,7 @@ Older builds rejected concurrent chat requests with a `rate_limit_error` saying
Example: Example:
```bash ```bash
LINGMA_PROXY_MAX_CONCURRENT=8 lingma-ipc-proxy --port 8095 LINGMA_PROXY_MAX_CONCURRENT=8 lingma-proxy --port 8095
``` ```
## Function Calling / Tool Calling ## Function Calling / Tool Calling
@@ -460,7 +462,7 @@ cd desktop
wails build -platform windows/amd64 -clean wails build -platform windows/amd64 -clean
``` ```
The desktop bundle name is always `Lingma IPC Proxy`. The desktop bundle name is always `Lingma Proxy`.
## Release Plan ## Release Plan
@@ -480,4 +482,4 @@ Planned improvements:
## Acknowledgements ## Acknowledgements
This project is based on the protocol insight and initial discovery work from [coolxll/lingma-ipc-proxy](https://github.com/coolxll/lingma-ipc-proxy). The core idea of connecting to Lingma's private local IPC protocol and exposing standard API endpoints came from that project. This fork extends the implementation with broader OpenAI/Anthropic compatibility, tool emulation, image handling, desktop app support, request/log inspection, cross-platform packaging, and release automation. The **IPC plugin mode** is based on the protocol insight and initial discovery work from [coolxll/lingma-ipc-proxy](https://github.com/coolxll/lingma-ipc-proxy). That project first demonstrated that Lingma's private local IPC protocol can be bridged to standard HTTP API endpoints. Lingma Proxy keeps that IPC path as a compatibility backend and extends it with broader OpenAI/Anthropic compatibility, tool emulation, image handling, desktop app support, request/log inspection, cross-platform packaging, and release automation. The default **Remote API mode** is a separate backend that calls Lingma remote APIs directly and is documented independently above.

View File

@@ -2,7 +2,7 @@
[English](./README.md) | [简体中文](./README.zh-CN.md) [English](./README.md) | [简体中文](./README.zh-CN.md)
**Lingma Proxy** 是一个通义灵码 API 适配层。它可以把 Lingma 插件的本地私有 IPC / WebSocket 能力转换成标准 **OpenAI 兼容接口****Anthropic 兼容接口**也可以使用实验性的远端 API 模式直接调用 Lingma 远端接口,让 Claude Code、Cline、Continue、OpenCode、自研 Agent 等第三方客户端可以直接调用 Lingma 后端模型。 **Lingma Proxy** 是一个通义灵码 API 适配层。它可以通过默认推荐的远端 API 模式直接调用 Lingma 远端接口,也可以把 Lingma 插件的本地私有 IPC / WebSocket 能力转换成标准 **OpenAI 兼容接口****Anthropic 兼容接口**,让 Claude Code、Cline、Continue、OpenCode、自研 Agent 等第三方客户端可以直接调用 Lingma 后端模型。
项目同时提供两种使用方式: 项目同时提供两种使用方式:
@@ -11,8 +11,8 @@
代理后端支持两种模式: 代理后端支持两种模式:
- **远端 API 模式(默认,实验**:读取 Lingma 本地登录缓存或显式凭据,直接调用 Lingma 远端接口。优点是不依赖 IDE 插件窗口IPC 会话,体验更像官方 API;目前更推荐给 Claude Code / Hermes 这类本地 Agent。 - **远端 API 模式(默认,推荐**:读取 Lingma 本地登录缓存或显式凭据,直接调用 Lingma 远端接口。它更接近普通托管 API不依赖 IDE 插件窗口IPC 会话和插件执行环境;目前更推荐给 Claude Code / Hermes 这类本地 Agent。
- **IPC 插件模式**:连接本机 Lingma IDE 插件的 WebSocket / Named Pipe。优点是更接近 IDE 插件上下文,适合作为兼容性兜底。 - **IPC 插件模式**:连接本机 Lingma IDE 插件的 WebSocket / Named Pipe。更接近 IDE 插件上下文,但会继承 IDE 会话生命周期、插件本地状态和环境限制,主要作为兼容性兜底。
## 当前版本 ## 当前版本
@@ -24,22 +24,22 @@ GitHub Actions 会在 Release 中产出:
| 产物 | 平台 | 用途 | | 产物 | 平台 | 用途 |
| --- | --- | --- | | --- | --- | --- |
| `lingma-ipc-proxy_<tag>_darwin_arm64.tar.gz` | macOS | CLI 代理 | | `lingma-proxy_<tag>_darwin_arm64.tar.gz` | macOS | CLI 代理 |
| `lingma-ipc-proxy_<tag>_windows_amd64.zip` | Windows | CLI 代理 | | `lingma-proxy_<tag>_windows_amd64.zip` | Windows | CLI 代理 |
| `lingma-ipc-proxy-desktop_<tag>_darwin_arm64.dmg` | Apple Silicon Mac | 拖拽安装桌面 App | | `lingma-proxy-desktop_<tag>_darwin_arm64.dmg` | Apple Silicon Mac | 拖拽安装桌面 App |
| `lingma-ipc-proxy-desktop_<tag>_darwin_arm64.zip` | Apple Silicon Mac | `.app` 压缩包 | | `lingma-proxy-desktop_<tag>_darwin_arm64.zip` | Apple Silicon Mac | `.app` 压缩包 |
| `lingma-ipc-proxy-desktop_<tag>_windows_amd64.zip` | Windows | 桌面 App | | `lingma-proxy-desktop_<tag>_windows_amd64.zip` | Windows | 桌面 App |
| `lingma-ipc-proxy_<tag>_sha256.txt` | 全平台 | 校验文件 | | `lingma-proxy_<tag>_sha256.txt` | 全平台 | 校验文件 |
### 应该下载哪个包? ### 应该下载哪个包?
| 你的系统 | 推荐下载 | 说明 | | 你的系统 | 推荐下载 | 说明 |
| --- | --- | --- | | --- | --- | --- |
| Apple Silicon MacM1/M2/M3/M4 | `lingma-ipc-proxy-desktop_<tag>_darwin_arm64.dmg` | 打开 DMG 后把 `Lingma IPC Proxy.app` 拖到 `Applications`。 | | Apple Silicon MacM1/M2/M3/M4 | `lingma-proxy-desktop_<tag>_darwin_arm64.dmg` | 打开 DMG 后把 `Lingma Proxy.app` 拖到 `Applications`。 |
| Apple Silicon Mac想要压缩包 | `lingma-ipc-proxy-desktop_<tag>_darwin_arm64.zip` | 和 DMG 是同一个 App只是 zip 形式。 | | Apple Silicon Mac想要压缩包 | `lingma-proxy-desktop_<tag>_darwin_arm64.zip` | 和 DMG 是同一个 App只是 zip 形式。 |
| Windows x64 / x86_64 / AMD64 | `lingma-ipc-proxy-desktop_<tag>_windows_amd64.zip` | 普通 64 位 Windows 电脑都选这个,包括 Intel 和 AMD CPU。 | | Windows x64 / x86_64 / AMD64 | `lingma-proxy-desktop_<tag>_windows_amd64.zip` | 普通 64 位 Windows 电脑都选这个,包括 Intel 和 AMD CPU。 |
| 只想在 macOS 终端跑 CLI | `lingma-ipc-proxy_<tag>_darwin_arm64.tar.gz` | 只有命令行代理,没有桌面界面。 | | 只想在 macOS 终端跑 CLI | `lingma-proxy_<tag>_darwin_arm64.tar.gz` | 只有命令行代理,没有桌面界面。 |
| 只想在 Windows 终端跑 CLI | `lingma-ipc-proxy_<tag>_windows_amd64.zip` | 只有命令行代理,没有桌面界面。 | | 只想在 Windows 终端跑 CLI | `lingma-proxy_<tag>_windows_amd64.zip` | 只有命令行代理,没有桌面界面。 |
目前没有单独的 `windows_arm64` 包。常见 x64 Windows 机器请选择 `windows_amd64` 目前没有单独的 `windows_arm64` 包。常见 x64 Windows 机器请选择 `windows_amd64`
@@ -231,18 +231,18 @@ flowchart LR
CLI 也可以手动指定: CLI 也可以手动指定:
```bash ```bash
lingma-ipc-proxy --transport websocket --ws-url ws://127.0.0.1:36510 --port 8095 lingma-proxy --transport websocket --ws-url ws://127.0.0.1:36510 --port 8095
lingma-ipc-proxy --transport pipe --pipe '\\.\pipe\lingma-ipc' lingma-proxy --transport pipe --pipe '\\.\pipe\lingma-ipc'
``` ```
## 后端模式 ## 后端模式
### 远端 API 模式(默认,实验 ### 远端 API 模式(默认,推荐
远端模式直接调用 Lingma 远端接口: 远端模式直接调用 Lingma 远端接口:
```bash ```bash
lingma-ipc-proxy --backend remote --port 8095 lingma-proxy --backend remote --port 8095
``` ```
默认会只读导入: 默认会只读导入:
@@ -259,10 +259,10 @@ lingma-ipc-proxy --backend remote --port 8095
也可以指定显式凭据文件: 也可以指定显式凭据文件:
```bash ```bash
lingma-ipc-proxy \ lingma-proxy \
--backend remote \ --backend remote \
--remote-base-url https://lingma.alibabacloud.com \ --remote-base-url https://lingma.alibabacloud.com \
--remote-auth-file ~/.config/lingma-ipc-proxy/credentials.json --remote-auth-file ~/.config/lingma-proxy/credentials.json
``` ```
`credentials.json` 格式: `credentials.json` 格式:
@@ -282,6 +282,7 @@ lingma-ipc-proxy \
说明: 说明:
- 远端 API 模式是日常 Agent 使用的默认推荐模式。它绕过 IDE / 插件 IPC 运行时因此更少受到插件会话、IDE 当前项目和本地扩展环境限制影响。
- 远端模式不会写入或迁移你的登录态,只会读取本机 Lingma 缓存或你指定的凭据文件。 - 远端模式不会写入或迁移你的登录态,只会读取本机 Lingma 缓存或你指定的凭据文件。
- 如果 Lingma 插件配置过专属域名,远端模式会优先使用 `--remote-base-url``LINGMA_REMOTE_BASE_URL` 或配置文件;这些为空时,会扫描 macOS、Windows、Linux 上 Lingma 本地日志里的 `endpoint config:`、Marketplace service URL 等线索。 - 如果 Lingma 插件配置过专属域名,远端模式会优先使用 `--remote-base-url``LINGMA_REMOTE_BASE_URL` 或配置文件;这些为空时,会扫描 macOS、Windows、Linux 上 Lingma 本地日志里的 `endpoint config:`、Marketplace service URL 等线索。
- 桌面端设置页会展示当前解析到的远端域名和来源,但不会展示 token / key 明文。 - 桌面端设置页会展示当前解析到的远端域名和来源,但不会展示 token / key 明文。
@@ -294,10 +295,10 @@ lingma-ipc-proxy \
IPC 模式通过本机 Lingma IDE 插件通信: IPC 模式通过本机 Lingma IDE 插件通信:
```bash ```bash
lingma-ipc-proxy --backend ipc --transport auto --port 8095 lingma-proxy --backend ipc --transport auto --port 8095
``` ```
适合已经打开 VS Code / Lingma 插件、希望使用插件当前会话环境、并优先使用插件探测模型列表的场景。 适合已经打开 VS Code / Lingma 插件、希望使用插件当前会话环境、并优先使用插件探测模型列表的场景。相比远端 API 模式IPC 插件模式更依赖 IDE / 插件进程,也更容易受到插件会话、当前项目和本地环境的影响。
## 快速开始 ## 快速开始
@@ -310,8 +311,8 @@ lingma-ipc-proxy --backend ipc --transport auto --port 8095
### 使用桌面 App ### 使用桌面 App
1. 前往 [Releases](https://github.com/Lutiancheng1/lingma-ipc-proxy/releases) 下载桌面版。 1. 前往 [Releases](https://github.com/Lutiancheng1/lingma-proxy/releases) 下载桌面版。
2. macOS 解压后打开 `Lingma IPC Proxy.app` 2. macOS 解压后打开 `Lingma Proxy.app`
3. Windows 解压后运行桌面版 exe。 3. Windows 解压后运行桌面版 exe。
4. 点击启动代理。 4. 点击启动代理。
5. 点击 `探测模型` 5. 点击 `探测模型`
@@ -322,19 +323,19 @@ lingma-ipc-proxy --backend ipc --transport auto --port 8095
macOS macOS
```bash ```bash
git clone https://github.com/Lutiancheng1/lingma-ipc-proxy.git git clone https://github.com/Lutiancheng1/lingma-proxy.git
cd lingma-ipc-proxy cd lingma-proxy
go build -o ./dist/lingma-ipc-proxy ./cmd/lingma-ipc-proxy go build -o ./dist/lingma-proxy ./cmd/lingma-ipc-proxy
./dist/lingma-ipc-proxy --host 127.0.0.1 --port 8095 --session-mode auto ./dist/lingma-proxy --host 127.0.0.1 --port 8095 --session-mode auto
``` ```
Windows Windows
```powershell ```powershell
git clone https://github.com/Lutiancheng1/lingma-ipc-proxy.git git clone https://github.com/Lutiancheng1/lingma-proxy.git
cd lingma-ipc-proxy cd lingma-proxy
.\scripts\build.ps1 .\scripts\build.ps1
.\dist\lingma-ipc-proxy.exe --host 127.0.0.1 --port 8095 --session-mode auto .\dist\lingma-proxy.exe --host 127.0.0.1 --port 8095 --session-mode auto
``` ```
## 客户端配置 ## 客户端配置
@@ -417,6 +418,7 @@ export ANTHROPIC_API_KEY="any"
默认读取: 默认读取:
```text ```text
./lingma-proxy.json
./lingma-ipc-proxy.json ./lingma-ipc-proxy.json
``` ```
@@ -475,7 +477,7 @@ export ANTHROPIC_API_KEY="any"
示例: 示例:
```bash ```bash
LINGMA_PROXY_MAX_CONCURRENT=8 lingma-ipc-proxy --port 8095 LINGMA_PROXY_MAX_CONCURRENT=8 lingma-proxy --port 8095
``` ```
## 工具调用实现 ## 工具调用实现
@@ -559,10 +561,10 @@ wails build -platform windows/amd64 -clean
桌面端最终 App 名称统一为: 桌面端最终 App 名称统一为:
```text ```text
Lingma IPC Proxy Lingma Proxy
``` ```
不会再生成 `lingma-proxy-desktop` 旧包名 Release 资产文件名仍使用 `lingma-proxy-desktop_<tag>_...` 区分桌面端和 CLI 端
## GitHub Actions Release ## GitHub Actions Release
@@ -587,9 +589,9 @@ Release workflow 会执行:
## 与上游项目的关系 ## 与上游项目的关系
我对比了上游仓库 [coolxll/lingma-ipc-proxy](https://github.com/coolxll/lingma-ipc-proxy)。上游项目的核心贡献是发现并验证了 Lingma 本地私有 IPC 协议可以被代理成标准 HTTP API这是本项目的基础思路来源。 我对比了上游仓库 [coolxll/lingma-ipc-proxy](https://github.com/coolxll/lingma-ipc-proxy)。上游项目的核心贡献是发现并验证了 Lingma 本地私有 IPC 协议可以被代理成标准 HTTP API这是本项目 **IPC 插件模式** 的基础思路来源。
本项目在这个思路上继续扩展了: 本项目在 IPC 插件模式上继续扩展了:
- 更完整的 OpenAI / Anthropic 参数兼容 - 更完整的 OpenAI / Anthropic 参数兼容
- Tools / Function Calling 模拟 - Tools / Function Calling 模拟
@@ -614,4 +616,4 @@ Release workflow 会执行:
## 致谢 ## 致谢
本项目的协议实现思路参考并继承自 [coolxll/lingma-ipc-proxy](https://github.com/coolxll/lingma-ipc-proxy) 的协议发现工作。Lingma 私有本地 IPC 可以被转换为标准 OpenAI / Anthropic API 这一核心思想是该项目首先验证出来的;本项目在此基础上补充了更完整的协议兼容、工具调用、图片处理、桌面 App、请求 / 日志观测、跨平台打包和 release 自动化。 本项目的 **IPC 插件模式** 参考并继承自 [coolxll/lingma-ipc-proxy](https://github.com/coolxll/lingma-ipc-proxy) 的协议发现工作。Lingma 私有本地 IPC 可以被转换为标准 OpenAI / Anthropic API 这一核心思想是该项目首先验证出来的;Lingma Proxy 保留这条 IPC 路径作为兼容后端,并补充了更完整的协议兼容、工具调用、图片处理、桌面 App、请求 / 日志观测、跨平台打包和 release 自动化。默认推荐的 **远端 API 模式** 是独立后端,直接调用 Lingma 远端 API上文已单独说明。

View File

@@ -57,7 +57,7 @@ func main() {
server := httpapi.NewServer(addr, svc) server := httpapi.NewServer(addr, svc)
log.Printf("lingma-ipc-proxy listening on http://%s", addr) log.Printf("lingma-proxy listening on http://%s", addr)
log.Printf("session mode: %s", cfg.SessionMode) log.Printf("session mode: %s", cfg.SessionMode)
log.Printf("transport: %s", cfg.Transport) log.Printf("transport: %s", cfg.Transport)
log.Printf("mode: %s", cfg.Mode) log.Printf("mode: %s", cfg.Mode)
@@ -134,7 +134,7 @@ func loadConfig() (service.Config, string) {
remoteFallbackEnabled := flag.Bool("remote-fallback", cfg.RemoteFallbackEnabled, "Enable remote timeout/5xx fallback to the next available model") remoteFallbackEnabled := flag.Bool("remote-fallback", cfg.RemoteFallbackEnabled, "Enable remote timeout/5xx fallback to the next available model")
remoteFallbackModels := flag.String("remote-fallback-models", strings.Join(cfg.RemoteFallbackModels, ","), "Comma-separated remote fallback model IDs") remoteFallbackModels := flag.String("remote-fallback-models", strings.Join(cfg.RemoteFallbackModels, ","), "Comma-separated remote fallback model IDs")
sessionMode := flag.String("session-mode", string(cfg.SessionMode), "Session mode: auto, fresh, reuse") sessionMode := flag.String("session-mode", string(cfg.SessionMode), "Session mode: auto, fresh, reuse")
config := flag.String("config", valueOr(configPath, filepath.Join(currentDir(), "lingma-ipc-proxy.json")), "Path to JSON config file") config := flag.String("config", valueOr(configPath, filepath.Join(currentDir(), "lingma-proxy.json")), "Path to JSON config file")
flag.Parse() flag.Parse()
parsedSessionMode := parseSessionMode(*sessionMode) parsedSessionMode := parseSessionMode(*sessionMode)
@@ -176,9 +176,11 @@ func resolveConfigPath() (string, bool) {
if path := strings.TrimSpace(os.Getenv("LINGMA_PROXY_CONFIG")); path != "" { if path := strings.TrimSpace(os.Getenv("LINGMA_PROXY_CONFIG")); path != "" {
return path, true return path, true
} }
defaultPath := filepath.Join(currentDir(), "lingma-ipc-proxy.json") defaultPath := filepath.Join(currentDir(), "lingma-proxy.json")
if info, err := os.Stat(defaultPath); err == nil && !info.IsDir() { for _, candidate := range []string{defaultPath, filepath.Join(currentDir(), "lingma-ipc-proxy.json")} {
return defaultPath, true if info, err := os.Stat(candidate); err == nil && !info.IsDir() {
return candidate, true
}
} }
return defaultPath, false return defaultPath, false
} }

View File

@@ -198,6 +198,11 @@ func (a *App) QuitApp() {
a.beginQuit() a.beginQuit()
} }
// ForceQuitApp stops the proxy and exits the desktop process immediately.
func (a *App) ForceQuitApp() {
a.beginQuit()
}
// RequestQuitShortcut requires two shortcut presses to avoid accidental exits. // RequestQuitShortcut requires two shortcut presses to avoid accidental exits.
func (a *App) RequestQuitShortcut() { func (a *App) RequestQuitShortcut() {
now := time.Now() now := time.Now()
@@ -358,7 +363,7 @@ func (a *App) saveConfig(cfg service.Config) error {
if err != nil { if err != nil {
return err return err
} }
dir := filepath.Join(home, ".config", "lingma-ipc-proxy") dir := filepath.Join(home, ".config", "lingma-proxy")
if err := os.MkdirAll(dir, 0755); err != nil { if err := os.MkdirAll(dir, 0755); err != nil {
return err return err
} }
@@ -1041,15 +1046,19 @@ func configSearchPaths() []string {
var paths []string var paths []string
// 1. Executable directory (for dev / portable mode) // 1. Executable directory (for dev / portable mode)
if exe, err := os.Executable(); err == nil { if exe, err := os.Executable(); err == nil {
paths = append(paths, filepath.Join(filepath.Dir(exe), "lingma-proxy.json"))
paths = append(paths, filepath.Join(filepath.Dir(exe), "lingma-ipc-proxy.json")) paths = append(paths, filepath.Join(filepath.Dir(exe), "lingma-ipc-proxy.json"))
} }
// 2. Current working directory // 2. Current working directory
if wd, err := os.Getwd(); err == nil { if wd, err := os.Getwd(); err == nil {
paths = append(paths, filepath.Join(wd, "lingma-proxy.json"))
paths = append(paths, filepath.Join(wd, "lingma-ipc-proxy.json")) paths = append(paths, filepath.Join(wd, "lingma-ipc-proxy.json"))
} }
// 3. User home directory // 3. User home directory
if home, err := os.UserHomeDir(); err == nil { if home, err := os.UserHomeDir(); err == nil {
paths = append(paths, filepath.Join(home, "lingma-proxy.json"))
paths = append(paths, filepath.Join(home, "lingma-ipc-proxy.json")) paths = append(paths, filepath.Join(home, "lingma-ipc-proxy.json"))
paths = append(paths, filepath.Join(home, ".config", "lingma-proxy", "config.json"))
paths = append(paths, filepath.Join(home, ".config", "lingma-ipc-proxy", "config.json")) paths = append(paths, filepath.Join(home, ".config", "lingma-ipc-proxy", "config.json"))
} }
return paths return paths

View File

@@ -4,7 +4,7 @@
<meta charset="UTF-8"/> <meta charset="UTF-8"/>
<meta content="width=device-width, initial-scale=1.0" name="viewport"/> <meta content="width=device-width, initial-scale=1.0" name="viewport"/>
<link rel="icon" type="image/png" href="/favicon.png"/> <link rel="icon" type="image/png" href="/favicon.png"/>
<title>lingma-proxy-desktop</title> <title>Lingma Proxy</title>
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>

View File

@@ -6,7 +6,7 @@ import Models from './views/Models.vue'
import Requests from './views/Requests.vue' import Requests from './views/Requests.vue'
import Settings from './views/Settings.vue' import Settings from './views/Settings.vue'
import { EventsOff, EventsOn } from '../wailsjs/runtime' import { EventsOff, EventsOn } from '../wailsjs/runtime'
import { ClearLogs, GetLogs, GetStatus, HideWindow, MinimizeWindow } from '../wailsjs/go/main/App.js' import { ClearLogs, ForceQuitApp, GetLogs, GetStatus, HideWindow, MinimizeWindow } from '../wailsjs/go/main/App.js'
import lingmaIcon from './assets/images/lingma-icon.png' import lingmaIcon from './assets/images/lingma-icon.png'
const currentTab = ref('dashboard') const currentTab = ref('dashboard')
@@ -105,6 +105,17 @@ async function copyEndpoint() {
handleNotice('已复制接口地址:' + value) handleNotice('已复制接口地址:' + value)
} }
async function forceQuitApp() {
const confirmed = window.confirm('确定要停止代理并退出应用吗?')
if (!confirmed) return
showToast('正在停止代理并退出应用...')
try {
await ForceQuitApp()
} catch (e) {
addLog('error', '退出应用失败:' + (e.message || String(e)))
}
}
function safeEventsOn(name, handler) { function safeEventsOn(name, handler) {
try { try {
EventsOn(name, handler) EventsOn(name, handler)
@@ -215,7 +226,7 @@ onUnmounted(() => {
</span> </span>
<span> <span>
<strong>灵码代理</strong> <strong>灵码代理</strong>
<small>IPC Proxy</small> <small>Proxy</small>
</span> </span>
</button> </button>
@@ -260,6 +271,9 @@ onUnmounted(() => {
<button class="icon-button" type="button" :title="themeTitle()" @click="toggleTheme"> <button class="icon-button" type="button" :title="themeTitle()" @click="toggleTheme">
<i class="bi" :class="themeIcon()" aria-hidden="true"></i> <i class="bi" :class="themeIcon()" aria-hidden="true"></i>
</button> </button>
<button class="icon-button danger-icon-button" type="button" title="停止代理并退出应用" @click="forceQuitApp">
<i class="bi bi-power" aria-hidden="true"></i>
</button>
</div> </div>
</header> </header>

View File

@@ -1289,6 +1289,17 @@ button {
border: 1px solid var(--line); border: 1px solid var(--line);
} }
.danger-icon-button {
color: #b42318;
background: rgba(254, 226, 226, 0.72);
border-color: rgba(220, 38, 38, 0.24);
}
.danger-icon-button:hover {
color: #991b1b;
background: rgba(254, 202, 202, 0.88);
}
.primary-button:hover, .primary-button:hover,
.secondary-button:hover, .secondary-button:hover,
.ghost-button:hover, .ghost-button:hover,
@@ -1963,6 +1974,17 @@ button:disabled {
background: rgba(30, 41, 59, 0.66); background: rgba(30, 41, 59, 0.66);
} }
:root[data-theme='dark'] .danger-icon-button {
color: #fecaca;
border-color: rgba(248, 113, 113, 0.32);
background: rgba(127, 29, 29, 0.42);
}
:root[data-theme='dark'] .danger-icon-button:hover {
color: #fff1f2;
background: rgba(153, 27, 27, 0.62);
}
:root[data-theme='dark'] .strip-actions { :root[data-theme='dark'] .strip-actions {
background: rgba(15, 23, 42, 0.78); background: rgba(15, 23, 42, 0.78);
} }

View File

@@ -7,6 +7,8 @@ export function ClearLogs():Promise<void>;
export function ClearRequests():Promise<void>; export function ClearRequests():Promise<void>;
export function ForceQuitApp():Promise<void>;
export function GetConfig():Promise<service.Config>; export function GetConfig():Promise<service.Config>;
export function GetDetectionInfo():Promise<main.DetectionInfo>; export function GetDetectionInfo():Promise<main.DetectionInfo>;

View File

@@ -10,6 +10,10 @@ export function ClearRequests() {
return window['go']['main']['App']['ClearRequests'](); return window['go']['main']['App']['ClearRequests']();
} }
export function ForceQuitApp() {
return window['go']['main']['App']['ForceQuitApp']();
}
export function GetConfig() { export function GetConfig() {
return window['go']['main']['App']['GetConfig'](); return window['go']['main']['App']['GetConfig']();
} }

View File

@@ -21,7 +21,7 @@ func main() {
enableInspector := os.Getenv("LINGMA_DESKTOP_DEBUG") == "1" enableInspector := os.Getenv("LINGMA_DESKTOP_DEBUG") == "1"
err := wails.Run(&options.App{ err := wails.Run(&options.App{
Title: "Lingma IPC Proxy", Title: "Lingma Proxy",
Width: 1100, Width: 1100,
Height: 750, Height: 750,
MinWidth: 900, MinWidth: 900,
@@ -40,7 +40,7 @@ func main() {
OnBeforeClose: app.beforeClose, OnBeforeClose: app.beforeClose,
OnDomReady: app.onDomReady, OnDomReady: app.onDomReady,
SingleInstanceLock: &options.SingleInstanceLock{ SingleInstanceLock: &options.SingleInstanceLock{
UniqueId: "lingma-ipc-proxy-desktop", UniqueId: "lingma-proxy-desktop",
OnSecondInstanceLaunch: app.onSecondInstanceLaunch, OnSecondInstanceLaunch: app.onSecondInstanceLaunch,
}, },
Bind: []interface{}{ Bind: []interface{}{
@@ -57,8 +57,8 @@ func main() {
HideToolbarSeparator: true, HideToolbarSeparator: true,
}, },
About: &mac.AboutInfo{ About: &mac.AboutInfo{
Title: "Lingma IPC Proxy", Title: "Lingma Proxy",
Message: "A desktop GUI for lingma-ipc-proxy", Message: "A desktop GUI for Lingma Proxy",
}, },
}, },
}) })
@@ -86,7 +86,7 @@ func appMenu(app *App) *menu.Menu {
app.MinimizeWindow() app.MinimizeWindow()
}) })
appMenu.AddSeparator() appMenu.AddSeparator()
appMenu.AddText("退出 Lingma IPC Proxy", quitAccelerator, func(_ *menu.CallbackData) { appMenu.AddText("退出 Lingma Proxy", quitAccelerator, func(_ *menu.CallbackData) {
app.RequestQuitShortcut() app.RequestQuitShortcut()
}) })
@@ -100,7 +100,7 @@ func appMenu(app *App) *menu.Menu {
editMenu.AddText("全选", keys.CmdOrCtrl("a"), func(_ *menu.CallbackData) {}) editMenu.AddText("全选", keys.CmdOrCtrl("a"), func(_ *menu.CallbackData) {})
return menu.NewMenuFromItems( return menu.NewMenuFromItems(
menu.SubMenu("Lingma IPC Proxy", appMenu), menu.SubMenu("Lingma Proxy", appMenu),
menu.SubMenu("编辑", editMenu), menu.SubMenu("编辑", editMenu),
) )
} }

View File

@@ -1,6 +1,6 @@
{ {
"$schema": "https://wails.io/schemas/config.v2.json", "$schema": "https://wails.io/schemas/config.v2.json",
"name": "Lingma IPC Proxy", "name": "Lingma Proxy",
"outputfilename": "LingmaProxy", "outputfilename": "LingmaProxy",
"frontend:install": "npm install", "frontend:install": "npm install",
"frontend:build": "npm run build", "frontend:build": "npm run build",

View File

@@ -1,9 +1,9 @@
# lingma-ipc-proxy Architecture # Lingma Proxy Architecture
This document describes the current architecture of `lingma-ipc-proxy`, including both backend modes: This document describes the current architecture of **Lingma Proxy**, including both backend modes:
- `ipc`: bridge to the local Lingma IDE plugin transport - `remote`: the default and recommended mode, calling Lingma remote HTTP APIs directly with detected credentials
- `remote`: call Lingma remote HTTP APIs directly with detected credentials - `ipc`: a compatibility mode that bridges to the local Lingma IDE plugin transport
--- ---
@@ -35,7 +35,20 @@ flowchart LR
## 2. Runtime Modes ## 2. Runtime Modes
### 2.1 IPC mode ### 2.1 Remote API mode
`backend=remote`
- Reads Lingma remote base URL from config, environment, or detected local Lingma logs
- Loads credentials from:
- explicit `remote_auth_file`
- or detected Lingma login cache
- Calls remote model list and chat endpoints directly
- Supports timeout / 429 / 5xx fallback across available remote models
- Does not use local plugin session environment knobs
- Avoids IDE/plugin IPC session lifetime, working directory, and extension environment limitations
### 2.2 IPC plugin mode
`backend=ipc` `backend=ipc`
@@ -45,18 +58,7 @@ flowchart LR
- Named Pipe on Windows - Named Pipe on Windows
- Reuses Lingma plugin session semantics - Reuses Lingma plugin session semantics
- Session/environment options in the desktop UI apply only here - Session/environment options in the desktop UI apply only here
- This mode is based on the IPC protocol insight from `coolxll/lingma-ipc-proxy`
### 2.2 Remote API mode
`backend=remote`
- Reads Lingma remote base URL
- Loads credentials from:
- explicit `remote_auth_file`
- or detected Lingma cache under `~/.lingma`
- Calls remote model list and chat endpoints directly
- Supports timeout / 429 / 5xx fallback across available remote models
- Does not use local plugin session environment knobs
--- ---
@@ -261,7 +263,8 @@ Responsibilities:
Persisted local state: Persisted local state:
- config: `~/.config/lingma-ipc-proxy/config.json` - config: `~/.config/lingma-proxy/config.json`
- legacy config fallback: `~/.config/lingma-ipc-proxy/config.json`
- UI/runtime state: `~/.config/lingma-ipc-proxy/app-state.json` - UI/runtime state: `~/.config/lingma-ipc-proxy/app-state.json`
Production packaging rules: Production packaging rules:
@@ -277,8 +280,8 @@ Production packaging rules:
Because the two modes solve different problems: Because the two modes solve different problems:
- IPC mode preserves plugin session semantics and local tool environment - Remote mode avoids plugin runtime coupling and is usually better for third-party agent clients.
- Remote mode avoids plugin runtime coupling and is usually better for third-party agent clients - IPC mode preserves plugin session semantics and remains useful when the caller specifically wants the local plugin's context or model list.
### 7.2 Why keep tool emulation even with remote mode? ### 7.2 Why keep tool emulation even with remote mode?
@@ -313,4 +316,4 @@ If you are extending the system, start here:
--- ---
Document version: 2026-04-30 Document version: 2026-05-06

View File

@@ -1,9 +1,9 @@
# lingma-ipc-proxy 架构文档 # Lingma Proxy 架构文档
本文档描述 `lingma-ipc-proxy` 的当前架构,覆盖两种后端模式: 本文档描述 **Lingma Proxy** 的当前架构,覆盖两种后端模式:
- `ipc`:桥接本地 Lingma IDE 插件传输层 - `remote`:默认推荐模式,使用探测到的登录态直接调用 Lingma 远端 HTTP API
- `remote`:直接调用 Lingma 远端 HTTP API - `ipc`:兼容模式,桥接本地 Lingma IDE 插件传输层
--- ---
@@ -35,7 +35,20 @@ flowchart LR
## 2. 运行模式 ## 2. 运行模式
### 2.1 IPC 模式 ### 2.1 Remote API 模式
`backend=remote`
- 从配置、环境变量或本地 Lingma 日志中解析远端域名
- 加载认证信息:
- 显式指定的 `remote_auth_file`
- 或自动探测 Lingma 登录缓存
- 直接请求远端模型列表和聊天接口
- 支持远端超时 / 429 / 5xx 的模型兜底切换
- 不依赖本地插件会话环境参数
- 避免 IDE / 插件 IPC 会话生命周期、工作目录和扩展环境限制
### 2.2 IPC 插件模式
`backend=ipc` `backend=ipc`
@@ -45,18 +58,7 @@ flowchart LR
- WindowsNamed Pipe - WindowsNamed Pipe
- 复用 Lingma 插件自身的 session 语义 - 复用 Lingma 插件自身的 session 语义
- 桌面端里“会话与环境”相关配置只在这里生效 - 桌面端里“会话与环境”相关配置只在这里生效
- 该模式基于 `coolxll/lingma-ipc-proxy` 的 IPC 协议发现思路
### 2.2 Remote API 模式
`backend=remote`
- 解析远端域名
- 加载认证信息:
- 显式指定的 `remote_auth_file`
- 或自动探测 `~/.lingma` 下的缓存
- 直接请求远端模型列表和聊天接口
- 支持远端超时 / 429 / 5xx 的模型兜底切换
- 不依赖本地插件会话环境参数
--- ---
@@ -260,7 +262,8 @@ Wails 桌面端不是简单预览壳,而是本地代理的运维控制台。
本地持久化路径: 本地持久化路径:
- 配置:`~/.config/lingma-ipc-proxy/config.json` - 配置:`~/.config/lingma-proxy/config.json`
- 旧配置兼容读取:`~/.config/lingma-ipc-proxy/config.json`
- GUI 运行状态:`~/.config/lingma-ipc-proxy/app-state.json` - GUI 运行状态:`~/.config/lingma-ipc-proxy/app-state.json`
打包要求: 打包要求:
@@ -276,8 +279,8 @@ Wails 桌面端不是简单预览壳,而是本地代理的运维控制台。
因为两种模式解决的问题不同: 因为两种模式解决的问题不同:
- IPC 模式更贴近插件本地上下文和 session 语义 - Remote 模式避免插件运行时耦合,通常更适合第三方 Agent 客户端。
- Remote 模式更适合第三方 agent 客户端,减少对插件运行态的依赖 - IPC 模式保留插件会话语义,适合明确需要本地插件上下文或插件模型列表的场景。
### 7.2 为什么 Remote 也保留 Tool Emulation ### 7.2 为什么 Remote 也保留 Tool Emulation
@@ -312,4 +315,4 @@ Wails 桌面端不是简单预览壳,而是本地代理的运维控制台。
--- ---
文档版本2026-04-30 文档版本2026-05-06

View File

@@ -178,7 +178,7 @@ func (s *Server) handleRoot(w http.ResponseWriter, r *http.Request) {
} }
writeJSON(w, http.StatusOK, map[string]any{ writeJSON(w, http.StatusOK, map[string]any{
"ok": true, "ok": true,
"service": "lingma-ipc-proxy", "service": "lingma-proxy",
"state": s.svc.State(), "state": s.svc.State(),
}) })
} }
@@ -214,7 +214,7 @@ func (s *Server) handleDebugRequests(w http.ResponseWriter, r *http.Request) {
records := s.debugRecords(limit) records := s.debugRecords(limit)
writeJSON(w, http.StatusOK, map[string]any{ writeJSON(w, http.StatusOK, map[string]any{
"ok": true, "ok": true,
"service": "lingma-ipc-proxy", "service": "lingma-proxy",
"count": len(records), "count": len(records),
"requests": records, "requests": records,
"state": s.svc.State(), "state": s.svc.State(),
@@ -265,7 +265,7 @@ func (s *Server) handleCapabilities(w http.ResponseWriter, r *http.Request) {
} }
writeJSON(w, http.StatusOK, map[string]any{ writeJSON(w, http.StatusOK, map[string]any{
"service": "lingma-ipc-proxy", "service": "lingma-proxy",
"protocols": []string{ "protocols": []string{
"openai.chat_completions", "openai.chat_completions",
"anthropic.messages", "anthropic.messages",
@@ -441,8 +441,8 @@ func (s *Server) handleVersion(w http.ResponseWriter, r *http.Request) {
return return
} }
writeJSON(w, http.StatusOK, map[string]any{ writeJSON(w, http.StatusOK, map[string]any{
"version": "lingma-ipc-proxy", "version": "lingma-proxy",
"service": "lingma-ipc-proxy", "service": "lingma-proxy",
}) })
} }

View File

@@ -308,7 +308,7 @@ func (c *Client) headers(cred Credential, path string, body string) (map[string]
"Cosy-Machinetype": "", "Cosy-Machinetype": "",
"Cosy-Version": c.cfg.CosyVersion, "Cosy-Version": c.cfg.CosyVersion,
"Login-Version": "v2", "Login-Version": "v2",
"User-Agent": "lingma-ipc-proxy/remote", "User-Agent": "lingma-proxy/remote",
"Accept": "text/event-stream", "Accept": "text/event-stream",
"Cache-Control": "no-cache", "Cache-Control": "no-cache",
}, nil }, nil
@@ -396,6 +396,7 @@ func candidateConfigFiles() []string {
filepath.Join(home, ".lingma", "extension", "server", "config.json"), filepath.Join(home, ".lingma", "extension", "server", "config.json"),
filepath.Join(home, ".lingma", "extension", "local", "config.json"), filepath.Join(home, ".lingma", "extension", "local", "config.json"),
filepath.Join(home, ".lingma", "bin", "config.json"), filepath.Join(home, ".lingma", "bin", "config.json"),
filepath.Join(home, ".config", "lingma-proxy", "config.json"),
filepath.Join(home, ".config", "lingma-ipc-proxy", "config.json"), filepath.Join(home, ".config", "lingma-ipc-proxy", "config.json"),
filepath.Join(home, ".lingma", "logs", "lingma.log"), filepath.Join(home, ".lingma", "logs", "lingma.log"),
filepath.Join(home, ".lingma", "logs", "lingma-extension.log"), filepath.Join(home, ".lingma", "logs", "lingma-extension.log"),

View File

@@ -1,6 +1,6 @@
param( param(
[string]$OutputDir = "dist", [string]$OutputDir = "dist",
[string]$BinaryName = "lingma-ipc-proxy.exe", [string]$BinaryName = "lingma-proxy.exe",
[switch]$Clean [switch]$Clean
) )

View File

@@ -1,10 +1,10 @@
param( param(
[string]$ServiceName = "LingmaIpcProxy", [string]$ServiceName = "LingmaProxy",
[string]$BinaryPath = "", [string]$BinaryPath = "",
[string]$Arguments = "--host 127.0.0.1 --port 8095 --session-mode auto", [string]$Arguments = "--host 127.0.0.1 --port 8095 --session-mode auto",
[string]$WorkingDirectory = "", [string]$WorkingDirectory = "",
[string]$NssmPath = "nssm.exe", [string]$NssmPath = "nssm.exe",
[string]$Description = "Lingma IPC proxy service" [string]$Description = "Lingma Proxy service"
) )
$ErrorActionPreference = "Stop" $ErrorActionPreference = "Stop"
@@ -12,7 +12,7 @@ $ErrorActionPreference = "Stop"
$repoRoot = Split-Path -Parent $PSScriptRoot $repoRoot = Split-Path -Parent $PSScriptRoot
if ([string]::IsNullOrWhiteSpace($BinaryPath)) { if ([string]::IsNullOrWhiteSpace($BinaryPath)) {
$BinaryPath = Join-Path $repoRoot "dist\lingma-ipc-proxy.exe" $BinaryPath = Join-Path $repoRoot "dist\lingma-proxy.exe"
} }
if ([string]::IsNullOrWhiteSpace($WorkingDirectory)) { if ([string]::IsNullOrWhiteSpace($WorkingDirectory)) {
$WorkingDirectory = $repoRoot $WorkingDirectory = $repoRoot

View File

@@ -1,5 +1,5 @@
param( param(
[string]$ServiceName = "LingmaIpcProxy", [string]$ServiceName = "LingmaProxy",
[string]$BinaryPath = "", [string]$BinaryPath = "",
[string]$Arguments = "--host 127.0.0.1 --port 8095 --session-mode auto", [string]$Arguments = "--host 127.0.0.1 --port 8095 --session-mode auto",
[string]$WorkingDirectory = "", [string]$WorkingDirectory = "",
@@ -12,7 +12,7 @@ $ErrorActionPreference = "Stop"
$repoRoot = Split-Path -Parent $PSScriptRoot $repoRoot = Split-Path -Parent $PSScriptRoot
if ([string]::IsNullOrWhiteSpace($BinaryPath)) { if ([string]::IsNullOrWhiteSpace($BinaryPath)) {
$BinaryPath = Join-Path $repoRoot "dist\lingma-ipc-proxy.exe" $BinaryPath = Join-Path $repoRoot "dist\lingma-proxy.exe"
} }
if ([string]::IsNullOrWhiteSpace($WorkingDirectory)) { if ([string]::IsNullOrWhiteSpace($WorkingDirectory)) {
$WorkingDirectory = $repoRoot $WorkingDirectory = $repoRoot
@@ -21,7 +21,7 @@ if ([string]::IsNullOrWhiteSpace($WinSWExePath)) {
$WinSWExePath = Join-Path $repoRoot "dist\WinSW-x64.exe" $WinSWExePath = Join-Path $repoRoot "dist\WinSW-x64.exe"
} }
if ([string]::IsNullOrWhiteSpace($TemplatePath)) { if ([string]::IsNullOrWhiteSpace($TemplatePath)) {
$TemplatePath = Join-Path $PSScriptRoot "lingma-ipc-proxy.xml.template" $TemplatePath = Join-Path $PSScriptRoot "lingma-proxy.xml.template"
} }
if (!(Test-Path $BinaryPath)) { if (!(Test-Path $BinaryPath)) {
@@ -40,7 +40,7 @@ $serviceXmlPath = Join-Path $repoRoot "$ServiceName.xml"
$xml = Get-Content -Raw $TemplatePath $xml = Get-Content -Raw $TemplatePath
$xml = $xml.Replace("__SERVICE_ID__", $ServiceName) $xml = $xml.Replace("__SERVICE_ID__", $ServiceName)
$xml = $xml.Replace("__SERVICE_NAME__", $ServiceName) $xml = $xml.Replace("__SERVICE_NAME__", $ServiceName)
$xml = $xml.Replace("__SERVICE_DESCRIPTION__", "Lingma IPC proxy service") $xml = $xml.Replace("__SERVICE_DESCRIPTION__", "Lingma Proxy service")
$xml = $xml.Replace("__EXECUTABLE__", $BinaryPath) $xml = $xml.Replace("__EXECUTABLE__", $BinaryPath)
$xml = $xml.Replace("__ARGUMENTS__", $Arguments) $xml = $xml.Replace("__ARGUMENTS__", $Arguments)
$xml = $xml.Replace("__WORKDIR__", $WorkingDirectory) $xml = $xml.Replace("__WORKDIR__", $WorkingDirectory)

View File

@@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
# lingma-ipc-proxy macOS 功能测试脚本 # Lingma Proxy macOS 功能测试脚本
# 用法: ./scripts/test-macos.sh [host:port] # 用法: ./scripts/test-macos.sh [host:port]
ENDPOINT="${1:-127.0.0.1:8095}" ENDPOINT="${1:-127.0.0.1:8095}"
@@ -23,7 +23,7 @@ assert_contains() {
} }
echo "========================================" echo "========================================"
echo "lingma-ipc-proxy macOS 功能测试" echo "Lingma Proxy macOS 功能测试"
echo "端点: http://$ENDPOINT" echo "端点: http://$ENDPOINT"
echo "========================================" echo "========================================"