From 5505ccc6cb2dbc2230923d771d9b18052cf9a48e Mon Sep 17 00:00:00 2001 From: wisdgod Date: Mon, 30 Dec 2024 23:29:37 +0800 Subject: [PATCH] v0.1.3-rc.1 --- .env.example | 31 + .gitattributes | 6 + .github/workflows/build.yml | 120 +- .github/workflows/docker.yml | 9 + .gitignore | 9 +- Cargo.lock | 273 +- Cargo.toml | 19 +- Dockerfile | 65 +- README.md | 59 +- build.rs | 137 +- scripts/build.ps1 | 230 +- scripts/build.sh | 95 +- scripts/minify-html.js | 49 - scripts/minify.js | 81 + scripts/package-lock.json | 4 +- scripts/package.json | 6 +- scripts/setup-windows.ps1 | 31 - scripts/setup.ps1 | 179 ++ scripts/setup.sh | 157 + src/aiserver.rs | 1 + src/aiserver/v1.rs | 1 + src/aiserver/v1/aiserver.proto | 5051 ++++++++++++++++++++++++++++++++ src/app.rs | 5 + src/app/client.rs | 29 + src/app/constant.rs | 64 + src/app/models.rs | 447 +++ src/app/token.rs | 313 ++ src/app/utils.rs | 22 + src/chat.rs | 2 + src/chat/error.rs | 154 + src/chat/stream.rs | 127 + src/lib.rs | 446 ++- src/main.rs | 1214 +++++--- src/message.rs | 78 + src/models.rs | 108 +- start_instruction | 6 + static/config.html | 226 ++ static/logs.html | 382 +++ static/shared-styles.css | 169 ++ static/shared.js | 252 ++ static/tokeninfo.html | 184 +- 41 files changed, 9626 insertions(+), 1215 deletions(-) create mode 100644 .gitattributes delete mode 100644 scripts/minify-html.js create mode 100644 scripts/minify.js delete mode 100644 scripts/setup-windows.ps1 create mode 100644 scripts/setup.ps1 create mode 100644 scripts/setup.sh create mode 100644 src/aiserver.rs create mode 100644 src/aiserver/v1.rs create mode 100644 src/aiserver/v1/aiserver.proto create mode 100644 src/app.rs create mode 100644 src/app/client.rs create mode 100644 src/app/constant.rs create mode 100644 src/app/models.rs create mode 100644 src/app/token.rs create mode 100644 src/app/utils.rs create mode 100644 src/chat.rs create mode 100644 src/chat/error.rs create mode 100644 src/chat/stream.rs create mode 100644 src/message.rs create mode 100644 start_instruction create mode 100644 static/config.html create mode 100644 static/logs.html create mode 100644 static/shared-styles.css create mode 100644 static/shared.js diff --git a/.env.example b/.env.example index ba48f78..a781392 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,36 @@ +# 当前配置为默认值,请根据需要修改 + +# 服务器监听端口 PORT=3000 + +# 路由前缀,必须以 / 开头(如果不为空) ROUTE_PREFIX= + +# 认证令牌,必填 AUTH_TOKEN= + +# 启用流式响应检查,关闭则无法响应错误,代价是会对第一个块解析2次 +ENABLE_STREAM_CHECK=true + +# 流式消息结束后发送包含"finish_reason"为"stop"的空消息块 +INCLUDE_STOP_REASON_STREAM=true + +# 令牌文件路径 TOKEN_FILE=.token + +# 令牌列表文件路径 TOKEN_LIST_FILE=.token-list + +# (实验性)是否启用慢速池(true/false) +ENABLE_SLOW_POOL=false + +# 允许claude开头的模型请求绕过内置模型限制(true/false) +PASS_ANY_CLAUDE=false + +# 图片处理能力配置 +# 可选值: +# - none 或 disabled:禁用图片功能 +# - base64 或 base64-only:仅支持 base64 编码的图片 +# - all 或 base64-http:支持 base64 和 HTTP 图片 +# 注意:启用 HTTP 支持可能会暴露服务器 IP +VISION_ABILITY=base64 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..e441e8e --- /dev/null +++ b/.gitattributes @@ -0,0 +1,6 @@ +# 统一使用 LF +* text=auto eol=lf + +# 对特定文件类型设置 +*.bat text eol=crlf +*.ps1 text eol=crlf \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ad596dc..d2868d7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,6 +1,7 @@ name: Build on: + workflow_dispatch: push: tags: - 'v*' @@ -28,7 +29,8 @@ jobs: with: node-version: '20' cache: 'npm' - cache-dependency-path: 'scripts/package.json' + cache-dependency-path: 'scripts/package-lock.json' + run: cd scripts && npm install && cd .. - name: Install Rust uses: dtolnay/rust-toolchain@stable @@ -44,10 +46,11 @@ jobs: protobuf-compiler \ pkg-config \ libssl-dev \ - openssl - - # 安装 npm 依赖 - cd scripts && npm install && cd .. + openssl \ + musl-tools \ + musl-dev \ + libssl-dev:native \ + linux-libc-dev:native # 设置 OpenSSL 环境变量 echo "OPENSSL_DIR=/usr" >> $GITHUB_ENV @@ -55,72 +58,21 @@ jobs: echo "OPENSSL_INCLUDE_DIR=/usr/include/openssl" >> $GITHUB_ENV echo "PKG_CONFIG_PATH=/usr/lib/x86_64-linux-gnu/pkgconfig" >> $GITHUB_ENV - # - name: Set up Docker Buildx - # if: runner.os == 'Linux' - # uses: docker/setup-buildx-action@v3.8.0 - - # - name: Build Linux arm64 - # if: runner.os == 'Linux' - # run: | - # # 启用 QEMU 支持 - # docker run --rm --privileged multiarch/qemu-user-static --reset -p yes - - # # 创建 Dockerfile - # cat > Dockerfile.arm64 << 'EOF' - # FROM arm64v8/ubuntu:22.04 - - # ENV DEBIAN_FRONTEND=noninteractive - - # RUN apt-get update && apt-get install -y \ - # build-essential \ - # curl \ - # pkg-config \ - # libssl-dev \ - # protobuf-compiler \ - # nodejs \ - # npm \ - # git \ - # && rm -rf /var/lib/apt/lists/* - - # # 安装 Rust - # RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y - # ENV PATH="/root/.cargo/bin:${PATH}" - - # WORKDIR /build - # COPY . . - - # # 安装 npm 依赖 - # RUN cd scripts && npm install && cd .. - - # # 构建动态链接版本 - # RUN cargo build --release - - # # 构建静态链接版本 - # RUN RUSTFLAGS="-C target-feature=+crt-static" cargo build --release - # EOF - - # # 构建 arm64 版本 - # docker buildx build --platform linux/arm64 -f Dockerfile.arm64 -t builder-arm64 . - - # # 创建临时容器 - # docker create --name temp-container builder-arm64 sh - - # # 复制动态链接版本 - # docker cp temp-container:/build/target/release/cursor-api ./release/cursor-api-aarch64-unknown-linux-gnu - - # # 复制静态链接版本 - # docker cp temp-container:/build/target/release/cursor-api ./release/cursor-api-static-aarch64-unknown-linux-gnu - - # # 清理临时容器 - # docker rm temp-container - - name: Build Linux x86_64 (Dynamic) if: runner.os == 'Linux' run: bash scripts/build.sh - name: Build Linux x86_64 (Static) if: runner.os == 'Linux' - run: bash scripts/build.sh --static + run: | + # 使用 musl 目标 + rustup target remove x86_64-unknown-linux-gnu + rustup target add x86_64-unknown-linux-musl + + # 设置静态编译环境变量 + export CC=musl-gcc + + bash scripts/build.sh --static - name: Install macOS dependencies if: runner.os == 'macOS' @@ -137,18 +89,30 @@ jobs: run: | choco install -y protoc choco install -y openssl - echo "OPENSSL_DIR=C:/Program Files/OpenSSL-Win64" >> $GITHUB_ENV - echo "PKG_CONFIG_PATH=C:/Program Files/OpenSSL-Win64/lib/pkgconfig" >> $GITHUB_ENV - cd scripts && npm install && cd .. + choco install -y nodejs-lts - - name: Build (Dynamic) - if: runner.os != 'Linux' && runner.os != 'FreeBSD' + # 刷新环境变量 + $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") + + # 设置 OpenSSL 环境变量 + echo "OPENSSL_DIR=C:\Program Files\OpenSSL" >> $env:GITHUB_ENV + echo "PKG_CONFIG_PATH=C:\Program Files\OpenSSL\lib\pkgconfig" >> $env:GITHUB_ENV + + - name: Build macOS (Dynamic) + if: runner.os == 'macOS' || runner.os == 'Windows' run: bash scripts/build.sh - - name: Build (Static) - if: runner.os != 'Linux' && runner.os != 'FreeBSD' + - name: Build macOS (Static) + if: runner.os == 'macOS' || runner.os == 'Windows' run: bash scripts/build.sh --static + # - name: Verify build artifacts + # run: | + # if [ ! -d "release" ] || [ -z "$(ls -A release)" ]; then + # echo "Error: No build artifacts found in release directory" + # exit 1 + # fi + - name: Upload artifacts uses: actions/upload-artifact@v4.5.0 with: @@ -184,7 +148,11 @@ jobs: bash \ gmake \ pkgconf \ - openssl + openssl \ + libressl-devel \ + libiconv \ + gettext-tools \ + gettext-runtime export SSL_CERT_FILE=/etc/ssl/cert.pem @@ -192,11 +160,8 @@ jobs: cd /root git clone $GITHUB_SERVER_URL/$GITHUB_REPOSITORY . - # 然后再进入 scripts 目录 - cd scripts && npm install && cd .. - # 安装 rustup 和 Rust - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain stable + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain nightly # 设置持久化的 Rust 环境变量 echo '. "$HOME/.cargo/env"' >> /root/.profile @@ -210,7 +175,6 @@ jobs: # 加载环境变量 . /root/.profile - # 构建 echo "构建动态链接版本..." /usr/local/bin/bash scripts/build.sh diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 251069a..d755a17 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -2,6 +2,12 @@ name: Docker Build and Push on: workflow_dispatch: + inputs: + update_latest: + description: '是否更新 latest 标签' + required: true + type: boolean + default: false push: tags: - 'v*' @@ -36,6 +42,7 @@ jobs: with: images: ${{ env.IMAGE_NAME }} tags: | + type=raw,value=latest,enable=${{ github.event_name == 'workflow_dispatch' && inputs.update_latest }} type=raw,value=${{ steps.cargo_version.outputs.version }},enable=${{ github.event_name == 'workflow_dispatch' }} type=ref,event=tag,enable=${{ github.event_name == 'push' }} @@ -44,12 +51,14 @@ jobs: with: driver-opts: | image=moby/buildkit:latest + network=host - name: Build and push Docker image uses: docker/build-push-action@v6.10.0 with: context: . push: true + platforms: linux/amd64,linux/arm64 tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha diff --git a/.gitignore b/.gitignore index b2a26ae..83c1229 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,10 @@ /get-token/target /*.log /*.env -/static/tokeninfo.min.html +/static/*.min.html +/static/*.min.css +/static/*.min.js +/scripts/.asset-hashes.json node_modules .DS_Store /.vscode @@ -12,3 +15,7 @@ node_modules /cursor-api /cursor-api.exe /release + +/static/readme.html +/*.py +/src/decoder.rs \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index ec146e1..69d9ea2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -159,6 +159,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.6.0" @@ -180,12 +186,24 @@ version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +[[package]] +name = "bytemuck" +version = "1.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" + [[package]] name = "byteorder" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + [[package]] name = "bytes" version = "1.9.0" @@ -194,9 +212,9 @@ checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" [[package]] name = "cc" -version = "1.2.5" +version = "1.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e" +checksum = "8d6dbb628b8f8555f86d0323c2eb39e3ec81901f4b83e091db8a6a76d316a333" dependencies = [ "shlex", ] @@ -222,6 +240,12 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + [[package]] name = "core-foundation" version = "0.9.4" @@ -268,7 +292,7 @@ dependencies = [ [[package]] name = "cursor-api" -version = "0.1.1" +version = "0.1.3-rc.1" dependencies = [ "axum", "base64", @@ -277,7 +301,10 @@ dependencies = [ "dotenvy", "flate2", "futures", + "gif", "hex", + "image", + "lazy_static", "prost", "prost-build", "rand", @@ -286,6 +313,7 @@ dependencies = [ "serde", "serde_json", "sha2", + "sysinfo", "tokio", "tokio-stream", "tower-http", @@ -356,6 +384,15 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + [[package]] name = "fixedbitset" version = "0.4.2" @@ -500,6 +537,16 @@ dependencies = [ "wasi", ] +[[package]] +name = "gif" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2" +dependencies = [ + "color_quant", + "weezl", +] + [[package]] name = "gimli" version = "0.31.1" @@ -673,7 +720,7 @@ dependencies = [ "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows-core", + "windows-core 0.52.0", ] [[package]] @@ -824,6 +871,33 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "image" +version = "0.25.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd6f44aed642f18953a158afeb30206f4d50da59fbc66ecb53c66488de73563b" +dependencies = [ + "bytemuck", + "byteorder-lite", + "color_quant", + "gif", + "image-webp", + "num-traits", + "png", + "zune-core", + "zune-jpeg", +] + +[[package]] +name = "image-webp" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e031e8e3d94711a9ccb5d6ea357439ef3dcbed361798bd4071dc4d9793fbe22f" +dependencies = [ + "byteorder-lite", + "quick-error", +] + [[package]] name = "indexmap" version = "2.7.0" @@ -865,6 +939,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.169" @@ -914,6 +994,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" dependencies = [ "adler2", + "simd-adler32", ] [[package]] @@ -950,6 +1031,15 @@ dependencies = [ "tempfile", ] +[[package]] +name = "ntapi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" +dependencies = [ + "winapi", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -980,7 +1070,7 @@ version = "0.10.68" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" dependencies = [ - "bitflags", + "bitflags 2.6.0", "cfg-if", "foreign-types", "libc", @@ -1052,6 +1142,19 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +[[package]] +name = "png" +version = "0.17.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + [[package]] name = "ppv-lite86" version = "0.2.20" @@ -1133,10 +1236,16 @@ dependencies = [ ] [[package]] -name = "quote" -version = "1.0.37" +name = "quick-error" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + +[[package]] +name = "quote" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -1202,9 +1311,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" -version = "0.12.9" +version = "0.12.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" +checksum = "7fe060fe50f524be480214aba758c71f99f90ee8c83c5a36b5e9e1d568eb4eb3" dependencies = [ "async-compression", "base64", @@ -1237,6 +1346,7 @@ dependencies = [ "tokio", "tokio-native-tls", "tokio-util", + "tower", "tower-service", "url", "wasm-bindgen", @@ -1273,7 +1383,7 @@ version = "0.38.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" dependencies = [ - "bitflags", + "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", @@ -1321,9 +1431,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" [[package]] name = "ryu" @@ -1346,7 +1456,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags", + "bitflags 2.6.0", "core-foundation", "core-foundation-sys", "libc", @@ -1365,18 +1475,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.216" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.216" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", @@ -1434,6 +1544,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + [[package]] name = "slab" version = "0.4.9" @@ -1479,9 +1595,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.91" +version = "2.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53cbcb5a243bd33b7858b1d7f4aca2153490815872d86d955d6ea29f743c035" +checksum = "70ae51629bf965c5c098cc9e87908a3df5301051a9e087d6f9bef5c9771ed126" dependencies = [ "proc-macro2", "quote", @@ -1508,13 +1624,26 @@ dependencies = [ "syn", ] +[[package]] +name = "sysinfo" +version = "0.33.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fc858248ea01b66f19d8e8a6d55f41deaf91e9d495246fd01368d99935c6c01" +dependencies = [ + "core-foundation-sys", + "libc", + "memchr", + "ntapi", + "windows", +] + [[package]] name = "system-configuration" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags", + "bitflags 2.6.0", "core-foundation", "system-configuration-sys", ] @@ -1645,7 +1774,7 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "403fa3b783d4b626a8ad51d766ab03cb6d2dbfc46b1c5d4448395e6628dc9697" dependencies = [ - "bitflags", + "bitflags 2.6.0", "bytes", "http", "pin-project-lite", @@ -1858,6 +1987,44 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "weezl" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" +dependencies = [ + "windows-core 0.57.0", + "windows-targets", +] + [[package]] name = "windows-core" version = "0.52.0" @@ -1867,17 +2034,60 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "windows-core" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-result 0.1.2", + "windows-targets", +] + +[[package]] +name = "windows-implement" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "windows-registry" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" dependencies = [ - "windows-result", + "windows-result 0.2.0", "windows-strings", "windows-targets", ] +[[package]] +name = "windows-result" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-result" version = "0.2.0" @@ -1893,7 +2103,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ - "windows-result", + "windows-result 0.2.0", "windows-targets", ] @@ -2084,3 +2294,18 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zune-core" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" + +[[package]] +name = "zune-jpeg" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99a5bab8d7dedf81405c4bb1f2b83ea057643d9cb28778cea9eecddeedd2e028" +dependencies = [ + "zune-core", +] diff --git a/Cargo.toml b/Cargo.toml index 9847e92..561a7c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,28 +1,39 @@ [package] name = "cursor-api" -version = "0.1.1" +version = "0.1.3-rc.1" edition = "2021" authors = ["wisdgod "] +# license = "MIT" +# copyright = "Copyright (c) 2024 wisdgod" +description = "OpenAI format compatibility layer for the Cursor API" +repository = "https://github.com/wisdgod/cursor-api" [build-dependencies] prost-build = "0.13.4" +sha2 = { version = "0.10.8", default-features = false } +serde_json = "1.0.134" [dependencies] axum = { version = "0.7.9", features = ["json"] } base64 = { version = "0.22.1", default-features = false, features = ["std"] } +# brotli = { version = "7.0.0", default-features = false, features = ["std"] } bytes = "1.9.0" chrono = { version = "0.4.39", features = ["serde"] } dotenvy = "0.15.7" flate2 = { version = "1.0.35", default-features = false, features = ["rust_backend"] } futures = { version = "0.3.31", default-features = false, features = ["std"] } +gif = { version = "0.13.1", default-features = false, features = ["std"] } hex = { version = "0.4.3", default-features = false, features = ["std"] } +image = { version = "0.25.5", default-features = false, features = ["jpeg", "png", "gif", "webp"] } +lazy_static = "1.5.0" prost = "0.13.4" rand = { version = "0.8.5", default-features = false, features = ["std", "std_rng"] } regex = { version = "1.11.1", default-features = false, features = ["std", "perf"] } -reqwest = { version = "0.12.9", features = ["json", "gzip", "stream"] } -serde = { version = "1.0.216", features = ["derive"] } -serde_json = { version = "1.0.134", features = ["std"] } +reqwest = { version = "0.12.11", default-features = false, features = ["gzip", "json", "stream", "__tls", "charset", "default-tls", "h2", "http2", "macos-system-configuration"] } +serde = { version = "1.0.217", default-features = false, features = ["std", "derive"] } +serde_json = "1.0.134" sha2 = { version = "0.10.8", default-features = false } +sysinfo = { version = "0.33.1", default-features = false, features = ["system"] } tokio = { version = "1.42.0", features = ["rt-multi-thread", "macros", "net", "sync", "time"] } tokio-stream = { version = "0.1.17", features = ["time"] } tower-http = { version = "0.6.2", features = ["cors"] } diff --git a/Dockerfile b/Dockerfile index 6691f24..047ef11 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,48 +1,47 @@ -# 构建阶段 -FROM rust:1.83.0-slim-bookworm as builder - +# AMD64 构建阶段 +FROM --platform=linux/amd64 rust:1.83.0-slim-bookworm as builder-amd64 WORKDIR /app - -# 安装构建依赖 RUN apt-get update && \ apt-get install -y --no-install-recommends \ - build-essential \ - protobuf-compiler \ - pkg-config \ - libssl-dev \ - nodejs \ - npm \ + build-essential protobuf-compiler pkg-config libssl-dev nodejs npm \ && rm -rf /var/lib/apt/lists/* - -# 复制项目文件 COPY . . +RUN cargo build --release && \ + cp target/release/cursor-api /app/cursor-api -# 构建 -RUN rustup target add x86_64-unknown-linux-gnu && \ - cargo build --target x86_64-unknown-linux-gnu --release && \ - cp target/x86_64-unknown-linux-gnu/release/cursor-api /app/cursor-api - -# 运行阶段 -FROM debian:bookworm-slim - +# ARM64 构建阶段 +FROM --platform=linux/arm64 rust:1.83.0-slim-bookworm as builder-arm64 WORKDIR /app - -ENV TZ=Asia/Shanghai - -# 安装运行时依赖 RUN apt-get update && \ apt-get install -y --no-install-recommends \ - ca-certificates \ - tzdata \ + build-essential protobuf-compiler pkg-config libssl-dev nodejs npm \ && rm -rf /var/lib/apt/lists/* +COPY . . +RUN cargo build --release && \ + cp target/release/cursor-api /app/cursor-api -# 复制构建产物 -COPY --from=builder /app/cursor-api . +# AMD64 运行阶段 +FROM --platform=linux/amd64 debian:bookworm-slim as run-amd64 +WORKDIR /app +ENV TZ=Asia/Shanghai +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + ca-certificates tzdata \ + && rm -rf /var/lib/apt/lists/* +COPY --from=builder-amd64 /app/cursor-api . -# 设置默认端口 +# ARM64 运行阶段 +FROM --platform=linux/arm64 debian:bookworm-slim as run-arm64 +WORKDIR /app +ENV TZ=Asia/Shanghai +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + ca-certificates tzdata \ + && rm -rf /var/lib/apt/lists/* +COPY --from=builder-arm64 /app/cursor-api . + +# 通用配置 +FROM run-${TARGETARCH} ENV PORT=3000 - -# 动态暴露端口 EXPOSE ${PORT} - CMD ["./cursor-api"] \ No newline at end of file diff --git a/README.md b/README.md index 8591cf5..0faa06b 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ 1. 访问 [www.cursor.com](https://www.cursor.com) 并完成注册登录(赠送 250 次快速响应,可通过删除账号再注册重置) 2. 在浏览器中打开开发者工具(F12) -3. 找到 Application-Cookies 中名为 `WorkosCursorSessionToken` 的值并保存(相当于 openai 的密钥) +3. 找到 Application-Cookies 中名为 `WorkosCursorSessionToken` 的值并复制其第3个字段,%3A%3A是::的编码,cookie用:分隔值 ## 接口说明 @@ -74,7 +74,9 @@ 1. `.token` 文件:每行一个token,支持以下格式: ``` + # 这是注释 token1 + # alias与标签的作用差不多 alias::token2 ``` @@ -84,8 +86,10 @@ 2. `.token-list` 文件:每行为token和checksum的对应关系: ``` + # 这里的#表示这行在下次读取要删除 token1,checksum1 - token2,checksum2 + # 支持像.token一样的alias,冲突时以.token为准 + alias::token2,checksum2 ``` 该文件可以被自动管理,但用户仅可在确认自己拥有修改能力时修改,一般仅有以下情况需要手动修改: @@ -97,17 +101,19 @@ 写死了,后续也不会会支持自定义模型列表 ``` -cursor-small +claude-3.5-sonnet +gpt-4 +gpt-4o claude-3-opus cursor-fast +cursor-small +gpt-3.5 gpt-3.5-turbo gpt-4-turbo-2024-04-09 -gpt-4 gpt-4o-128k gemini-1.5-flash-500k claude-3-haiku-200k claude-3-5-sonnet-200k -claude-3-5-sonnet-20240620 claude-3-5-sonnet-20241022 gpt-4o-mini o1-mini @@ -121,30 +127,6 @@ gemini-2.0-flash-exp ## 部署 -### 本地部署 - -#### 从源码编译 - -需要安装 Rust 工具链和依赖: - -```bash -# 安装rust -curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh - -# 安装依赖(Debian/Ubuntu) -apt-get install -y build-essential protobuf-compiler pkg-config libssl-dev nodejs npm - -# 原生编译 -cargo build --release - -# 交叉编译,以x86_64-unknown-linux-gnu为例,老实说,这也算原生编译,因为使用了docker -cross build --target x86_64-unknown-linux-gnu --release -``` - -#### 使用预编译二进制 - -从 [Releases](https://github.com/wisdgod/cursor-api/releases) 下载对应平台的二进制文件。 - ### Docker 部署 #### Docker 运行示例 @@ -153,13 +135,6 @@ cross build --target x86_64-unknown-linux-gnu --release docker run -d -e PORT=3000 -e AUTH_TOKEN=your_token -p 3000:3000 wisdgod/cursor-api:latest ``` -#### Docker 构建示例 - -```bash -docker build -t cursor-api . -docker run -p 3000:3000 cursor-api -``` - ### huggingface部署 前提:一个huggingface账号 @@ -190,6 +165,8 @@ docker run -p 3000:3000 cursor-api TOKEN_LIST_FILE=.token-list ``` + 更多变量示例可访问 /env-example + 3. 重新部署 点击`Factory rebuild`,等待部署完成 @@ -210,15 +187,7 @@ docker run -p 3000:3000 cursor-api ### 跨平台编译 -使用提供的构建脚本: - -```bash -# 仅编译当前平台 -./scripts/build.sh - -# 交叉编译所有支持的平台 -./scripts/build.sh --cross -``` +自行配置cross编译环境 支持的平台: diff --git a/build.rs b/build.rs index 5931ce8..f9d3469 100644 --- a/build.rs +++ b/build.rs @@ -1,15 +1,19 @@ +use sha2::{Digest, Sha256}; +use std::collections::HashMap; +use std::fs; use std::io::Result; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::process::Command; +// 支持的文件类型 +const SUPPORTED_EXTENSIONS: [&str; 3] = ["html", "js", "css"]; + fn check_and_install_deps() -> Result<()> { let scripts_dir = Path::new("scripts"); let node_modules = scripts_dir.join("node_modules"); - // 如果 node_modules 不存在,运行 npm install if !node_modules.exists() { - println!("cargo:warning=Installing HTML minifier dependencies..."); - + println!("cargo:warning=Installing minifier dependencies..."); let status = Command::new("npm") .current_dir(scripts_dir) .arg("install") @@ -23,38 +27,139 @@ fn check_and_install_deps() -> Result<()> { Ok(()) } -fn minify_html() -> Result<()> { - println!("cargo:warning=Minifying HTML files..."); +fn get_files_hash() -> Result> { + let mut file_hashes = HashMap::new(); + let static_dir = Path::new("static"); + if static_dir.exists() { + for entry in fs::read_dir(static_dir)? { + let entry = entry?; + let path = entry.path(); + + // 检查是否是支持的文件类型,且不是已经压缩的文件 + if let Some(ext) = path.extension().and_then(|e| e.to_str()) { + if SUPPORTED_EXTENSIONS.contains(&ext) && !path.to_string_lossy().contains(".min.") + { + let content = fs::read(&path)?; + let mut hasher = Sha256::new(); + hasher.update(&content); + let hash = format!("{:x}", hasher.finalize()); + file_hashes.insert(path, hash); + } + } + } + } + + Ok(file_hashes) +} + +fn load_saved_hashes() -> Result> { + let hash_file = Path::new("scripts/.asset-hashes.json"); + if hash_file.exists() { + let content = fs::read_to_string(hash_file)?; + let hash_map: HashMap = serde_json::from_str(&content)?; + Ok(hash_map + .into_iter() + .map(|(k, v)| (PathBuf::from(k), v)) + .collect()) + } else { + Ok(HashMap::new()) + } +} + +fn save_hashes(hashes: &HashMap) -> Result<()> { + let hash_file = Path::new("scripts/.asset-hashes.json"); + let string_map: HashMap = hashes + .iter() + .map(|(k, v)| (k.to_string_lossy().into_owned(), v.clone())) + .collect(); + let content = serde_json::to_string_pretty(&string_map)?; + fs::write(hash_file, content)?; + Ok(()) +} + +fn minify_assets() -> Result<()> { + // 获取现有文件的哈希 + let current_hashes = get_files_hash()?; + + if current_hashes.is_empty() { + println!("cargo:warning=No files to minify"); + return Ok(()); + } + + // 加载保存的哈希值 + let saved_hashes = load_saved_hashes()?; + + // 找出需要更新的文件 + let files_to_update: Vec<_> = current_hashes + .iter() + .filter(|(path, current_hash)| { + let ext = path.extension().and_then(|e| e.to_str()).unwrap_or(""); + let min_path = path.with_file_name(format!( + "{}.min.{}", + path.file_stem().unwrap().to_string_lossy(), + ext + )); + + // 检查压缩后的文件是否存在 + if !min_path.exists() { + return true; + } + + // 检查原始文件是否发生变化 + saved_hashes + .get(*path) + .map_or(true, |saved_hash| saved_hash != *current_hash) + }) + .map(|(path, _)| path.file_name().unwrap().to_string_lossy().into_owned()) + .collect(); + + if files_to_update.is_empty() { + println!("cargo:warning=No files need to be updated"); + return Ok(()); + } + + println!("cargo:warning=Minifying {} files...", files_to_update.len()); + + // 运行压缩脚本 let status = Command::new("node") - .args(&["scripts/minify-html.js"]) + .arg("scripts/minify.js") + .args(&files_to_update) .status()?; if !status.success() { - panic!("HTML minification failed"); + panic!("Asset minification failed"); } + + // 保存新的哈希值 + save_hashes(¤t_hashes)?; + Ok(()) } fn main() -> Result<()> { // Proto 文件处理 - println!("cargo:rerun-if-changed=src/message.proto"); + println!("cargo:rerun-if-changed=src/aiserver/v1/aiserver.proto"); let mut config = prost_build::Config::new(); - config.type_attribute(".", "#[derive(serde::Serialize, serde::Deserialize)]"); + // config.type_attribute(".", "#[derive(serde::Serialize, serde::Deserialize)]"); + // config.type_attribute( + // "aiserver.v1.ThrowErrorCheckRequest", + // "#[derive(serde::Serialize, serde::Deserialize)]" + // ); config - .compile_protos(&["src/message.proto"], &["src/"]) + .compile_protos(&["src/aiserver/v1/aiserver.proto"], &["src/aiserver/v1/"]) .unwrap(); - // HTML 文件处理 - println!("cargo:rerun-if-changed=static/tokeninfo.html"); - println!("cargo:rerun-if-changed=scripts/minify-html.js"); + // 静态资源文件处理 + println!("cargo:rerun-if-changed=scripts/minify.js"); println!("cargo:rerun-if-changed=scripts/package.json"); + println!("cargo:rerun-if-changed=static"); // 检查并安装依赖 check_and_install_deps()?; - // 运行 HTML 压缩 - minify_html()?; + // 运行资源压缩 + minify_assets()?; Ok(()) } diff --git a/scripts/build.ps1 b/scripts/build.ps1 index 06840e0..0b9105f 100644 --- a/scripts/build.ps1 +++ b/scripts/build.ps1 @@ -1,158 +1,126 @@ -# ɫ -function Write-Info { Write-Host "[INFO] $args" -ForegroundColor Blue } -function Write-Warn { Write-Host "[WARN] $args" -ForegroundColor Yellow } -function Write-Error { Write-Host "[ERROR] $args" -ForegroundColor Red; exit 1 } +# 参数处理 +param( + [switch]$Static, + [switch]$Help, + [ValidateSet("x86_64", "aarch64", "i686")] + [string]$Architecture +) -# ҪĹ -function Test-Requirements { - $tools = @("cargo", "protoc", "npm", "node") - $missing = @() +# 设置错误时停止执行 +$ErrorActionPreference = "Stop" - foreach ($tool in $tools) { - if (!(Get-Command $tool -ErrorAction SilentlyContinue)) { - $missing += $tool - } - } +# 颜色输出函数 +function Write-Info { param($Message) Write-Host "[INFO] $Message" -ForegroundColor Blue } +function Write-Warn { param($Message) Write-Host "[WARN] $Message" -ForegroundColor Yellow } +function Write-Error { param($Message) Write-Host "[ERROR] $Message" -ForegroundColor Red; exit 1 } - if ($missing.Count -gt 0) { - Write-Error "ȱٱҪ: $($missing -join ', ')" - } -} +# 检查必要的工具 +function Check-Requirements { + $tools = @("cargo", "protoc", "npm", "node") + $missing = @() -# Test-Requirements º -function Initialize-VSEnvironment { - Write-Info "ڳʼ Visual Studio ..." - - # ֱʹ֪ vcvarsall.bat · - $vcvarsallPath = "E:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" - - if (-not (Test-Path $vcvarsallPath)) { - Write-Error "δҵ vcvarsall.bat: $vcvarsallPath" - return - } - - Write-Info "ʹ vcvarsall.bat ·: $vcvarsallPath" - - # ȡ - $archArg = "x64" - $command = "`"$vcvarsallPath`" $archArg && set" - - try { - $output = cmd /c "$command" 2>&1 - - # Ƿɹִ - if ($LASTEXITCODE -ne 0) { - Write-Error "vcvarsall.bat ִʧܣ˳: $LASTEXITCODE" - return + foreach ($tool in $tools) { + if (-not (Get-Command $tool -ErrorAction SilentlyContinue)) { + $missing += $tool } - - # µǰ PowerShell ỰĻ - foreach ($line in $output) { - if ($line -match "^([^=]+)=(.*)$") { - $name = $matches[1] - $value = $matches[2] - if (![string]::IsNullOrEmpty($name)) { - Set-Item -Path "env:$name" -Value $value -ErrorAction SilentlyContinue - } - } - } - - Write-Info "Visual Studio ʼ" } - catch { - Write-Error "ʼ Visual Studio ʱ: $_" + + if ($missing.Count -gt 0) { + Write-Error "缺少必要工具: $($missing -join ', ')" } } -# Ϣ +# 帮助信息 function Show-Help { - Write-Host @" -÷: $(Split-Path $MyInvocation.MyCommand.Path -Leaf) [ѡ] + Write-Host @" +用法: $(Split-Path $MyInvocation.ScriptName -Leaf) [选项] -ѡ: - --static ʹþ̬ӣĬ϶̬ӣ - --help ʾ˰Ϣ +选项: + -Static 使用静态链接(默认动态链接) + -Help 显示此帮助信息 -Ĭϱ Windows ֵ֧ļܹ (x64 arm64) +不带参数时使用默认配置构建 "@ } -# -function New-Target { - param ( - [string]$target, - [string]$rustflags - ) +# 构建函数 +function Build-Target { + param ( + [string]$Target, + [string]$RustFlags + ) - Write-Info "ڹ $target..." + Write-Info "正在构建 $Target..." - # ûִй - $env:RUSTFLAGS = $rustflags - cargo build --target $target --release + # 设置环境变量 + $env:RUSTFLAGS = $RustFlags - # ƶ - $binaryName = "cursor-api" - if ($UseStatic) { - $binaryName += "-static" - } + # 构建 + if ($Target -ne (rustc -Vv | Select-String "host: (.*)" | ForEach-Object { $_.Matches.Groups[1].Value })) { + cargo build --target $Target --release + } else { + cargo build --release + } - $sourcePath = "target/$target/release/cursor-api.exe" - $targetPath = "release/${binaryName}-${target}.exe" + # 移动编译产物到 release 目录 + $binaryName = "cursor-api" + if ($Static) { + $binaryName += "-static" + } - if (Test-Path $sourcePath) { - Copy-Item $sourcePath $targetPath -Force - Write-Info "ɹ $target" - } - else { - Write-Warn "δҵ: $target" - return $false - } - return $true + $binaryPath = if ($Target -eq (rustc -Vv | Select-String "host: (.*)" | ForEach-Object { $_.Matches.Groups[1].Value })) { + "target/release/cursor-api.exe" + } else { + "target/$Target/release/cursor-api.exe" + } + + if (Test-Path $binaryPath) { + Copy-Item $binaryPath "release/$binaryName-$Target.exe" + Write-Info "完成构建 $Target" + } else { + Write-Warn "构建产物未找到: $Target" + Write-Warn "查找路径: $binaryPath" + Write-Warn "当前目录内容:" + Get-ChildItem -Recurse target/ + return $false + } + + return $true } -# -$UseStatic = $false - -foreach ($arg in $args) { - switch ($arg) { - "--static" { $UseStatic = $true } - "--help" { Show-Help; exit 0 } - default { Write-Error "δ֪: $arg" } - } +if ($Help) { + Show-Help + exit 0 } -# -try { - # - Test-Requirements +# 检查依赖 +Check-Requirements - # ʼ Visual Studio - Initialize-VSEnvironment +# 创建 release 目录 +New-Item -ItemType Directory -Force -Path release | Out-Null - # release Ŀ¼ - New-Item -ItemType Directory -Force -Path "release" | Out-Null - - # Ŀƽ̨ - $targets = @( - "x86_64-pc-windows-msvc", - "aarch64-pc-windows-msvc" - ) - - # þ̬ӱ־ - $rustflags = "" - if ($UseStatic) { - $rustflags = "-C target-feature=+crt-static" - } - - Write-Info "ʼ..." - - # Ŀ - foreach ($target in $targets) { - New-Target -target $target -rustflags $rustflags - } - - Write-Info "ɣ" +# 设置静态链接标志 +$rustFlags = "" +if ($Static) { + $rustFlags = "-C target-feature=+crt-static" } -catch { - Write-Error "з: $_" -} \ No newline at end of file + +# 获取目标架构 +$arch = if ($Architecture) { + $Architecture +} else { + switch ($env:PROCESSOR_ARCHITECTURE) { + "AMD64" { "x86_64" } + "ARM64" { "aarch64" } + "X86" { "i686" } + default { Write-Error "不支持的架构: $env:PROCESSOR_ARCHITECTURE" } + } +} +$target = "$arch-pc-windows-msvc" + +Write-Info "开始构建..." +if (-not (Build-Target -Target $target -RustFlags $rustFlags)) { + Write-Error "构建失败" +} + +Write-Info "构建完成!" \ No newline at end of file diff --git a/scripts/build.sh b/scripts/build.sh index c310861..3eb2308 100644 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -6,11 +6,6 @@ info() { echo -e "\033[1;34m[INFO]\033[0m $*"; } warn() { echo -e "\033[1;33m[WARN]\033[0m $*"; } error() { echo -e "\033[1;31m[ERROR]\033[0m $*" >&2; exit 1; } -# 检查是否在 Linux 环境 -is_linux() { - [ "$(uname -s)" = "Linux" ] -} - # 检查必要的工具 check_requirements() { local missing_tools=() @@ -22,23 +17,29 @@ check_requirements() { fi done - # cross 工具检查(仅在 Linux 上需要) - if [[ "$OS" == "Linux" ]] && ! command -v cross &>/dev/null; then - missing_tools+=("cross") - fi - if [[ ${#missing_tools[@]} -gt 0 ]]; then error "缺少必要工具: ${missing_tools[*]}" fi } +# 解析参数 +USE_STATIC=false + +while [[ $# -gt 0 ]]; do + case $1 in + --static) USE_STATIC=true ;; + --help) show_help; exit 0 ;; + *) error "未知参数: $1" ;; + esac + shift +done + # 帮助信息 show_help() { cat << EOF 用法: $(basename "$0") [选项] 选项: - --cross 使用 cross 进行交叉编译(仅在 Linux 上有效) --static 使用静态链接(默认动态链接) --help 显示此帮助信息 @@ -46,22 +47,6 @@ show_help() { EOF } -# 判断是否使用 cross -should_use_cross() { - local target=$1 - # 如果不是 Linux 环境,直接返回 false - if [[ "$OS" != "Linux" ]]; then - return 1 - fi - - # 在 Linux 环境下,以下目标不使用 cross: - # 1. Linux 上的 x86_64-unknown-linux-gnu - if [[ "$target" == "x86_64-unknown-linux-gnu" ]]; then - return 1 - fi - return 0 -} - # 并行构建函数 build_target() { local target=$1 @@ -73,15 +58,11 @@ build_target() { # 确定文件后缀 [[ $target == *"windows"* ]] && extension=".exe" - # 判断是否使用 cross - if should_use_cross "$target"; then - env RUSTFLAGS="$rustflags" cross build --target "$target" --release + # 构建 + if [[ $target != "$CURRENT_TARGET" ]]; then + env RUSTFLAGS="$rustflags" cargo build --target "$target" --release else - if [[ $target != "$CURRENT_TARGET" ]]; then - env RUSTFLAGS="$rustflags" cargo build --target "$target" --release - else - env RUSTFLAGS="$rustflags" cargo build --release - fi + env RUSTFLAGS="$rustflags" cargo build --release fi # 移动编译产物到 release 目录 @@ -117,7 +98,13 @@ get_target() { local os=$2 case "$os" in "Darwin") echo "${arch}-apple-darwin" ;; - "Linux") echo "${arch}-unknown-linux-gnu" ;; + "Linux") + if [[ $USE_STATIC == true ]]; then + echo "${arch}-unknown-linux-musl" + else + echo "${arch}-unknown-linux-gnu" + fi + ;; "MINGW"*|"MSYS"*|"CYGWIN"*|"Windows_NT") echo "${arch}-pc-windows-msvc" ;; "FreeBSD") echo "${arch}-unknown-freebsd" ;; *) error "不支持的系统: $os" ;; @@ -134,16 +121,16 @@ CURRENT_TARGET=$(get_target "$ARCH" "$OS") get_targets() { case "$1" in "linux") - # Linux 构建所有 Linux 目标和 FreeBSD 目标 - echo "x86_64-unknown-linux-gnu x86_64-unknown-freebsd" + # Linux 只构建当前架构 + echo "$CURRENT_TARGET" ;; "freebsd") - # FreeBSD 只构建当前架构的 FreeBSD 目标 - echo "${ARCH}-unknown-freebsd" + # FreeBSD 只构建当前架构 + echo "$CURRENT_TARGET" ;; "windows") - # Windows 构建所有 Windows 目标 - echo "x86_64-pc-windows-msvc" + # Windows 只构建当前架构 + echo "$CURRENT_TARGET" ;; "macos") # macOS 构建所有 macOS 目标 @@ -153,33 +140,21 @@ get_targets() { esac } -# 解析参数 -USE_STATIC=false - -while [[ $# -gt 0 ]]; do - case $1 in - --static) USE_STATIC=true ;; - --help) show_help; exit 0 ;; - *) error "未知参数: $1" ;; - esac - shift -done - # 检查依赖 check_requirements # 确定要构建的目标 case "$OS" in - "Darwin") + Darwin) TARGETS=($(get_targets "macos")) ;; - "Linux") + Linux) TARGETS=($(get_targets "linux")) ;; - "FreeBSD") + FreeBSD) TARGETS=($(get_targets "freebsd")) ;; - "MINGW"*|"MSYS"*|"CYGWIN"*|"Windows_NT") + MINGW*|MSYS*|CYGWIN*|Windows_NT) TARGETS=($(get_targets "windows")) ;; *) error "不支持的系统: $OS" ;; @@ -189,8 +164,8 @@ esac mkdir -p release # 设置静态链接标志 -RUSTFLAGS="" -[[ $USE_STATIC == true ]] && RUSTFLAGS="-C target-feature=+crt-static" +RUSTFLAGS="-C link-arg=-s" +[[ $USE_STATIC == true ]] && RUSTFLAGS="-C target-feature=+crt-static -C link-arg=-s" # 并行构建所有目标 info "开始构建..." diff --git a/scripts/minify-html.js b/scripts/minify-html.js deleted file mode 100644 index dcf17fa..0000000 --- a/scripts/minify-html.js +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env node - -const { minify } = require('html-minifier-terser'); -const fs = require('fs'); -const path = require('path'); - -// 配置选项 -const options = { - collapseWhitespace: true, - removeComments: true, - removeEmptyAttributes: true, - removeOptionalTags: true, - removeRedundantAttributes: true, - removeScriptTypeAttributes: true, - removeStyleLinkTypeAttributes: true, - minifyCSS: true, - minifyJS: true, - processScripts: ['application/json'], -}; - -// 处理文件 -async function minifyFile(inputPath, outputPath) { - try { - const html = fs.readFileSync(inputPath, 'utf8'); - const minified = await minify(html, options); - fs.writeFileSync(outputPath, minified); - console.log(`✓ Minified ${path.basename(inputPath)} -> ${path.basename(outputPath)}`); - } catch (err) { - console.error(`✗ Error processing ${inputPath}:`, err); - process.exit(1); - } -} - -// 主函数 -async function main() { - const staticDir = path.join(__dirname, '..', 'static'); - const files = [ - ['tokeninfo.html', 'tokeninfo.min.html'], - ]; - - for (const [input, output] of files) { - await minifyFile( - path.join(staticDir, input), - path.join(staticDir, output) - ); - } -} - -main(); \ No newline at end of file diff --git a/scripts/minify.js b/scripts/minify.js new file mode 100644 index 0000000..e4c1ed6 --- /dev/null +++ b/scripts/minify.js @@ -0,0 +1,81 @@ +#!/usr/bin/env node + +const { minify: minifyHtml } = require('html-minifier-terser'); +const { minify: minifyJs } = require('terser'); +const CleanCSS = require('clean-css'); +const fs = require('fs'); +const path = require('path'); + +// 配置选项 +const options = { + collapseWhitespace: true, + removeComments: true, + removeEmptyAttributes: true, + removeOptionalTags: true, + removeRedundantAttributes: true, + removeScriptTypeAttributes: true, + removeStyleLinkTypeAttributes: true, + minifyCSS: true, + minifyJS: true, + processScripts: ['application/json'], +}; + +// CSS 压缩选项 +const cssOptions = { + level: 2 +}; + +// 处理文件 +async function minifyFile(inputPath, outputPath) { + try { + const ext = path.extname(inputPath).toLowerCase(); + const content = fs.readFileSync(inputPath, 'utf8'); + let minified; + + switch (ext) { + case '.html': + minified = await minifyHtml(content, options); + break; + case '.js': + const result = await minifyJs(content); + minified = result.code; + break; + case '.css': + minified = new CleanCSS(cssOptions).minify(content).styles; + break; + default: + throw new Error(`Unsupported file type: ${ext}`); + } + + fs.writeFileSync(outputPath, minified); + console.log(`✓ Minified ${path.basename(inputPath)} -> ${path.basename(outputPath)}`); + } catch (err) { + console.error(`✗ Error processing ${inputPath}:`, err); + process.exit(1); + } +} + +// 主函数 +async function main() { + // 获取命令行参数,跳过前两个参数(node和脚本路径) + const files = process.argv.slice(2); + + if (files.length === 0) { + console.error('No input files specified'); + process.exit(1); + } + + const staticDir = path.join(__dirname, '..', 'static'); + + for (const file of files) { + const inputPath = path.join(staticDir, file); + const ext = path.extname(file); + const outputPath = path.join( + staticDir, + file.replace(ext, `.min${ext}`) + ); + await minifyFile(inputPath, outputPath); + } +} + +main(); \ No newline at end of file diff --git a/scripts/package-lock.json b/scripts/package-lock.json index b7fec75..82715b0 100644 --- a/scripts/package-lock.json +++ b/scripts/package-lock.json @@ -8,7 +8,9 @@ "name": "html-minifier-scripts", "version": "1.0.0", "dependencies": { - "html-minifier-terser": "^7.2.0" + "clean-css": "^5.3.3", + "html-minifier-terser": "^7.2.0", + "terser": "^5.37.0" }, "engines": { "node": ">=14.0.0" diff --git a/scripts/package.json b/scripts/package.json index 7d41d23..c1c08da 100644 --- a/scripts/package.json +++ b/scripts/package.json @@ -6,6 +6,8 @@ "node": ">=14.0.0" }, "dependencies": { - "html-minifier-terser": "^7.2.0" + "clean-css": "^5.3.3", + "html-minifier-terser": "^7.2.0", + "terser": "^5.37.0" } -} \ No newline at end of file +} diff --git a/scripts/setup-windows.ps1 b/scripts/setup-windows.ps1 deleted file mode 100644 index b4ff0de..0000000 --- a/scripts/setup-windows.ps1 +++ /dev/null @@ -1,31 +0,0 @@ -# PowerShell Ϊ UTF-8 -[Console]::OutputEncoding = [System.Text.Encoding]::UTF8 -$OutputEncoding = [System.Text.Encoding]::UTF8 - -# ǷԹԱȨ -if (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { - Write-Warning "ԹԱȨд˽ű" - exit 1 -} - -# 鲢װ Chocolatey -if (!(Get-Command choco -ErrorAction SilentlyContinue)) { - Write-Output "ڰװ Chocolatey..." - Set-ExecutionPolicy Bypass -Scope Process -Force - [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072 - iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1')) -} - -# װҪĹ -Write-Output "ڰװҪĹ..." -choco install -y mingw -choco install -y protoc -choco install -y git - -# װ Rust -Write-Output "ڰװ Rust ..." -rustup target add x86_64-pc-windows-msvc -rustup target add x86_64-unknown-linux-gnu -cargo install cross - -Write-Output "װɣ" \ No newline at end of file diff --git a/scripts/setup.ps1 b/scripts/setup.ps1 new file mode 100644 index 0000000..3687fda --- /dev/null +++ b/scripts/setup.ps1 @@ -0,0 +1,179 @@ +# ôʱִֹͣ +$ErrorActionPreference = "Stop" +$ProgressPreference = "SilentlyContinue" # ӿٶ + +# ɫ +function Write-Info { param($Message) Write-Host "[INFO] $Message" -ForegroundColor Blue } +function Write-Warn { param($Message) Write-Host "[WARN] $Message" -ForegroundColor Yellow } +function Write-Success { param($Message) Write-Host "[SUCCESS] $Message" -ForegroundColor Green } +function Write-Error { param($Message) Write-Host "[ERROR] $Message" -ForegroundColor Red; exit 1 } + +# ԱȨ +function Test-Administrator { + $user = [Security.Principal.WindowsIdentity]::GetCurrent() + $principal = New-Object Security.Principal.WindowsPrincipal $user + return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) +} + +if (-not (Test-Administrator)) { + Write-Error "ԹԱȨд˽ű" +} + +# Ϣ +function Show-Help { + Write-Host @" +÷: $(Split-Path $MyInvocation.ScriptName -Leaf) [ѡ] + +ѡ: + -NoVS װ Visual Studio Build Tools + -NoRust װ Rust + -NoNode װ Node.js + -Help ʾ˰Ϣ + +ʾ: + .\setup.ps1 + .\setup.ps1 -NoVS + .\setup.ps1 -NoRust -NoNode +"@ +} + +# +param( + [switch]$NoVS, + [switch]$NoRust, + [switch]$NoNode, + [switch]$Help +) + +if ($Help) { + Show-Help + exit 0 +} + +# 鲢װ Chocolatey +function Install-Chocolatey { + Write-Info " Chocolatey..." + if (-not (Get-Command choco -ErrorAction SilentlyContinue)) { + Write-Info "װ Chocolatey..." + Set-ExecutionPolicy Bypass -Scope Process -Force + [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072 + try { + Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1')) + } + catch { + Write-Error "װ Chocolatey ʧ: $_" + } + # ˢ» + $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") + } +} + +# װ Visual Studio Build Tools +function Install-VSBuildTools { + if ($NoVS) { + Write-Info " Visual Studio Build Tools װ" + return + } + + Write-Info " Visual Studio Build Tools..." + $vsPath = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" + if (-not (Test-Path $vsPath)) { + Write-Info "װ Visual Studio Build Tools..." + try { + # ذװ + $vsInstallerUrl = "https://aka.ms/vs/17/release/vs_BuildTools.exe" + $vsInstallerPath = "$env:TEMP\vs_BuildTools.exe" + Invoke-WebRequest -Uri $vsInstallerUrl -OutFile $vsInstallerPath + + # װ + $process = Start-Process -FilePath $vsInstallerPath -ArgumentList ` + "--quiet", "--wait", "--norestart", "--nocache", ` + "--installPath", "${env:ProgramFiles(x86)}\Microsoft Visual Studio\2022\BuildTools", ` + "--add", "Microsoft.VisualStudio.Workload.VCTools" ` + -NoNewWindow -Wait -PassThru + + if ($process.ExitCode -ne 0) { + Write-Error "Visual Studio Build Tools װʧ" + } + + Remove-Item $vsInstallerPath -Force + } + catch { + Write-Error "װ Visual Studio Build Tools ʧ: $_" + } + } + else { + Write-Info "Visual Studio Build Tools Ѱװ" + } +} + +# װ Rust +function Install-Rust { + if ($NoRust) { + Write-Info " Rust װ" + return + } + + Write-Info " Rust..." + if (-not (Get-Command rustc -ErrorAction SilentlyContinue)) { + Write-Info "װ Rust..." + try { + $rustupInit = "$env:TEMP\rustup-init.exe" + Invoke-WebRequest -Uri "https://win.rustup.rs" -OutFile $rustupInit + Start-Process -FilePath $rustupInit -ArgumentList "-y" -Wait + Remove-Item $rustupInit -Force + + # ˢ» + $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") + } + catch { + Write-Error "װ Rust ʧ: $_" + } + } + + # Ŀƽ̨ + Write-Info " Rust Ŀƽ̨..." + $arch = if ([Environment]::Is64BitOperatingSystem) { "x86_64" } else { "i686" } + rustup target add "$arch-pc-windows-msvc" +} + +# װ +function Install-Tools { + Write-Info "װҪ..." + + # װ protoc + if (-not (Get-Command protoc -ErrorAction SilentlyContinue)) { + Write-Info "װ Protocol Buffers..." + choco install -y protoc + } + + # װ Git + if (-not (Get-Command git -ErrorAction SilentlyContinue)) { + Write-Info "װ Git..." + choco install -y git + } + + # װ Node.js + if (-not $NoNode -and -not (Get-Command node -ErrorAction SilentlyContinue)) { + Write-Info "װ Node.js..." + choco install -y nodejs + } + + # ˢ» + $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") +} + +# +try { + Write-Info "ʼװҪ..." + + Install-Chocolatey + Install-VSBuildTools + Install-Rust + Install-Tools + + Write-Success "װɣ" +} +catch { + Write-Error "װгִ: $_" +} \ No newline at end of file diff --git a/scripts/setup.sh b/scripts/setup.sh new file mode 100644 index 0000000..6a42bda --- /dev/null +++ b/scripts/setup.sh @@ -0,0 +1,157 @@ +#!/bin/bash + +# 设置错误时退出 +set -e + +# 颜色输出 +RED='\033[0;31m' +GREEN='\033[0;32m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +info() { + echo -e "${BLUE}[INFO] $1${NC}" +} + +error() { + echo -e "${RED}[ERROR] $1${NC}" + exit 1 +} + +# 检查是否为 root 用户(FreeBSD 和 Linux) +if [ "$(uname)" != "Darwin" ] && [ "$EUID" -ne 0 ]; then + error "请使用 root 权限运行此脚本 (sudo ./setup.sh)" +fi + +# 检测包管理器 +if command -v brew &> /dev/null; then + PKG_MANAGER="brew" + info "检测到 macOS/Homebrew 系统" +elif command -v pkg &> /dev/null; then + PKG_MANAGER="pkg" + info "检测到 FreeBSD 系统" +elif command -v apt-get &> /dev/null; then + PKG_MANAGER="apt-get" + info "检测到 Debian/Ubuntu 系统" +elif command -v dnf &> /dev/null; then + PKG_MANAGER="dnf" + info "检测到 Fedora/RHEL 系统" +elif command -v yum &> /dev/null; then + PKG_MANAGER="yum" + info "检测到 CentOS 系统" +else + error "未检测到支持的包管理器" +fi + +# 更新包管理器缓存 +info "更新包管理器缓存..." +case $PKG_MANAGER in + "brew") + brew update + ;; + "pkg") + pkg update + ;; + *) + $PKG_MANAGER update -y + ;; +esac + +# 安装基础构建工具 +info "安装基础构建工具..." +case $PKG_MANAGER in + "brew") + brew install \ + protobuf \ + pkg-config \ + openssl \ + curl \ + git \ + node + ;; + "pkg") + pkg install -y \ + gmake \ + protobuf \ + pkgconf \ + openssl \ + curl \ + git \ + node + ;; + "apt-get") + $PKG_MANAGER install -y --no-install-recommends \ + build-essential \ + protobuf-compiler \ + pkg-config \ + libssl-dev \ + ca-certificates \ + curl \ + tzdata \ + git + ;; + *) + $PKG_MANAGER install -y \ + gcc \ + gcc-c++ \ + make \ + protobuf-compiler \ + pkg-config \ + openssl-devel \ + ca-certificates \ + curl \ + tzdata \ + git + ;; +esac + +# 安装 Node.js 和 npm(如果还没有通过包管理器安装) +if ! command -v node &> /dev/null && [ "$PKG_MANAGER" != "brew" ] && [ "$PKG_MANAGER" != "pkg" ]; then + info "安装 Node.js 和 npm..." + if [ "$PKG_MANAGER" = "apt-get" ]; then + curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - + $PKG_MANAGER install -y nodejs + else + curl -fsSL https://rpm.nodesource.com/setup_lts.x | bash - + $PKG_MANAGER install -y nodejs + fi +fi + +# 安装 Rust(如果未安装) +if ! command -v rustc &> /dev/null; then + info "安装 Rust..." + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + . "$HOME/.cargo/env" +fi + +# 添加目标平台 +info "添加 Rust 目标平台..." +case "$(uname)" in + "FreeBSD") + rustup target add x86_64-unknown-freebsd + ;; + "Darwin") + rustup target add x86_64-apple-darwin aarch64-apple-darwin + ;; + *) + rustup target add x86_64-unknown-linux-gnu + ;; +esac + +# 清理包管理器缓存 +case $PKG_MANAGER in + "apt-get") + rm -rf /var/lib/apt/lists/* + ;; + "pkg") + pkg clean -y + ;; +esac + +# 设置时区(除了 macOS) +if [ "$(uname)" != "Darwin" ]; then + info "设置时区为 Asia/Shanghai..." + ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime +fi + +echo -e "${GREEN}安装完成!${NC}" \ No newline at end of file diff --git a/src/aiserver.rs b/src/aiserver.rs new file mode 100644 index 0000000..a3a6d96 --- /dev/null +++ b/src/aiserver.rs @@ -0,0 +1 @@ +pub mod v1; diff --git a/src/aiserver/v1.rs b/src/aiserver/v1.rs new file mode 100644 index 0000000..f886b8b --- /dev/null +++ b/src/aiserver/v1.rs @@ -0,0 +1 @@ +include!(concat!(env!("OUT_DIR"), "/aiserver.v1.rs")); diff --git a/src/aiserver/v1/aiserver.proto b/src/aiserver/v1/aiserver.proto new file mode 100644 index 0000000..ba899b1 --- /dev/null +++ b/src/aiserver/v1/aiserver.proto @@ -0,0 +1,5051 @@ +syntax = "proto3"; +package aiserver.v1; +option go_package = "cursor/gen/aiserver/v1;aiserverv1"; +enum ClientSideToolV2 { // aiserver.v1.ClientSideToolV2 + CLIENT_SIDE_TOOL_V2_UNSPECIFIED = 0; + CLIENT_SIDE_TOOL_V2_READ_SEMSEARCH_FILES = 1; + CLIENT_SIDE_TOOL_V2_READ_FILE_FOR_IMPORTS = 2; + CLIENT_SIDE_TOOL_V2_RIPGREP_SEARCH = 3; + CLIENT_SIDE_TOOL_V2_RUN_TERMINAL_COMMAND = 4; + CLIENT_SIDE_TOOL_V2_READ_FILE = 5; + CLIENT_SIDE_TOOL_V2_LIST_DIR = 6; + CLIENT_SIDE_TOOL_V2_EDIT_FILE = 7; + CLIENT_SIDE_TOOL_V2_FILE_SEARCH = 8; + CLIENT_SIDE_TOOL_V2_SEMANTIC_SEARCH_FULL = 9; + CLIENT_SIDE_TOOL_V2_CREATE_FILE = 10; + CLIENT_SIDE_TOOL_V2_DELETE_FILE = 11; +} +enum EmbeddingModel { // aiserver.v1.EmbeddingModel + EMBEDDING_MODEL_UNSPECIFIED = 0; + EMBEDDING_MODEL_VOYAGE_CODE_2 = 1; + EMBEDDING_MODEL_TEXT_EMBEDDINGS_LARGE_3 = 2; + EMBEDDING_MODEL_QWEN_1_5B_CUSTOM = 3; +} +enum ChunkType { // aiserver.v1.ChunkType + CHUNK_TYPE_UNSPECIFIED = 0; + CHUNK_TYPE_CODEBASE = 1; + CHUNK_TYPE_LONG_FILE = 2; + CHUNK_TYPE_DOCS = 3; +} +enum FastApplySource { // aiserver.v1.FastApplySource + FAST_APPLY_SOURCE_UNSPECIFIED = 0; + FAST_APPLY_SOURCE_COMPOSER = 1; + FAST_APPLY_SOURCE_CLICKED_APPLY = 2; + FAST_APPLY_SOURCE_CACHED_APPLY = 3; +} +enum BuiltinTool { // aiserver.v1.BuiltinTool + BUILTIN_TOOL_UNSPECIFIED = 0; + BUILTIN_TOOL_SEARCH = 1; + BUILTIN_TOOL_READ_CHUNK = 2; + BUILTIN_TOOL_GOTODEF = 3; + BUILTIN_TOOL_EDIT = 4; + BUILTIN_TOOL_UNDO_EDIT = 5; + BUILTIN_TOOL_END = 6; + BUILTIN_TOOL_NEW_FILE = 7; + BUILTIN_TOOL_ADD_TEST = 8; + BUILTIN_TOOL_RUN_TEST = 9; + BUILTIN_TOOL_DELETE_TEST = 10; + BUILTIN_TOOL_SAVE_FILE = 11; + BUILTIN_TOOL_GET_TESTS = 12; + BUILTIN_TOOL_GET_SYMBOLS = 13; + BUILTIN_TOOL_SEMANTIC_SEARCH = 14; + BUILTIN_TOOL_GET_PROJECT_STRUCTURE = 15; + BUILTIN_TOOL_CREATE_RM_FILES = 16; + BUILTIN_TOOL_RUN_TERMINAL_COMMANDS = 17; + BUILTIN_TOOL_NEW_EDIT = 18; + BUILTIN_TOOL_READ_WITH_LINTER = 19; +} +enum FeatureType { // aiserver.v1.FeatureType + FEATURE_TYPE_UNSPECIFIED = 0; + FEATURE_TYPE_EDIT = 1; + FEATURE_TYPE_GENERATE = 2; + FEATURE_TYPE_INLINE_LONG_COMPLETION = 3; +} +enum TaskStatus { // aiserver.v1.TaskStatus + TASK_STATUS_UNSPECIFIED = 0; + TASK_STATUS_RUNNING = 1; + TASK_STATUS_PAUSED = 2; + TASK_STATUS_DONE = 3; + TASK_STATUS_NOT_STARTED = 4; +} +enum RerankerAlgorithm { // aiserver.v1.RerankerAlgorithm + RERANKER_ALGORITHM_UNSPECIFIED = 0; + RERANKER_ALGORITHM_LULEA = 1; + RERANKER_ALGORITHM_UMEA = 2; + RERANKER_ALGORITHM_NONE = 3; + RERANKER_ALGORITHM_LLAMA = 4; + RERANKER_ALGORITHM_STARCODER_V1 = 5; + RERANKER_ALGORITHM_GPT_3_5_LOGPROBS = 6; + RERANKER_ALGORITHM_LULEA_HAIKU = 7; + RERANKER_ALGORITHM_COHERE = 8; + RERANKER_ALGORITHM_VOYAGE = 9; + RERANKER_ALGORITHM_VOYAGE_EMBEDS = 10; + RERANKER_ALGORITHM_IDENTITY = 11; + RERANKER_ALGORITHM_ADA_EMBEDS = 12; +} +enum RechunkerChoice { // aiserver.v1.RechunkerChoice + RECHUNKER_CHOICE_UNSPECIFIED = 0; + RECHUNKER_CHOICE_IDENTITY = 1; + RECHUNKER_CHOICE_600_TOKS = 2; + RECHUNKER_CHOICE_2400_TOKS = 3; + RECHUNKER_CHOICE_4000_TOKS = 4; +} +enum LintGenerator { // aiserver.v1.LintGenerator + LINT_GENERATOR_UNSPECIFIED = 0; + LINT_GENERATOR_NAIVE = 1; + LINT_GENERATOR_COMMENT_PIPELINE = 2; + LINT_GENERATOR_SIMPLE_BUG = 3; + LINT_GENERATOR_SIMPLE_LINT_RULES = 4; +} +enum LintDiscriminator { // aiserver.v1.LintDiscriminator + LINT_DISCRIMINATOR_UNSPECIFIED = 0; + LINT_DISCRIMINATOR_SPECIFIC_RULES = 1; + LINT_DISCRIMINATOR_COMPILE_ERRORS = 2; + LINT_DISCRIMINATOR_CHANGE_BEHAVIOR = 3; + LINT_DISCRIMINATOR_RELEVANCE = 4; + LINT_DISCRIMINATOR_USER_AWARENESS = 5; + LINT_DISCRIMINATOR_CORRECTNESS = 6; + LINT_DISCRIMINATOR_CHUNKING = 7; + LINT_DISCRIMINATOR_TYPO = 8; + LINT_DISCRIMINATOR_CONFIDENCE = 9; + LINT_DISCRIMINATOR_DISMISSED_BUGS = 10; +} +enum CppSource { // aiserver.v1.CppSource + CPP_SOURCE_UNSPECIFIED = 0; + CPP_SOURCE_LINE_CHANGE = 1; + CPP_SOURCE_TYPING = 2; + CPP_SOURCE_OPTION_HOLD = 3; + CPP_SOURCE_LINTER_ERRORS = 4; + CPP_SOURCE_PARAMETER_HINTS = 5; + CPP_SOURCE_CURSOR_PREDICTION = 6; + CPP_SOURCE_MANUAL_TRIGGER = 7; + CPP_SOURCE_EDITOR_CHANGE = 8; +} +enum ChunkingStrategy { // aiserver.v1.ChunkingStrategy + CHUNKING_STRATEGY_UNSPECIFIED = 0; + CHUNKING_STRATEGY_DEFAULT = 1; +} +message HealthCheckRequest { // aiserver.v1.HealthCheckRequest +} +message HealthCheckResponse { // aiserver.v1.HealthCheckResponse + enum Status { // aiserver.v1.HealthCheckResponse.Status + STATUS_UNSPECIFIED = 0; + STATUS_HEALTHY = 1; + } + Status status = 1; +} +message PrivacyCheckRequest { // aiserver.v1.PrivacyCheckRequest +} +message PrivacyCheckResponse { // aiserver.v1.PrivacyCheckResponse + bool is_on_privacy_pod = 1; + bool is_ghost_mode_on = 2; +} +message TimeLeftHealthCheckResponse { // aiserver.v1.TimeLeftHealthCheckResponse + string time_left = 1; +} +message ThrowErrorCheckRequest { // aiserver.v1.ThrowErrorCheckRequest + enum Error { // aiserver.v1.ErrorDetails.Error + ERROR_UNSPECIFIED = 0; + ERROR_BAD_API_KEY = 1; + ERROR_BAD_USER_API_KEY = 2; + ERROR_NOT_LOGGED_IN = 3; + ERROR_INVALID_AUTH_ID = 4; + ERROR_NOT_HIGH_ENOUGH_PERMISSIONS = 5; + ERROR_AGENT_REQUIRES_LOGIN = 6; + ERROR_BAD_MODEL_NAME = 7; + ERROR_NOT_FOUND = 8; + ERROR_DEPRECATED = 9; + ERROR_USER_NOT_FOUND = 10; + ERROR_FREE_USER_RATE_LIMIT_EXCEEDED = 11; + ERROR_PRO_USER_RATE_LIMIT_EXCEEDED = 12; + ERROR_FREE_USER_USAGE_LIMIT = 13; + ERROR_PRO_USER_USAGE_LIMIT = 14; + ERROR_RESOURCE_EXHAUSTED = 15; + ERROR_AUTH_TOKEN_NOT_FOUND = 16; + ERROR_AUTH_TOKEN_EXPIRED = 17; + ERROR_OPENAI = 18; + ERROR_OPENAI_RATE_LIMIT_EXCEEDED = 19; + ERROR_OPENAI_ACCOUNT_LIMIT_EXCEEDED = 20; + ERROR_TASK_UUID_NOT_FOUND = 21; + ERROR_TASK_NO_PERMISSIONS = 22; + ERROR_AGENT_ENGINE_NOT_FOUND = 23; + ERROR_MAX_TOKENS = 24; + ERROR_PRO_USER_ONLY = 25; + ERROR_API_KEY_NOT_SUPPORTED = 26; + ERROR_USER_ABORTED_REQUEST = 27; + ERROR_GENERIC_RATE_LIMIT_EXCEEDED = 28; + ERROR_SLASH_EDIT_FILE_TOO_LONG = 29; + ERROR_FILE_UNSUPPORTED = 30; + ERROR_GPT_4_VISION_PREVIEW_RATE_LIMIT = 31; + ERROR_CUSTOM_MESSAGE = 32; + ERROR_OUTDATED_CLIENT = 33; + ERROR_CLAUDE_IMAGE_TOO_LARGE = 34; + ERROR_GITGRAPH_NOT_FOUND = 35; + ERROR_FILE_NOT_FOUND = 36; + ERROR_API_KEY_RATE_LIMIT = 37; + ERROR_DEBOUNCED = 38; + ERROR_BAD_REQUEST = 39; + ERROR_REPOSITORY_SERVICE_REPOSITORY_IS_NOT_INITIALIZED = 40; + ERROR_UNAUTHORIZED = 41; + } + Error error = 1; +} +message ThrowErrorCheckResponse { // aiserver.v1.ThrowErrorCheckResponse +} +message AvailableModelsRequest { // aiserver.v1.AvailableModelsRequest + bool is_nightly = 1; + bool include_long_context_models = 2; +} +message AvailableModelsResponse { // aiserver.v1.AvailableModelsResponse + message AvailableModel { // aiserver.v1.AvailableModelsResponse.AvailableModel + string name = 1; + bool default_on = 2; + optional bool is_long_context_only = 3; + optional bool is_chat_only = 4; + } + repeated AvailableModel models = 2; + repeated string model_names = 1; +} +message GetChatRequest { // aiserver.v1.GetChatRequest + CurrentFileInfo current_file = 1; + repeated ConversationMessage conversation = 2; + repeated RepositoryInfo repositories = 3; + ExplicitContext explicit_context = 4; + optional string workspace_root_path = 5; + repeated CodeBlock code_blocks = 6; + ModelDetails model_details = 7; + repeated string documentation_identifiers = 8; + string request_id = 9; + LinterErrors linter_errors = 10; + optional string summary = 11; + optional int32 summary_up_until_index = 12; + optional bool allow_long_file_scan = 13; + optional bool is_bash = 14; + string conversation_id = 15; + optional bool can_handle_filenames_after_language_ids = 16; + optional string use_web = 17; + repeated ChatQuote quotes = 18; + optional DebugInfo debug_info = 19; + optional string workspace_id = 20; + repeated ChatExternalLink external_links = 21; + repeated CommitNote commit_notes = 23; + optional bool long_context_mode = 22; + optional bool is_eval = 24; + optional int32 desired_max_tokens = 26; + ContextAST context_ast = 25; + optional bool is_composer = 27; + optional bool runnable_code_blocks = 28; + optional bool should_cache = 29; +} +message CurrentFileInfo { // aiserver.v1.CurrentFileInfo + message NotebookCell { // aiserver.v1.CurrentFileInfo.NotebookCell + } + string relative_workspace_path = 1; + string contents = 2; + bool rely_on_filesync = 18; + optional string sha_256_hash = 17; + repeated NotebookCell cells = 16; + repeated BM25Chunk top_chunks = 10; + int32 contents_start_at_line = 9; + CursorPosition cursor_position = 3; + repeated DataframeInfo dataframes = 4; + int32 total_number_of_lines = 8; + string language_id = 5; + CursorRange selection = 6; + optional int32 alternative_version_id = 11; + repeated Diagnostic diagnostics = 7; + optional int32 file_version = 14; + repeated int32 cell_start_lines = 15; + string workspace_root_path = 19; +} +message BM25Chunk { // aiserver.v1.BM25Chunk + string content = 1; + SimplestRange range = 2; + int32 score = 3; + string relative_path = 4; +} +message SimplestRange { // aiserver.v1.SimplestRange + int32 start_line = 1; + int32 end_line_inclusive = 2; +} +message CursorPosition { // aiserver.v1.CursorPosition + int32 line = 1; + int32 column = 2; +} +message DataframeInfo { // aiserver.v1.DataframeInfo + message Column { // aiserver.v1.DataframeInfo.Column + string key = 1; + string type = 2; + } + string name = 1; + string shape = 2; + int32 data_dimensionality = 3; + repeated Column columns = 6; + int32 row_count = 7; + string index_column = 8; +} +message CursorRange { // aiserver.v1.CursorRange + CursorPosition start_position = 1; + CursorPosition end_position = 2; +} +message Diagnostic { // aiserver.v1.Diagnostic + enum DiagnosticSeverity { // aiserver.v1.Diagnostic.DiagnosticSeverity + DIAGNOSTIC_SEVERITY_UNSPECIFIED = 0; + DIAGNOSTIC_SEVERITY_ERROR = 1; + DIAGNOSTIC_SEVERITY_WARNING = 2; + DIAGNOSTIC_SEVERITY_INFORMATION = 3; + DIAGNOSTIC_SEVERITY_HINT = 4; + } + message RelatedInformation { // aiserver.v1.Diagnostic.RelatedInformation + string message = 1; + CursorRange range = 2; + } + string message = 1; + CursorRange range = 2; + DiagnosticSeverity severity = 3; + repeated RelatedInformation related_information = 4; +} +message ConversationMessage { // aiserver.v1.ConversationMessage + enum MessageType { // aiserver.v1.ConversationMessage.MessageType + MESSAGE_TYPE_UNSPECIFIED = 0; + MESSAGE_TYPE_HUMAN = 1; + MESSAGE_TYPE_AI = 2; + } + message CodeChunk { // aiserver.v1.ConversationMessage.CodeChunk + enum SummarizationStrategy { // aiserver.v1.ConversationMessage.CodeChunk.SummarizationStrategy + SUMMARIZATION_STRATEGY_NONE_UNSPECIFIED = 0; + SUMMARIZATION_STRATEGY_SUMMARIZED = 1; + SUMMARIZATION_STRATEGY_EMBEDDED = 2; + } + enum Intent { // aiserver.v1.ConversationMessage.CodeChunk.Intent + INTENT_UNSPECIFIED = 0; + INTENT_COMPOSER_FILE = 1; + INTENT_COMPRESSED_COMPOSER_FILE = 2; + INTENT_RECENTLY_VIEWED_FILE = 3; + INTENT_OUTLINE = 4; + INTENT_MENTIONED_FILE = 5; + } + string relative_workspace_path = 1; + int32 start_line_number = 2; + repeated string lines = 3; + optional SummarizationStrategy summarization_strategy = 4; + string language_identifier = 5; + optional Intent intent = 6; + optional bool is_final_version = 7; + optional bool is_first_version = 8; + optional bool contents_are_missing = 9; + } + message ApproximateLintError { // aiserver.v1.ConversationMessage.ApproximateLintError + string message = 1; + string value = 2; + int32 start_line = 3; + int32 end_line = 4; + int32 start_column = 5; + int32 end_column = 6; + } + message Lints { // aiserver.v1.ConversationMessage.Lints + GetLintsForChangeResponse lints = 1; + string chat_codeblock_model_value = 2; + } + message ToolResult { // aiserver.v1.ConversationMessage.ToolResult + message CodeChunk { // aiserver.v1.ConversationMessage.CodeChunk + enum SummarizationStrategy { // aiserver.v1.ConversationMessage.CodeChunk.SummarizationStrategy + SUMMARIZATION_STRATEGY_NONE_UNSPECIFIED = 0; + SUMMARIZATION_STRATEGY_SUMMARIZED = 1; + SUMMARIZATION_STRATEGY_EMBEDDED = 2; + } + enum Intent { // aiserver.v1.ConversationMessage.CodeChunk.Intent + INTENT_UNSPECIFIED = 0; + INTENT_COMPOSER_FILE = 1; + INTENT_COMPRESSED_COMPOSER_FILE = 2; + INTENT_RECENTLY_VIEWED_FILE = 3; + INTENT_OUTLINE = 4; + INTENT_MENTIONED_FILE = 5; + } + string relative_workspace_path = 1; + int32 start_line_number = 2; + repeated string lines = 3; + optional SummarizationStrategy summarization_strategy = 4; + string language_identifier = 5; + optional Intent intent = 6; + optional bool is_final_version = 7; + optional bool is_first_version = 8; + optional bool contents_are_missing = 9; + } + string tool_call_id = 1; + string tool_name = 2; + uint32 tool_index = 3; + string args = 4; + string raw_args = 5; + repeated CodeChunk attached_code_chunks = 6; + optional string content = 7; + ClientSideToolV2Result result = 8; + optional ToolResultError error = 9; + } + message NotepadContext { // aiserver.v1.ConversationMessage.NotepadContext + message CodeChunk { // aiserver.v1.ConversationMessage.CodeChunk + enum SummarizationStrategy { // aiserver.v1.ConversationMessage.CodeChunk.SummarizationStrategy + SUMMARIZATION_STRATEGY_NONE_UNSPECIFIED = 0; + SUMMARIZATION_STRATEGY_SUMMARIZED = 1; + SUMMARIZATION_STRATEGY_EMBEDDED = 2; + } + enum Intent { // aiserver.v1.ConversationMessage.CodeChunk.Intent + INTENT_UNSPECIFIED = 0; + INTENT_COMPOSER_FILE = 1; + INTENT_COMPRESSED_COMPOSER_FILE = 2; + INTENT_RECENTLY_VIEWED_FILE = 3; + INTENT_OUTLINE = 4; + INTENT_MENTIONED_FILE = 5; + } + string relative_workspace_path = 1; + int32 start_line_number = 2; + repeated string lines = 3; + optional SummarizationStrategy summarization_strategy = 4; + string language_identifier = 5; + optional Intent intent = 6; + optional bool is_final_version = 7; + optional bool is_first_version = 8; + optional bool contents_are_missing = 9; + } + string name = 1; + string text = 2; + repeated CodeChunk attached_code_chunks = 3; + repeated string attached_folders = 4; + repeated Commit commits = 5; + repeated PullRequest pull_requests = 6; + repeated GitDiff git_diffs = 7; + repeated ImageProto images = 8; + } + message EditTrailContext { // aiserver.v1.ConversationMessage.EditTrailContext + message EditLocation { // aiserver.v1.ConversationMessage.EditLocation + string relative_workspace_path = 1; + SimplestRange range = 3; + SimplestRange initial_range = 4; + string context_lines = 5; + string text = 6; + SimplestRange text_range = 7; + } + string unique_id = 1; + repeated EditLocation edit_trail_sorted = 2; + } + message RecentLocation { // aiserver.v1.ConversationMessage.RecentLocation + string relative_workspace_path = 1; + int32 line_number = 2; + } + string text = 1; + MessageType type = 2; + repeated CodeChunk attached_code_chunks = 3; + repeated CodeBlock codebase_context_chunks = 4; + repeated Commit commits = 5; + repeated PullRequest pull_requests = 6; + repeated GitDiff git_diffs = 7; + repeated SimpleFileDiff assistant_suggested_diffs = 8; + repeated InterpreterResult interpreter_results = 9; + repeated ImageProto images = 10; + repeated string attached_folders = 11; + repeated ApproximateLintError approximate_lint_errors = 12; + string bubble_id = 13; + optional string server_bubble_id = 32; + repeated FolderInfo attached_folders_new = 14; + repeated Lints lints = 15; + repeated UserResponseToSuggestedCodeBlock user_responses_to_suggested_code_blocks = 16; + repeated string relevant_files = 17; + repeated ToolResult tool_results = 18; + repeated NotepadContext notepads = 19; + optional bool is_capability_iteration = 20; + repeated ComposerCapabilityRequest capabilities = 21; + repeated EditTrailContext edit_trail_contexts = 22; + repeated SuggestedCodeBlock suggested_code_blocks = 23; + repeated RedDiff diffs_for_compressing_files = 24; + repeated LinterErrorsWithoutFileContents multi_file_linter_errors = 25; + repeated DiffHistoryData diff_histories = 26; + repeated CodeChunk recently_viewed_files = 27; + repeated RecentLocation recent_locations_history = 28; + bool is_agentic = 29; + repeated ComposerFileDiffHistory file_diff_trajectories = 30; + optional ConversationSummary conversation_summary = 31; +} +message CodeBlock { // aiserver.v1.CodeBlock + message Signatures { // aiserver.v1.CodeBlock.Signatures + repeated CursorRange ranges = 1; + } + string relative_workspace_path = 1; + optional string file_contents = 2; + CursorRange range = 3; + string contents = 4; + Signatures signatures = 5; + optional string override_contents = 6; + optional string original_contents = 7; + repeated DetailedLine detailed_lines = 8; +} +message DetailedLine { // aiserver.v1.DetailedLine + string text = 1; + float line_number = 2; + bool is_signature = 3; +} +message Commit { // aiserver.v1.Commit + string sha = 1; + string message = 2; + string description = 3; + repeated FileDiff diff = 4; + string author = 5; + string date = 6; +} +message FileDiff { // aiserver.v1.FileDiff + message Chunk { // aiserver.v1.FileDiff.Chunk + string content = 1; + repeated string lines = 2; + int32 old_start = 3; + int32 old_lines = 4; + int32 new_start = 5; + int32 new_lines = 6; + } + string from = 1; + string to = 2; + repeated Chunk chunks = 3; +} +message PullRequest { // aiserver.v1.PullRequest + string title = 1; + string body = 2; + repeated FileDiff diff = 3; +} +message GitDiff { // aiserver.v1.GitDiff + enum DiffType { // aiserver.v1.GitDiff.DiffType + DIFF_TYPE_UNSPECIFIED = 0; + DIFF_TYPE_DIFF_TO_HEAD = 1; + DIFF_TYPE_DIFF_FROM_BRANCH_TO_MAIN = 2; + } + repeated FileDiff diffs = 1; + DiffType diff_type = 2; +} +message SimpleFileDiff { // aiserver.v1.SimpleFileDiff + message Chunk { // aiserver.v1.SimpleFileDiff.Chunk + repeated string old_lines = 1; + repeated string new_lines = 2; + LineRange old_range = 3; + LineRange new_range = 4; + } + string relative_workspace_path = 1; + repeated Chunk chunks = 3; +} +message LineRange { // aiserver.v1.LineRange + int32 start_line_number = 1; + int32 end_line_number_inclusive = 2; +} +message InterpreterResult { // aiserver.v1.InterpreterResult + string output = 1; + bool success = 2; +} +message ImageProto { // aiserver.v1.ImageProto + message Dimension { // aiserver.v1.ImageProto.Dimension + int32 width = 1; + int32 height = 2; + } + bytes data = 1; + Dimension dimension = 2; +} +message FolderInfo { // aiserver.v1.FolderInfo + string relative_path = 1; + repeated FolderFileInfo files = 2; +} +message FolderFileInfo { // aiserver.v1.FolderFileInfo + string relative_path = 1; + string content = 2; + bool truncated = 3; + float score = 4; +} +message GetLintsForChangeResponse { // aiserver.v1.GetLintsForChangeResponse + message Lint { // aiserver.v1.GetLintsForChangeResponse.Lint + message QuickFix { // aiserver.v1.GetLintsForChangeResponse.Lint.QuickFix + message Edit { // aiserver.v1.GetLintsForChangeResponse.Lint.QuickFix.Edit + string relative_workspace_path = 1; + string text = 2; + int32 start_line_number_one_indexed = 3; + int32 start_column_one_indexed = 4; + int32 end_line_number_inclusive_one_indexed = 5; + int32 end_column_one_indexed = 6; + } + string message = 1; + string kind = 2; + bool is_preferred = 3; + repeated Edit edits = 4; + } + string message = 1; + string severity = 2; + string relative_workspace_path = 3; + int32 start_line_number_one_indexed = 4; + int32 start_column_one_indexed = 5; + int32 end_line_number_inclusive_one_indexed = 6; + int32 end_column_one_indexed = 7; + repeated QuickFix quick_fixes = 9; + } + repeated Lint lints = 1; +} +message UserResponseToSuggestedCodeBlock { // aiserver.v1.UserResponseToSuggestedCodeBlock + enum UserResponseType { // aiserver.v1.UserResponseToSuggestedCodeBlock.UserResponseType + USER_RESPONSE_TYPE_UNSPECIFIED = 0; + USER_RESPONSE_TYPE_ACCEPT = 1; + USER_RESPONSE_TYPE_REJECT = 2; + USER_RESPONSE_TYPE_MODIFY = 3; + } + UserResponseType user_response_type = 1; + string file_path = 2; + optional FileDiff user_modifications_to_suggested_code_blocks = 3; +} +message ClientSideToolV2Result { // aiserver.v1.ClientSideToolV2Result + ClientSideToolV2 tool = 1; + ReadSemsearchFilesResult read_semsearch_files_result = 2; + ReadFileForImportsResult read_file_for_imports_result = 3; + RipgrepSearchResult ripgrep_search_result = 4; + RunTerminalCommandResult run_terminal_command_result = 5; + ReadFileResult read_file_result = 6; + ListDirResult list_dir_result = 9; + EditFileResult edit_file_result = 10; + ToolCallFileSearchResult file_search_result = 11; + SemanticSearchFullResult semantic_search_full_result = 18; + CreateFileResult create_file_result = 19; + DeleteFileResult delete_file_result = 20; + optional ToolResultError error = 8; +} +message ReadSemsearchFilesResult { // aiserver.v1.ReadSemsearchFilesResult + repeated CodeResult code_results = 1; +} +message CodeResult { // aiserver.v1.CodeResult + CodeBlock code_block = 1; + float score = 2; +} +message ReadFileForImportsResult { // aiserver.v1.ReadFileForImportsResult + string contents = 1; +} +message RipgrepSearchResult { // aiserver.v1.RipgrepSearchResult + RipgrepSearchResultInternal internal = 1; +} +message RipgrepSearchResultInternal { // aiserver.v1.RipgrepSearchResultInternal + message IFileMatch { // aiserver.v1.RipgrepSearchResultInternal.IFileMatch + message ITextSearchResult { // aiserver.v1.RipgrepSearchResultInternal.ITextSearchResult + message ITextSearchMatch { // aiserver.v1.RipgrepSearchResultInternal.ITextSearchMatch + message ISearchRangeSetPairing { // aiserver.v1.RipgrepSearchResultInternal.ISearchRangeSetPairing + message ISearchRange { // aiserver.v1.RipgrepSearchResultInternal.ISearchRange + int32 start_line_number = 1; + int32 start_column = 2; + int32 end_line_number = 3; + int32 end_column = 4; + } + ISearchRange source = 1; + ISearchRange preview = 2; + } + optional string uri = 1; + repeated ISearchRangeSetPairing range_locations = 2; + string preview_text = 3; + optional int32 webview_index = 4; + optional string cell_fragment = 5; + } + message ITextSearchContext { // aiserver.v1.RipgrepSearchResultInternal.ITextSearchContext + optional string uri = 1; + string text = 2; + int32 line_number = 3; + } + ITextSearchMatch match = 1; + ITextSearchContext context = 2; + } + string resource = 1; + repeated ITextSearchResult results = 2; + } + enum SearchCompletionExitCode { // aiserver.v1.RipgrepSearchResultInternal.SearchCompletionExitCode + SEARCH_COMPLETION_EXIT_CODE_UNSPECIFIED = 0; + SEARCH_COMPLETION_EXIT_CODE_NORMAL = 1; + SEARCH_COMPLETION_EXIT_CODE_NEW_SEARCH_STARTED = 2; + } + message ITextSearchCompleteMessage { // aiserver.v1.RipgrepSearchResultInternal.ITextSearchCompleteMessage + enum TextSearchCompleteMessageType { // aiserver.v1.RipgrepSearchResultInternal.TextSearchCompleteMessageType + TEXT_SEARCH_COMPLETE_MESSAGE_TYPE_UNSPECIFIED = 0; + TEXT_SEARCH_COMPLETE_MESSAGE_TYPE_INFORMATION = 1; + TEXT_SEARCH_COMPLETE_MESSAGE_TYPE_WARNING = 2; + } + string text = 1; + TextSearchCompleteMessageType type = 2; + optional bool trusted = 3; + } + message IFileSearchStats { // aiserver.v1.RipgrepSearchResultInternal.IFileSearchStats + message ISearchEngineStats { // aiserver.v1.RipgrepSearchResultInternal.ISearchEngineStats + int32 file_walk_time = 1; + int32 directories_walked = 2; + int32 files_walked = 3; + int32 cmd_time = 4; + optional int32 cmd_result_count = 5; + } + message ICachedSearchStats { // aiserver.v1.RipgrepSearchResultInternal.ICachedSearchStats + bool cache_was_resolved = 1; + int32 cache_lookup_time = 2; + int32 cache_filter_time = 3; + int32 cache_entry_count = 4; + } + message IFileSearchProviderStats { // aiserver.v1.RipgrepSearchResultInternal.IFileSearchProviderStats + int32 provider_time = 1; + int32 post_process_time = 2; + } + enum FileSearchProviderType { // aiserver.v1.RipgrepSearchResultInternal.IFileSearchStats.FileSearchProviderType + FILE_SEARCH_PROVIDER_TYPE_UNSPECIFIED = 0; + FILE_SEARCH_PROVIDER_TYPE_FILE_SEARCH_PROVIDER = 1; + FILE_SEARCH_PROVIDER_TYPE_SEARCH_PROCESS = 2; + } + bool from_cache = 1; + ISearchEngineStats search_engine_stats = 2; + ICachedSearchStats cached_search_stats = 3; + IFileSearchProviderStats file_search_provider_stats = 4; + int32 result_count = 5; + FileSearchProviderType type = 6; + optional int32 sorting_time = 7; + } + message ITextSearchStats { // aiserver.v1.RipgrepSearchResultInternal.ITextSearchStats + enum TextSearchProviderType { // aiserver.v1.RipgrepSearchResultInternal.ITextSearchStats.TextSearchProviderType + TEXT_SEARCH_PROVIDER_TYPE_UNSPECIFIED = 0; + TEXT_SEARCH_PROVIDER_TYPE_TEXT_SEARCH_PROVIDER = 1; + TEXT_SEARCH_PROVIDER_TYPE_SEARCH_PROCESS = 2; + TEXT_SEARCH_PROVIDER_TYPE_AI_TEXT_SEARCH_PROVIDER = 3; + } + TextSearchProviderType type = 1; + } + repeated IFileMatch results = 1; + optional SearchCompletionExitCode exit = 2; + optional bool limit_hit = 3; + repeated ITextSearchCompleteMessage messages = 4; + IFileSearchStats file_search_stats = 5; + ITextSearchStats text_search_stats = 6; +} +message RunTerminalCommandResult { // aiserver.v1.RunTerminalCommandResult + string output = 1; + int32 exit_code = 2; + optional bool rejected = 3; + bool popped_out_into_background = 4; +} +message ReadFileResult { // aiserver.v1.ReadFileResult + string contents = 1; + bool did_downgrade_to_line_range = 2; + bool did_shorten_line_range = 3; + bool did_set_default_line_range = 4; + optional string full_file_contents = 5; + optional string outline = 6; + optional int32 start_line_one_indexed = 7; + optional int32 end_line_one_indexed_inclusive = 8; + string relative_workspace_path = 9; + bool did_shorten_char_range = 10; +} +message ListDirResult { // aiserver.v1.ListDirResult + message File { // aiserver.v1.ListDirResult.File + message Timestamp { // google.protobuf.Timestamp + int64 seconds = 1; + int32 nanos = 2; + } + string name = 1; + bool is_directory = 2; + optional int64 size = 3; + optional Timestamp last_modified = 4; + optional int32 num_children = 5; + optional int32 num_lines = 6; + } + repeated File files = 1; + string directory_relative_workspace_path = 2; +} +message EditFileResult { // aiserver.v1.EditFileResult + message FileDiff { // aiserver.v1.EditFileResult.FileDiff + message ChunkDiff { // aiserver.v1.EditFileResult.FileDiff.ChunkDiff + string diff_string = 1; + int32 old_start = 2; + int32 new_start = 3; + int32 old_lines = 4; + int32 new_lines = 5; + int32 lines_removed = 6; + int32 lines_added = 7; + } + enum Editor { // aiserver.v1.EditFileResult.FileDiff.Editor + EDITOR_UNSPECIFIED = 0; + EDITOR_AI = 1; + EDITOR_HUMAN = 2; + } + repeated ChunkDiff chunks = 1; + Editor editor = 2; + bool hit_timeout = 3; + } + FileDiff diff = 1; + bool is_applied = 2; + bool apply_failed = 3; +} +message ToolCallFileSearchResult { // aiserver.v1.ToolCallFileSearchResult + message File { // aiserver.v1.ToolCallFileSearchResult.File + string uri = 1; + } + repeated File files = 1; + optional bool limit_hit = 2; + int32 num_results = 3; +} +message SemanticSearchFullResult { // aiserver.v1.SemanticSearchFullResult + repeated CodeResult code_results = 1; +} +message CreateFileResult { // aiserver.v1.CreateFileResult + bool file_created_successfully = 1; + bool file_already_exists = 2; +} +message DeleteFileResult { // aiserver.v1.DeleteFileResult + bool rejected = 1; + bool file_non_existent = 2; + bool file_deleted_successfully = 3; +} +message ToolResultError { // aiserver.v1.ToolResultError + string client_visible_error_message = 1; + string model_visible_error_message = 2; +} +message ComposerCapabilityRequest { // aiserver.v1.ComposerCapabilityRequest + enum ComposerCapabilityType { // aiserver.v1.ComposerCapabilityRequest.ComposerCapabilityType + COMPOSER_CAPABILITY_TYPE_UNSPECIFIED = 0; + COMPOSER_CAPABILITY_TYPE_LOOP_ON_LINTS = 1; + COMPOSER_CAPABILITY_TYPE_LOOP_ON_TESTS = 2; + COMPOSER_CAPABILITY_TYPE_MEGA_PLANNER = 3; + COMPOSER_CAPABILITY_TYPE_LOOP_ON_COMMAND = 4; + COMPOSER_CAPABILITY_TYPE_TOOL_CALL = 5; + COMPOSER_CAPABILITY_TYPE_DIFF_REVIEW = 6; + COMPOSER_CAPABILITY_TYPE_CONTEXT_PICKING = 7; + COMPOSER_CAPABILITY_TYPE_EDIT_TRAIL = 8; + COMPOSER_CAPABILITY_TYPE_AUTO_CONTEXT = 9; + COMPOSER_CAPABILITY_TYPE_CONTEXT_PLANNER = 10; + COMPOSER_CAPABILITY_TYPE_DIFF_HISTORY = 11; + COMPOSER_CAPABILITY_TYPE_REMEMBER_THIS = 12; + COMPOSER_CAPABILITY_TYPE_DECOMPOSER = 13; + COMPOSER_CAPABILITY_TYPE_USES_CODEBASE = 14; + COMPOSER_CAPABILITY_TYPE_TOOL_FORMER = 15; + } + message LoopOnLintsCapability { // aiserver.v1.ComposerCapabilityRequest.LoopOnLintsCapability + repeated LinterErrors linter_errors = 1; + optional string custom_instructions = 2; + } + message LoopOnTestsCapability { // aiserver.v1.ComposerCapabilityRequest.LoopOnTestsCapability + repeated string test_names = 1; + optional string custom_instructions = 2; + } + message MegaPlannerCapability { // aiserver.v1.ComposerCapabilityRequest.MegaPlannerCapability + optional string custom_instructions = 1; + } + message LoopOnCommandCapability { // aiserver.v1.ComposerCapabilityRequest.LoopOnCommandCapability + string command = 1; + optional string custom_instructions = 2; + optional string output = 3; + optional int32 exit_code = 4; + } + message ToolCallCapability { // aiserver.v1.ComposerCapabilityRequest.ToolCallCapability + message ToolSchema { // aiserver.v1.ComposerCapabilityRequest.ToolSchema + enum ToolType { // aiserver.v1.ComposerCapabilityRequest.ToolType + TOOL_TYPE_UNSPECIFIED = 0; + TOOL_TYPE_ADD_FILE_TO_CONTEXT = 1; + TOOL_TYPE_RUN_TERMINAL_COMMAND = 2; + TOOL_TYPE_ITERATE = 3; + TOOL_TYPE_REMOVE_FILE_FROM_CONTEXT = 4; + TOOL_TYPE_SEMANTIC_SEARCH_CODEBASE = 5; + } + ToolType type = 1; + string name = 2; + repeated string required = 4; + } + optional string custom_instructions = 1; + repeated ToolSchema tool_schemas = 2; + repeated string relevant_files = 3; + repeated string files_in_context = 4; + repeated string semantic_search_files = 5; + } + message DiffReviewCapability { // aiserver.v1.ComposerCapabilityRequest.DiffReviewCapability + message SimpleFileDiff { // aiserver.v1.ComposerCapabilityRequest.DiffReviewCapability.SimpleFileDiff + message Chunk { // aiserver.v1.ComposerCapabilityRequest.DiffReviewCapability.SimpleFileDiff.Chunk + repeated string old_lines = 1; + repeated string new_lines = 2; + LineRange old_range = 3; + LineRange new_range = 4; + } + string relative_workspace_path = 1; + repeated Chunk chunks = 3; + } + optional string custom_instructions = 1; + repeated SimpleFileDiff diffs = 2; + } + message ContextPickingCapability { // aiserver.v1.ComposerCapabilityRequest.ContextPickingCapability + optional string custom_instructions = 1; + repeated string potential_context_files = 2; + repeated CodeChunk potential_context_code_chunks = 3; + repeated string files_in_context = 4; + } + message EditTrailCapability { // aiserver.v1.ComposerCapabilityRequest.EditTrailCapability + optional string custom_instructions = 1; + } + message AutoContextCapability { // aiserver.v1.ComposerCapabilityRequest.AutoContextCapability + optional string custom_instructions = 1; + repeated string additional_files = 2; + } + message ContextPlannerCapability { // aiserver.v1.ComposerCapabilityRequest.ContextPlannerCapability + optional string custom_instructions = 1; + repeated CodeChunk attached_code_chunks = 2; + } + message RememberThisCapability { // aiserver.v1.ComposerCapabilityRequest.RememberThisCapability + optional string custom_instructions = 1; + string memory = 2; + } + message DecomposerCapability { // aiserver.v1.ComposerCapabilityRequest.DecomposerCapability + optional string custom_instructions = 1; + } + ComposerCapabilityType type = 1; + LoopOnLintsCapability loop_on_lints = 2; + LoopOnTestsCapability loop_on_tests = 3; + MegaPlannerCapability mega_planner = 4; + LoopOnCommandCapability loop_on_command = 5; + ToolCallCapability tool_call = 6; + DiffReviewCapability diff_review = 7; + ContextPickingCapability context_picking = 8; + EditTrailCapability edit_trail = 9; + AutoContextCapability auto_context = 10; + ContextPlannerCapability context_planner = 11; + RememberThisCapability remember_this = 12; + DecomposerCapability decomposer = 13; +} +message LinterErrors { // aiserver.v1.LinterErrors + string relative_workspace_path = 1; + repeated LinterError errors = 2; + string file_contents = 3; +} +message LinterError { // aiserver.v1.LinterError + message RelatedInformation { // aiserver.v1.Diagnostic.RelatedInformation + string message = 1; + CursorRange range = 2; + } + enum DiagnosticSeverity { // aiserver.v1.Diagnostic.DiagnosticSeverity + DIAGNOSTIC_SEVERITY_UNSPECIFIED = 0; + DIAGNOSTIC_SEVERITY_ERROR = 1; + DIAGNOSTIC_SEVERITY_WARNING = 2; + DIAGNOSTIC_SEVERITY_INFORMATION = 3; + DIAGNOSTIC_SEVERITY_HINT = 4; + } + string message = 1; + CursorRange range = 2; + optional string source = 3; + repeated RelatedInformation related_information = 4; + optional DiagnosticSeverity severity = 5; +} +message CodeChunk { // aiserver.v1.CodeChunk + enum SummarizationStrategy { // aiserver.v1.CodeChunk.SummarizationStrategy + SUMMARIZATION_STRATEGY_NONE_UNSPECIFIED = 0; + SUMMARIZATION_STRATEGY_SUMMARIZED = 1; + SUMMARIZATION_STRATEGY_EMBEDDED = 2; + } + enum Intent { // aiserver.v1.CodeChunk.Intent + INTENT_UNSPECIFIED = 0; + INTENT_COMPOSER_FILE = 1; + INTENT_COMPRESSED_COMPOSER_FILE = 2; + } + string relative_workspace_path = 1; + int32 start_line_number = 2; + repeated string lines = 3; + optional SummarizationStrategy summarization_strategy = 4; + string language_identifier = 5; + optional Intent intent = 6; + optional bool is_final_version = 7; + optional bool is_first_version = 8; +} +message SuggestedCodeBlock { // aiserver.v1.SuggestedCodeBlock + string relative_workspace_path = 1; +} +message RedDiff { // aiserver.v1.RedDiff + string relative_workspace_path = 1; + repeated SimplestRange red_ranges = 2; + repeated SimplestRange red_ranges_reversed = 3; + string start_hash = 4; + string end_hash = 5; +} +message LinterErrorsWithoutFileContents { // aiserver.v1.LinterErrorsWithoutFileContents + string relative_workspace_path = 1; + repeated LinterError errors = 2; +} +message DiffHistoryData { // aiserver.v1.DiffHistoryData + string relative_workspace_path = 1; + repeated ComposerFileDiff diffs = 2; + double timestamp = 3; + string unique_id = 4; + ComposerFileDiff start_to_end_diff = 5; +} +message ComposerFileDiff { // aiserver.v1.ComposerFileDiff + message ChunkDiff { // aiserver.v1.ComposerFileDiff.ChunkDiff + string diff_string = 1; + int32 old_start = 2; + int32 new_start = 3; + int32 old_lines = 4; + int32 new_lines = 5; + int32 lines_removed = 6; + int32 lines_added = 7; + } + enum Editor { // aiserver.v1.ComposerFileDiff.Editor + EDITOR_UNSPECIFIED = 0; + EDITOR_AI = 1; + EDITOR_HUMAN = 2; + } + repeated ChunkDiff chunks = 1; + Editor editor = 2; + bool hit_timeout = 3; +} +message ComposerFileDiffHistory { // aiserver.v1.ComposerFileDiffHistory + string file_name = 1; + repeated string diff_history = 2; + repeated double diff_history_timestamps = 3; +} +message ConversationSummary { // aiserver.v1.ConversationSummary + string summary = 1; + string truncation_last_bubble_id_inclusive = 2; + string client_should_start_sending_from_inclusive_bubble_id = 3; +} +message RepositoryInfo { // aiserver.v1.RepositoryInfo + string relative_workspace_path = 1; + repeated string remote_urls = 2; + repeated string remote_names = 3; + string repo_name = 4; + string repo_owner = 5; + bool is_tracked = 6; + bool is_local = 7; + optional int32 num_files = 8; + optional double orthogonal_transform_seed = 9; + optional EmbeddingModel preferred_embedding_model = 10; +} +message ExplicitContext { // aiserver.v1.ExplicitContext + string context = 1; + optional string repo_context = 2; +} +message ModelDetails { // aiserver.v1.ModelDetails + optional string model_name = 1; + optional string api_key = 2; + optional bool enable_ghost_mode = 3; + optional AzureState azure_state = 4; + optional bool enable_slow_pool = 5; + optional string openai_api_base_url = 6; +} +message AzureState { // aiserver.v1.AzureState + string api_key = 1; + string base_url = 2; + string deployment = 3; + bool use_azure = 4; +} +message ChatQuote { // aiserver.v1.ChatQuote + string markdown = 1; + string bubble_id = 2; + int32 section_index = 3; +} +message DebugInfo { // aiserver.v1.DebugInfo + message Breakpoint { // aiserver.v1.DebugInfo.Breakpoint + string relative_workspace_path = 1; + int32 line_number = 2; + repeated string lines_before_breakpoint = 3; + repeated string lines_after_breakpoint = 4; + optional string exception_info = 5; + } + message CallStackFrame { // aiserver.v1.DebugInfo.CallStackFrame + message Scope { // aiserver.v1.DebugInfo.Scope + message Variable { // aiserver.v1.DebugInfo.Variable + string name = 1; + string value = 2; + optional string type = 3; + } + string name = 1; + repeated Variable variables = 2; + } + string relative_workspace_path = 1; + int32 line_number = 2; + string function_name = 3; + repeated Scope scopes = 4; + } + Breakpoint breakpoint = 1; + repeated CallStackFrame call_stack = 2; + repeated CodeBlock history = 3; +} +message ChatExternalLink { // aiserver.v1.ChatExternalLink + string url = 1; + string uuid = 2; +} +message CommitNote { // aiserver.v1.CommitNote + string note = 1; + string commit_hash = 2; +} +message ContextAST { // aiserver.v1.ContextAST + repeated ContainerTree files = 1; +} +message ContainerTree { // aiserver.v1.ContainerTree + string relative_workspace_path = 1; + repeated ContainerTreeNode nodes = 2; +} +message ContainerTreeNode { // aiserver.v1.ContainerTreeNode + message Container { // aiserver.v1.ContainerTreeNode.Container + message Reference { // aiserver.v1.ContainerTreeNode.Reference + string value = 1; + string relative_workspace_path = 2; + } + string doc_string = 1; + string header = 2; + string trailer = 3; + repeated ContainerTreeNode children = 5; + repeated Reference references = 6; + double score = 7; + } + message Blob { // aiserver.v1.ContainerTreeNode.Blob + optional string value = 1; + } + message Symbol { // aiserver.v1.ContainerTreeNode.Symbol + message Reference { // aiserver.v1.ContainerTreeNode.Reference + string value = 1; + string relative_workspace_path = 2; + } + string doc_string = 1; + string value = 2; + repeated Reference references = 6; + double score = 7; + } + Container container = 1; + Blob blob = 2; + Symbol symbol = 3; +} +message StreamChatResponse { // aiserver.v1.StreamChatResponse + message ChunkIdentity { // aiserver.v1.StreamChatResponse.ChunkIdentity + string file_name = 1; + int32 start_line = 2; + int32 end_line = 3; + string text = 4; + ChunkType chunk_type = 5; + } + string text = 1; + optional string server_bubble_id = 22; + optional string debugging_only_chat_prompt = 2; + optional int32 debugging_only_token_count = 3; + DocumentationCitation document_citation = 4; + optional string filled_prompt = 5; + optional bool is_big_file = 6; + optional string intermediate_text = 7; + optional bool is_using_slow_request = 10; + optional ChunkIdentity chunk_identity = 8; + optional DocsReference docs_reference = 9; + optional WebCitation web_citation = 11; + optional StatusUpdates status_updates = 12; + optional ServerTimingInfo timing_info = 13; + optional SymbolLink symbol_link = 14; + optional FileLink file_link = 15; + optional ConversationSummary conversation_summary = 16; + optional ServiceStatusUpdate service_status_update = 17; +} +message DocumentationCitation { // aiserver.v1.DocumentationCitation + repeated DocumentationChunk chunks = 1; +} +message DocumentationChunk { // aiserver.v1.DocumentationChunk + string doc_name = 1; + string page_url = 2; + string documentation_chunk = 3; + float score = 4; + string page_title = 5; +} +message DocsReference { // aiserver.v1.DocsReference + string title = 1; + string url = 2; +} +message WebCitation { // aiserver.v1.WebCitation + repeated WebReference references = 1; +} +message WebReference { // aiserver.v1.WebReference + string title = 2; + string url = 1; +} +message StatusUpdates { // aiserver.v1.StatusUpdates + repeated StatusUpdate updates = 1; +} +message StatusUpdate { // aiserver.v1.StatusUpdate + string message = 1; + optional string metadata = 2; +} +message ServerTimingInfo { // aiserver.v1.ServerTimingInfo + double server_start_time = 1; + double server_first_token_time = 2; + double server_request_sent_time = 3; + double server_end_time = 4; +} +message SymbolLink { // aiserver.v1.SymbolLink + string symbol_name = 1; + string symbol_search_string = 2; + string relative_workspace_path = 3; + int32 rough_line_number = 4; +} +message FileLink { // aiserver.v1.FileLink + string display_name = 1; + string relative_workspace_path = 2; +} +message ServiceStatusUpdate { // aiserver.v1.ServiceStatusUpdate + string message = 1; + string codicon = 2; + optional bool allow_command_links_potentially_unsafe_please_only_use_for_handwritten_trusted_markdown = 3; +} +message RerankDocumentsRequest { // aiserver.v1.RerankDocumentsRequest + string query = 1; + repeated Document documents = 2; +} +message Document { // aiserver.v1.Document + string content = 1; + string id = 2; +} +message RerankDocumentsResponse { // aiserver.v1.RerankDocumentsResponse + repeated DocumentIdsWithScores documents = 1; +} +message DocumentIdsWithScores { // aiserver.v1.DocumentIdsWithScores + string document_id = 1; + float score = 2; +} +message GetComposerChatRequest { // aiserver.v1.GetComposerChatRequest + message RedDiff { // aiserver.v1.GetComposerChatRequest.RedDiff + string relative_workspace_path = 1; + repeated SimplestRange red_ranges = 2; + repeated SimplestRange red_ranges_reversed = 3; + string start_hash = 4; + string end_hash = 5; + } + message RecentEdits { // aiserver.v1.GetComposerChatRequest.RecentEdits + message CodeBlockInfo { // aiserver.v1.GetComposerChatRequest.RecentEdits.CodeBlockInfo + string relative_workspace_path = 1; + optional string content_before = 2; + optional string content_after = 3; + optional string generation_uuid = 4; + optional int32 version = 5; + } + message FileInfo { // aiserver.v1.GetComposerChatRequest.RecentEdits.FileInfo + string relative_workspace_path = 1; + string content = 2; + } + repeated CodeBlockInfo code_block_info = 1; + repeated FileInfo final_file_values = 2; + optional string edits_belong_to_composer_generation_uuid = 3; + } + repeated ConversationMessage conversation = 1; + optional bool allow_long_file_scan = 2; + ExplicitContext explicit_context = 3; + optional bool can_handle_filenames_after_language_ids = 4; + ModelDetails model_details = 5; + LinterErrors linter_errors = 6; + repeated string documentation_identifiers = 7; + optional string use_web = 8; + repeated ComposerExternalLink external_links = 9; + optional ConversationMessage project_context = 10; + repeated RedDiff diffs_for_compressing_files = 11; + optional bool compress_edits = 12; + optional bool should_cache = 13; + repeated LinterErrors multi_file_linter_errors = 14; + CurrentFileInfo current_file = 15; + optional RecentEdits recent_edits = 16; + optional bool use_reference_composer_diff_prompt = 17; + repeated ComposerFileDiffHistory file_diff_histories = 18; + optional bool use_new_compression_scheme = 19; + repeated RankedContext additional_ranked_context = 20; + repeated ChatQuote quotes = 21; + optional bool willing_to_pay_extra_for_speed = 22; +} +message ComposerExternalLink { // aiserver.v1.ComposerExternalLink + string url = 1; + string uuid = 2; +} +message RankedContext { // aiserver.v1.RankedContext + ContextToRank context = 1; + float score = 2; +} +message ContextToRank { // aiserver.v1.ContextToRank + string relative_workspace_path = 1; + string contents = 2; + optional LineRange line_range = 3; +} +message StreamChatContextRequest { // aiserver.v1.StreamChatContextRequest + message CodeContext { // aiserver.v1.StreamChatContextRequest.CodeContext + repeated CodeBlock chunks = 1; + repeated CodeResult scored_chunks = 2; + } + CurrentFileInfo current_file = 1; + repeated ConversationMessage conversation = 2; + repeated RepositoryInfo repositories = 3; + ExplicitContext explicit_context = 4; + optional string workspace_root_path = 5; + repeated CodeBlock code_blocks = 6; + ModelDetails model_details = 7; + repeated string documentation_identifiers = 8; + string query = 9; + CodeContext code_context = 10; + bool rerank_results = 11; + FullFileSearchResult file_search_results = 12; + CodeSearchResult code_search_results = 13; + LinterErrors linter_errors = 14; + optional bool is_bash = 15; + bool rerank_results_v2 = 16; + string conversation_id = 17; + bool can_handle_filenames_after_language_ids = 18; + bool long_context_mode = 19; + bool is_eval = 20; + string request_id = 21; + optional int32 desired_max_tokens = 22; + optional bool runnable_code_blocks = 23; +} +message FullFileSearchResult { // aiserver.v1.FullFileSearchResult + repeated FileResult results = 1; +} +message FileResult { // aiserver.v1.FileResult + File file = 1; + float score = 2; +} +message File { // aiserver.v1.File + string relative_workspace_path = 1; + string contents = 2; +} +message CodeSearchResult { // aiserver.v1.CodeSearchResult + repeated CodeResult results = 1; +} +message StreamChatContextResponse { // aiserver.v1.StreamChatContextResponse + message UsedCode { // aiserver.v1.StreamChatContextResponse.UsedCode + repeated CodeResult code_results = 1; + } + message CodeLink { // aiserver.v1.StreamChatContextResponse.CodeLink + string relative_workspace_path = 1; + int32 start_line_number = 2; + int32 end_line_number = 3; + } + message ChunkIdentity { // aiserver.v1.StreamChatContextResponse.ChunkIdentity + string file_name = 1; + int32 start_line = 2; + int32 end_line = 3; + string text = 4; + ChunkType chunk_type = 5; + } + string text = 1; + optional string debugging_only_chat_prompt = 2; + optional int32 debugging_only_token_count = 3; + DocumentationCitation document_citation = 4; + optional string filled_prompt = 5; + UsedCode used_code = 6; + CodeLink code_link = 7; + optional ChunkIdentity chunk_identity = 8; + optional DocsReference docs_reference = 9; + optional SymbolLink symbol_link = 10; + optional FileLink file_link = 11; +} +message WarmComposerCacheResponse { // aiserver.v1.WarmComposerCacheResponse + bool did_warm_cache = 1; +} +message KeepComposerCacheWarmRequest { // aiserver.v1.KeepComposerCacheWarmRequest + GetComposerChatRequest request = 1; + string request_id = 2; + bool is_composer_visible = 3; +} +message KeepComposerCacheWarmResponse { // aiserver.v1.KeepComposerCacheWarmResponse + bool did_keep_warm = 1; +} +message PotentialLocsRequest { // aiserver.v1.PotentialLocsRequest + string text = 1; +} +message PotentialLocsResponse { // aiserver.v1.PotentialLocsResponse + string potential_loc = 1; +} +message PotentialLocsUnderneathRequest { // aiserver.v1.PotentialLocsUnderneathRequest + string file = 1; + repeated SimplestRange ranges = 2; + string query = 3; +} +message PotentialLocsUnderneathResponse { // aiserver.v1.PotentialLocsUnderneathResponse + string text = 1; +} +message PotentialLocsInitialQueriesRequest { // aiserver.v1.PotentialLocsInitialQueriesRequest + string query = 1; +} +message PotentialLocsInitialQueriesResponse { // aiserver.v1.PotentialLocsInitialQueriesResponse + string hyde_query = 1; +} +message GetNotepadChatRequest { // aiserver.v1.GetNotepadChatRequest + repeated ConversationMessage conversation = 1; + optional bool allow_long_file_scan = 2; + ExplicitContext explicit_context = 3; + optional bool can_handle_filenames_after_language_ids = 4; + ModelDetails model_details = 5; + LinterErrors linter_errors = 6; + repeated string documentation_identifiers = 7; + optional string use_web = 8; + repeated ComposerExternalLink external_links = 9; + optional ConversationMessage project_context = 10; +} +message GetChatTitleRequest { // aiserver.v1.GetChatTitleRequest + repeated ConversationMessage conversation = 2; +} +message GetChatTitleResponse { // aiserver.v1.GetChatTitleResponse + string title = 1; +} +message GetCompletionRequest { // aiserver.v1.GetCompletionRequest + UniqueFileIdentifier file_identifier = 1; + CursorPosition cursor_position = 2; + SurroundingLines surrounding_lines = 3; + ExplicitContext explicit_context = 4; + repeated string suggestions_from_editor = 5; +} +message UniqueFileIdentifier { // aiserver.v1.UniqueFileIdentifier + string project_uuid = 1; + string relative_path = 2; + optional string language_id = 3; +} +message SurroundingLines { // aiserver.v1.SurroundingLines + int32 start_line = 1; + repeated string lines = 2; +} +message GetCompletionResponse { // aiserver.v1.GetCompletionResponse + string completion = 1; + float score = 2; + optional string debugging_only_completion_prompt = 3; +} +message GetSearchRequest { // aiserver.v1.GetSearchRequest + string query = 1; + repeated RepositoryInfo repositories = 2; + int32 top_k = 3; + repeated string restrict_to_buckets = 4; +} +message GetSearchResponse { // aiserver.v1.GetSearchResponse + repeated FileSearchResult results = 1; +} +message FileSearchResult { // aiserver.v1.FileSearchResult + string repository_relative_workspace_path = 1; + string file_relative_repository_path = 2; + string chunk = 3; + float distance = 4; +} +message StreamInlineEditsRequest { // aiserver.v1.StreamInlineEditsRequest + CurrentFileInfo current_file = 1; + string prompt = 2; + repeated RepositoryInfo repositories = 3; + ExplicitContext explicit_context = 4; +} +message StreamInlineEditsResponse { // aiserver.v1.StreamInlineEditsResponse + string line = 1; + optional string debugging_only_prompt = 2; + optional int32 debugging_only_token_count = 3; +} +message SummarizeConversationResponse { // aiserver.v1.SummarizeConversationResponse + bool did_summarize = 1; + int32 up_until_index = 2; + string summary = 3; +} +message IsolatedTreesitterRequest { // aiserver.v1.IsolatedTreesitterRequest + string file_content = 1; + string language_id = 2; + string command_id = 3; +} +message IsolatedTreesitterResponse { // aiserver.v1.IsolatedTreesitterResponse + message TreesitterSymbolNameItem { // aiserver.v1.IsolatedTreesitterResponse.TreesitterSymbolNameItem + message TreeSitterPosition { // aiserver.v1.IsolatedTreesitterResponse.TreeSitterPosition + int32 row = 1; + int32 column = 2; + } + string symbol_name = 1; + optional TreeSitterPosition start_position = 2; + optional TreeSitterPosition end_position = 3; + } + repeated TreesitterSymbolNameItem items = 1; +} +message GetSimplePromptRequest { // aiserver.v1.GetSimplePromptRequest + string query = 1; + string answer_placeholder = 2; +} +message GetSimplePromptResponse { // aiserver.v1.GetSimplePromptResponse + string result = 1; +} +message CheckLongFilesFitResponse { // aiserver.v1.CheckLongFilesFitResponse + bool did_fit = 1; +} +message GetEvaluationPromptRequest { // aiserver.v1.GetEvaluationPromptRequest + enum EvaluationPromptType { // aiserver.v1.GetEvaluationPromptRequest.EvaluationPromptType + EVALUATION_PROMPT_TYPE_UNSPECIFIED = 0; + EVALUATION_PROMPT_TYPE_GENERATE = 1; + EVALUATION_PROMPT_TYPE_CHAT = 2; + } + enum RerankingStrategy { // aiserver.v1.GetEvaluationPromptRequest.RerankingStrategy + RERANKING_STRATEGY_UNSPECIFIED = 0; + RERANKING_STRATEGY_DISTANCE_ONLY = 1; + RERANKING_STRATEGY_GPT4_RELEVANCE = 2; + } + EvaluationPromptType prompt_type = 1; + CurrentFileInfo current_file = 2; + string query = 3; + string bucket_id = 4; + string query_strategy = 5; + int32 token_limit = 6; + RerankingStrategy reranking_strategy = 7; +} +message GetEvaluationPromptResponse { // aiserver.v1.GetEvaluationPromptResponse + string prompt = 1; + int32 token_count = 2; + int32 estimated_token_count = 3; +} +message GetUserInfoRequest { // aiserver.v1.GetUserInfoRequest +} +message GetUserInfoResponse { // aiserver.v1.GetUserInfoResponse + string user_id = 1; + string jupyter_token = 2; + UsageData usage = 3; +} +message UsageData { // aiserver.v1.UsageData + int32 gpt4_requests = 2; + int32 gpt4_max_requests = 3; +} +message ClearAndRedoEntireBucketRequest { // aiserver.v1.ClearAndRedoEntireBucketRequest + string bucket_id = 1; + optional string commit = 2; +} +message ClearAndRedoEntireBucketResponse { // aiserver.v1.ClearAndRedoEntireBucketResponse +} +message StreamBranchGeminiRequest { // aiserver.v1.StreamBranchGeminiRequest + message PastThought { // aiserver.v1.StreamBranchGeminiRequest.PastThought + string text = 1; + double time_in_unix_seconds = 2; + } + message BranchDiff { // aiserver.v1.StreamBranchGeminiRequest.BranchDiff + message FileDiff { // aiserver.v1.StreamBranchGeminiRequest.BranchDiff.FileDiff + string file_name = 1; + string diff = 2; + bool too_big = 3; + } + repeated FileDiff file_diffs = 1; + repeated Commit commits = 2; + } + message File { // aiserver.v1.StreamBranchGeminiRequest.File + string relative_workspace_path = 1; + string text = 2; + } + message FileWithPriority { // aiserver.v1.StreamBranchGeminiRequest.FileWithPriority + string relative_workspace_path = 1; + string text = 2; + float priority = 3; + } + string branch_name = 1; + string branch_notes = 2; + string global_notes = 3; + repeated PastThought past_thoughts = 4; + BranchDiff diff_to_base_branch = 5; + repeated Commit potentially_relevant_commits = 6; + repeated File files = 7; + repeated FileWithPriority context_graph_files = 8; + repeated File crucial_files = 12; + optional string override_model = 9; + optional int32 override_token_limit = 10; +} +message StreamBranchGeminiResponse { // aiserver.v1.StreamBranchGeminiResponse + string text = 1; + optional string cached_prompt = 2; +} +message StreamBranchFileSelectionsRequest { // aiserver.v1.StreamBranchFileSelectionsRequest + string ai_response = 1; + optional string override_model = 2; + optional int32 override_token_limit = 3; +} +message StreamBranchFileSelectionsResponse { // aiserver.v1.StreamBranchFileSelectionsResponse + message FileInstruction { // aiserver.v1.StreamBranchFileSelectionsResponse.FileInstruction + string relative_workspace_path = 1; + string instruction = 2; + } + repeated FileInstruction file_instructions = 1; +} +message StreamBackgroundEditRequest { // aiserver.v1.StreamBackgroundEditRequest + CurrentFileInfo current_file = 1; + repeated RepositoryInfo repositories = 2; + ExplicitContext explicit_context = 3; + optional string workspace_root_path = 4; + string git_diff = 5; + repeated ConversationMessage conversation = 6; + string query = 7; + ModelDetails model_details = 8; + string stop = 9; + int32 import_line_in_diff = 10; +} +message StreamGPTFourEditRequest { // aiserver.v1.StreamGPTFourEditRequest + CurrentFileInfo current_file = 1; + repeated ConversationMessage conversation = 2; + repeated RepositoryInfo repositories = 3; + ExplicitContext explicit_context = 4; + optional string workspace_root_path = 5; + string query = 6; + repeated CodeBlock code_blocks = 7; + string session_id = 14; + ModelDetails model_details = 9; + repeated string documentation_identifiers = 10; + LinterErrors linter_errors = 11; + repeated CodeBlock prompt_code_blocks = 12; + bool fast_mode = 13; +} +message WarmChatCacheRequest { // aiserver.v1.WarmChatCacheRequest + GetChatRequest request = 1; +} +message WarmChatCacheResponse { // aiserver.v1.WarmChatCacheResponse + bool did_warm_cache = 1; +} +message StreamEditRequest { // aiserver.v1.StreamEditRequest + CurrentFileInfo current_file = 1; + repeated ConversationMessage conversation = 2; + repeated RepositoryInfo repositories = 3; + ExplicitContext explicit_context = 4; + optional string workspace_root_path = 5; + string query = 6; + repeated CodeBlock code_blocks = 7; + ModelDetails model_details = 9; + repeated string documentation_identifiers = 10; + LinterErrors linter_errors = 11; + repeated CodeBlock prompt_code_blocks = 12; + string session_id = 14; + CmdKDebugInfo cmd_k_debug_info = 13; + bool fast_mode = 15; + StreamEditRequest original_request = 16; + repeated ImageProto images = 17; + repeated CmdKExternalLink links = 18; +} +message CmdKDebugInfo { // aiserver.v1.CmdKDebugInfo + message UnsavedFiles { // aiserver.v1.CmdKDebugInfo.UnsavedFiles + string relative_workspace_path = 1; + string contents = 2; + } + message OpenEditor { // aiserver.v1.CmdKDebugInfo.OpenEditor + string relative_workspace_path = 1; + int32 editor_group_index = 2; + int32 editor_group_id = 3; + bool is_active = 4; + } + message CppFileDiffHistory { // aiserver.v1.CmdKDebugInfo.CppFileDiffHistory + string file_name = 1; + repeated string diff_history = 2; + } + message PastThought { // aiserver.v1.CmdKDebugInfo.PastThought + string text = 1; + double time_in_unix_seconds = 2; + } + string remote_url = 1; + string commit_id = 2; + string git_patch = 3; + repeated UnsavedFiles unsaved_files = 4; + double unix_timestamp_ms = 5; + repeated OpenEditor open_editors = 6; + repeated CppFileDiffHistory file_diff_histories = 7; + string branch_name = 8; + string branch_notes = 9; + string branch_notes_rich = 12; + string global_notes = 10; + repeated PastThought past_thoughts = 11; + string base_branch_name = 13; + string base_branch_commit_id = 14; +} +message CmdKExternalLink { // aiserver.v1.CmdKExternalLink + string url = 1; + string uuid = 2; +} +message PreloadEditRequest { // aiserver.v1.PreloadEditRequest + StreamEditRequest req = 1; +} +message PreloadEditResponse { // aiserver.v1.PreloadEditResponse +} +message StreamFastEditRequest { // aiserver.v1.StreamFastEditRequest + CurrentFileInfo current_file = 1; + repeated RepositoryInfo repositories = 3; + ExplicitContext explicit_context = 4; + optional string workspace_root_path = 5; + string query = 6; + repeated CodeBlock code_blocks = 7; + ModelDetails model_details = 9; + repeated string documentation_identifiers = 10; + LinterErrors linter_errors = 11; +} +message StreamFastEditResponse { // aiserver.v1.StreamFastEditResponse + int32 line_number = 2; + int32 replace_num_lines = 3; + string edit_uuid = 5; + optional bool done = 4; + optional string new_line = 6; + bool reset_new_lines = 7; +} +message StreamGenerateRequest { // aiserver.v1.StreamGenerateRequest + CurrentFileInfo current_file = 1; + repeated ConversationMessage conversation = 2; + repeated RepositoryInfo repositories = 3; + ExplicitContext explicit_context = 4; + optional string workspace_root_path = 5; + string query = 6; + repeated CodeBlock code_blocks = 7; + ModelDetails model_details = 9; + repeated string documentation_identifiers = 10; + LinterErrors linter_errors = 11; + repeated CodeBlock prompt_code_blocks = 12; + string session_id = 14; + CmdKDebugInfo cmd_k_debug_info = 13; + bool fast_mode = 15; + StreamGenerateRequest original_request = 16; +} +message StreamInlineLongCompletionRequest { // aiserver.v1.StreamInlineLongCompletionRequest + message ContextBlock { // aiserver.v1.StreamInlineLongCompletionRequest.ContextBlock + enum ContextType { // aiserver.v1.StreamInlineLongCompletionRequest.ContextBlock.ContextType + CONTEXT_TYPE_UNSPECIFIED = 0; + CONTEXT_TYPE_RECENT_LOCATIONS = 1; + } + ContextType context_type = 1; + repeated CodeBlock blocks = 2; + } + CurrentFileInfo current_file = 1; + repeated RepositoryInfo repositories = 6; + repeated ContextBlock context_blocks = 7; + ExplicitContext explicit_context = 13; + ModelDetails model_details = 14; + LinterErrors linter_errors = 15; +} +message SlashEditRequest { // aiserver.v1.SlashEditRequest + enum FastApplyModelType { // aiserver.v1.SlashEditRequest.FastApplyModelType + FAST_APPLY_MODEL_TYPE_UNSPECIFIED = 0; + FAST_APPLY_MODEL_TYPE_DEFAULT = 1; + FAST_APPLY_MODEL_TYPE_DEEPSEEK = 2; + FAST_APPLY_MODEL_TYPE_SONNET = 3; + FAST_APPLY_MODEL_TYPE_OPUS_DIFF = 4; + FAST_APPLY_MODEL_TYPE_SMART_REWRITE = 5; + FAST_APPLY_MODEL_TYPE_GPT4 = 6; + FAST_APPLY_MODEL_TYPE_GPT4_NOSPEC = 7; + FAST_APPLY_MODEL_TYPE_SMART_REWRITE_NOSPEC = 8; + FAST_APPLY_MODEL_TYPE_OPUS = 9; + FAST_APPLY_MODEL_TYPE_HAIKU = 10; + FAST_APPLY_MODEL_TYPE_GPT4O_NOSPEC = 11; + FAST_APPLY_MODEL_TYPE_GPT4O_DIFF = 12; + FAST_APPLY_MODEL_TYPE_CODESTRAL_REWRITE = 13; + FAST_APPLY_MODEL_TYPE_DEEPSEEK_33B = 14; + FAST_APPLY_MODEL_TYPE_SONNET_35_DIFF = 15; + FAST_APPLY_MODEL_TYPE_SONNET_35_REWRITE = 16; + FAST_APPLY_MODEL_TYPE_PROMPTED_DEEPSEEK_V2 = 17; + FAST_APPLY_MODEL_TYPE_CODESTRAL_REWRITE_OLD = 18; + FAST_APPLY_MODEL_TYPE_CODESTRAL_REWRITE_FP16 = 19; + FAST_APPLY_MODEL_TYPE_DEEPSEEK_33B_V2 = 20; + FAST_APPLY_MODEL_TYPE_CODESTRAL_V4 = 21; + FAST_APPLY_MODEL_TYPE_CODESTRAL_V5 = 22; + FAST_APPLY_MODEL_TYPE_CODESTRAL_V6 = 23; + FAST_APPLY_MODEL_TYPE_CODESTRAL_V7 = 24; + } + CurrentFileInfo current_file = 2; + repeated ConversationMessage conversation = 3; + ExplicitContext explicit_context = 4; + ModelDetails model_details = 7; + bool is_cmd_i = 8; + optional string summary = 11; + optional int32 summary_up_until_index = 12; + optional bool should_use_turbo_debug_prompt = 13; + optional LineRange edit_selection = 14; + repeated CurrentFileInfo files = 15; + optional string clicked_code_block_contents = 16; + optional bool is_an_optimistic_request_for_caching_and_linting = 17; + optional string specific_instructions = 18; + bool use_fast_apply = 19; + FastApplyModelType fast_apply_model_type = 20; + optional bool use_chunk_speculation_for_long_files = 25; + optional string parent_request_id = 26; + optional FastApplySource source = 27; + optional bool is_reapply = 28; + optional bool willing_to_pay_extra_for_speed = 29; +} +message SlashEditResponse { // aiserver.v1.SlashEditResponse + StreamCmdKResponse cmd_k_response = 1; +} +message StreamCmdKResponse { // aiserver.v1.StreamCmdKResponse + message EditStart { // aiserver.v1.StreamCmdKResponse.EditStart + int32 start_line_number = 1; + int32 edit_id = 2; + optional int32 max_end_line_number_exclusive = 3; + optional string file_path = 4; + } + message EditStream { // aiserver.v1.StreamCmdKResponse.EditStream + string text = 1; + int32 edit_id = 2; + optional string file_path = 3; + } + message EditEnd { // aiserver.v1.StreamCmdKResponse.EditEnd + int32 end_line_number_exclusive = 1; + int32 edit_id = 2; + optional string file_path = 3; + } + message Chat { // aiserver.v1.StreamCmdKResponse.Chat + string text = 1; + } + message StatusUpdate { // aiserver.v1.StreamCmdKResponse.StatusUpdate + repeated string messages = 1; + } + EditStart edit_start = 1; + EditStream edit_stream = 2; + EditEnd edit_end = 3; + Chat chat = 4; + StatusUpdate status_update = 5; +} +message SlashEditFollowUpWithPreviousEditsRequest { // aiserver.v1.SlashEditFollowUpWithPreviousEditsRequest + repeated ConversationMessage conversation = 1; + ModelDetails model_details = 2; + repeated SlashEditPreviousEdit previous_edits = 3; +} +message SlashEditPreviousEdit { // aiserver.v1.SlashEditPreviousEdit + repeated string original_lines = 1; + repeated string new_lines = 2; + string relative_workspace_path = 3; + LineRange range = 4; +} +message StreamSlashEditFollowUpWithPreviousEditsResponse { // aiserver.v1.StreamSlashEditFollowUpWithPreviousEditsResponse + message Chat { // aiserver.v1.StreamSlashEditFollowUpWithPreviousEditsResponse.Chat + string text = 1; + } + message EditsToUpdate { // aiserver.v1.StreamSlashEditFollowUpWithPreviousEditsResponse.EditsToUpdate + repeated SlashEditPreviousEdit previous_edits = 1; + } + Chat chat = 1; + EditsToUpdate edits_to_update = 2; +} +message StreamAiPreviewsRequest { // aiserver.v1.StreamAiPreviewsRequest + CurrentFileInfo current_file = 1; + StreamAiPreviewsIntent intent = 2; + ModelDetails model_details = 14; + optional bool is_detailed = 15; +} +message StreamAiPreviewsIntent { // aiserver.v1.StreamAiPreviewsIntent + repeated DocumentSymbolWithText main_symbols_to_analyze_from_go_to_def = 1; + HoverDetails main_symbol_hover_details = 4; + repeated DocumentSymbolWithText related_symbols = 3; + repeated DocumentSymbolWithText main_symbols_to_analyze_from_implementations = 6; +} +message DocumentSymbolWithText { // aiserver.v1.DocumentSymbolWithText + DocumentSymbol symbol = 1; + string relative_workspace_path = 2; + string text_in_symbol_range = 3; + UriComponents uri_components = 4; +} +message DocumentSymbol { // aiserver.v1.DocumentSymbol + enum SymbolKind { // aiserver.v1.DocumentSymbol.SymbolKind + SYMBOL_KIND_UNSPECIFIED = 0; + SYMBOL_KIND_FILE = 1; + SYMBOL_KIND_MODULE = 2; + SYMBOL_KIND_NAMESPACE = 3; + SYMBOL_KIND_PACKAGE = 4; + SYMBOL_KIND_CLASS = 5; + SYMBOL_KIND_METHOD = 6; + SYMBOL_KIND_PROPERTY = 7; + SYMBOL_KIND_FIELD = 8; + SYMBOL_KIND_CONSTRUCTOR = 9; + SYMBOL_KIND_ENUM = 10; + SYMBOL_KIND_INTERFACE = 11; + SYMBOL_KIND_FUNCTION = 12; + SYMBOL_KIND_VARIABLE = 13; + SYMBOL_KIND_CONSTANT = 14; + SYMBOL_KIND_STRING = 15; + SYMBOL_KIND_NUMBER = 16; + SYMBOL_KIND_BOOLEAN = 17; + SYMBOL_KIND_ARRAY = 18; + SYMBOL_KIND_OBJECT = 19; + SYMBOL_KIND_KEY = 20; + SYMBOL_KIND_NULL = 21; + SYMBOL_KIND_ENUM_MEMBER = 22; + SYMBOL_KIND_STRUCT = 23; + SYMBOL_KIND_EVENT = 24; + SYMBOL_KIND_OPERATOR = 25; + SYMBOL_KIND_TYPE_PARAMETER = 26; + } + message Range { // aiserver.v1.DocumentSymbol.Range + int32 start_line_number = 1; + int32 start_column = 2; + int32 end_line_number = 3; + int32 end_column = 4; + } + string name = 1; + string detail = 2; + SymbolKind kind = 3; + string container_name = 5; + Range range = 6; + Range selection_range = 7; + repeated DocumentSymbol children = 8; +} +message UriComponents { // aiserver.v1.UriComponents + string scheme = 1; + optional string authority = 2; + optional string path = 3; + optional string query = 4; + optional string fragment = 5; +} +message HoverDetails { // aiserver.v1.HoverDetails + string code_details = 1; + repeated string markdown_blocks = 2; +} +message StreamAiPreviewsResponse { // aiserver.v1.StreamAiPreviewsResponse + string text = 1; +} +message ShouldTurnOnCppOnboardingRequest { // aiserver.v1.ShouldTurnOnCppOnboardingRequest +} +message ShouldTurnOnCppOnboardingResponse { // aiserver.v1.ShouldTurnOnCppOnboardingResponse + bool should_turn_on_cpp_onboarding = 1; +} +message ReviewRequest { // aiserver.v1.ReviewRequest + string chunk = 1; + string file_context = 2; + LineRange chunk_range = 3; + optional string diff_string = 4; + optional string custom_instructions = 5; +} +message ReviewResponse { // aiserver.v1.ReviewResponse + string text = 1; + optional string prompt = 2; + optional string tldr = 3; + optional bool is_bug = 4; + repeated ReviewBug bugs = 5; +} +message ReviewBug { // aiserver.v1.ReviewBug + string id = 1; + optional int32 start_line = 2; + optional int32 end_line = 3; + optional string description = 4; + optional int32 severity = 5; + optional string tldr = 6; +} +message ReviewChatRequest { // aiserver.v1.ReviewChatRequest + string chunk = 1; + string file_context = 2; + LineRange chunk_range = 3; + repeated ReviewChatMessage messages = 4; +} +message ReviewChatMessage { // aiserver.v1.ReviewChatMessage + enum ReviewChatMessageType { // aiserver.v1.ReviewChatMessage.ReviewChatMessageType + REVIEW_CHAT_MESSAGE_TYPE_UNSPECIFIED = 0; + REVIEW_CHAT_MESSAGE_TYPE_HUMAN = 1; + REVIEW_CHAT_MESSAGE_TYPE_AI = 2; + } + string text = 1; + ReviewChatMessageType type = 2; +} +message ReviewChatResponse { // aiserver.v1.ReviewChatResponse + string text = 1; + optional bool should_resolve = 2; +} +message CheckQueuePositionRequest { // aiserver.v1.CheckQueuePositionRequest + string orig_request_id = 1; + ModelDetails model_details = 2; + string usage_uuid = 3; +} +message CheckQueuePositionResponse { // aiserver.v1.CheckQueuePositionResponse + message CustomLink { // aiserver.v1.CheckQueuePositionResponse.CustomLink + string address = 1; + string message = 2; + } + int32 position = 1; + optional int32 seconds_left_to_wait = 2; + optional int32 new_queue_position = 7; + bool hit_hard_limit = 3; + bool could_enable_usage_based_pricing_to_skip = 4; + UsageEventDetails usage_event_details = 5; + CustomLink custom_link = 6; +} +message UsageEventDetails { // aiserver.v1.UsageEventDetails + message Chat { // aiserver.v1.UsageEventDetails.Chat + string model_intent = 1; + } + message ContextChat { // aiserver.v1.UsageEventDetails.ContextChat + string model_intent = 1; + } + message CmdK { // aiserver.v1.UsageEventDetails.CmdK + string model_intent = 1; + } + message TerminalCmdK { // aiserver.v1.UsageEventDetails.TerminalCmdK + string model_intent = 1; + } + message AiReviewAcceptedComment { // aiserver.v1.UsageEventDetails.AiReviewAcceptedComment + } + message InterpreterChat { // aiserver.v1.UsageEventDetails.InterpreterChat + string model_intent = 1; + } + message SlashEdit { // aiserver.v1.UsageEventDetails.SlashEdit + string model_intent = 1; + } + message Composer { // aiserver.v1.UsageEventDetails.Composer + string model_intent = 1; + } + message FastApply { // aiserver.v1.UsageEventDetails.FastApply + bool is_optimistic = 1; + bool willing_to_pay_extra_for_speed = 2; + } + message WarmComposer { // aiserver.v1.UsageEventDetails.WarmComposer + string model_intent = 1; + } + message BugFinderTriggerV1 { // aiserver.v1.UsageEventDetails.BugFinderTriggerV1 + bool in_background_subsidized = 1; + int32 cost_cents = 2; + } + Chat chat = 1; + ContextChat context_chat = 2; + CmdK cmd_k = 3; + TerminalCmdK terminal_cmd_k = 4; + AiReviewAcceptedComment ai_review_accepted_comment = 5; + InterpreterChat interpreter_chat = 6; + SlashEdit slash_edit = 7; + Composer composer = 8; + FastApply fast_apply = 9; + WarmComposer warm_composer = 10; + BugFinderTriggerV1 bug_finder_trigger_v1 = 11; +} +message CheckUsageBasedPriceRequest { // aiserver.v1.CheckUsageBasedPriceRequest + UsageEventDetails usage_event_details = 1; +} +message CheckUsageBasedPriceResponse { // aiserver.v1.CheckUsageBasedPriceResponse + string markdown_response = 1; + int32 cents = 2; + string price_id = 3; +} +message DoThisForMeCheckRequest { // aiserver.v1.DoThisForMeCheckRequest + string generation_uuid = 1; + string completion = 2; +} +message DoThisForMeCheckResponse { // aiserver.v1.DoThisForMeCheckResponse + message SkipAction { // aiserver.v1.DoThisForMeCheckResponse.SkipAction + } + message EditAction { // aiserver.v1.DoThisForMeCheckResponse.EditAction + string relative_workspace_path = 1; + } + message CreateAction { // aiserver.v1.DoThisForMeCheckResponse.CreateAction + string relative_workspace_path = 1; + } + message RunAction { // aiserver.v1.DoThisForMeCheckResponse.RunAction + string command = 1; + } + SkipAction skip_action = 1; + EditAction edit_action = 2; + CreateAction create_action = 3; + RunAction run_action = 4; + string reasoning = 5; +} +message DoThisForMeRequest { // aiserver.v1.DoThisForMeRequest + string generation_uuid = 1; + string completion = 2; + DoThisForMeCheckResponse action = 3; +} +message DoThisForMeResponseWrapped { // aiserver.v1.DoThisForMeResponseWrapped + DoThisForMeResponse real_response = 1; + string background_task_uuid = 2; +} +message DoThisForMeResponse { // aiserver.v1.DoThisForMeResponse + message UpdateStatus { // aiserver.v1.DoThisForMeResponse.UpdateStatus + string status = 1; + } + UpdateStatus update_status = 1; +} +message StreamChatToolformerResponse { // aiserver.v1.StreamChatToolformerResponse + message Output { // aiserver.v1.StreamChatToolformerResponse.Output + string text = 1; + } + message ToolAction { // aiserver.v1.StreamChatToolformerResponse.ToolAction + string user_facing_text = 1; + string raw_model_output = 3; + ToolCall tool_call = 2; + bool more_to_come = 4; + } + message Thought { // aiserver.v1.StreamChatToolformerResponse.Thought + string text = 1; + } + optional string toolformer_session_id = 1; + Output output = 2; + ToolAction tool_action = 3; + Thought thought = 4; +} +message ToolCall { // aiserver.v1.ToolCall + BuiltinToolCall builtin_tool_call = 1; + CustomToolCall custom_tool_call = 2; +} +message BuiltinToolCall { // aiserver.v1.BuiltinToolCall + BuiltinTool tool = 1; + SearchParams search_params = 2; + ReadChunkParams read_chunk_params = 3; + GotodefParams gotodef_params = 4; + EditParams edit_params = 5; + UndoEditParams undo_edit_params = 6; + EndParams end_params = 7; + NewFileParams new_file_params = 8; + AddTestParams add_test_params = 9; + RunTestParams run_test_params = 10; + DeleteTestParams delete_test_params = 11; + SaveFileParams save_file_params = 12; + GetTestsParams get_tests_params = 13; + GetSymbolsParams get_symbols_params = 14; + SemanticSearchParams semantic_search_params = 15; + GetProjectStructureParams get_project_structure_params = 16; + CreateRmFilesParams create_rm_files_params = 17; + RunTerminalCommandsParams run_terminal_commands_params = 18; + NewEditParams new_edit_params = 19; + ReadWithLinterParams read_with_linter_params = 20; + AddUiStepParams add_ui_step_params = 21; + ReadSemsearchFilesParams read_semsearch_files_params = 23; + ReadFileForImportsParams read_file_for_imports_params = 24; + CreateFileParams create_file_params = 25; + DeleteFileParams delete_file_params = 26; + optional string tool_call_id = 22; +} +message SearchParams { // aiserver.v1.SearchParams + string query = 1; + bool regex = 2; + string include_pattern = 3; + string exclude_pattern = 4; + bool filename_search = 5; +} +message ReadChunkParams { // aiserver.v1.ReadChunkParams + string relative_workspace_path = 1; + int32 start_line_number = 2; + optional int32 num_lines = 3; +} +message GotodefParams { // aiserver.v1.GotodefParams + string relative_workspace_path = 1; + int32 line_number = 2; + string symbol = 3; +} +message EditParams { // aiserver.v1.EditParams + enum FrontendEditType { // aiserver.v1.EditParams.FrontendEditType + FRONTEND_EDIT_TYPE_UNSPECIFIED = 0; + FRONTEND_EDIT_TYPE_INLINE_DIFFS = 1; + FRONTEND_EDIT_TYPE_SIMPLE = 2; + } + string relative_workspace_path = 1; + optional int32 line_number = 2; + int32 replace_num_lines = 3; + repeated string new_lines = 4; + optional bool replace_whole_file = 7; + string edit_id = 5; + FrontendEditType frontend_edit_type = 6; + optional bool auto_fix_all_linter_errors_in_file = 8; +} +message UndoEditParams { // aiserver.v1.UndoEditParams +} +message EndParams { // aiserver.v1.EndParams +} +message NewFileParams { // aiserver.v1.NewFileParams + string relative_workspace_path = 1; +} +message AddTestParams { // aiserver.v1.AddTestParams + string relative_workspace_path = 1; + string test_name = 2; + string test_code = 3; +} +message RunTestParams { // aiserver.v1.RunTestParams + string relative_workspace_path = 1; + optional string test_name = 2; +} +message DeleteTestParams { // aiserver.v1.DeleteTestParams + string relative_workspace_path = 1; + optional string test_name = 2; +} +message SaveFileParams { // aiserver.v1.SaveFileParams + string relative_workspace_path = 1; +} +message GetTestsParams { // aiserver.v1.GetTestsParams + string relative_workspace_path = 1; +} +message GetSymbolsParams { // aiserver.v1.GetSymbolsParams + message LineRange { // aiserver.v1.GetSymbolsParams.LineRange + int32 start_line_number = 1; + int32 end_line_number_inclusive = 2; + } + string relative_workspace_path = 1; + optional LineRange line_range = 2; + bool include_children = 3; +} +message SemanticSearchParams { // aiserver.v1.SemanticSearchParams + string query = 1; + optional string include_pattern = 2; + optional string exclude_pattern = 3; + int32 top_k = 4; + optional string index_id = 5; + bool grab_whole_file = 6; +} +message GetProjectStructureParams { // aiserver.v1.GetProjectStructureParams +} +message CreateRmFilesParams { // aiserver.v1.CreateRmFilesParams + repeated string removed_file_paths = 1; + repeated string created_file_paths = 2; + repeated string created_directory_paths = 3; +} +message RunTerminalCommandsParams { // aiserver.v1.RunTerminalCommandsParams + repeated string commands = 1; + string commands_uuid = 2; +} +message NewEditParams { // aiserver.v1.NewEditParams + string relative_workspace_path = 1; + optional int32 start_line_number = 2; + optional int32 end_line_number = 3; + string text = 4; + string edit_id = 5; + bool first_edit = 6; +} +message ReadWithLinterParams { // aiserver.v1.ReadWithLinterParams + string relative_workspace_path = 1; +} +message AddUiStepParams { // aiserver.v1.AddUiStepParams + message SearchResults { // aiserver.v1.AddUiStepParams.SearchResults + message SearchResult { // aiserver.v1.AddUiStepParams.SearchResult + string relative_workspace_path = 1; + } + repeated SearchResult search_results = 1; + } + string conversation_id = 1; + SearchResults search_results = 2; +} +message ReadSemsearchFilesParams { // aiserver.v1.ReadSemsearchFilesParams + RepositoryInfo repository_info = 1; + repeated CodeResult code_results = 2; + string query = 3; +} +message ReadFileForImportsParams { // aiserver.v1.ReadFileForImportsParams + string relative_file_path = 1; +} +message CreateFileParams { // aiserver.v1.CreateFileParams + string relative_workspace_path = 1; +} +message DeleteFileParams { // aiserver.v1.DeleteFileParams + string relative_workspace_path = 1; +} +message CustomToolCall { // aiserver.v1.CustomToolCall + string tool_id = 1; + string params = 2; +} +message StreamChatToolformerContinueRequest { // aiserver.v1.StreamChatToolformerContinueRequest + string toolformer_session_id = 1; + ToolResult tool_result = 2; +} +message ToolResult { // aiserver.v1.ToolResult + BuiltinToolResult builtin_tool_result = 1; + CustomToolResult custom_tool_result = 2; + ErrorToolResult error_tool_result = 3; +} +message BuiltinToolResult { // aiserver.v1.BuiltinToolResult + BuiltinTool tool = 1; + SearchResult search_result = 2; + ReadChunkResult read_chunk_result = 3; + GotodefResult gotodef_result = 4; + EditResult edit_result = 5; + UndoEditResult undo_edit_result = 6; + EndResult end_result = 7; + NewFileResult new_file_result = 8; + AddTestResult add_test_result = 9; + RunTestResult run_test_result = 10; + DeleteTestResult delete_test_result = 11; + SaveFileResult save_file_result = 12; + GetTestsResult get_tests_result = 13; + GetSymbolsResult get_symbols_result = 14; + SemanticSearchResult semantic_search_result = 15; + GetProjectStructureResult get_project_structure_result = 16; + CreateRmFilesResult create_rm_files_result = 17; + RunTerminalCommandsResult run_terminal_commands_result = 18; + NewEditResult new_edit_result = 19; + ReadWithLinterResult read_with_linter_result = 20; + AddUiStepResult add_ui_step_result = 21; + ReadSemsearchFilesResult read_semsearch_files_result = 22; + CreateFileResult create_file_result = 23; + DeleteFileResult delete_file_result = 24; +} +message SearchResult { // aiserver.v1.SearchResult + repeated SearchToolFileSearchResult file_results = 1; + int32 num_total_matches = 2; + int32 num_total_matched_files = 3; + bool num_total_may_be_incomplete = 4; + bool files_only = 5; +} +message SearchToolFileSearchResult { // aiserver.v1.SearchToolFileSearchResult + message Line { // aiserver.v1.SearchToolFileSearchResult.Line + int32 line_number = 1; + string text = 2; + } + string relative_workspace_path = 1; + int32 num_matches = 2; + repeated Line potentially_relevant_lines = 3; + bool cropped = 4; +} +message ReadChunkResult { // aiserver.v1.ReadChunkResult + string relative_workspace_path = 1; + int32 start_line_number = 2; + repeated string lines = 3; + int32 total_num_lines = 4; + bool cropped = 5; +} +message GotodefResult { // aiserver.v1.GotodefResult + repeated GotodefToolFileSearchResult results = 1; +} +message GotodefToolFileSearchResult { // aiserver.v1.GotodefToolFileSearchResult + message Line { // aiserver.v1.GotodefToolFileSearchResult.Line + int32 line_number = 1; + string text = 2; + } + string relative_workspace_path = 1; + repeated Line potentially_relevant_lines = 3; +} +message EditResult { // aiserver.v1.EditResult + message Feedback { // aiserver.v1.EditResult.Feedback + message RelatedInformation { // aiserver.v1.EditResult.RelatedInformation + string message = 1; + int32 start_line_number = 2; + int32 end_line_number = 3; + string relative_workspace_path = 4; + } + string message = 1; + string severity = 2; + int32 start_line_number = 3; + int32 end_line_number = 4; + repeated RelatedInformation related_information = 5; + } + repeated string feedback = 1; + int32 context_start_line_number = 2; + repeated string context_lines = 3; + string file = 4; + int32 file_total_lines = 5; + repeated Feedback structured_feedback = 6; +} +message UndoEditResult { // aiserver.v1.UndoEditResult + repeated string feedback = 1; + string relative_workspace_path = 4; + int32 context_start_line_number = 2; + repeated string context_lines = 3; + int32 context_total_num_lines = 5; + int32 file_total_lines = 6; +} +message EndResult { // aiserver.v1.EndResult +} +message NewFileResult { // aiserver.v1.NewFileResult + string relative_workspace_path = 1; + int32 file_total_lines = 2; +} +message AddTestResult { // aiserver.v1.AddTestResult + message Feedback { // aiserver.v1.AddTestResult.Feedback + message RelatedInformation { // aiserver.v1.AddTestResult.RelatedInformation + string message = 1; + int32 start_line_number = 2; + int32 end_line_number = 3; + string relative_workspace_path = 4; + } + string message = 1; + string severity = 2; + int32 start_line_number = 3; + int32 end_line_number = 4; + repeated RelatedInformation related_information = 5; + } + repeated Feedback feedback = 1; +} +message RunTestResult { // aiserver.v1.RunTestResult + string result = 1; +} +message DeleteTestResult { // aiserver.v1.DeleteTestResult +} +message SaveFileResult { // aiserver.v1.SaveFileResult +} +message GetTestsResult { // aiserver.v1.GetTestsResult + message Test { // aiserver.v1.GetTestsResult.Test + string name = 1; + repeated string lines = 2; + } + repeated Test tests = 1; +} +message GetSymbolsResult { // aiserver.v1.GetSymbolsResult + repeated DocumentSymbol symbols = 1; +} +message SemanticSearchResult { // aiserver.v1.SemanticSearchResult + message Item { // aiserver.v1.SemanticSearchResult.Item + string relative_workspace_path = 1; + float score = 2; + string content = 3; + SimpleRange range = 4; + optional string original_content = 5; + repeated DetailedLine detailed_lines = 6; + } + repeated Item results = 1; +} +message SimpleRange { // aiserver.v1.SimpleRange + int32 start_line_number = 1; + int32 start_column = 2; + int32 end_line_number_inclusive = 3; + int32 end_column = 4; +} +message GetProjectStructureResult { // aiserver.v1.GetProjectStructureResult + message File { // aiserver.v1.GetProjectStructureResult.File + string relative_workspace_path = 1; + string outline = 2; + } + repeated File files = 1; + string root_workspace_path = 2; +} +message CreateRmFilesResult { // aiserver.v1.CreateRmFilesResult + repeated string created_file_paths = 1; + repeated string removed_file_paths = 2; +} +message RunTerminalCommandsResult { // aiserver.v1.RunTerminalCommandsResult + repeated string outputs = 1; +} +message NewEditResult { // aiserver.v1.NewEditResult +} +message ReadWithLinterResult { // aiserver.v1.ReadWithLinterResult + string contents = 1; + repeated Diagnostic diagnostics = 2; +} +message AddUiStepResult { // aiserver.v1.AddUiStepResult +} +message CustomToolResult { // aiserver.v1.CustomToolResult + string tool_id = 1; + string result = 2; +} +message ErrorToolResult { // aiserver.v1.ErrorToolResult + string error_message = 1; +} +message PushAiThoughtRequest { // aiserver.v1.PushAiThoughtRequest + message Metadata { // aiserver.v1.PushAiThoughtRequest.Metadata + message AcceptedHallucinatedFunctionEvent { // aiserver.v1.PushAiThoughtRequest.Metadata.AcceptedHallucinatedFunctionEvent + string implementation_uuid = 1; + string hallucinated_function_uuid = 2; + string implementation = 3; + string source = 4; + string implementation_reqid = 5; + string plan_reqid = 6; + string reflection_reqid = 7; + } + AcceptedHallucinatedFunctionEvent accepted_hallucinated_function_event = 1; + } + string thought = 1; + CmdKDebugInfo cmd_k_debug_info = 2; + bool automated = 3; + optional Metadata metadata = 4; +} +message PushAiThoughtResponse { // aiserver.v1.PushAiThoughtResponse +} +message CheckDoableAsTaskRequest { // aiserver.v1.CheckDoableAsTaskRequest + string model_output = 1; + ModelDetails model_details = 2; +} +message CheckDoableAsTaskResponse { // aiserver.v1.CheckDoableAsTaskResponse + bool doable_as_task = 1; +} +message ReportGroundTruthCandidateRequest { // aiserver.v1.ReportGroundTruthCandidateRequest + string request_id = 1; + int32 time_since_completed_action_ms = 2; + FeatureType feature_type = 3; + string relative_workspace_path = 4; + string contents = 5; + LineRange selection_in_question = 6; + int32 lines_above_and_below = 7; +} +message ReportGroundTruthCandidateResponse { // aiserver.v1.ReportGroundTruthCandidateResponse +} +message ReportCmdKFateRequest { // aiserver.v1.ReportCmdKFateRequest + enum Fate { // aiserver.v1.ReportCmdKFateRequest.Fate + FATE_UNSPECIFIED = 0; + FATE_CANCELLED = 1; + FATE_ACCEPTED = 2; + FATE_REJECTED = 3; + FATE_FOLLOWED_UP = 4; + FATE_REPROMPTED = 5; + } + string request_id = 1; + Fate fate = 2; +} +message ReportCmdKFateResponse { // aiserver.v1.ReportCmdKFateResponse +} +message ShowWelcomeScreenRequest { // aiserver.v1.ShowWelcomeScreenRequest +} +message ShowWelcomeScreenResponse { // aiserver.v1.ShowWelcomeScreenResponse + repeated string enable_cards = 1; +} +message InterfaceAgentInitRequest { // aiserver.v1.InterfaceAgentInitRequest + ModelDetails model_details = 1; + bool debugging_only_live_mode = 2; + InterfaceAgentClientState interface_agent_client_state = 3; +} +message InterfaceAgentClientState { // aiserver.v1.InterfaceAgentClientState + string interface_relative_workspace_path = 3; + repeated string interface_lines = 4; + optional string test_relative_workspace_path = 5; + repeated string test_lines = 10; + optional string implementation_relative_workspace_path = 6; + repeated string implementation_lines = 7; + string language = 8; + string testing_framework = 9; +} +message InterfaceAgentInitResponse { // aiserver.v1.InterfaceAgentInitResponse + string task_uuid = 1; + string human_readable_title = 2; +} +message StreamInterfaceAgentStatusRequest { // aiserver.v1.StreamInterfaceAgentStatusRequest + string task_uuid = 1; +} +message StreamInterfaceAgentStatusResponse { // aiserver.v1.StreamInterfaceAgentStatusResponse + InterfaceAgentStatus status = 1; +} +message InterfaceAgentStatus { // aiserver.v1.InterfaceAgentStatus + enum Status { // aiserver.v1.InterfaceAgentStatus.Status + STATUS_UNSPECIFIED = 0; + STATUS_WAITING = 1; + STATUS_RUNNING = 2; + STATUS_SUCCESS = 3; + STATUS_FAILURE = 4; + } + Status validate_configuration = 1; + Status stub_new_function = 2; + Status verify_spec = 3; + Status write_test_plan = 15; + Status write_tests = 4; + Status write_implementation = 5; + Status implement_new_function = 6; + Status run_tests = 7; + string validate_configuration_message = 8; + string stub_new_function_message = 9; + string verify_spec_message = 10; + string write_test_plan_message = 16; + string write_tests_message = 11; + string write_implementation_message = 12; + string implement_new_function_message = 13; + string run_tests_message = 14; +} +message TaskGetInterfaceAgentStatusRequest { // aiserver.v1.TaskGetInterfaceAgentStatusRequest + InterfaceAgentClientState interface_agent_client_state = 1; +} +message TaskGetInterfaceAgentStatusResponseWrapped { // aiserver.v1.TaskGetInterfaceAgentStatusResponseWrapped + TaskGetInterfaceAgentStatusResponse real_response = 1; + string background_task_uuid = 2; +} +message TaskGetInterfaceAgentStatusResponse { // aiserver.v1.TaskGetInterfaceAgentStatusResponse + InterfaceAgentStatus status = 1; +} +message TaskInitRequest { // aiserver.v1.TaskInitRequest + TaskInstruction instruction = 1; + ModelDetails model_details = 2; + bool debugging_only_live_mode = 3; + optional string engine_id = 4; +} +message TaskInstruction { // aiserver.v1.TaskInstruction + message CodeChunk { // aiserver.v1.TaskInstruction.CodeChunk + string relative_workspace_path = 1; + int32 start_line_number = 2; + repeated string lines = 3; + } + string text = 1; + repeated CodeChunk attached_code_chunks = 2; + CurrentFileInfo current_file = 3; + repeated RepositoryInfo repositories = 4; + ExplicitContext explicit_context = 5; +} +message TaskInitResponse { // aiserver.v1.TaskInitResponse + string task_uuid = 1; + string human_readable_title = 2; +} +message TaskPauseRequest { // aiserver.v1.TaskPauseRequest + string task_uuid = 1; +} +message TaskPauseResponse { // aiserver.v1.TaskPauseResponse +} +message TaskInfoRequest { // aiserver.v1.TaskInfoRequest + string task_uuid = 1; +} +message TaskInfoResponse { // aiserver.v1.TaskInfoResponse + string human_readable_title = 1; + TaskStatus task_status = 2; + int32 last_log_sequence_number = 3; +} +message TaskStreamLogRequest { // aiserver.v1.TaskStreamLogRequest + string task_uuid = 1; + int32 start_sequence_number = 2; +} +message TaskStreamLogResponse { // aiserver.v1.TaskStreamLogResponse + message InfoUpdate { // aiserver.v1.TaskStreamLogResponse.InfoUpdate + optional string human_readable_title = 1; + optional TaskStatus task_status = 2; + } + TaskLogItem streamed_log_item = 1; + InfoUpdate info_update = 2; + TaskInfoResponse initial_task_info = 3; +} +message TaskLogItem { // aiserver.v1.TaskLogItem + int32 sequence_number = 1; + bool is_not_done = 2; + TaskLogOutput output = 3; + TaskLogToolAction tool_action = 4; + TaskLogThought thought = 5; + TaskUserMessage user_message = 6; + TaskInstruction instruction = 7; + TaskLogToolResult tool_result = 8; +} +message TaskLogOutput { // aiserver.v1.TaskLogOutput + string text = 1; +} +message TaskLogToolAction { // aiserver.v1.TaskLogToolAction + string user_facing_text = 1; + string raw_model_output = 3; + ToolCall tool_call = 2; +} +message TaskLogThought { // aiserver.v1.TaskLogThought + string text = 1; +} +message TaskUserMessage { // aiserver.v1.TaskUserMessage + message CodeChunk { // aiserver.v1.TaskUserMessage.CodeChunk + string relative_workspace_path = 1; + int32 start_line_number = 2; + repeated string lines = 3; + } + string text = 1; + repeated CodeChunk attached_code_chunks = 2; +} +message TaskLogToolResult { // aiserver.v1.TaskLogToolResult + ToolResult tool_result = 1; + int32 action_sequence_number = 2; +} +message TaskSendMessageRequest { // aiserver.v1.TaskSendMessageRequest + string task_uuid = 1; + TaskUserMessage user_message = 2; + bool wants_attention_right_now = 3; +} +message TaskSendMessageResponse { // aiserver.v1.TaskSendMessageResponse +} +message TaskProvideResultRequest { // aiserver.v1.TaskProvideResultRequest + string task_uuid = 1; + int32 action_sequence_number = 2; + ToolResult tool_result = 3; +} +message TaskProvideResultResponse { // aiserver.v1.TaskProvideResultResponse +} +message CreateExperimentalIndexRequest { // aiserver.v1.CreateExperimentalIndexRequest + repeated string files = 1; + string target_dir = 2; + string repo = 3; +} +message CreateExperimentalIndexResponse { // aiserver.v1.CreateExperimentalIndexResponse + string index_id = 1; +} +message ListExperimentalIndexFilesRequest { // aiserver.v1.ListExperimentalIndexFilesRequest + string index_id = 1; +} +message ListExperimentalIndexFilesResponse { // aiserver.v1.ListExperimentalIndexFilesResponse + string index_id = 1; + repeated IndexFileData files = 2; +} +message IndexFileData { // aiserver.v1.IndexFileData + message NodeData { // aiserver.v1.IndexFileData.NodeData + string node_id = 1; + string stage = 2; + string content = 3; + string summary = 4; + } + string index_id = 1; + string workspace_relative_path = 2; + string stage = 3; + int32 order = 4; + repeated NodeData nodes = 5; +} +message ListenExperimentalIndexRequest { // aiserver.v1.ListenExperimentalIndexRequest + string index_id = 1; +} +message ListenExperimentalIndexResponse { // aiserver.v1.ListenExperimentalIndexResponse + message ReadyItem { // aiserver.v1.ListenExperimentalIndexResponse.ReadyItem + string index_id = 1; + ListenExperimentalIndexRequest request = 2; + } + message RegisterItem { // aiserver.v1.ListenExperimentalIndexResponse.RegisterItem + RegisterFileToIndexResponse response = 1; + RegisterFileToIndexRequest request = 2; + string req_uuid = 3; + } + message ChooseItem { // aiserver.v1.ListenExperimentalIndexResponse.ChooseItem + ChooseCodeReferencesResponse response = 1; + ChooseCodeReferencesRequest request = 2; + string req_uuid = 3; + } + message SummarizeItem { // aiserver.v1.ListenExperimentalIndexResponse.SummarizeItem + SummarizeWithReferencesResponse response = 1; + SummarizeWithReferencesRequest request = 2; + string req_uuid = 3; + } + message ErrorItem { // aiserver.v1.ListenExperimentalIndexResponse.ErrorItem + string message = 1; + int32 status_code = 2; + RegisterFileToIndexRequest register = 3; + ChooseCodeReferencesRequest choose = 4; + SummarizeWithReferencesRequest summarize = 5; + string req_uuid = 6; + } + string index_id = 1; + ReadyItem ready = 2; + RegisterItem register = 3; + ChooseItem choose = 4; + SummarizeItem summarize = 5; + ErrorItem error = 6; +} +message RegisterFileToIndexResponse { // aiserver.v1.RegisterFileToIndexResponse + string file_id = 1; + string root_context_node_id = 2; + repeated URIResolutionAttempt dependency_resolution_attempts = 3; + IndexFileData file_data = 4; +} +message URIResolutionAttempt { // aiserver.v1.URIResolutionAttempt + string workspace_relative_path = 1; + string node_id = 2; + CodeSymbolWithAction symbol = 3; +} +message CodeSymbolWithAction { // aiserver.v1.CodeSymbolWithAction + enum CodeSymbolAction { // aiserver.v1.CodeSymbolWithAction.CodeSymbolAction + CODE_SYMBOL_ACTION_UNSPECIFIED = 0; + CODE_SYMBOL_ACTION_GO_TO_DEFINITION = 1; + CODE_SYMBOL_ACTION_GO_TO_IMPLEMENTATION = 2; + CODE_SYMBOL_ACTION_REFERENCES = 3; + } + string workspace_relative_path = 1; + int32 line_number = 2; + int32 symbol_start_column = 3; + int32 symbol_end_column = 4; + CodeSymbolAction action = 5; + string symbol = 6; +} +message RegisterFileToIndexRequest { // aiserver.v1.RegisterFileToIndexRequest + string index_id = 1; + string workspace_relative_path = 2; + SerializedContextNode root_context_node = 3; + repeated string content = 4; +} +message SerializedContextNode { // aiserver.v1.SerializedContextNode + string workspace_relative_path = 1; + int32 start_line_number = 2; + int32 end_line_number = 3; + repeated SerializedContextNode children = 4; + FileCodeSnippets node_snippets = 5; +} +message FileCodeSnippets { // aiserver.v1.FileCodeSnippets + string relative_workspace_path = 1; + int32 total_lines = 2; + repeated CodeSnippet snippets = 3; +} +message CodeSnippet { // aiserver.v1.CodeSnippet + int32 start_line_number = 1; + int32 end_line_number = 2; + repeated string lines = 3; +} +message ChooseCodeReferencesResponse { // aiserver.v1.ChooseCodeReferencesResponse + message FileResponse { // aiserver.v1.ChooseCodeReferencesResponse.FileResponse + message NodeResponse { // aiserver.v1.ChooseCodeReferencesResponse.NodeResponse + string node_id = 1; + repeated CodeSymbolWithAction actions = 2; + bool skipped = 3; + repeated string dependencies = 4; + } + string file_id = 1; + repeated NodeResponse node_responses = 2; + } + message NodeResponse { // aiserver.v1.ChooseCodeReferencesResponse.NodeResponse + string node_id = 1; + repeated CodeSymbolWithAction actions = 2; + bool skipped = 3; + repeated string dependencies = 4; + } + FileResponse file = 1; + NodeResponse node = 2; +} +message ChooseCodeReferencesRequest { // aiserver.v1.ChooseCodeReferencesRequest + message FileRequest { // aiserver.v1.ChooseCodeReferencesRequest.FileRequest + string file_id = 1; + } + message NodeRequest { // aiserver.v1.ChooseCodeReferencesRequest.NodeRequest + string node_id = 1; + } + string index_id = 1; + FileRequest file = 2; + NodeRequest node = 3; + bool recompute = 4; +} +message SummarizeWithReferencesResponse { // aiserver.v1.SummarizeWithReferencesResponse + message Success { // aiserver.v1.SummarizeWithReferencesResponse.Success + string summary = 1; + } + message Dependency { // aiserver.v1.SummarizeWithReferencesResponse.Dependency + repeated string nodes = 2; + } + Success success = 1; + Dependency dependency = 2; + string node_id = 3; +} +message SummarizeWithReferencesRequest { // aiserver.v1.SummarizeWithReferencesRequest + string index_id = 1; + string node_id = 2; + bool recompute = 3; +} +message RequestReceivedResponse { // aiserver.v1.RequestReceivedResponse + string req_uuid = 1; +} +message SetupIndexDependenciesRequest { // aiserver.v1.SetupIndexDependenciesRequest + string index_id = 1; + string file_id = 3; + repeated URIResolutionResult dependency_resolution_results = 2; +} +message URIResolutionResult { // aiserver.v1.URIResolutionResult + URIResolutionAttempt request = 1; + repeated string resolved_paths = 2; +} +message SetupIndexDependenciesResponse { // aiserver.v1.SetupIndexDependenciesResponse +} +message ComputeIndexTopoSortRequest { // aiserver.v1.ComputeIndexTopoSortRequest + string index_id = 1; +} +message ComputeIndexTopoSortResponse { // aiserver.v1.ComputeIndexTopoSortResponse +} +message StreamChatDeepContextRequest { // aiserver.v1.StreamChatDeepContextRequest + repeated ConversationMessage conversation = 1; + ExplicitContext explicit_context = 2; + ModelDetails model_details = 3; + SearchRepositoryDeepContextResponse context_results = 4; + bool rerank_results = 5; +} +message SearchRepositoryDeepContextResponse { // aiserver.v1.SearchRepositoryDeepContextResponse + repeated NodeResult top_nodes = 1; + repeated ReflectionResult reflections = 2; + string index_id = 3; +} +message NodeResult { // aiserver.v1.NodeResult + message NodeData { // aiserver.v1.IndexFileData.NodeData + string node_id = 1; + string stage = 2; + string content = 3; + string summary = 4; + } + NodeData node = 1; + File file = 2; + float score = 3; +} +message ReflectionResult { // aiserver.v1.ReflectionResult + ReflectionData reflection = 1; + float score = 2; +} +message ReflectionData { // aiserver.v1.ReflectionData + string index_id = 1; + string id = 2; + string summary = 3; +} +message StreamChatDeepContextResponse { // aiserver.v1.StreamChatDeepContextResponse + string text = 1; +} +message RegisterCodeReferencesRequest { // aiserver.v1.RegisterCodeReferencesRequest + string node_id = 1; + repeated SymbolActionResults references = 2; +} +message SymbolActionResults { // aiserver.v1.SymbolActionResults + CodeSymbolWithAction action = 1; + repeated SymbolActionResultReference references = 2; +} +message SymbolActionResultReference { // aiserver.v1.SymbolActionResultReference + SimpleRange range = 1; + FileCodeSnippets reference = 2; +} +message RegisterCodeReferencesResponse { // aiserver.v1.RegisterCodeReferencesResponse + repeated string dependencies = 1; +} +message ExtractPathsRequest { // aiserver.v1.ExtractPathsRequest + FileCodeSnippets file_code_snippets = 1; +} +message ExtractPathsResponse { // aiserver.v1.ExtractPathsResponse + repeated CodeSymbolWithAction paths = 1; +} +message DocumentationQueryRequest { // aiserver.v1.DocumentationQueryRequest + string doc_identifier = 1; + string query = 2; + uint32 top_k = 3; + bool rerank_results = 4; +} +message DocumentationQueryResponse { // aiserver.v1.DocumentationQueryResponse + enum Status { // aiserver.v1.DocumentationQueryResponse.Status + STATUS_UNSPECIFIED = 0; + STATUS_NOT_FOUND = 1; + STATUS_SUCCESS = 2; + STATUS_FAILURE = 3; + } + string doc_identifier = 1; + string doc_name = 2; + repeated DocumentationChunk doc_chunks = 3; + Status status = 4; +} +message AvailableDocsRequest { // aiserver.v1.AvailableDocsRequest + string partial_url = 1; + string partial_doc_name = 2; + bool get_all = 3; + repeated string additional_doc_identifiers = 4; +} +message AvailableDocsResponse { // aiserver.v1.AvailableDocsResponse + repeated DocumentationInfo docs = 1; +} +message DocumentationInfo { // aiserver.v1.DocumentationInfo + string doc_identifier = 1; + DocumentationMetadata metadata = 2; +} +message DocumentationMetadata { // aiserver.v1.DocumentationMetadata + string prefix_url = 1; + string doc_name = 2; + bool is_different_prefix_origin = 3; + string true_prefix_url = 4; + bool public = 5; + optional int32 team_id = 6; +} +message ReportFeedbackRequest { // aiserver.v1.ReportFeedbackRequest + enum FeedbackType { // aiserver.v1.ReportFeedbackRequest.FeedbackType + FEEDBACK_TYPE_UNSPECIFIED = 0; + FEEDBACK_TYPE_LOW_PRIORITY = 1; + FEEDBACK_TYPE_HIGH_PRIORITY = 2; + } + string feedback = 1; + FeedbackType feedback_type = 2; +} +message ReportFeedbackResponse { // aiserver.v1.ReportFeedbackResponse +} +message ReportBugRequest { // aiserver.v1.ReportBugRequest + enum BugType { // aiserver.v1.ReportBugRequest.BugType + BUG_TYPE_UNSPECIFIED = 0; + BUG_TYPE_LOW = 1; + BUG_TYPE_MEDIUM = 2; + BUG_TYPE_URGENT = 3; + BUG_TYPE_CRASH = 4; + BUG_TYPE_CONNECTION_ERROR = 5; + BUG_TYPE_IDEA = 6; + BUG_TYPE_MISC_AUTOMATIC_ERROR = 7; + } + string bug = 1; + BugType bug_type = 2; + BugContext context = 3; + string contact_email = 4; +} +message BugContext { // aiserver.v1.BugContext + enum Error { // aiserver.v1.ErrorDetails.Error + ERROR_UNSPECIFIED = 0; + ERROR_BAD_API_KEY = 1; + ERROR_BAD_USER_API_KEY = 2; + ERROR_NOT_LOGGED_IN = 3; + ERROR_INVALID_AUTH_ID = 4; + ERROR_NOT_HIGH_ENOUGH_PERMISSIONS = 5; + ERROR_AGENT_REQUIRES_LOGIN = 6; + ERROR_BAD_MODEL_NAME = 7; + ERROR_NOT_FOUND = 8; + ERROR_DEPRECATED = 9; + ERROR_USER_NOT_FOUND = 10; + ERROR_FREE_USER_RATE_LIMIT_EXCEEDED = 11; + ERROR_PRO_USER_RATE_LIMIT_EXCEEDED = 12; + ERROR_FREE_USER_USAGE_LIMIT = 13; + ERROR_PRO_USER_USAGE_LIMIT = 14; + ERROR_RESOURCE_EXHAUSTED = 15; + ERROR_AUTH_TOKEN_NOT_FOUND = 16; + ERROR_AUTH_TOKEN_EXPIRED = 17; + ERROR_OPENAI = 18; + ERROR_OPENAI_RATE_LIMIT_EXCEEDED = 19; + ERROR_OPENAI_ACCOUNT_LIMIT_EXCEEDED = 20; + ERROR_TASK_UUID_NOT_FOUND = 21; + ERROR_TASK_NO_PERMISSIONS = 22; + ERROR_AGENT_ENGINE_NOT_FOUND = 23; + ERROR_MAX_TOKENS = 24; + ERROR_PRO_USER_ONLY = 25; + ERROR_API_KEY_NOT_SUPPORTED = 26; + ERROR_USER_ABORTED_REQUEST = 27; + ERROR_GENERIC_RATE_LIMIT_EXCEEDED = 28; + ERROR_SLASH_EDIT_FILE_TOO_LONG = 29; + ERROR_FILE_UNSUPPORTED = 30; + ERROR_GPT_4_VISION_PREVIEW_RATE_LIMIT = 31; + ERROR_CUSTOM_MESSAGE = 32; + ERROR_OUTDATED_CLIENT = 33; + ERROR_CLAUDE_IMAGE_TOO_LARGE = 34; + ERROR_GITGRAPH_NOT_FOUND = 35; + ERROR_FILE_NOT_FOUND = 36; + ERROR_API_KEY_RATE_LIMIT = 37; + ERROR_DEBOUNCED = 38; + ERROR_BAD_REQUEST = 39; + ERROR_REPOSITORY_SERVICE_REPOSITORY_IS_NOT_INITIALIZED = 40; + ERROR_UNAUTHORIZED = 41; + } + repeated string screenshots = 1; + CurrentFileInfo current_file = 2; + repeated ConversationMessage conversation = 3; + repeated LogFile logs = 4; + string console_logs = 5; + string cursor_version = 6; + string os = 7; + string proto_url = 8; + string failing_requst_id = 9; + string connection_error_raw = 10; + CmdKDebugInfo debug_info = 12; + optional int32 connect_error_code = 13; + optional Error error_detail_code = 14; + optional string error_detail_title = 15; + optional string error_detail_detail = 16; +} +message LogFile { // aiserver.v1.LogFile + string relative_path_to_cursor_folder = 1; + string contents = 2; +} +message ReportBugResponse { // aiserver.v1.ReportBugResponse +} +message GenerateTldrRequest { // aiserver.v1.GenerateTldrRequest + string text = 1; +} +message GenerateTldrResponse { // aiserver.v1.GenerateTldrResponse + string summary = 1; + string all = 2; +} +message TaskStreamChatContextRequest { // aiserver.v1.TaskStreamChatContextRequest + CurrentFileInfo current_file = 1; + repeated ConversationMessage conversation = 2; + repeated RepositoryInfo repositories = 3; + ExplicitContext explicit_context = 4; + optional string workspace_root_path = 5; + repeated CodeBlock code_blocks = 6; + ModelDetails model_details = 7; + repeated string documentation_identifiers = 8; + LinterErrors linter_errors = 14; + AdvancedCodebaseContextOptions advanced_codebase_context = 15; + optional bool is_eval = 16; + string request_id = 17; + optional int32 desired_token_limit = 18; +} +message AdvancedCodebaseContextOptions { // aiserver.v1.AdvancedCodebaseContextOptions + int32 num_results_per_search = 1; + optional string include_pattern = 2; + optional string exclude_pattern = 3; + RerankerAlgorithm reranker = 4; + optional string index_id = 5; + bool reasoning_step = 6; + optional RechunkerChoice rechunker = 7; +} +message TaskStreamChatContextResponseWrapped { // aiserver.v1.TaskStreamChatContextResponseWrapped + TaskStreamChatContextResponse real_response = 1; + string background_task_uuid = 2; +} +message TaskStreamChatContextResponse { // aiserver.v1.TaskStreamChatContextResponse + message Output { // aiserver.v1.TaskStreamChatContextResponse.Output + string text = 1; + } + message GatheringStep { // aiserver.v1.TaskStreamChatContextResponse.GatheringStep + string title = 1; + int32 index = 2; + string query = 3; + } + message GatheringFile { // aiserver.v1.TaskStreamChatContextResponse.GatheringFile + string relative_workspace_path = 1; + SimpleRange range = 2; + int32 step_index = 3; + float score = 4; + } + message RerankingStep { // aiserver.v1.TaskStreamChatContextResponse.RerankingStep + string title = 1; + int32 index = 2; + } + message RerankingFile { // aiserver.v1.TaskStreamChatContextResponse.RerankingFile + string relative_workspace_path = 1; + SimpleRange range = 2; + string reason = 3; + bool failed = 4; + float score = 5; + int32 step_index = 6; + } + message ReasoningStep { // aiserver.v1.TaskStreamChatContextResponse.ReasoningStep + string title = 1; + int32 index = 2; + } + message ReasoningSubstep { // aiserver.v1.TaskStreamChatContextResponse.ReasoningSubstep + string markdown_explanation = 1; + int32 step_index = 2; + } + Output output = 1; + GatheringStep gathering_step = 2; + GatheringFile gathering_file = 3; + RerankingStep reranking_step = 4; + RerankingFile reranking_file = 5; + ReasoningStep reasoning_step = 6; + ReasoningSubstep reasoning_substep = 7; +} +message RerankerRequest { // aiserver.v1.RerankerRequest + repeated CodeResult code_results = 1; + string query = 2; + int32 num_blocks = 3; + CurrentFileInfo current_file = 4; + repeated ConversationMessage conversation = 5; + ApiDetails api_details = 6; + FullFileSearchResult file_search_results = 7; + CodeSearchResult code_search_results = 8; +} +message ApiDetails { // aiserver.v1.ApiDetails + string api_key = 1; + optional bool enable_ghost_mode = 2; +} +message RerankerResponse { // aiserver.v1.RerankerResponse + repeated CodeResult results = 1; +} +message ModelQueryRequest { // aiserver.v1.ModelQueryRequest + enum QueryType { // aiserver.v1.ModelQueryRequest.QueryType + QUERY_TYPE_UNSPECIFIED = 0; + QUERY_TYPE_KEYWORDS = 1; + QUERY_TYPE_EMBEDDINGS = 2; + } + CurrentFileInfo current_file = 1; + repeated ConversationMessage conversation = 2; + repeated RepositoryInfo repositories = 3; + ExplicitContext explicit_context = 4; + optional string workspace_root_path = 5; + repeated CodeBlock code_blocks = 6; + ModelDetails model_details = 7; + QueryType query_type = 8; + RepositoryInfo repository_info = 9; + bool faster_and_stupider = 10; + bool use_globs = 11; +} +message ModelQueryResponse { // aiserver.v1.ModelQueryResponse + message Query { // aiserver.v1.ModelQueryResponse.Query + string query = 1; + bool successful_parse = 2; + repeated string good_file_extensions = 3; + repeated string bad_file_extensions = 4; + repeated string good_paths = 5; + repeated string bad_paths = 6; + } + repeated Query queries = 1; +} +message ModelQueryResponseV2 { // aiserver.v1.ModelQueryResponseV2 + message QueryItem { // aiserver.v1.ModelQueryResponseV2.QueryItem + string text = 1; + string glob = 2; + int32 index = 3; + } + QueryItem query = 1; + string reasoning = 2; +} +message IntentPredictionRequest { // aiserver.v1.IntentPredictionRequest + repeated ConversationMessage messages = 1; + ContextOptions context_options = 2; + ModelDetails model_details = 3; +} +message ContextOptions { // aiserver.v1.ContextOptions + message AllDocumentation { // aiserver.v1.ContextOptions.AllDocumentation + message Documentation { // aiserver.v1.ContextOptions.AllDocumentation.Documentation + string name = 1; + string url = 2; + string identifier = 3; + } + repeated Documentation available_docs = 1; + } + message CurrentFileContents { // aiserver.v1.ContextOptions.CurrentFileContents + string relative_workspace_path = 1; + string contents = 2; + CursorPosition cursor_position = 3; + repeated DataframeInfo dataframes = 4; + string language_id = 5; + CursorRange selection = 6; + } + message LinterDiagnostics { // aiserver.v1.ContextOptions.LinterDiagnostics + message Diagnostic { // aiserver.v1.ContextOptions.LinterDiagnostics.Diagnostic + string message = 1; + string source = 2; + CursorRange range = 3; + string relative_workspace_path = 4; + } + string relative_workspace_path = 1; + string contents = 2; + repeated Diagnostic diagnostics = 3; + } + message GlobalContext { // aiserver.v1.ContextOptions.GlobalContext + } + AllDocumentation all_documentation = 1; + CurrentFileContents current_file_contents = 2; + LinterDiagnostics linter_diagnostics = 3; + GlobalContext global_context = 4; +} +message IntentPredictionResponse { // aiserver.v1.IntentPredictionResponse + message ChosenDocumentation { // aiserver.v1.IntentPredictionResponse.ChosenDocumentation + repeated int32 doc_indices = 1; + repeated string doc_identifiers = 2; + repeated string doc_names = 3; + } + message ChosenFileContents { // aiserver.v1.IntentPredictionResponse.ChosenFileContents + } + message ChosenLinterDiagnostics { // aiserver.v1.IntentPredictionResponse.ChosenLinterDiagnostics + repeated int32 diagnostic_indices = 1; + } + ChosenDocumentation chosen_documentation = 1; + ChosenFileContents chosen_file_contents = 2; + ChosenLinterDiagnostics chosen_linter_diagnostics = 3; + bool use_global_context = 4; + bool use_with_folder_context = 5; +} +message StreamCursorTutorRequest { // aiserver.v1.StreamCursorTutorRequest + repeated ConversationMessage conversation = 1; + ModelDetails model_details = 2; +} +message StreamCursorTutorResponse { // aiserver.v1.StreamCursorTutorResponse + string text = 1; +} +message CheckFeatureStatusRequest { // aiserver.v1.CheckFeatureStatusRequest + string feature_name = 1; +} +message CheckFeatureStatusResponse { // aiserver.v1.CheckFeatureStatusResponse + bool enabled = 1; +} +message GetEffectiveTokenLimitRequest { // aiserver.v1.GetEffectiveTokenLimitRequest + ModelDetails model_details = 1; +} +message GetEffectiveTokenLimitResponse { // aiserver.v1.GetEffectiveTokenLimitResponse + int32 token_limit = 1; +} +message ContextScoresRequest { // aiserver.v1.ContextScoresRequest + string source_range = 1; + repeated string method_signatures = 2; +} +message ContextScoresResponse { // aiserver.v1.ContextScoresResponse + repeated float scores = 1; +} +message StreamCppRequest { // aiserver.v1.StreamCppRequest + enum ControlToken { // aiserver.v1.StreamCppRequest.ControlToken + CONTROL_TOKEN_UNSPECIFIED = 0; + CONTROL_TOKEN_QUIET = 1; + CONTROL_TOKEN_LOUD = 2; + CONTROL_TOKEN_OP = 3; + } + CurrentFileInfo current_file = 1; + repeated string diff_history = 2; + optional string model_name = 3; + optional LinterErrors linter_errors = 4; + repeated CppContextItem context_items = 13; + repeated string diff_history_keys = 5; + optional bool give_debug_output = 6; + repeated CppFileDiffHistory file_diff_histories = 7; + repeated CppFileDiffHistory merged_diff_histories = 8; + repeated BlockDiffPatch block_diff_patches = 9; + optional bool is_nightly = 10; + optional bool is_debug = 11; + optional bool immediately_ack = 12; + optional bool enable_more_context = 17; + repeated CppParameterHint parameter_hints = 14; + repeated LspSubgraphFullContext lsp_contexts = 15; + optional CppIntentInfo cpp_intent_info = 16; + optional string workspace_id = 18; + repeated AdditionalFile additional_files = 19; + optional ControlToken control_token = 20; + optional double client_time = 21; + repeated FilesyncUpdateWithModelVersion filesync_updates = 22; + double time_since_request_start = 23; + double time_at_request_send = 24; +} +message CppContextItem { // aiserver.v1.CppContextItem + string contents = 1; + optional string symbol = 2; + string relative_workspace_path = 3; + float score = 4; +} +message CppFileDiffHistory { // aiserver.v1.CppFileDiffHistory + string file_name = 1; + repeated string diff_history = 2; + repeated double diff_history_timestamps = 3; +} +message BlockDiffPatch { // aiserver.v1.BlockDiffPatch + message ModelWindow { // aiserver.v1.BlockDiffPatch.ModelWindow + repeated string lines = 1; + int32 start_line_number = 2; + int32 end_line_number = 3; + } + message Change { // aiserver.v1.BlockDiffPatch.Change + string text = 1; + IRange range = 2; + } + ModelWindow start_model_window = 1; + repeated Change changes = 3; + string relative_path = 4; + string model_uuid = 7; + int32 start_from_change_index = 5; +} +message IRange { // aiserver.v1.IRange + int32 start_line_number = 1; + int32 start_column = 2; + int32 end_line_number = 3; + int32 end_column = 4; +} +message CppParameterHint { // aiserver.v1.CppParameterHint + string label = 1; + optional string documentation = 2; +} +message LspSubgraphFullContext { // aiserver.v1.LspSubgraphFullContext + string uri = 1; + string symbol_name = 2; + repeated LspSubgraphPosition positions = 3; + repeated LspSubgraphContextItem context_items = 4; + float score = 5; +} +message LspSubgraphPosition { // aiserver.v1.LspSubgraphPosition + int32 line = 1; + int32 character = 2; +} +message LspSubgraphContextItem { // aiserver.v1.LspSubgraphContextItem + optional string uri = 1; + string type = 2; + string content = 3; + optional LspSubgraphRange range = 4; +} +message LspSubgraphRange { // aiserver.v1.LspSubgraphRange + int32 start_line = 1; + int32 start_character = 2; + int32 end_line = 3; + int32 end_character = 4; +} +message CppIntentInfo { // aiserver.v1.CppIntentInfo + string source = 1; +} +message AdditionalFile { // aiserver.v1.AdditionalFile + string relative_workspace_path = 1; + bool is_open = 2; + repeated string visible_range_content = 3; + optional double last_viewed_at = 4; +} +message FilesyncUpdateWithModelVersion { // aiserver.v1.FilesyncUpdateWithModelVersion + int32 model_version = 1; + string relative_workspace_path = 2; + repeated SingleUpdateRequest updates = 3; + int32 expected_file_length = 4; +} +message SingleUpdateRequest { // aiserver.v1.SingleUpdateRequest + int32 start_position = 1; + int32 end_position = 2; + int32 change_length = 3; + string replaced_string = 4; + SimpleRange range = 5; +} +message StreamCppResponse { // aiserver.v1.StreamCppResponse + string text = 1; + optional int32 suggestion_start_line = 2; + optional int32 suggestion_confidence = 3; + optional bool done_stream = 4; + optional string debug_model_output = 5; + optional string debug_model_input = 6; + optional string debug_stream_time = 7; + optional string debug_total_time = 8; + optional string debug_ttft_time = 9; + optional string debug_server_timing = 10; + optional LineRange range_to_replace = 11; +} +message CppConfigRequest { // aiserver.v1.CppConfigRequest + optional bool is_nightly = 1; + string model = 2; +} +message CppConfigResponse { // aiserver.v1.CppConfigResponse + message MergeBehavior { // aiserver.v1.CppConfigResponse.MergeBehavior + string type = 1; + optional int32 limit = 2; + optional int32 radius = 3; + } + enum Heuristic { // aiserver.v1.CppConfigResponse.Heuristic + HEURISTIC_UNSPECIFIED = 0; + HEURISTIC_LOTS_OF_ADDED_TEXT = 1; + HEURISTIC_DUPLICATING_LINE_AFTER_SUGGESTION = 2; + HEURISTIC_DUPLICATING_MULTIPLE_LINES_AFTER_SUGGESTION = 3; + HEURISTIC_REVERTING_USER_CHANGE = 4; + HEURISTIC_OUTPUT_EXTENDS_BEYOND_RANGE_AND_IS_REPEATED = 5; + HEURISTIC_SUGGESTING_RECENTLY_REJECTED_EDIT = 6; + } + message ImportPredictionConfig { // aiserver.v1.CppConfigResponse.ImportPredictionConfig + bool is_disabled_by_backend = 1; + bool should_turn_on_automatically = 2; + bool python_enabled = 3; + } + message RecentlyRejectedEditThresholds { // aiserver.v1.CppConfigResponse.RecentlyRejectedEditThresholds + int32 hard_reject_threshold = 1; + int32 soft_reject_threshold = 2; + } + optional int32 above_radius = 1; + optional int32 below_radius = 2; + optional MergeBehavior merge_behavior = 4; + optional bool is_on = 5; + optional bool is_ghost_text = 6; + optional bool should_let_user_enable_cpp_even_if_not_pro = 7; + repeated Heuristic heuristics = 8; + repeated string exclude_recently_viewed_files_patterns = 9; + bool enable_rvf_tracking = 10; + int32 global_debounce_duration_millis = 11; + int32 client_debounce_duration_millis = 12; + string cpp_url = 13; + bool use_whitespace_diff_history = 14; + ImportPredictionConfig import_prediction_config = 15; + bool enable_filesync_debounce_skipping = 16; + float check_filesync_hash_percent = 17; + string geo_cpp_backend_url = 18; + optional RecentlyRejectedEditThresholds recently_rejected_edit_thresholds = 19; +} +message CppEditHistoryStatusRequest { // aiserver.v1.CppEditHistoryStatusRequest +} +message CppEditHistoryStatusResponse { // aiserver.v1.CppEditHistoryStatusResponse + bool on = 1; + bool only_if_explicit = 2; +} +message CppAppendRequest { // aiserver.v1.CppAppendRequest + bytes changes = 1; +} +message CppAppendResponse { // aiserver.v1.CppAppendResponse + bool success = 1; +} +message CheckNumberConfigRequest { // aiserver.v1.CheckNumberConfigRequest + string key = 1; +} +message CheckNumberConfigResponse { // aiserver.v1.CheckNumberConfigResponse + int32 value = 1; +} +message StreamTerminalAutocompleteRequest { // aiserver.v1.StreamTerminalAutocompleteRequest + string current_command = 1; + repeated string command_history = 2; + optional string model_name = 3; + repeated CppFileDiffHistory file_diff_histories = 4; + optional string git_diff = 5; + repeated string commit_history = 6; + repeated string past_results = 7; +} +message StreamTerminalAutocompleteResponse { // aiserver.v1.StreamTerminalAutocompleteResponse + string text = 1; + optional bool done_stream = 2; +} +message StreamPseudocodeGeneratorRequest { // aiserver.v1.StreamPseudocodeGeneratorRequest + CurrentFileInfo current_file = 1; + PseudocodeTarget target = 2; +} +message PseudocodeTarget { // aiserver.v1.PseudocodeTarget + SimpleRange range = 1; + string content = 2; +} +message StreamPseudocodeGeneratorResponse { // aiserver.v1.StreamPseudocodeGeneratorResponse + string text = 1; +} +message StreamPseudocodeMapperRequest { // aiserver.v1.StreamPseudocodeMapperRequest + PseudocodeTarget target = 2; + string pseudocode = 1; +} +message StreamPseudocodeMapperResponse { // aiserver.v1.StreamPseudocodeMapperResponse + string text = 1; +} +message StreamAiLintBugRequest { // aiserver.v1.StreamAiLintBugRequest + message CodeChunk { // aiserver.v1.StreamAiLintBugRequest.CodeChunk + string relative_workspace_path = 1; + int32 start_line_number = 2; + repeated string lines = 3; + repeated string context_lines_before = 4; + repeated string context_lines_after = 5; + } + message CodeChunkList { // aiserver.v1.StreamAiLintBugRequest.CodeChunkList + message CodeChunk { // aiserver.v1.StreamAiLintBugRequest.CodeChunk + string relative_workspace_path = 1; + int32 start_line_number = 2; + repeated string lines = 3; + repeated string context_lines_before = 4; + repeated string context_lines_after = 5; + } + repeated CodeChunk chunks = 13; + repeated int32 referred_start_lines = 14; + repeated int32 referred_end_lines = 15; + } + message DiscriminatorOptions { // aiserver.v1.StreamAiLintBugRequest.DiscriminatorOptions + bool specific_rules = 1; + bool compile_errors = 2; + bool change_behavior = 3; + bool match_code = 4; + bool relevance = 5; + bool user_awareness = 6; + } + repeated CodeChunk chunks_to_analyze = 1; + ExplicitContext explicit_context = 4; + optional string workspace_root_path = 5; + ModelDetails model_details = 9; + repeated AiLintBug dismissed_bugs = 10; + repeated AiLintBug active_bugs = 11; + repeated AiLintRule lint_rules = 12; + repeated CodeChunkList clients = 14; + repeated LintDiscriminator force_enable_discriminators = 17; + repeated LintDiscriminator force_disable_discriminators = 18; + repeated LintGenerator force_enable_generators = 19; + repeated LintGenerator force_disable_generators = 20; + int32 version = 21; + optional DiscriminatorOptions discriminator_options = 15; + bool debug_mode = 16; +} +message AiLintBug { // aiserver.v1.AiLintBug + string relative_workspace_path = 1; + string uuid = 8; + string message = 2; + SimpleRange replace_range = 3; + string replace_text = 4; + string replace_initial_text = 5; + SimpleRange reevaluate_range = 6; + string reevaluate_initial_text = 7; + LintGenerator generator = 9; + repeated LintDiscriminatorResult discriminator_results = 10; + LogprobsLintPayload logprobs_payload = 11; +} +message LintDiscriminatorResult { // aiserver.v1.LintDiscriminatorResult + LintDiscriminator discriminator = 1; + bool allow = 2; + string reasoning = 3; +} +message LogprobsLintPayload { // aiserver.v1.LogprobsLintPayload + string chunk = 1; + string problematic_line = 2; + int32 start_col = 3; + int32 end_col = 4; + string most_likely_replace = 5; + int32 line_chunk_index_zero_based = 6; +} +message AiLintRule { // aiserver.v1.AiLintRule + string text = 1; +} +message StreamAiLintBugResponse { // aiserver.v1.StreamAiLintBugResponse + AiLintBug bug = 1; + string background_task_uuid = 2; +} +message StreamAiCursorHelpRequest { // aiserver.v1.StreamAiCursorHelpRequest + repeated CursorHelpConversationMessage messages = 1; + string user_os = 2; + ModelDetails model_details = 3; +} +message CursorHelpConversationMessage { // aiserver.v1.CursorHelpConversationMessage + string id = 1; + string role = 2; + string content = 3; +} +message StreamAiCursorHelpResponse { // aiserver.v1.StreamAiCursorHelpResponse + string text = 1; + repeated string actions = 2; +} +message LogUserLintReplyRequest { // aiserver.v1.LogUserLintReplyRequest + string uuid = 1; + string user_action = 2; + bool debug_mode = 3; +} +message LogUserLintReplyResponse { // aiserver.v1.LogUserLintReplyResponse +} +message LogLinterExplicitUserFeedbackRequest { // aiserver.v1.LogLinterExplicitUserFeedbackRequest + enum LinterUserFeedback { // aiserver.v1.LogLinterExplicitUserFeedbackRequest.LinterUserFeedback + LINTER_USER_FEEDBACK_UNSPECIFIED = 0; + LINTER_USER_FEEDBACK_CORRECT = 1; + LINTER_USER_FEEDBACK_INCORRECT = 2; + LINTER_USER_FEEDBACK_OTHER = 3; + } + AiLintBug bug = 1; + LinterUserFeedback user_feedback = 3; + string user_feedback_details = 4; +} +message LogLinterExplicitUserFeedbackResponse { // aiserver.v1.LogLinterExplicitUserFeedbackResponse +} +message FixMarkersRequest { // aiserver.v1.FixMarkersRequest + message Marker { // aiserver.v1.FixMarkersRequest.Marker + message RelatedInformation { // aiserver.v1.FixMarkersRequest.Marker.RelatedInformation + string message = 1; + string relative_workspace_path = 2; + repeated string relevant_lines = 3; + int32 start_line = 4; + } + message ContextRange { // aiserver.v1.FixMarkersRequest.Marker.ContextRange + int32 start_line = 1; + int32 end_line_inclusive = 2; + } + message AncestorTypeDefinition { // aiserver.v1.FixMarkersRequest.Marker.AncestorTypeDefinition + string name = 1; + string relative_workspace_path = 2; + int32 start_line = 3; + repeated string lines = 4; + } + message InsertedSymbolType { // aiserver.v1.FixMarkersRequest.Marker.InsertedSymbolType + string symbol_name = 1; + string symbol_type = 2; + string relative_workspace_path = 3; + int32 symbol_line = 4; + } + message QuickFix { // aiserver.v1.FixMarkersRequest.Marker.QuickFix + message Edit { // aiserver.v1.FixMarkersRequest.Marker.QuickFix.Edit + string relative_workspace_path = 1; + int32 start_line = 2; + int32 end_line_inclusive = 3; + repeated string deleted_lines = 4; + repeated string add_lines = 5; + int32 snapshot = 6; + } + string message = 1; + string kind = 2; + bool is_preferred = 3; + repeated Edit edits = 4; + } + message ClassInformation { // aiserver.v1.FixMarkersRequest.Marker.ClassInformation + message Constructor { // aiserver.v1.FixMarkersRequest.Marker.ClassInformation.Constructor + int32 start_line = 1; + int32 end_line_inclusive = 2; + } + string class_name = 1; + int32 start_line = 2; + repeated int32 top_level_lines = 3; + repeated string lines = 4; + repeated Constructor constructors = 5; + string detail = 6; + } + message FunctionSignature { // aiserver.v1.FixMarkersRequest.Marker.FunctionSignature + message FunctionParameter { // aiserver.v1.FixMarkersRequest.Marker.FunctionSignature.FunctionParameter + string label = 1; + string documentation = 2; + } + string label = 1; + string documentation = 2; + repeated FunctionParameter parameters = 3; + } + repeated string lines = 1; + int32 start_line = 2; + int32 end_line_inclusive = 3; + string message = 4; + string relative_workspace_path = 5; + repeated RelatedInformation related_information = 6; + repeated ContextRange context_ranges = 7; + repeated AncestorTypeDefinition ancestor_type_definitions = 8; + repeated InsertedSymbolType inserted_symbol_types = 9; + repeated QuickFix quick_fixes = 10; + int32 start_column = 11; + int32 end_column_inclusive = 12; + repeated ClassInformation class_information = 13; + repeated FunctionSignature function_signatures = 14; + int32 snapshot = 15; + } + repeated Marker markers = 1; + ModelDetails model_details = 2; + int32 iteration_number = 3; + string sequence_id = 4; + string user_instruction = 5; +} +message FixMarkersResponse { // aiserver.v1.FixMarkersResponse + message Change { // aiserver.v1.FixMarkersResponse.Change + int32 start_line = 1; + int32 end_line_exclusive = 2; + repeated string deleted_lines = 3; + repeated string add_lines = 4; + } + string relative_workspace_path = 1; + repeated Change changes = 2; + bool success = 3; + int32 iteration_number = 4; +} +message ReportInlineActionRequest { // aiserver.v1.ReportInlineActionRequest + string action = 1; + string generation_uuid = 2; +} +message ReportInlineActionResponse { // aiserver.v1.ReportInlineActionResponse +} +message StreamPriomptPromptRequest { // aiserver.v1.StreamPriomptPromptRequest + string prompt_props = 2; + string prompt_props_type_name = 3; + bool skip_login_check = 5; + ModelDetails model_details = 4; +} +message StreamPriomptPromptResponse { // aiserver.v1.StreamPriomptPromptResponse + string text = 1; +} +message StreamLintRequest { // aiserver.v1.StreamLintRequest + CurrentFileInfo current_file = 1; + repeated ConversationMessage conversation = 2; + repeated RepositoryInfo repositories = 3; + ExplicitContext explicit_context = 4; + optional string workspace_root_path = 5; + string query = 6; + repeated CodeBlock code_blocks = 7; + ModelDetails model_details = 9; + repeated string documentation_identifiers = 10; + repeated string bad_notifications = 11; + string lint_rules = 12; +} +message StreamNewRuleRequest { // aiserver.v1.StreamNewRuleRequest + string current_rules = 1; + string dismissed_bug = 2; +} +message AiProjectRequest { // aiserver.v1.AiProjectRequest + string description = 1; + ModelDetails model_details = 2; +} +message AiProjectResponse { // aiserver.v1.AiProjectResponse + string text = 1; +} +message ToCamelCaseRequest { // aiserver.v1.ToCamelCaseRequest + string text = 1; +} +message ToCamelCaseResponse { // aiserver.v1.ToCamelCaseResponse + string text = 1; +} +message ReportGenerationFeedbackRequest { // aiserver.v1.ReportGenerationFeedbackRequest + enum FeedbackType { // aiserver.v1.ReportGenerationFeedbackRequest.FeedbackType + FEEDBACK_TYPE_UNSPECIFIED = 0; + FEEDBACK_TYPE_THUMBS_UP = 1; + FEEDBACK_TYPE_THUMBS_DOWN = 2; + FEEDBACK_TYPE_NEUTRAL = 3; + } + FeedbackType feedback_type = 1; + string request_id = 2; + optional string comment = 3; +} +message ReportGenerationFeedbackResponse { // aiserver.v1.ReportGenerationFeedbackResponse +} +message GetThoughtAnnotationRequest { // aiserver.v1.GetThoughtAnnotationRequest + string request_id = 1; +} +message GetThoughtAnnotationResponse { // aiserver.v1.GetThoughtAnnotationResponse + AiThoughtAnnotation thought_annotation = 1; +} +message AiThoughtAnnotation { // aiserver.v1.AiThoughtAnnotation + string request_id = 1; + string auth_id = 2; + CmdKDebugInfo debug_info = 3; + string thought = 4; +} +message StreamWebCmdKV1Request { // aiserver.v1.StreamWebCmdKV1Request + string relative_workspace_path = 1; + string file_contents = 2; + string prompt = 3; + LineRange selection_range = 4; + ModelDetails model_details = 5; + repeated ImageProto images = 10; +} +message StreamWebCmdKV1Response { // aiserver.v1.StreamWebCmdKV1Response + StreamCmdKResponse cmd_k_response = 1; +} +message StreamNextCursorPredictionRequest { // aiserver.v1.StreamNextCursorPredictionRequest + message FileVisibleRange { // aiserver.v1.StreamNextCursorPredictionRequest.FileVisibleRange + message VisibleRange { // aiserver.v1.StreamNextCursorPredictionRequest.VisibleRange + int32 start_line_number_inclusive = 1; + int32 end_line_number_exclusive = 2; + } + string filename = 1; + repeated VisibleRange visible_ranges = 2; + } + CurrentFileInfo current_file = 1; + repeated string diff_history = 2; + optional string model_name = 3; + optional LinterErrors linter_errors = 4; + repeated CppContextItem context_items = 13; + repeated string diff_history_keys = 5; + optional bool give_debug_output = 6; + repeated CppFileDiffHistory file_diff_histories = 7; + repeated CppFileDiffHistory merged_diff_histories = 8; + repeated BlockDiffPatch block_diff_patches = 9; + optional bool is_nightly = 10; + optional bool is_debug = 11; + optional bool immediately_ack = 12; + optional bool enable_more_context = 17; + repeated CppParameterHint parameter_hints = 14; + repeated LspSubgraphFullContext lsp_contexts = 15; + optional CppIntentInfo cpp_intent_info = 16; + optional string workspace_id = 18; + repeated FilesyncUpdateWithModelVersion file_sync_updates = 19; + repeated FileVisibleRange file_visible_ranges = 20; +} +message StreamNextCursorPredictionResponse { // aiserver.v1.StreamNextCursorPredictionResponse + string text = 1; + int32 line_number = 2; + bool is_not_in_range = 3; + string file_name = 4; +} +message IsCursorPredictionEnabledRequest { // aiserver.v1.IsCursorPredictionEnabledRequest +} +message IsCursorPredictionEnabledResponse { // aiserver.v1.IsCursorPredictionEnabledResponse + bool enabled = 1; +} +message GetCppEditClassificationRequest { // aiserver.v1.GetCppEditClassificationRequest + StreamCppRequest cpp_request = 1; + repeated SuggestedEdit suggested_edits = 25; + bool marker_touches_green = 26; + string current_file_contents_for_linter_errors = 27; +} +message SuggestedEdit { // aiserver.v1.SuggestedEdit + SimpleRange edit_range = 1; + string text = 2; +} +message GetCppEditClassificationResponse { // aiserver.v1.GetCppEditClassificationResponse + message ScoredEdit { // aiserver.v1.GetCppEditClassificationResponse.ScoredEdit + message LogProbs { // aiserver.v1.GetCppEditClassificationResponse.LogProbs + repeated string tokens = 1; + repeated double token_logprobs = 2; + } + SuggestedEdit edit = 1; + LogProbs log_probs = 2; + } + repeated ScoredEdit scored_edits = 1; + ScoredEdit noop_edit = 2; + optional bool should_noop = 3; + ScoredEdit generation_edit = 4; +} +message GetTerminalCompletionRequest { // aiserver.v1.GetTerminalCompletionRequest + string current_command = 1; + repeated string command_history = 2; + optional string model_name = 3; + repeated CppFileDiffHistory file_diff_histories = 4; + optional string git_diff = 5; + repeated string commit_history = 6; + repeated string past_results = 7; + ModelDetails model_details = 8; + string user_platform = 9; + string current_folder = 10; + repeated CurrentFolderFileOrFolder current_folder_structure = 11; + repeated File relevant_files = 12; +} +message CurrentFolderFileOrFolder { // aiserver.v1.CurrentFolderFileOrFolder + string name = 1; + bool is_folder = 2; +} +message GetTerminalCompletionResponse { // aiserver.v1.GetTerminalCompletionResponse + string command = 1; +} +message TakeNotesOnCommitDiffRequest { // aiserver.v1.TakeNotesOnCommitDiffRequest + CommitDiffString diff = 1; + string commit_hash = 2; +} +message CommitDiffString { // aiserver.v1.CommitDiffString + string diff = 1; +} +message TakeNotesOnCommitDiffResponse { // aiserver.v1.TakeNotesOnCommitDiffResponse + repeated CommitNoteWithEmbeddings notes = 1; +} +message CommitNoteWithEmbeddings { // aiserver.v1.CommitNoteWithEmbeddings + string note = 1; + string commit_hash = 2; + repeated double embeddings = 3; +} +message BulkEmbedRequest { // aiserver.v1.BulkEmbedRequest + repeated string texts = 1; +} +message BulkEmbedResponse { // aiserver.v1.BulkEmbedResponse + repeated EmbeddingResponse embeddings = 1; +} +message EmbeddingResponse { // aiserver.v1.EmbeddingResponse + repeated double embedding = 1; +} +message ContinueChatRequestWithCommitsRequest { // aiserver.v1.ContinueChatRequestWithCommitsRequest + string session_id = 1; + repeated SimpleCommitWithDiff commits = 2; + string request_id = 3; +} +message SimpleCommitWithDiff { // aiserver.v1.SimpleCommitWithDiff + string commit_hash = 1; + string diff = 2; +} +message EmptyResponse { // aiserver.v1.EmptyResponse +} +message BackgroundCmdKEvalRequest { // aiserver.v1.BackgroundCmdKEvalRequest + enum Experiment { // aiserver.v1.BackgroundCmdKEvalRequest.Experiment + EXPERIMENT_UNSPECIFIED = 0; + EXPERIMENT_REFLECT = 1; + EXPERIMENT_CMD_K_ORIGINAL_RADIUS = 2; + EXPERIMENT_LOOP_ON_LINTS = 3; + EXPERIMENT_CHAT_AND_APPLY = 4; + EXPERIMENT_COMMIT_NOTES = 5; + EXPERIMENT_COALESCE_GENERATIONS = 6; + EXPERIMENT_REWORD_INSTRUCTIONS = 7; + EXPERIMENT_CODEBASE_CHUNKS = 8; + EXPERIMENT_SPEC_AND_APPLY = 9; + EXPERIMENT_ASK_CODEBASE = 10; + } + message ProposedChange { // aiserver.v1.BackgroundCmdKEvalRequest.ProposedChange + message Lint { // aiserver.v1.BackgroundCmdKEvalRequest.Lint + message QuickFix { // aiserver.v1.BackgroundCmdKEvalRequest.Lint.QuickFix + message Edit { // aiserver.v1.BackgroundCmdKEvalRequest.Lint.QuickFix.Edit + string relative_workspace_path = 1; + string text = 2; + int32 start_line_number_one_indexed = 3; + int32 start_column_one_indexed = 4; + int32 end_line_number_inclusive_one_indexed = 5; + int32 end_column_one_indexed = 6; + } + string message = 1; + string kind = 2; + bool is_preferred = 3; + repeated Edit edits = 4; + } + string message = 1; + string severity = 2; + string relative_workspace_path = 3; + int32 start_line_number_one_indexed = 4; + int32 start_column_one_indexed = 5; + int32 end_line_number_inclusive_one_indexed = 6; + int32 end_column_one_indexed = 7; + repeated QuickFix quick_fixes = 9; + } + string change = 1; + repeated Lint linter_errors = 2; + } + string instruction = 1; + CurrentFileInfo current_file = 2; + SimpleRange selection_range = 3; + string ground_truth = 4; + Experiment experiment = 5; + bool run_automated_eval = 6; + repeated ProposedChange proposed_change_history = 7; + repeated CommitNote commit_notes = 8; + repeated CodeBlock related_code_blocks = 9; +} +message BackgroundCmdKEvalResponse { // aiserver.v1.BackgroundCmdKEvalResponse + string proposed_change = 1; +} +message BackgroundCmdKRequest { // aiserver.v1.BackgroundCmdKRequest + enum Type { // aiserver.v1.BackgroundCmdKRequest.Type + TYPE_UNSPECIFIED = 0; + TYPE_REFLECT = 1; + TYPE_LOOP_ON_LINTS = 2; + TYPE_CHAT_AND_APPLY = 3; + TYPE_COALESCE_GENERATIONS = 4; + TYPE_CODEBASE_CHUNKS = 5; + TYPE_SPEC_AND_APPLY = 6; + TYPE_ASK_CODEBASE = 7; + TYPE_FINETUNED_INSTRUCTIONS = 8; + TYPE_USEFUL_TYPES = 9; + TYPE_CHAT_AND_APPLY_UNDERSPECIFIED = 10; + } + message ProposedChange { // aiserver.v1.BackgroundCmdKRequest.ProposedChange + message Lint { // aiserver.v1.BackgroundCmdKRequest.Lint + message QuickFix { // aiserver.v1.BackgroundCmdKRequest.Lint.QuickFix + message Edit { // aiserver.v1.BackgroundCmdKRequest.Lint.QuickFix.Edit + string relative_workspace_path = 1; + string text = 2; + int32 start_line_number_one_indexed = 3; + int32 start_column_one_indexed = 4; + int32 end_line_number_inclusive_one_indexed = 5; + int32 end_column_one_indexed = 6; + } + string message = 1; + string kind = 2; + bool is_preferred = 3; + repeated Edit edits = 4; + } + string message = 1; + string severity = 2; + string relative_workspace_path = 3; + int32 start_line_number_one_indexed = 4; + int32 start_column_one_indexed = 5; + int32 end_line_number_inclusive_one_indexed = 6; + int32 end_column_one_indexed = 7; + repeated QuickFix quick_fixes = 9; + } + string change = 1; + repeated Lint linter_errors = 2; + } + message Lint { // aiserver.v1.BackgroundCmdKRequest.Lint + message QuickFix { // aiserver.v1.BackgroundCmdKRequest.Lint.QuickFix + message Edit { // aiserver.v1.BackgroundCmdKRequest.Lint.QuickFix.Edit + string relative_workspace_path = 1; + string text = 2; + int32 start_line_number_one_indexed = 3; + int32 start_column_one_indexed = 4; + int32 end_line_number_inclusive_one_indexed = 5; + int32 end_column_one_indexed = 6; + } + string message = 1; + string kind = 2; + bool is_preferred = 3; + repeated Edit edits = 4; + } + string message = 1; + string severity = 2; + string relative_workspace_path = 3; + int32 start_line_number_one_indexed = 4; + int32 start_column_one_indexed = 5; + int32 end_line_number_inclusive_one_indexed = 6; + int32 end_column_one_indexed = 7; + repeated QuickFix quick_fixes = 9; + } + message UsefulType { // aiserver.v1.BackgroundCmdKRequest.UsefulType + string relative_workspace_path = 1; + int32 start_line = 2; + string text = 3; + optional double score = 4; + } + message RecentlyViewedFile { // aiserver.v1.BackgroundCmdKRequest.RecentlyViewedFile + message VisibleRange { // aiserver.v1.BackgroundCmdKRequest.RecentlyViewedFile.VisibleRange + int32 start_line_number_inclusive = 1; + int32 end_line_number_exclusive = 2; + optional int32 viewed_at = 3; + optional int32 global_order_descending = 4; + } + string relative_workspace_path = 1; + string contents = 2; + repeated VisibleRange visible_ranges = 3; + } + message Diff { // aiserver.v1.BackgroundCmdKRequest.Diff + string relative_workspace_path = 1; + string diff = 2; + } + string instruction = 1; + CurrentFileInfo current_file = 2; + SimpleRange selection_range = 3; + Type type = 4; + repeated ProposedChange proposed_change_history = 5; + repeated CodeBlock related_code_blocks = 6; + repeated CppFileDiffHistory diff_history = 7; + repeated Lint linter_errors = 8; + repeated UsefulType useful_types = 9; + repeated RecentlyViewedFile recently_viewed_files = 10; + repeated Diff recent_diffs = 11; + optional bool multiple_completions = 12; +} +message BackgroundCmdKResponse { // aiserver.v1.BackgroundCmdKResponse + string proposed_change = 1; +} +message StreamCursorMotionRequest { // aiserver.v1.StreamCursorMotionRequest + CurrentFileInfo current_file_info = 1; + SimpleRange selection_range = 2; + string instruction = 3; + ModelDetails model_details = 4; +} +message StreamCursorMotionResponse { // aiserver.v1.StreamCursorMotionResponse + string text = 1; +} +message CalculateAutoSelectionRequest { // aiserver.v1.CalculateAutoSelectionRequest + CurrentFileInfo current_file_info = 1; + CursorPosition cursor_position = 2; + SimpleRange selection_range = 3; + ModelDetails model_details = 4; + repeated HeuristicsSelection heuristics_selections = 5; +} +message HeuristicsSelection { // aiserver.v1.HeuristicsSelection + enum HeuristicsSelectionType { // aiserver.v1.HeuristicsSelection.HeuristicsSelectionType + HEURISTICS_SELECTION_TYPE_UNSPECIFIED = 0; + HEURISTICS_SELECTION_TYPE_GROUP = 1; + HEURISTICS_SELECTION_TYPE_LINE = 2; + HEURISTICS_SELECTION_TYPE_FOLDING = 3; + } + HeuristicsSelectionType type = 1; + int32 start_line = 2; + int32 end_line = 3; +} +message CalculateAutoSelectionResponse { // aiserver.v1.CalculateAutoSelectionResponse + repeated AutoSelectionResult results = 1; +} +message AutoSelectionResult { // aiserver.v1.AutoSelectionResult + int32 start_line = 1; + int32 end_line = 2; + repeated AutoSelectionInstructions instructions = 3; +} +message AutoSelectionInstructions { // aiserver.v1.AutoSelectionInstructions + string text = 1; + int32 start_line = 2; + int32 end_line = 3; +} +message GetAtSymbolSuggestionsRequest { // aiserver.v1.GetAtSymbolSuggestionsRequest + CurrentFileInfo current_file_info = 1; + repeated AtSymbolDependencyInformation at_symbol_dependencies = 2; + repeated AtSymbolOption at_symbol_options = 3; + string user_query = 4; + ModelDetails model_details = 5; +} +message AtSymbolDependencyInformation { // aiserver.v1.AtSymbolDependencyInformation + string name = 1; + string from_file = 2; +} +message AtSymbolOption { // aiserver.v1.AtSymbolOption + int32 index = 1; + string text = 2; + string type = 3; +} +message GetAtSymbolSuggestionsResponse { // aiserver.v1.GetAtSymbolSuggestionsResponse + repeated int32 indices = 1; + string explanation = 2; +} +message GetCodebaseQuestionsResponse { // aiserver.v1.GetCodebaseQuestionsResponse + repeated string questions = 1; +} +message GetRankedContextFromContextBankRequest { // aiserver.v1.GetRankedContextFromContextBankRequest + GetComposerChatRequest composer_request = 1; + repeated ContextToRank context_to_rank = 2; +} +message GetRankedContextFromContextBankResponse { // aiserver.v1.GetRankedContextFromContextBankResponse + repeated RankedContext ranked_context = 1; +} +message EditHistoryAppendChangesRequest { // aiserver.v1.EditHistoryAppendChangesRequest + enum PrivacyModeStatus { // aiserver.v1.EditHistoryAppendChangesRequest.PrivacyModeStatus + PRIVACY_MODE_STATUS_UNSPECIFIED = 0; + PRIVACY_MODE_STATUS_PRIVACY_ENABLED = 1; + PRIVACY_MODE_STATUS_IMPLICIT_NO_PRIVACY = 2; + PRIVACY_MODE_STATUS_EXPLICIT_NO_PRIVACY = 3; + } + string session_id = 1; + string model_uuid = 2; + optional string starting_model_value = 3; + optional int32 starting_model_version = 10; + string relative_path = 5; + string uri = 14; + string client_version = 6; + optional string client_commit = 8; + repeated ModelChange changes = 4; + repeated CppSessionEvent session_events = 9; + bool model_changes_may_be_out_of_order = 11; + PrivacyModeStatus privacy_mode_status = 12; + repeated CppHistoryAppendEvent events = 7; + float time_origin = 13; +} +message ModelChange { // aiserver.v1.ModelChange + string text = 1; + IRange range = 2; + optional string final_model_hash = 3; + optional int32 model_version_immediately_after_this_change = 4; + optional double performance_now_timestamp = 5; + optional bool is_undoing = 7; + optional bool is_redoing = 8; + bool model_is_attached_to_editor = 9; + bool model_is_attached_to_the_active_editor = 10; + repeated CursorSelection cursor_selections = 11; + int32 model_version_at_metadata_retrieval_time = 12; +} +message CursorSelection { // aiserver.v1.CursorSelection + int32 selection_start_line_number = 1; + int32 selection_start_column = 2; + int32 position_line_number = 3; + int32 position_column = 4; +} +message CppSessionEvent { // aiserver.v1.CppSessionEvent + CppAcceptEventNew accept_event = 2; + CppRejectEventNew reject_event = 3; + CppManualTriggerEventNew manual_trigger_event = 4; + CppStoppedTrackingModelEvent stopped_tracking_model_event = 6; + CppSuggestEvent suggest_event = 7; + CppLinterErrorEvent linter_error_event = 8; + CppDebouncedCursorMovementEvent debounced_cursor_movement_event = 9; + CppEditorChangedEvent editor_changed_event = 10; + CppCopyEvent copy_event = 11; + CppChangeQuickActionEvent quick_action_event = 13; + CppQuickActionFireEvent quick_action_fire_event = 14; + ModelOpenedEvent model_opened_event = 15; + CmdKEvent cmd_k_event = 17; + ChatEvent chat_event = 18; + AiRequestEvent ai_event = 19; + ScrollEvent scroll_event = 21; + EditorCloseEvent editor_close_event = 22; + TabCloseEvent tab_close_event = 23; + ModelAddedEvent model_added_event = 33; + CppPartialAcceptEvent partial_accept_event = 26; + AcceptCursorPredictionEvent accept_cursor_prediction_event = 27; + RejectCursorPredictionEvent reject_cursor_prediction_event = 28; + SuggestCursorPredictionEvent suggest_cursor_prediction_event = 29; + CppTriggerEvent cpp_trigger_event = 30; + FinishedCppGenerationEvent finished_cpp_generation_event = 31; + BugBotEvent bug_bot_event = 32; + BackgroundFilesEvent background_files_event = 16; + CppTerminalEvent terminal_event = 20; + CppGitContextEvent git_context_event = 24; + double performance_now_timestamp = 5; + optional double performance_time_origin = 25; +} +message CppAcceptEventNew { // aiserver.v1.CppAcceptEventNew + CurrentlyShownCppSuggestion cpp_suggestion = 1; + PointInTimeModel point_in_time_model = 7; +} +message CurrentlyShownCppSuggestion { // aiserver.v1.CurrentlyShownCppSuggestion + int32 suggestion_id = 1; + string suggestion_text = 2; + int32 model_version_when_the_change_is_first_indicated_to_the_user_but_not_shown_in_the_model = 3; + optional IRange range_of_suggestion_in_current_model = 4; + string original_text = 5; +} +message PointInTimeModel { // aiserver.v1.PointInTimeModel + string model_uuid = 1; + int32 model_version = 2; + string relative_path = 3; + string model_id = 4; +} +message CppRejectEventNew { // aiserver.v1.CppRejectEventNew + CurrentlyShownCppSuggestion cpp_suggestion = 1; + PointInTimeModel point_in_time_model = 7; +} +message CppManualTriggerEventNew { // aiserver.v1.CppManualTriggerEventNew + int32 line_number_one_indexed = 1; + int32 column_number_one_indexed = 2; + PointInTimeModel point_in_time_model = 7; +} +message CppStoppedTrackingModelEvent { // aiserver.v1.CppStoppedTrackingModelEvent + enum StoppedTrackingModelReason { // aiserver.v1.CppStoppedTrackingModelEvent.StoppedTrackingModelReason + STOPPED_TRACKING_MODEL_REASON_UNSPECIFIED = 0; + STOPPED_TRACKING_MODEL_REASON_FILE_TOO_BIG = 1; + STOPPED_TRACKING_MODEL_REASON_FILE_DISPOSED = 2; + STOPPED_TRACKING_MODEL_REASON_CHANGE_TOO_BIG = 3; + } + string model_uuid = 1; + string relative_path = 2; + StoppedTrackingModelReason reason = 3; +} +message CppSuggestEvent { // aiserver.v1.CppSuggestEvent + CurrentlyShownCppSuggestion cpp_suggestion = 1; + PointInTimeModel point_in_time_model = 2; + RecoverableCppData recoverable_cpp_data = 3; +} +message RecoverableCppData { // aiserver.v1.RecoverableCppData + string request_id = 1; + string suggestion_text = 2; + IRange suggestion_range = 3; + OneIndexedPosition position = 4; +} +message OneIndexedPosition { // aiserver.v1.OneIndexedPosition + int32 line_number_one_indexed = 1; + int32 column_one_indexed = 2; +} +message CppLinterErrorEvent { // aiserver.v1.CppLinterErrorEvent + PointInTimeModel point_in_time_model = 1; + repeated LinterError added_errors = 2; + repeated LinterError removed_errors = 3; + repeated LinterError errors = 4; +} +message CppDebouncedCursorMovementEvent { // aiserver.v1.CppDebouncedCursorMovementEvent + PointInTimeModel point_in_time_model = 1; + OneIndexedPosition cursor_position = 2; +} +message CppEditorChangedEvent { // aiserver.v1.CppEditorChangedEvent + PointInTimeModel point_in_time_model = 1; + OneIndexedPosition cursor_position = 2; + repeated IRange visible_ranges = 3; + string editor_id = 4; +} +message CppCopyEvent { // aiserver.v1.CppCopyEvent + string clipboard_contents = 1; +} +message CppChangeQuickActionEvent { // aiserver.v1.CppChangeQuickActionEvent + PointInTimeModel point_in_time_model = 1; + repeated CppQuickAction added = 2; + repeated CppQuickAction removed = 3; + repeated CppQuickAction actions = 4; +} +message CppQuickAction { // aiserver.v1.CppQuickAction + message Edit { // aiserver.v1.CppQuickAction.Edit + string text = 1; + IRange range = 2; + } + string title = 1; + repeated Edit edits = 2; + optional bool is_preferred = 3; + CppQuickActionCommand command = 4; +} +message CppQuickActionCommand { // aiserver.v1.CppQuickActionCommand + string title = 1; + string id = 2; + repeated string arguments = 3; +} +message CppQuickActionFireEvent { // aiserver.v1.CppQuickActionFireEvent + PointInTimeModel point_in_time_model = 1; + CppQuickActionCommand quick_action_command = 2; + CppQuickAction quick_action_event = 3; +} +message ModelOpenedEvent { // aiserver.v1.ModelOpenedEvent + PointInTimeModel point_in_time_model = 1; +} +message CmdKEvent { // aiserver.v1.CmdKEvent + message SubmitPrompt { // aiserver.v1.CmdKEvent.SubmitPrompt + IRange original_range = 1; + string original_text = 2; + string prompt = 3; + } + message EndOfGeneration { // aiserver.v1.CmdKEvent.EndOfGeneration + } + message InterruptGeneration { // aiserver.v1.CmdKEvent.InterruptGeneration + } + message AcceptDiffs { // aiserver.v1.CmdKEvent.AcceptDiffs + } + message RejectDiffs { // aiserver.v1.CmdKEvent.RejectDiffs + } + message RejectPartialDiff { // aiserver.v1.CmdKEvent.RejectPartialDiff + IRange green_range = 1; + repeated string green_lines = 2; + repeated string red_lines = 3; + } + message AcceptPartialDiff { // aiserver.v1.CmdKEvent.AcceptPartialDiff + IRange green_range = 1; + repeated string green_lines = 2; + repeated string red_lines = 3; + } + PointInTimeModel point_in_time_model = 1; + string request_id = 2; + optional string prompt_bar_id = 20; + SubmitPrompt submit_prompt = 3; + EndOfGeneration end_of_generation = 4; + InterruptGeneration interrupt_generation = 5; + AcceptDiffs accept_all = 6; + RejectDiffs reject_all = 7; + RejectPartialDiff reject_partial_diff = 8; + AcceptPartialDiff accept_partial_diff = 9; +} +message ChatEvent { // aiserver.v1.ChatEvent + message SubmitPrompt { // aiserver.v1.ChatEvent.SubmitPrompt + string prompt = 1; + } + message EndOfAnyGeneration { // aiserver.v1.ChatEvent.EndOfAnyGeneration + } + message EndOfUninterruptedGeneration { // aiserver.v1.ChatEvent.EndOfUninterruptedGeneration + } + string request_id = 1; + SubmitPrompt submit_prompt = 2; + EndOfAnyGeneration end_of_any_generation = 3; + EndOfUninterruptedGeneration end_of_uninterrupted_generation = 4; +} +message AiRequestEvent { // aiserver.v1.AiRequestEvent + enum RequestType { // aiserver.v1.AiRequestEvent.RequestType + REQUEST_TYPE_UNSPECIFIED = 0; + REQUEST_TYPE_START = 1; + REQUEST_TYPE_END = 2; + } + RequestType request_type = 1; + string request_id = 2; +} +message ScrollEvent { // aiserver.v1.ScrollEvent + PointInTimeModel point_in_time_model = 1; + repeated IRange visible_ranges = 2; + string editor_id = 3; +} +message EditorCloseEvent { // aiserver.v1.EditorCloseEvent + string editor_id = 1; +} +message TabCloseEvent { // aiserver.v1.TabCloseEvent + MaybeDefinedPointInTimeModel point_in_time_model = 1; +} +message MaybeDefinedPointInTimeModel { // aiserver.v1.MaybeDefinedPointInTimeModel + optional string model_uuid = 1; + int32 model_version = 2; + string relative_path = 3; + string model_id = 4; +} +message ModelAddedEvent { // aiserver.v1.ModelAddedEvent + MaybeDefinedPointInTimeModel point_in_time_model = 1; + string full_uri = 2; + string model_id = 3; + string uri_scheme = 4; + bool is_too_large_for_syncing = 5; + bool is_too_large_for_tokenization = 6; + bool is_too_large_for_heap_operation = 7; +} +message CppPartialAcceptEvent { // aiserver.v1.CppPartialAcceptEvent + CurrentlyShownCppSuggestion cpp_suggestion = 1; + Edit edit = 2; + PointInTimeModel point_in_time_model = 3; +} +message Edit { // aiserver.v1.Edit + string text = 1; + IRange range = 2; +} +message AcceptCursorPredictionEvent { // aiserver.v1.AcceptCursorPredictionEvent + CursorPrediction cursor_prediction = 1; + PointInTimeModel point_in_time_model = 2; +} +message CursorPrediction { // aiserver.v1.CursorPrediction + enum CursorPredictionSource { // aiserver.v1.CursorPrediction.CursorPredictionSource + CURSOR_PREDICTION_SOURCE_UNSPECIFIED = 0; + CURSOR_PREDICTION_SOURCE_ALWAYS_ON = 1; + CURSOR_PREDICTION_SOURCE_ACCEPT = 2; + CURSOR_PREDICTION_SOURCE_UNDO = 3; + CURSOR_PREDICTION_SOURCE_EDITOR_CHANGE = 4; + } + string request_id = 1; + int32 prediction_id = 2; + int32 line_number = 3; + CursorPredictionSource source = 4; +} +message RejectCursorPredictionEvent { // aiserver.v1.RejectCursorPredictionEvent + CursorPrediction cursor_prediction = 1; + PointInTimeModel point_in_time_model = 2; +} +message SuggestCursorPredictionEvent { // aiserver.v1.SuggestCursorPredictionEvent + CursorPrediction cursor_prediction = 1; + PointInTimeModel point_in_time_model = 2; +} +message CppTriggerEvent { // aiserver.v1.CppTriggerEvent + string generation_uuid = 1; + int32 model_version = 2; + OneIndexedPosition cursor_position = 3; + PointInTimeModel point_in_time_model = 4; + CppSource source = 5; +} +message FinishedCppGenerationEvent { // aiserver.v1.FinishedCppGenerationEvent + PointInTimeModel point_in_time_model = 1; + RecoverableCppData recoverable_cpp_data = 2; +} +message BugBotEvent { // aiserver.v1.BugBotEvent + message Started { // aiserver.v1.BugBotEvent.Started + } + message ReportsGenerated { // aiserver.v1.BugBotEvent.ReportsGenerated + BugReports bug_reports = 1; + } + message PressedFixInComposer { // aiserver.v1.BugBotEvent.PressedFixInComposer + string bug_report_id = 1; + } + message PressedOpenInEditor { // aiserver.v1.BugBotEvent.PressedOpenInEditor + BugLocation bug_location = 1; + string bug_report_id = 2; + } + message ViewedReport { // aiserver.v1.BugBotEvent.ViewedReport + message ReportView { // aiserver.v1.BugBotEvent.ViewedReport.ReportView + string bug_report_id = 1; + double view_percentage = 2; + double text_percentage = 3; + } + int32 seconds_viewed = 1; + repeated ReportView report_views = 2; + } + message UserFeedback { // aiserver.v1.BugBotEvent.UserFeedback + string bug_report_id = 1; + string feedback = 2; + } + message PressedAddToChat { // aiserver.v1.BugBotEvent.PressedAddToChat + string bug_report_id = 1; + } + message BackgroundIntervalStarted { // aiserver.v1.BugBotEvent.BackgroundIntervalStarted + } + message BackgroundIntervalEnded { // aiserver.v1.BugBotEvent.BackgroundIntervalEnded + bool success = 1; + } + message BackgroundIntervalInterrupted { // aiserver.v1.BugBotEvent.BackgroundIntervalInterrupted + enum BackgroundIntervalInterruptedReason { // aiserver.v1.BugBotEvent.BackgroundIntervalInterruptedReason + BACKGROUND_INTERVAL_INTERRUPTED_REASON_UNSPECIFIED = 0; + BACKGROUND_INTERVAL_INTERRUPTED_REASON_DISABLED = 1; + BACKGROUND_INTERVAL_INTERRUPTED_REASON_TOO_RECENT = 2; + BACKGROUND_INTERVAL_INTERRUPTED_REASON_UNVIEWED_BUG_REPORTS = 3; + BACKGROUND_INTERVAL_INTERRUPTED_REASON_NOT_IN_GIT_REPO = 4; + BACKGROUND_INTERVAL_INTERRUPTED_REASON_DEFAULT_BRANCH_IS_NOT_CURRENT_BRANCH = 5; + BACKGROUND_INTERVAL_INTERRUPTED_REASON_NO_GIT_USER = 6; + BACKGROUND_INTERVAL_INTERRUPTED_REASON_NO_LAST_COMMIT = 7; + BACKGROUND_INTERVAL_INTERRUPTED_REASON_LAST_COMMIT_NOT_MADE_BY_USER = 8; + BACKGROUND_INTERVAL_INTERRUPTED_REASON_LAST_COMMIT_TOO_OLD = 9; + BACKGROUND_INTERVAL_INTERRUPTED_REASON_DIFF_TOO_LONG = 10; + BACKGROUND_INTERVAL_INTERRUPTED_REASON_DIFF_TOO_SHORT = 11; + BACKGROUND_INTERVAL_INTERRUPTED_REASON_TELEMETRY_UNHEALTHY = 12; + } + BackgroundIntervalInterruptedReason reason = 1; + } + message BackgroundIntervalErrored { // aiserver.v1.BugBotEvent.BackgroundIntervalErrored + string error_message = 1; + } + string request_id = 1; + Started started = 2; + ReportsGenerated reports_generated = 3; + PressedFixInComposer pressed_fix_in_composer = 4; + PressedOpenInEditor pressed_open_in_editor = 5; + ViewedReport viewed_report = 6; + UserFeedback user_feedback = 7; + PressedAddToChat pressed_add_to_chat = 8; + BackgroundIntervalStarted background_interval_started = 9; + BackgroundIntervalEnded background_interval_ended = 10; + BackgroundIntervalInterrupted background_interval_interrupted = 11; + BackgroundIntervalErrored background_interval_errored = 12; +} +message BugReports { // aiserver.v1.BugReports + repeated BugReport bug_reports = 1; +} +message BugReport { // aiserver.v1.BugReport + repeated BugLocation locations = 1; + string id = 2; + string description = 3; + optional float confidence = 4; +} +message BugLocation { // aiserver.v1.BugLocation + string file = 1; + int32 start_line = 2; + int32 end_line = 3; +} +message BackgroundFilesEvent { // aiserver.v1.BackgroundFilesEvent + message BackgroundFile { // aiserver.v1.BackgroundFilesEvent.BackgroundFile + string relative_workspace_path = 1; + string contents = 2; + string hash = 3; + string full_path = 4; + } + repeated BackgroundFile files = 2; +} +message CppTerminalEvent { // aiserver.v1.CppTerminalEvent + message TerminalInput { // aiserver.v1.CppTerminalEvent.TerminalInput + repeated string buffered_keypresses = 1; + } + message CommandStarted { // aiserver.v1.CppTerminalEvent.CommandStarted + string command = 1; + double started_timestamp_unix_ms = 2; + bool command_was_trimmed = 3; + } + message CommandFinished { // aiserver.v1.CppTerminalEvent.CommandFinished + string command = 1; + optional int32 exit_code = 2; + string output = 3; + double finished_timestamp_unix_ms = 4; + bool command_was_trimmed = 5; + bool output_was_trimmed = 6; + } + int32 terminal_id = 1; + string terminal_path = 2; + optional string terminal_cwd = 6; + TerminalInput terminal_input = 3; + CommandStarted command_started = 4; + CommandFinished command_finished = 5; +} +message CppGitContextEvent { // aiserver.v1.CppGitContextEvent + message Head { // aiserver.v1.CppGitContextEvent.Head + message UpstreamRef { // aiserver.v1.CppGitContextEvent.Head.UpstreamRef + string remote = 1; + string name = 2; + optional string commit = 3; + } + string type = 1; + optional string name = 2; + optional string commit = 3; + optional string remote = 4; + optional UpstreamRef upstream_ref = 5; + optional int32 ahead = 6; + optional int32 behind = 7; + } + message Ref { // aiserver.v1.CppGitContextEvent.Ref + string type = 1; + optional string name = 2; + optional string commit = 3; + optional string remote = 4; + } + message Remote { // aiserver.v1.CppGitContextEvent.Remote + string name = 1; + optional string fetch_url = 2; + optional string push_url = 3; + bool is_read_only = 4; + } + message Submodule { // aiserver.v1.CppGitContextEvent.Submodule + string name = 1; + string path = 2; + string url = 3; + } + message Commit { // aiserver.v1.CppGitContextEvent.Commit + message CommitShortStat { // aiserver.v1.CppGitContextEvent.Commit.CommitShortStat + int32 files = 1; + int32 insertions = 2; + int32 deletions = 3; + } + string hash = 1; + string message = 2; + repeated string parents = 3; + optional string author_date = 4; + optional string author_name = 5; + optional string author_email = 6; + optional string commit_date = 7; + optional CommitShortStat short_stat = 8; + } + message Change { // aiserver.v1.CppGitContextEvent.Change + string uri = 1; + string original_uri = 2; + optional string rename_uri = 3; + string status = 4; + } + string relative_workspace_path = 1; + string root_fs_path = 2; + optional Head head = 3; + repeated Ref refs = 4; + repeated Remote remotes = 5; + repeated Submodule submodules = 6; + optional Commit rebase_commit = 7; + repeated Change merge_changes = 8; + repeated Change index_changes = 9; + repeated Change working_tree_changes = 10; +} +message CppHistoryAppendEvent { // aiserver.v1.CppHistoryAppendEvent + ModelChange model_change = 1; + CppAcceptEvent accept_event = 2; + CppRejectEvent reject_event = 3; + CppManualTriggerEvent manual_trigger_event = 4; + optional string final_model_hash = 10; +} +message CppAcceptEvent { // aiserver.v1.CppAcceptEvent + CppSuggestion cpp_suggestion = 1; +} +message CppSuggestion { // aiserver.v1.CppSuggestion + string suggestion_text = 1; + IRange range = 2; + bool seen = 5; + SelectionWithOrientation editor_selection_before_peek = 6; +} +message SelectionWithOrientation { // aiserver.v1.SelectionWithOrientation + int32 selection_start_line_number = 1; + int32 selection_start_column = 2; + int32 position_line_number = 3; + int32 position_column = 4; +} +message CppRejectEvent { // aiserver.v1.CppRejectEvent + CppSuggestion cpp_suggestion = 1; +} +message CppManualTriggerEvent { // aiserver.v1.CppManualTriggerEvent + CursorPosition position = 2; +} +message EditHistoryAppendChangesResponse { // aiserver.v1.EditHistoryAppendChangesResponse + bool success = 1; +} +message DevOnlyGetPastRequestIdsRequest { // aiserver.v1.DevOnlyGetPastRequestIdsRequest + optional int32 count = 1; + optional int32 page = 2; +} +message DevOnlyGetPastRequestIdsResponse { // aiserver.v1.DevOnlyGetPastRequestIdsResponse + repeated DevOnlyPastRequest past_requests = 1; + int32 total_count = 10; + bool has_more = 11; +} +message DevOnlyPastRequest { // aiserver.v1.DevOnlyPastRequest + string request_id = 1; + string date_time = 2; + string model_name = 3; + string feature_name = 4; + string s3_uri = 5; + string status = 6; + int32 num_prompt_tokens = 7; + int32 num_completion_tokens = 8; + string api_call_method = 9; +} +message GetFilesForComposerRequest { // aiserver.v1.GetFilesForComposerRequest + repeated ConversationMessage conversation = 1; + repeated CurrentFileInfo files = 2; + optional bool rerank_results = 3; + FullFileSearchResult file_search_results = 4; + CodeSearchResult code_search_results = 5; + optional bool rerank_results_v2 = 6; + optional bool long_context_mode = 7; + optional bool is_eval = 8; + optional string request_id = 9; + ModelDetails model_details = 10; +} +message GetFilesForComposerResponse { // aiserver.v1.GetFilesForComposerResponse + repeated string relative_workspace_paths = 1; +} +message TryParseTypeScriptTreeSitterRequest { // aiserver.v1.TryParseTypeScriptTreeSitterRequest + string workspace_relative_path = 1; + string text = 2; +} +message TryParseTypeScriptTreeSitterResponse { // aiserver.v1.TryParseTypeScriptTreeSitterResponse + string text = 1; +} +message NameTabRequest { // aiserver.v1.NameTabRequest + repeated ConversationMessage messages = 1; +} +message NameTabResponse { // aiserver.v1.NameTabResponse + string name = 1; + string reason = 2; +} +message IsTerminalFinishedRequest { // aiserver.v1.IsTerminalFinishedRequest + string terminal_content = 1; +} +message IsTerminalFinishedResponse { // aiserver.v1.IsTerminalFinishedResponse + bool is_finished = 1; + optional string reason = 2; +} +message TestModelStatusRequest { // aiserver.v1.TestModelStatusRequest + string model_name = 1; +} +message TestModelStatusResponse { // aiserver.v1.TestModelStatusResponse + string text = 1; + float latency = 2; + float ttft = 3; + float max_time_between_chunks = 4; + string server_timing = 5; +} +message FindBugsRequest { // aiserver.v1.FindBugsRequest + CurrentFileInfo current_file = 1; + ModelDetails model_details = 2; +} +message FindBugsResponse { // aiserver.v1.FindBugsResponse + message Bug { // aiserver.v1.FindBugsResponse.Bug + string description = 1; + int32 line_number = 2; + float confidence = 3; + } + optional Bug bug = 1; +} +message ContextRerankingRequest { // aiserver.v1.ContextRerankingRequest + optional CurrentFileInfo current_file = 1; + repeated ConversationMessage chat_conversation_history = 2; + repeated CppFileDiffHistory cpp_diff_trajectories = 3; + repeated ContextRerankingCandidateFile candidate_files = 4; +} +message ContextRerankingCandidateFile { // aiserver.v1.ContextRerankingCandidateFile + string file_name = 1; + string file_content = 2; +} +message ContextRerankingResponse { // aiserver.v1.ContextRerankingResponse + repeated float reranking_scores = 1; +} +message AutoContextRequest { // aiserver.v1.AutoContextRequest + string text = 1; + repeated AutoContextFile candidate_files = 2; + ModelDetails model_details = 3; +} +message AutoContextFile { // aiserver.v1.AutoContextFile + string relative_workspace_path = 1; + string file_content = 2; +} +message AutoContextResponse { // aiserver.v1.AutoContextResponse + repeated AutoContextRankedFile ranked_files = 1; +} +message AutoContextRankedFile { // aiserver.v1.AutoContextRankedFile + string relative_workspace_path = 1; + float reranking_score = 2; +} +message WriteGitCommitMessageRequest { // aiserver.v1.WriteGitCommitMessageRequest + repeated string diffs = 1; + repeated string previous_commit_messages = 2; +} +message WriteGitCommitMessageResponse { // aiserver.v1.WriteGitCommitMessageResponse + string commit_message = 1; +} +message StreamBugBotRequest { // aiserver.v1.StreamBugBotRequest + GitDiff git_diff = 1; + ModelDetails model_details = 2; + optional string user_instructions = 3; + optional string bug_detection_guidelines = 4; + optional int32 iterations = 5; + bool in_background_subsidized = 6; + optional string session_id = 7; + optional string price_id = 8; + bool has_telemetry = 9; +} +message StreamBugBotResponse { // aiserver.v1.StreamBugBotResponse + optional BugReports bug_reports = 1; + BugBotStatus status = 2; +} +message BugBotStatus { // aiserver.v1.BugBotStatus + enum Status { // aiserver.v1.BugBotStatus.Status + STATUS_UNSPECIFIED = 0; + STATUS_IN_PROGRESS = 1; + STATUS_IN_PROGRESS_ITERATIONS = 2; + STATUS_DONE = 3; + } + Status status = 1; + string message = 2; + optional int32 iterations_completed = 3; + optional int32 total_iterations = 4; + optional int32 total_tokens = 5; + optional int32 processed_tokens = 6; + optional float processed_cost = 7; + optional int32 thinking_tokens = 8; + optional float thinking_cost = 9; +} +message CheckBugBotPriceRequest { // aiserver.v1.CheckBugBotPriceRequest + int32 diff_char_len = 1; + int32 iterations = 2; + ModelDetails model_details = 3; +} +message CheckBugBotPriceResponse { // aiserver.v1.CheckBugBotPriceResponse + double cost = 1; + string price_id = 2; +} +message CheckBugBotTelemetryHealthyRequest { // aiserver.v1.CheckBugBotTelemetryHealthyRequest + string session_id = 1; +} +message CheckBugBotTelemetryHealthyResponse { // aiserver.v1.CheckBugBotTelemetryHealthyResponse + bool is_healthy = 1; +} +message GetSuggestedBugBotIterationsRequest { // aiserver.v1.GetSuggestedBugBotIterationsRequest + int32 diff_char_len = 1; + ModelDetails model_details = 2; +} +message GetSuggestedBugBotIterationsResponse { // aiserver.v1.GetSuggestedBugBotIterationsResponse + int32 iterations = 1; +} +message TestBidiRequest { // aiserver.v1.TestBidiRequest + string message = 1; +} +message TestBidiResponse { // aiserver.v1.TestBidiResponse + string message = 1; +} +message FastRepoInitHandshakeRequest { // aiserver.v1.FastRepoInitHandshakeRequest + RepositoryInfo repository = 1; + string root_hash = 2; + string potential_legacy_repo_name = 3; +} +message FastRepoInitHandshakeResponse { // aiserver.v1.FastRepoInitHandshakeResponse + enum Status { // aiserver.v1.FastRepoInitHandshakeResponse.Status + STATUS_UNSPECIFIED = 0; + STATUS_UP_TO_DATE = 1; + STATUS_OUT_OF_SYNC = 2; + STATUS_FAILURE = 3; + STATUS_EMPTY = 4; + } + Status status = 1; + string repo_name = 2; +} +message SyncMerkleSubtreeRequest { // aiserver.v1.SyncMerkleSubtreeRequest + RepositoryInfo repository = 1; + PartialPathItem local_partial_path = 2; +} +message PartialPathItem { // aiserver.v1.PartialPathItem + string relative_workspace_path = 1; + string hash_of_node = 2; +} +message SyncMerkleSubtreeResponse { // aiserver.v1.SyncMerkleSubtreeResponse + message Mismatch { // aiserver.v1.SyncMerkleSubtreeResponse.Mismatch + repeated PartialPathItem children = 1; + } + bool match = 1; + Mismatch mismatch = 2; +} +message FastUpdateFileRequest { // aiserver.v1.FastUpdateFileRequest + message LocalFile { // aiserver.v1.FastUpdateFileRequest.LocalFile + File file = 1; + string hash = 2; + string unencrypted_relative_workspace_path = 3; + } + enum UpdateType { // aiserver.v1.FastUpdateFileRequest.UpdateType + UPDATE_TYPE_UNSPECIFIED = 0; + UPDATE_TYPE_ADD = 1; + UPDATE_TYPE_DELETE = 2; + UPDATE_TYPE_MODIFY = 3; + } + RepositoryInfo repository = 1; + PartialPathItem directory = 2; + LocalFile local_file = 3; + repeated PartialPathItem ancestor_spline = 4; + UpdateType update_type = 5; +} +message FastUpdateFileResponse { // aiserver.v1.FastUpdateFileResponse + enum Status { // aiserver.v1.FastUpdateFileResponse.Status + STATUS_UNSPECIFIED = 0; + STATUS_SUCCESS = 1; + STATUS_FAILURE = 2; + STATUS_EXPECTED_FAILURE = 3; + } + Status status = 1; +} +message SearchRepositoryRequest { // aiserver.v1.SearchRepositoryRequest + string query = 1; + RepositoryInfo repository = 2; + int32 top_k = 3; + ModelDetails model_details = 4; + bool rerank = 5; + optional bool context_cache_request = 6; + optional string glob_filter = 7; + optional string not_glob_filter = 8; + optional int32 race_n_requests = 9; +} +message SearchRepositoryResponse { // aiserver.v1.SearchRepositoryResponse + repeated CodeResult code_results = 1; +} +message RemoveRepositoryRequest { // aiserver.v1.RemoveRepositoryRequest + RepositoryInfo repository = 1; +} +message RemoveRepositoryResponse { // aiserver.v1.RemoveRepositoryResponse + enum Status { // aiserver.v1.RemoveRepositoryResponse.Status + STATUS_UNSPECIFIED = 0; + STATUS_NOT_FOUND = 1; + STATUS_NOT_AUTHORIZED = 2; + STATUS_STARTED = 3; + STATUS_SUCCESS = 4; + } + Status status = 1; +} +message SemSearchRequest { // aiserver.v1.SemSearchRequest + SearchRepositoryRequest request = 1; +} +message SemSearchResponse { // aiserver.v1.SemSearchResponse + message SemSearchMetadata { // aiserver.v1.SemSearchResponse.SemSearchMetadata + optional string query_embedding_model = 1; + optional int32 server_side_latency_ms = 2; + optional int32 embed_latency_ms = 3; + optional int32 knn_latency_ms = 4; + } + SearchRepositoryResponse response = 1; + optional SemSearchMetadata metadata = 2; + repeated CodeResultWithClassificationInfo code_results = 3; +} +message CodeResultWithClassificationInfo { // aiserver.v1.CodeResultWithClassificationInfo + message LineNumberClassification { // aiserver.v1.CodeResultWithClassificationInfo.LineNumberClassification + DetailedLine detailed_line = 1; + string query_computed_for = 2; + repeated string matched_strings = 3; + SimpleRange highlight_range = 4; + } + CodeResult code_result = 1; + optional LineNumberClassification line_number_classification = 2; +} +message EnsureIndexCreatedRequest { // aiserver.v1.EnsureIndexCreatedRequest + RepositoryInfo repository = 1; +} +message EnsureIndexCreatedResponse { // aiserver.v1.EnsureIndexCreatedResponse +} +message GetHighLevelFolderDescriptionRequest { // aiserver.v1.GetHighLevelFolderDescriptionRequest + message Readme { // aiserver.v1.GetHighLevelFolderDescriptionRequest.Readme + string relative_workspace_path = 1; + string contents = 2; + } + repeated Readme readmes = 1; + repeated string top_level_relative_workspace_paths = 2; + string workspace_root_path = 4; +} +message GetHighLevelFolderDescriptionResponse { // aiserver.v1.GetHighLevelFolderDescriptionResponse + string description = 1; +} +message GetEmbeddingsRequest { // aiserver.v1.GetEmbeddingsRequest + repeated string texts = 1; +} +message GetEmbeddingsResponse { // aiserver.v1.GetEmbeddingsResponse + message Embedding { // aiserver.v1.GetEmbeddingsResponse.Embedding + repeated float embedding = 1; + } + repeated Embedding embeddings = 2; +} +message GetUploadLimitsRequest { // aiserver.v1.GetUploadLimitsRequest + optional RepositoryInfo repository = 1; +} +message GetUploadLimitsResponse { // aiserver.v1.GetUploadLimitsResponse + int32 soft_limit = 1; + int32 hard_limit = 2; +} +message GetNumFilesToSendRequest { // aiserver.v1.GetNumFilesToSendRequest + RepositoryInfo repository = 1; +} +message GetNumFilesToSendResponse { // aiserver.v1.GetNumFilesToSendResponse + int32 num_files = 1; +} +message GetAvailableChunkingStrategiesRequest { // aiserver.v1.GetAvailableChunkingStrategiesRequest + RepositoryInfo repository = 1; +} +message GetAvailableChunkingStrategiesResponse { // aiserver.v1.GetAvailableChunkingStrategiesResponse + repeated ChunkingStrategy chunking_strategies = 1; +} +message GetLineNumberClassificationsRequest { // aiserver.v1.GetLineNumberClassificationsRequest + string query = 1; + repeated CodeResult code_results = 2; +} +message GetLineNumberClassificationsResponse { // aiserver.v1.GetLineNumberClassificationsResponse + CodeResultWithClassificationInfo classified_result = 1; +} +service AiService { + rpc HealthCheck(HealthCheckRequest) returns ( HealthCheckResponse) {} + rpc PrivacyCheck(PrivacyCheckRequest) returns ( PrivacyCheckResponse) {} + rpc TimeLeftHealthCheck(HealthCheckRequest) returns ( TimeLeftHealthCheckResponse) {} + rpc ThrowErrorCheck(ThrowErrorCheckRequest) returns ( ThrowErrorCheckResponse) {} + rpc AvailableModels(AvailableModelsRequest) returns ( AvailableModelsResponse) {} + rpc StreamChatTryReallyHard(GetChatRequest) returns (stream StreamChatResponse) {} + rpc RerankDocuments(RerankDocumentsRequest) returns ( RerankDocumentsResponse) {} + rpc StreamComposer(GetComposerChatRequest) returns (stream StreamChatResponse) {} + rpc StreamComposerContext(StreamChatContextRequest) returns (stream StreamChatContextResponse) {} + rpc WarmComposerCache(GetComposerChatRequest) returns ( WarmComposerCacheResponse) {} + rpc KeepComposerCacheWarm(KeepComposerCacheWarmRequest) returns ( KeepComposerCacheWarmResponse) {} + rpc StreamPotentialLocs(PotentialLocsRequest) returns (stream PotentialLocsResponse) {} + rpc StreamPotentialLocsUnderneath(PotentialLocsUnderneathRequest) returns (stream PotentialLocsUnderneathResponse) {} + rpc StreamPotentialLocsInitialQueries(PotentialLocsInitialQueriesRequest) returns (stream PotentialLocsInitialQueriesResponse) {} + rpc StreamNotepadChat(GetNotepadChatRequest) returns (stream StreamChatResponse) {} + rpc GetChatTitle(GetChatTitleRequest) returns ( GetChatTitleResponse) {} + rpc GetCompletion(GetCompletionRequest) returns ( GetCompletionResponse) {} + rpc GetSearch(GetSearchRequest) returns ( GetSearchResponse) {} + rpc StreamInlineEdits(StreamInlineEditsRequest) returns (stream StreamInlineEditsResponse) {} + rpc SummarizeConversation(GetChatRequest) returns ( SummarizeConversationResponse) {} + rpc IsolatedTreesitter(IsolatedTreesitterRequest) returns ( IsolatedTreesitterResponse) {} + rpc GetSimplePrompt(GetSimplePromptRequest) returns ( GetSimplePromptResponse) {} + rpc CheckLongFilesFit(GetChatRequest) returns ( CheckLongFilesFitResponse) {} + rpc GetEvaluationPrompt(GetEvaluationPromptRequest) returns ( GetEvaluationPromptResponse) {} + rpc GetUserInfo(GetUserInfoRequest) returns ( GetUserInfoResponse) {} + rpc ClearAndRedoEntireBucket(ClearAndRedoEntireBucketRequest) returns ( ClearAndRedoEntireBucketResponse) {} + rpc StreamBranchGemini(StreamBranchGeminiRequest) returns (stream StreamBranchGeminiResponse) {} + rpc StreamBranchFileSelections(StreamBranchFileSelectionsRequest) returns (stream StreamBranchFileSelectionsResponse) {} + rpc StreamBackgroundEdit(StreamBackgroundEditRequest) returns (stream StreamChatResponse) {} + rpc StreamGPTFourEdit(StreamGPTFourEditRequest) returns (stream StreamChatResponse) {} + rpc StreamChat(GetChatRequest) returns (stream StreamChatResponse) {} + rpc StreamChatWeb(GetChatRequest) returns (stream StreamChatResponse) {} + rpc WarmChatCache(WarmChatCacheRequest) returns ( WarmChatCacheResponse) {} + rpc StreamEdit(StreamEditRequest) returns (stream StreamChatResponse) {} + rpc PreloadEdit(PreloadEditRequest) returns ( PreloadEditResponse) {} + rpc StreamFastEdit(StreamFastEditRequest) returns (stream StreamFastEditResponse) {} + rpc StreamGenerate(StreamGenerateRequest) returns (stream StreamChatResponse) {} + rpc StreamInlineLongCompletion(StreamInlineLongCompletionRequest) returns (stream StreamChatResponse) {} + rpc SlashEdit(SlashEditRequest) returns (stream SlashEditResponse) {} + rpc SlashEditFollowUpWithPreviousEdits(SlashEditFollowUpWithPreviousEditsRequest) returns (stream StreamSlashEditFollowUpWithPreviousEditsResponse) {} + rpc StreamAiPreviews(StreamAiPreviewsRequest) returns (stream StreamAiPreviewsResponse) {} + rpc ShouldTurnOnCppOnboarding(ShouldTurnOnCppOnboardingRequest) returns ( ShouldTurnOnCppOnboardingResponse) {} + rpc StreamReview(ReviewRequest) returns (stream ReviewResponse) {} + rpc StreamReviewChat(ReviewChatRequest) returns (stream ReviewChatResponse) {} + rpc CheckQueuePosition(CheckQueuePositionRequest) returns ( CheckQueuePositionResponse) {} + rpc CheckUsageBasedPrice(CheckUsageBasedPriceRequest) returns ( CheckUsageBasedPriceResponse) {} + rpc DoThisForMeCheck(DoThisForMeCheckRequest) returns ( DoThisForMeCheckResponse) {} + rpc StreamDoThisForMe(DoThisForMeRequest) returns (stream DoThisForMeResponseWrapped) {} + rpc StreamChatToolformer(GetChatRequest) returns (stream StreamChatToolformerResponse) {} + rpc StreamChatToolformerContinue(StreamChatToolformerContinueRequest) returns (stream StreamChatToolformerResponse) {} + rpc PushAiThought(PushAiThoughtRequest) returns ( PushAiThoughtResponse) {} + rpc CheckDoableAsTask(CheckDoableAsTaskRequest) returns ( CheckDoableAsTaskResponse) {} + rpc ReportGroundTruthCandidate(ReportGroundTruthCandidateRequest) returns ( ReportGroundTruthCandidateResponse) {} + rpc ReportCmdKFate(ReportCmdKFateRequest) returns ( ReportCmdKFateResponse) {} + rpc ShowWelcomeScreen(ShowWelcomeScreenRequest) returns ( ShowWelcomeScreenResponse) {} + rpc InterfaceAgentInit(InterfaceAgentInitRequest) returns ( InterfaceAgentInitResponse) {} + rpc StreamInterfaceAgentStatus(StreamInterfaceAgentStatusRequest) returns (stream StreamInterfaceAgentStatusResponse) {} + rpc TaskGetInterfaceAgentStatus(TaskGetInterfaceAgentStatusRequest) returns (stream TaskGetInterfaceAgentStatusResponseWrapped) {} + rpc TaskInit(TaskInitRequest) returns ( TaskInitResponse) {} + rpc TaskPause(TaskPauseRequest) returns ( TaskPauseResponse) {} + rpc TaskInfo(TaskInfoRequest) returns ( TaskInfoResponse) {} + rpc TaskStreamLog(TaskStreamLogRequest) returns (stream TaskStreamLogResponse) {} + rpc TaskSendMessage(TaskSendMessageRequest) returns ( TaskSendMessageResponse) {} + rpc TaskProvideResult(TaskProvideResultRequest) returns ( TaskProvideResultResponse) {} + rpc CreateExperimentalIndex(CreateExperimentalIndexRequest) returns ( CreateExperimentalIndexResponse) {} + rpc ListExperimentalIndexFiles(ListExperimentalIndexFilesRequest) returns ( ListExperimentalIndexFilesResponse) {} + rpc ListenExperimentalIndex(ListenExperimentalIndexRequest) returns (stream ListenExperimentalIndexResponse) {} + rpc RegisterFileToIndex(RegisterFileToIndexRequest) returns ( RequestReceivedResponse) {} + rpc SetupIndexDependencies(SetupIndexDependenciesRequest) returns ( SetupIndexDependenciesResponse) {} + rpc ComputeIndexTopoSort(ComputeIndexTopoSortRequest) returns ( ComputeIndexTopoSortResponse) {} + rpc StreamChatDeepContext(StreamChatDeepContextRequest) returns (stream StreamChatDeepContextResponse) {} + rpc ChooseCodeReferences(ChooseCodeReferencesRequest) returns ( RequestReceivedResponse) {} + rpc RegisterCodeReferences(RegisterCodeReferencesRequest) returns ( RegisterCodeReferencesResponse) {} + rpc ExtractPaths(ExtractPathsRequest) returns ( ExtractPathsResponse) {} + rpc SummarizeWithReferences(SummarizeWithReferencesRequest) returns ( RequestReceivedResponse) {} + rpc DocumentationQuery(DocumentationQueryRequest) returns ( DocumentationQueryResponse) {} + rpc AvailableDocs(AvailableDocsRequest) returns ( AvailableDocsResponse) {} + rpc ReportFeedback(ReportFeedbackRequest) returns ( ReportFeedbackResponse) {} + rpc ReportBug(ReportBugRequest) returns ( ReportBugResponse) {} + rpc StreamChatContext(StreamChatContextRequest) returns (stream StreamChatContextResponse) {} + rpc GenerateTldr(GenerateTldrRequest) returns ( GenerateTldrResponse) {} + rpc TaskStreamChatContext(TaskStreamChatContextRequest) returns (stream TaskStreamChatContextResponseWrapped) {} + rpc RerankResults(RerankerRequest) returns ( RerankerResponse) {} + rpc ModelQuery(ModelQueryRequest) returns ( ModelQueryResponse) {} + rpc ModelQueryV2(ModelQueryRequest) returns (stream ModelQueryResponseV2) {} + rpc IntentPrediction(IntentPredictionRequest) returns ( IntentPredictionResponse) {} + rpc StreamCursorTutor(StreamCursorTutorRequest) returns (stream StreamCursorTutorResponse) {} + rpc CheckFeatureStatus(CheckFeatureStatusRequest) returns ( CheckFeatureStatusResponse) {} + rpc GetEffectiveTokenLimit(GetEffectiveTokenLimitRequest) returns ( GetEffectiveTokenLimitResponse) {} + rpc GetContextScores(ContextScoresRequest) returns ( ContextScoresResponse) {} + rpc StreamCpp(StreamCppRequest) returns (stream StreamCppResponse) {} + rpc CppConfig(CppConfigRequest) returns ( CppConfigResponse) {} + rpc CppEditHistoryStatus(CppEditHistoryStatusRequest) returns ( CppEditHistoryStatusResponse) {} + rpc CppAppend(CppAppendRequest) returns ( CppAppendResponse) {} + rpc CheckNumberConfig(CheckNumberConfigRequest) returns ( CheckNumberConfigResponse) {} + rpc StreamTerminalAutocomplete(StreamTerminalAutocompleteRequest) returns (stream StreamTerminalAutocompleteResponse) {} + rpc StreamPseudocodeGenerator(StreamPseudocodeGeneratorRequest) returns (stream StreamPseudocodeGeneratorResponse) {} + rpc StreamPseudocodeMapper(StreamPseudocodeMapperRequest) returns (stream StreamPseudocodeMapperResponse) {} + rpc StreamAiLintBug(StreamAiLintBugRequest) returns (stream StreamAiLintBugResponse) {} + rpc StreamAiCursorHelp(StreamAiCursorHelpRequest) returns (stream StreamAiCursorHelpResponse) {} + rpc LogUserLintReply(LogUserLintReplyRequest) returns ( LogUserLintReplyResponse) {} + rpc LogLinterExplicitUserFeedback(LogLinterExplicitUserFeedbackRequest) returns ( LogLinterExplicitUserFeedbackResponse) {} + rpc StreamFixMarkers(FixMarkersRequest) returns (stream FixMarkersResponse) {} + rpc ReportInlineAction(ReportInlineActionRequest) returns ( ReportInlineActionResponse) {} + rpc StreamPriomptPrompt(StreamPriomptPromptRequest) returns (stream StreamPriomptPromptResponse) {} + rpc StreamLint(StreamLintRequest) returns (stream StreamChatResponse) {} + rpc StreamNewLintRule(StreamNewRuleRequest) returns (stream StreamChatResponse) {} + rpc AiProject(AiProjectRequest) returns (stream AiProjectResponse) {} + rpc ToCamelCase(ToCamelCaseRequest) returns ( ToCamelCaseResponse) {} + rpc ReportGenerationFeedback(ReportGenerationFeedbackRequest) returns ( ReportGenerationFeedbackResponse) {} + rpc GetThoughtAnnotation(GetThoughtAnnotationRequest) returns ( GetThoughtAnnotationResponse) {} + rpc StreamWebCmdKV1(StreamWebCmdKV1Request) returns (stream StreamWebCmdKV1Response) {} + rpc StreamNextCursorPrediction(StreamNextCursorPredictionRequest) returns (stream StreamNextCursorPredictionResponse) {} + rpc IsCursorPredictionEnabled(IsCursorPredictionEnabledRequest) returns ( IsCursorPredictionEnabledResponse) {} + rpc GetCppEditClassification(GetCppEditClassificationRequest) returns ( GetCppEditClassificationResponse) {} + rpc GetTerminalCompletion(GetTerminalCompletionRequest) returns ( GetTerminalCompletionResponse) {} + rpc TakeNotesOnCommitDiff(TakeNotesOnCommitDiffRequest) returns ( TakeNotesOnCommitDiffResponse) {} + rpc BulkEmbed(BulkEmbedRequest) returns ( BulkEmbedResponse) {} + rpc ContinueChatRequestWithCommits(ContinueChatRequestWithCommitsRequest) returns ( EmptyResponse) {} + rpc BackgroundCmdKEval(BackgroundCmdKEvalRequest) returns (stream BackgroundCmdKEvalResponse) {} + rpc BackgroundCmdK(BackgroundCmdKRequest) returns (stream BackgroundCmdKResponse) {} + rpc StreamCursorMotion(StreamCursorMotionRequest) returns (stream StreamCursorMotionResponse) {} + rpc CalculateAutoSelection(CalculateAutoSelectionRequest) returns ( CalculateAutoSelectionResponse) {} + rpc GetAtSymbolSuggestions(GetAtSymbolSuggestionsRequest) returns ( GetAtSymbolSuggestionsResponse) {} + rpc GetCodebaseQuestions(GetChatRequest) returns ( GetCodebaseQuestionsResponse) {} + rpc GetRankedContextFromContextBank(GetRankedContextFromContextBankRequest) returns (stream GetRankedContextFromContextBankResponse) {} + rpc CppEditHistoryAppend(EditHistoryAppendChangesRequest) returns ( EditHistoryAppendChangesResponse) {} + rpc DevOnlyGetPastRequestIds(DevOnlyGetPastRequestIdsRequest) returns ( DevOnlyGetPastRequestIdsResponse) {} + rpc GetFilesForComposer(GetFilesForComposerRequest) returns ( GetFilesForComposerResponse) {} + rpc TryParseTypeScriptTreeSitter(TryParseTypeScriptTreeSitterRequest) returns ( TryParseTypeScriptTreeSitterResponse) {} + rpc NameTab(NameTabRequest) returns ( NameTabResponse) {} + rpc IsTerminalFinished(IsTerminalFinishedRequest) returns ( IsTerminalFinishedResponse) {} + rpc TestModelStatus(TestModelStatusRequest) returns ( TestModelStatusResponse) {} + rpc FindBugs(FindBugsRequest) returns ( FindBugsResponse) {} + rpc ContextReranking(ContextRerankingRequest) returns ( ContextRerankingResponse) {} + rpc AutoContext(AutoContextRequest) returns ( AutoContextResponse) {} + rpc WriteGitCommitMessage(WriteGitCommitMessageRequest) returns ( WriteGitCommitMessageResponse) {} + rpc StreamBugBot(StreamBugBotRequest) returns (stream StreamBugBotResponse) {} + rpc CheckBugBotPrice(CheckBugBotPriceRequest) returns ( CheckBugBotPriceResponse) {} + rpc CheckBugBotTelemetryHealthy(CheckBugBotTelemetryHealthyRequest) returns ( CheckBugBotTelemetryHealthyResponse) {} + rpc GetSuggestedBugBotIterations(GetSuggestedBugBotIterationsRequest) returns ( GetSuggestedBugBotIterationsResponse) {} + rpc TestBidi(TestBidiRequest) returns ( TestBidiResponse) {} +} +service RepositoryService { + rpc FastRepoInitHandshake(FastRepoInitHandshakeRequest) returns ( FastRepoInitHandshakeResponse) {} + rpc SyncMerkleSubtree(SyncMerkleSubtreeRequest) returns ( SyncMerkleSubtreeResponse) {} + rpc FastUpdateFile(FastUpdateFileRequest) returns ( FastUpdateFileResponse) {} + rpc SearchRepositoryV2(SearchRepositoryRequest) returns ( SearchRepositoryResponse) {} + rpc RemoveRepositoryV2(RemoveRepositoryRequest) returns ( RemoveRepositoryResponse) {} + rpc SemSearchFast(SemSearchRequest) returns (stream SemSearchResponse) {} + rpc SemSearch(SemSearchRequest) returns (stream SemSearchResponse) {} + rpc EnsureIndexCreated(EnsureIndexCreatedRequest) returns ( EnsureIndexCreatedResponse) {} + rpc GetHighLevelFolderDescription(GetHighLevelFolderDescriptionRequest) returns ( GetHighLevelFolderDescriptionResponse) {} + rpc GetEmbeddings(GetEmbeddingsRequest) returns ( GetEmbeddingsResponse) {} + rpc GetUploadLimits(GetUploadLimitsRequest) returns ( GetUploadLimitsResponse) {} + rpc GetNumFilesToSend(GetNumFilesToSendRequest) returns ( GetNumFilesToSendResponse) {} + rpc GetAvailableChunkingStrategies(GetAvailableChunkingStrategiesRequest) returns ( GetAvailableChunkingStrategiesResponse) {} + rpc GetLineNumberClassifications(GetLineNumberClassificationsRequest) returns (stream GetLineNumberClassificationsResponse) {} +} diff --git a/src/app.rs b/src/app.rs new file mode 100644 index 0000000..f83e629 --- /dev/null +++ b/src/app.rs @@ -0,0 +1,5 @@ +pub mod models; +pub mod constant; +pub mod token; +pub mod utils; +pub mod client; diff --git a/src/app/client.rs b/src/app/client.rs new file mode 100644 index 0000000..1d4947c --- /dev/null +++ b/src/app/client.rs @@ -0,0 +1,29 @@ +use crate::app::constant::*; +use reqwest::Client; +use uuid::Uuid; + +/// 返回预构建的 Cursor API 客户端 +pub fn build_client(auth_token: &str, checksum: &str, endpoint: &str) -> reqwest::RequestBuilder { + let client = Client::new(); + let trace_id = Uuid::new_v4().to_string(); + let content_type = if endpoint == CURSOR_API2_STREAM_CHAT { + CONTENT_TYPE_CONNECT_PROTO + } else { + CONTENT_TYPE_PROTO + }; + + client + .post(format!("{}{}", CURSOR_API2_BASE_URL, endpoint)) + .header(HEADER_NAME_CONTENT_TYPE, content_type) + .header(HEADER_NAME_AUTHORIZATION, format!("{}{}", AUTHORIZATION_BEARER_PREFIX, auth_token)) + .header("connect-accept-encoding", "gzip,br") + .header("connect-protocol-version", "1") + .header("user-agent", "connect-es/1.6.1") + .header("x-amzn-trace-id", format!("Root={}", trace_id)) + .header("x-cursor-checksum", checksum) + .header("x-cursor-client-version", "0.42.5") + .header("x-cursor-timezone", "Asia/Shanghai") + .header("x-ghost-mode", "false") + .header("x-request-id", trace_id) + .header("Host", CURSOR_API2_HOST) +} diff --git a/src/app/constant.rs b/src/app/constant.rs new file mode 100644 index 0000000..5447ad6 --- /dev/null +++ b/src/app/constant.rs @@ -0,0 +1,64 @@ +pub const PKG_VERSION: &str = env!("CARGO_PKG_VERSION"); +pub const PKG_NAME: &str = env!("CARGO_PKG_NAME"); +pub const PKG_DESCRIPTION: &str = env!("CARGO_PKG_DESCRIPTION"); +pub const PKG_AUTHORS: &str = env!("CARGO_PKG_AUTHORS"); +pub const PKG_REPOSITORY: &str = env!("CARGO_PKG_REPOSITORY"); + +pub const ROUTER_ROOT_PATH: &str = "/"; +pub const ROUTER_HEALTH_PATH: &str = "/health"; +pub const ROUTER_GET_CHECKSUM: &str = "/get-checksum"; +pub const ROUTER_GET_USER_INFO_PATH: &str = "/get-user-info"; +pub const ROUTER_LOGS_PATH: &str = "/logs"; +pub const ROUTER_CONFIG_PATH: &str = "/config"; +pub const ROUTER_TOKENINFO_PATH: &str = "/tokeninfo"; +pub const ROUTER_GET_TOKENINFO_PATH: &str = "/get-tokeninfo"; +pub const ROUTER_UPDATE_TOKENINFO_PATH: &str = "/update-tokeninfo"; +pub const ROUTER_ENV_EXAMPLE_PATH: &str = "/env-example"; +pub const ROUTER_SHARED_STYLES_PATH: &str = "/static/shared-styles.css"; +pub const ROUTER_SHARED_JS_PATH: &str = "/static/shared.js"; + +pub const STATUS: &str = "status"; +pub const MESSAGE: &str = "message"; +pub const ERROR: &str = "error"; + +pub const TOKEN_FILE: &str = "token_file"; +pub const TOKEN_LIST_FILE: &str = "token_list_file"; +pub const TOKENS: &str = "tokens"; +pub const TOKEN_LIST: &str = "token_list"; + +pub const STATUS_SUCCESS: &str = "success"; +pub const STATUS_FAILED: &str = "failed"; + +pub const HEADER_NAME_CONTENT_TYPE: &str = "content-type"; +pub const HEADER_NAME_AUTHORIZATION: &str = "Authorization"; + +pub const CONTENT_TYPE_PROTO: &str = "application/proto"; +pub const CONTENT_TYPE_CONNECT_PROTO: &str = "application/connect+proto"; +pub const CONTENT_TYPE_TEXT_HTML_WITH_UTF8: &str = "text/html;charset=utf-8"; +pub const CONTENT_TYPE_TEXT_PLAIN_WITH_UTF8: &str = "text/plain;charset=utf-8"; + +pub const AUTHORIZATION_BEARER_PREFIX: &str = "Bearer "; + +pub const OBJECT_CHAT_COMPLETION: &str = "chat.completion"; +pub const OBJECT_CHAT_COMPLETION_CHUNK: &str = "chat.completion.chunk"; + +pub const CURSOR_API2_HOST: &str = "api2.cursor.sh"; +pub const CURSOR_API2_BASE_URL: &str = "https://api2.cursor.sh/aiserver.v1.AiService/"; + +pub const CURSOR_API2_STREAM_CHAT: &str = "StreamChat"; +pub const CURSOR_API2_GET_USER_INFO: &str = "GetUserInfo"; + +pub const FINISH_REASON_STOP: &str = "stop"; + +pub const LONG_CONTEXT_MODELS: [&str; 4] = [ + "gpt-4o-128k", + "gemini-1.5-flash-500k", + "claude-3-haiku-200k", + "claude-3-5-sonnet-200k", +]; + +pub const MODEL_OBJECT: &str = "model"; +pub const ANTHROPIC: &str = "anthropic"; +pub const CURSOR: &str = "cursor"; +pub const GOOGLE: &str = "google"; +pub const OPENAI: &str = "openai"; diff --git a/src/app/models.rs b/src/app/models.rs new file mode 100644 index 0000000..6c55d58 --- /dev/null +++ b/src/app/models.rs @@ -0,0 +1,447 @@ +use super::{constant::*, token::UserUsageInfo}; +use crate::message::Message; +use chrono::{DateTime, Local}; +use lazy_static::lazy_static; +use serde::{Deserialize, Serialize}; +use std::sync::RwLock; + +// 页面内容类型枚举 +#[derive(Clone, Serialize, Deserialize)] +#[serde(tag = "type", content = "content")] +pub enum PageContent { + #[serde(rename = "default")] + Default, // 默认行为 + #[serde(rename = "text")] + Text(String), // 纯文本 + #[serde(rename = "html")] + Html(String), // HTML 内容 +} + +impl Default for PageContent { + fn default() -> Self { + Self::Default + } +} + +// 静态配置 +#[derive(Clone)] +pub struct AppConfig { + enable_stream_check: bool, + include_stop_stream: bool, + vision_ability: VisionAbility, + enable_slow_pool: bool, + allow_claude: bool, + auth_token: String, + token_file: String, + token_list_file: String, + route_prefix: String, + pub start_time: chrono::DateTime, + pages: Pages, +} + +#[derive(Serialize, Deserialize, Clone)] +pub enum VisionAbility { + #[serde(rename = "none", alias = "disabled")] + None, + #[serde(rename = "base64", alias = "base64-only")] + Base64, + #[serde(rename = "all", alias = "base64-http")] + All, +} + +impl VisionAbility { + pub fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "none" | "disabled" => Ok(Self::None), + "base64" | "base64-only" => Ok(Self::Base64), + "all" | "base64-http" => Ok(Self::All), + _ => Err("Invalid VisionAbility value"), + } + } +} + +impl Default for VisionAbility { + fn default() -> Self { + Self::Base64 + } +} + +#[derive(Clone)] +pub struct Pages { + pub root_content: PageContent, + pub logs_content: PageContent, + pub config_content: PageContent, + pub tokeninfo_content: PageContent, + pub shared_styles_content: PageContent, + pub shared_js_content: PageContent, +} + +impl Default for Pages { + fn default() -> Self { + Self { + root_content: PageContent::Default, + logs_content: PageContent::Default, + config_content: PageContent::Default, + tokeninfo_content: PageContent::Default, + shared_styles_content: PageContent::Default, + shared_js_content: PageContent::Default, + } + } +} + +// 运行时状态 +pub struct AppState { + pub total_requests: u64, + pub active_requests: u64, + pub request_logs: Vec, + pub token_infos: Vec, +} + +// 全局配置实例 +lazy_static! { + pub static ref APP_CONFIG: RwLock = RwLock::new(AppConfig::default()); +} + +impl Default for AppConfig { + fn default() -> Self { + Self { + enable_stream_check: true, + include_stop_stream: true, + vision_ability: VisionAbility::Base64, + enable_slow_pool: false, + allow_claude: false, + auth_token: String::new(), + token_file: ".token".to_string(), + token_list_file: ".token-list".to_string(), + route_prefix: String::new(), + start_time: chrono::Local::now(), + pages: Pages::default(), + } + } +} + +impl AppConfig { + pub fn init( + enable_stream_check: bool, + include_stop_stream: bool, + vision_ability: VisionAbility, + enable_slow_pool: bool, + allow_claude: bool, + auth_token: String, + token_file: String, + token_list_file: String, + route_prefix: String, + ) { + if let Ok(mut config) = APP_CONFIG.write() { + config.enable_stream_check = enable_stream_check; + config.include_stop_stream = include_stop_stream; + config.vision_ability = vision_ability; + config.enable_slow_pool = enable_slow_pool; + config.allow_claude = allow_claude; + config.auth_token = auth_token; + config.token_file = token_file; + config.token_list_file = token_list_file; + config.route_prefix = route_prefix; + } + } + + pub fn get_stream_check() -> bool { + APP_CONFIG + .read() + .map(|config| config.enable_stream_check) + .unwrap_or(true) + } + + pub fn get_stop_stream() -> bool { + APP_CONFIG + .read() + .map(|config| config.include_stop_stream) + .unwrap_or(true) + } + + pub fn get_vision_ability() -> VisionAbility { + APP_CONFIG + .read() + .map(|config| config.vision_ability.clone()) + .unwrap_or_default() + } + + pub fn get_slow_pool() -> bool { + APP_CONFIG + .read() + .map(|config| config.enable_slow_pool) + .unwrap_or(false) + } + + pub fn get_allow_claude() -> bool { + APP_CONFIG + .read() + .map(|config| config.allow_claude) + .unwrap_or(false) + } + + pub fn get_auth_token() -> String { + APP_CONFIG + .read() + .map(|config| config.auth_token.clone()) + .unwrap_or_default() + } + + pub fn get_token_file() -> String { + APP_CONFIG + .read() + .map(|config| config.token_file.clone()) + .unwrap_or_default() + } + + pub fn get_token_list_file() -> String { + APP_CONFIG + .read() + .map(|config| config.token_list_file.clone()) + .unwrap_or_default() + } + + pub fn get_route_prefix() -> String { + APP_CONFIG + .read() + .map(|config| config.route_prefix.clone()) + .unwrap_or_default() + } + + pub fn get_page_content(path: &str) -> Option { + APP_CONFIG.read().ok().map(|config| match path { + ROUTER_ROOT_PATH => config.pages.root_content.clone(), + ROUTER_LOGS_PATH => config.pages.logs_content.clone(), + ROUTER_CONFIG_PATH => config.pages.config_content.clone(), + ROUTER_TOKENINFO_PATH => config.pages.tokeninfo_content.clone(), + ROUTER_SHARED_STYLES_PATH => config.pages.shared_styles_content.clone(), + ROUTER_SHARED_JS_PATH => config.pages.shared_js_content.clone(), + _ => PageContent::Default, + }) + } + + pub fn update_stream_check(enable: bool) -> Result<(), &'static str> { + if let Ok(mut config) = APP_CONFIG.write() { + config.enable_stream_check = enable; + Ok(()) + } else { + Err("无法更新配置") + } + } + + pub fn update_stop_stream(enable: bool) -> Result<(), &'static str> { + if let Ok(mut config) = APP_CONFIG.write() { + config.include_stop_stream = enable; + Ok(()) + } else { + Err("无法更新配置") + } + } + + pub fn update_vision_ability(new_ability: VisionAbility) -> Result<(), &'static str> { + if let Ok(mut config) = APP_CONFIG.write() { + config.vision_ability = new_ability; + Ok(()) + } else { + Err("无法更新配置") + } + } + + pub fn update_slow_pool(enable: bool) -> Result<(), &'static str> { + if let Ok(mut config) = APP_CONFIG.write() { + config.enable_slow_pool = enable; + Ok(()) + } else { + Err("无法更新配置") + } + } + + pub fn update_allow_claude(enable: bool) -> Result<(), &'static str> { + if let Ok(mut config) = APP_CONFIG.write() { + config.allow_claude = enable; + Ok(()) + } else { + Err("无法更新配置") + } + } + + pub fn update_page_content(path: &str, content: PageContent) -> Result<(), &'static str> { + if let Ok(mut config) = APP_CONFIG.write() { + match path { + ROUTER_ROOT_PATH => config.pages.root_content = content, + ROUTER_LOGS_PATH => config.pages.logs_content = content, + ROUTER_CONFIG_PATH => config.pages.config_content = content, + ROUTER_TOKENINFO_PATH => config.pages.tokeninfo_content = content, + ROUTER_SHARED_STYLES_PATH => config.pages.shared_styles_content = content, + ROUTER_SHARED_JS_PATH => config.pages.shared_js_content = content, + _ => return Err("无效的路径"), + } + Ok(()) + } else { + Err("无法更新配置") + } + } + + pub fn reset_stream_check() -> Result<(), &'static str> { + if let Ok(mut config) = APP_CONFIG.write() { + config.enable_stream_check = true; + Ok(()) + } else { + Err("无法重置配置") + } + } + + pub fn reset_stop_stream() -> Result<(), &'static str> { + if let Ok(mut config) = APP_CONFIG.write() { + config.include_stop_stream = true; + Ok(()) + } else { + Err("无法重置配置") + } + } + + pub fn reset_vision_ability() -> Result<(), &'static str> { + if let Ok(mut config) = APP_CONFIG.write() { + config.vision_ability = VisionAbility::Base64; + Ok(()) + } else { + Err("无法重置配置") + } + } + + pub fn reset_slow_pool() -> Result<(), &'static str> { + if let Ok(mut config) = APP_CONFIG.write() { + config.enable_slow_pool = false; + Ok(()) + } else { + Err("无法重置配置") + } + } + + pub fn reset_allow_claude() -> Result<(), &'static str> { + if let Ok(mut config) = APP_CONFIG.write() { + config.allow_claude = false; + Ok(()) + } else { + Err("无法重置配置") + } + } + + pub fn reset_page_content(path: &str) -> Result<(), &'static str> { + if let Ok(mut config) = APP_CONFIG.write() { + match path { + ROUTER_ROOT_PATH => config.pages.root_content = PageContent::Default, + ROUTER_LOGS_PATH => config.pages.logs_content = PageContent::Default, + ROUTER_CONFIG_PATH => config.pages.config_content = PageContent::Default, + ROUTER_TOKENINFO_PATH => config.pages.tokeninfo_content = PageContent::Default, + ROUTER_SHARED_STYLES_PATH => { + config.pages.shared_styles_content = PageContent::Default + } + ROUTER_SHARED_JS_PATH => config.pages.shared_js_content = PageContent::Default, + _ => return Err("无效的路径"), + } + Ok(()) + } else { + Err("无法重置配置") + } + } +} + +impl AppState { + pub fn new(token_infos: Vec) -> Self { + Self { + total_requests: 0, + active_requests: 0, + request_logs: Vec::new(), + token_infos, + } + } + + pub fn update_token_infos(&mut self, token_infos: Vec) { + self.token_infos = token_infos; + } +} + +// 模型定义 +#[derive(Serialize, Clone)] +pub struct Model { + pub id: String, + pub created: i64, + pub object: String, + pub owned_by: String, +} + +// impl Model { +// pub fn is_pesticide(&self) -> bool { +// !(self.owned_by.as_str() == CURSOR || self.id.as_str() == "gpt-4o-mini") +// } +// } + +// 请求日志 +#[derive(Serialize, Clone)] +pub struct RequestLog { + pub timestamp: DateTime, + pub model: String, + pub token_info: TokenInfo, + #[serde(skip_serializing_if = "Option::is_none")] + pub prompt: Option, + pub stream: bool, + pub status: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub error: Option, +} + +// pub struct PromptList(Option); + +// impl PromptList { +// pub fn to_vec(&self) -> Vec<> +// } + +// 聊天请求 +#[derive(Deserialize)] +pub struct ChatRequest { + pub model: String, + pub messages: Vec, + #[serde(default)] + pub stream: bool, +} + +// 用于存储 token 信息 +#[derive(Serialize, Clone)] +pub struct TokenInfo { + pub token: String, + pub checksum: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub alias: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub usage: Option, +} + +// TokenUpdateRequest 结构体 +#[derive(Deserialize)] +pub struct TokenUpdateRequest { + pub tokens: String, + #[serde(default)] + pub token_list: Option, +} + +// 添加用于接收更新请求的结构体 +#[derive(Deserialize)] +pub struct ConfigUpdateRequest { + #[serde(default)] + pub action: String, // "get", "update", "reset" + #[serde(default)] + pub path: String, + #[serde(default)] + pub content: Option, // "default", "text", "html" + #[serde(default)] + pub enable_stream_check: Option, + #[serde(default)] + pub include_stop_stream: Option, + #[serde(default)] + pub vision_ability: Option, + #[serde(default)] + pub enable_slow_pool: Option, + #[serde(default)] + pub enable_all_claude: Option, +} diff --git a/src/app/token.rs b/src/app/token.rs new file mode 100644 index 0000000..a146fc2 --- /dev/null +++ b/src/app/token.rs @@ -0,0 +1,313 @@ +use super::{ + constant::*, + models::{AppConfig, AppState, TokenInfo, TokenUpdateRequest}, + utils::i32_to_u32, +}; +use crate::aiserver::v1::GetUserInfoResponse; +use axum::http::HeaderMap; +use axum::{ + extract::{Query, State}, + Json, +}; +use image::EncodableLayout; +use prost::Message; +use reqwest::StatusCode; +use serde::{Deserialize, Serialize}; +use std::sync::Arc; +use tokio::sync::Mutex; + +// 规范化文件内容并写入 +fn normalize_and_write(content: &str, file_path: &str) -> String { + let normalized = content.replace("\r\n", "\n"); + if normalized != content { + if let Err(e) = std::fs::write(file_path, &normalized) { + eprintln!("警告: 无法更新规范化的文件: {}", e); + } + } + normalized +} + +// 解析token和别名 +fn parse_token_alias(token_part: &str, line: &str) -> Option<(String, Option)> { + match token_part.split("::").collect::>() { + parts if parts.len() == 1 => Some((parts[0].to_string(), None)), + parts if parts.len() == 2 => Some((parts[1].to_string(), Some(parts[0].to_string()))), + _ => { + eprintln!("警告: 忽略无效的行: {}", line); + None + } + } +} + +// Token 加载函数 +pub fn load_tokens() -> Vec { + let token_file = AppConfig::get_token_file(); + let token_list_file = AppConfig::get_token_list_file(); + + // 确保文件存在 + for file in [&token_file, &token_list_file] { + if !std::path::Path::new(file).exists() { + if let Err(e) = std::fs::write(file, "") { + eprintln!("警告: 无法创建文件 '{}': {}", file, e); + } + } + } + + // 读取和规范化 token 文件 + let token_entries = match std::fs::read_to_string(&token_file) { + Ok(content) => { + let normalized = normalize_and_write(&content, &token_file); + normalized + .lines() + .filter_map(|line| { + let line = line.trim(); + if line.is_empty() || line.starts_with('#') { + return None; + } + parse_token_alias(line, line) + }) + .collect::>() + } + Err(e) => { + eprintln!("警告: 无法读取token文件 '{}': {}", token_file, e); + Vec::new() + } + }; + + // 读取和规范化 token-list 文件 + let mut token_map: std::collections::HashMap)> = + match std::fs::read_to_string(&token_list_file) { + Ok(content) => { + let normalized = normalize_and_write(&content, &token_list_file); + normalized + .lines() + .filter_map(|line| { + let line = line.trim(); + if line.is_empty() || line.starts_with('#') { + return None; + } + + let parts: Vec<&str> = line.split(',').collect(); + match parts[..] { + [token_part, checksum] => { + let (token, alias) = parse_token_alias(token_part, line)?; + Some((token, (checksum.to_string(), alias))) + } + _ => { + eprintln!("警告: 忽略无效的token-list行: {}", line); + None + } + } + }) + .collect() + } + Err(e) => { + eprintln!("警告: 无法读取token-list文件: {}", e); + std::collections::HashMap::new() + } + }; + + // 更新或添加新token + for (token, alias) in token_entries { + if let Some((_, existing_alias)) = token_map.get(&token) { + // 只在alias不同时更新已存在的token + if alias != *existing_alias { + if let Some((checksum, _)) = token_map.get(&token) { + token_map.insert(token.clone(), (checksum.clone(), alias)); + } + } + } else { + // 为新token生成checksum + let checksum = + crate::generate_checksum(&crate::generate_hash(), Some(&crate::generate_hash())); + token_map.insert(token, (checksum, alias)); + } + } + + // 更新 token-list 文件 + let token_list_content = token_map + .iter() + .map(|(token, (checksum, alias))| { + if let Some(alias) = alias { + format!("{}::{},{}", alias, token, checksum) + } else { + format!("{},{}", token, checksum) + } + }) + .collect::>() + .join("\n"); + + if let Err(e) = std::fs::write(&token_list_file, token_list_content) { + eprintln!("警告: 无法更新token-list文件: {}", e); + } + + // 转换为 TokenInfo vector + token_map + .into_iter() + .map(|(token, (checksum, alias))| TokenInfo { + token, + checksum, + alias, + usage: None, + }) + .collect() +} + +// 更新 TokenInfo 处理 +pub async fn handle_update_tokeninfo( + State(state): State>>, +) -> Json { + // 重新加载 tokens + let token_infos = load_tokens(); + + // 更新应用状态 + { + let mut state = state.lock().await; + state.token_infos = token_infos; + } + + Json(serde_json::json!({ + STATUS: STATUS_SUCCESS, + MESSAGE: "Token list has been reloaded" + })) +} + +// 获取 TokenInfo 处理 +pub async fn handle_get_tokeninfo( + State(_state): State>>, + headers: HeaderMap, +) -> Result, StatusCode> { + let auth_token = AppConfig::get_auth_token(); + let token_file = AppConfig::get_token_file(); + let token_list_file = AppConfig::get_token_list_file(); + + // 验证 AUTH_TOKEN + let auth_header = headers + .get(HEADER_NAME_AUTHORIZATION) + .and_then(|h| h.to_str().ok()) + .and_then(|h| h.strip_prefix(AUTHORIZATION_BEARER_PREFIX)) + .ok_or(StatusCode::UNAUTHORIZED)?; + + if auth_header != auth_token { + return Err(StatusCode::UNAUTHORIZED); + } + + // 读取文件内容 + let tokens = std::fs::read_to_string(&token_file).unwrap_or_else(|_| String::new()); + let token_list = std::fs::read_to_string(&token_list_file).unwrap_or_else(|_| String::new()); + + Ok(Json(serde_json::json!({ + STATUS: STATUS_SUCCESS, + "token_file": token_file, + "token_list_file": token_list_file, + "tokens": tokens, + "token_list": token_list + }))) +} + +pub async fn handle_update_tokeninfo_post( + State(state): State>>, + headers: HeaderMap, + Json(request): Json, +) -> Result, StatusCode> { + let auth_token = AppConfig::get_auth_token(); + let token_file = AppConfig::get_token_file(); + let token_list_file = AppConfig::get_token_list_file(); + + // 验证 AUTH_TOKEN + let auth_header = headers + .get(HEADER_NAME_AUTHORIZATION) + .and_then(|h| h.to_str().ok()) + .and_then(|h| h.strip_prefix(AUTHORIZATION_BEARER_PREFIX)) + .ok_or(StatusCode::UNAUTHORIZED)?; + + if auth_header != auth_token { + return Err(StatusCode::UNAUTHORIZED); + } + + // 写入 .token 文件 + std::fs::write(&token_file, &request.tokens).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + + // 如果提供了 token_list,则写入 + if let Some(token_list) = request.token_list { + std::fs::write(&token_list_file, token_list) + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + } + + // 重新加载 tokens + let token_infos = load_tokens(); + let token_infos_len = token_infos.len(); + + // 更新应用状态 + { + let mut state = state.lock().await; + state.token_infos = token_infos; + } + + Ok(Json(serde_json::json!({ + STATUS: STATUS_SUCCESS, + MESSAGE: "Token files have been updated and reloaded", + "token_file": token_file, + "token_list_file": token_list_file, + "token_count": token_infos_len + }))) +} + +#[derive(Deserialize)] +pub struct GetUserInfoQuery { + alias: String, +} + +pub async fn get_user_info( + State(state): State>>, + Query(query): Query, +) -> Json { + let (auth_token, checksum) = match { + let app_token_infos = &state.lock().await.token_infos; + app_token_infos + .iter() + .find(|token_info| token_info.alias == Some(query.alias.clone())) + .map(|token_info| (token_info.token.clone(), token_info.checksum.clone())) + } { + Some(token) => token, + None => return Json(GetUserInfo::Error("No data".to_string())), + }; + + match get_user_usage(&auth_token, &checksum).await { + Some(usage) => Json(GetUserInfo::Usage(usage)), + None => Json(GetUserInfo::Error("No data".to_string())), + } +} + +pub async fn get_user_usage(auth_token: &str, checksum: &str) -> Option { + // 构建请求客户端 + let client = super::client::build_client(auth_token, checksum, CURSOR_API2_GET_USER_INFO); + let response = client + .body(Vec::new()) + .send() + .await + .ok()? + .bytes() + .await + .ok()?; + let user_info = GetUserInfoResponse::decode(response.as_bytes()).ok()?; + + user_info.usage.map(|user_usage| UserUsageInfo { + fast_requests: i32_to_u32(user_usage.gpt4_requests), + max_fast_requests: i32_to_u32(user_usage.gpt4_max_requests), + }) +} + +#[derive(Serialize)] +pub enum GetUserInfo { + #[serde[rename = "usage"]] + Usage(UserUsageInfo), + #[serde[rename = "error"]] + Error(String), +} + +#[derive(Serialize, Clone)] +pub struct UserUsageInfo { + pub fast_requests: u32, + pub max_fast_requests: u32, +} diff --git a/src/app/utils.rs b/src/app/utils.rs new file mode 100644 index 0000000..7a3712c --- /dev/null +++ b/src/app/utils.rs @@ -0,0 +1,22 @@ +pub fn parse_bool_from_env(key: &str, default: bool) -> bool { + std::env::var(key) + .ok() + .map(|v| match v.to_lowercase().as_str() { + "true" | "1" => true, + "false" | "0" => false, + _ => default, + }) + .unwrap_or(default) +} + +pub fn parse_string_from_env(key: &str, default: &str) -> String { + std::env::var(key).unwrap_or_else(|_| default.to_string()) +} + +pub fn i32_to_u32(value: i32) -> u32 { + if value < 0 { + 0 + } else { + value as u32 + } +} diff --git a/src/chat.rs b/src/chat.rs new file mode 100644 index 0000000..2c797f3 --- /dev/null +++ b/src/chat.rs @@ -0,0 +1,2 @@ +pub mod stream; +pub mod error; diff --git a/src/chat/error.rs b/src/chat/error.rs new file mode 100644 index 0000000..0db0cd4 --- /dev/null +++ b/src/chat/error.rs @@ -0,0 +1,154 @@ +use crate::aiserver::v1::throw_error_check_request::Error as ErrorType; +use reqwest::StatusCode; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +pub struct ChatError { + pub error: ErrorBody, +} + +#[derive(Serialize, Deserialize)] +pub struct ErrorBody { + pub code: String, + pub message: String, + pub details: Vec, +} + +#[derive(Serialize, Deserialize)] +pub struct ErrorDetail { + #[serde(rename = "type")] + pub error_type: String, + pub debug: ErrorDebug, + pub value: String, +} + +#[derive(Serialize, Deserialize)] +pub struct ErrorDebug { + pub error: String, + pub details: ErrorDetails, + #[serde(rename = "isExpected")] + pub is_expected: bool, +} + +impl ErrorDebug { + pub fn is_valid(&self) -> bool { + ErrorType::from_str_name(&self.error).is_some() + } + + pub fn status_code(&self) -> u16 { + match ErrorType::from_str_name(&self.error) { + Some(error) => match error { + ErrorType::Unspecified => 500, + ErrorType::BadApiKey + | ErrorType::BadUserApiKey + | ErrorType::InvalidAuthId + | ErrorType::AuthTokenNotFound + | ErrorType::AuthTokenExpired + | ErrorType::Unauthorized => 401, + ErrorType::NotLoggedIn + | ErrorType::NotHighEnoughPermissions + | ErrorType::AgentRequiresLogin + | ErrorType::ProUserOnly + | ErrorType::TaskNoPermissions => 403, + ErrorType::NotFound + | ErrorType::UserNotFound + | ErrorType::TaskUuidNotFound + | ErrorType::AgentEngineNotFound + | ErrorType::GitgraphNotFound + | ErrorType::FileNotFound => 404, + ErrorType::FreeUserRateLimitExceeded + | ErrorType::ProUserRateLimitExceeded + | ErrorType::OpenaiRateLimitExceeded + | ErrorType::OpenaiAccountLimitExceeded + | ErrorType::GenericRateLimitExceeded + | ErrorType::Gpt4VisionPreviewRateLimit + | ErrorType::ApiKeyRateLimit => 429, + ErrorType::BadRequest + | ErrorType::BadModelName + | ErrorType::SlashEditFileTooLong + | ErrorType::FileUnsupported + | ErrorType::ClaudeImageTooLarge => 400, + _ => 500, + }, + None => 500, + } + } +} + +#[derive(Serialize, Deserialize)] +pub struct ErrorDetails { + pub title: String, + pub detail: String, + #[serde(rename = "isRetryable")] + pub is_retryable: bool, +} + +impl ChatError { + pub fn to_json(&self) -> serde_json::Value { + serde_json::to_value(self).unwrap() + } + + pub fn to_error_response(&self) -> ErrorResponse { + if self.error.details.is_empty() { + return ErrorResponse { + status: 500, + code: "ERROR_UNKNOWN".to_string(), + error: None, + }; + } + ErrorResponse { + status: self.error.details[0].debug.status_code(), + code: self.error.details[0].debug.error.clone(), + error: Some(Error { + message: self.error.details[0].debug.details.title.clone(), + details: self.error.details[0].debug.details.detail.clone(), + value: self.error.details[0].value.clone(), + }), + } + } +} + +#[derive(Serialize)] +pub struct ErrorResponse { + pub status: u16, + pub code: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub error: Option, +} + +#[derive(Serialize)] +pub struct Error { + pub message: String, + pub details: String, + pub value: String, +} + +impl ErrorResponse { + pub fn to_json(&self) -> serde_json::Value { + serde_json::to_value(self).unwrap() + } + + pub fn status_code(&self) -> StatusCode { + StatusCode::from_u16(self.status).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR) + } + + pub fn native_code(&self) -> String { + self.code.replace("_", " ").to_lowercase() + } +} + +pub enum StreamError { + ChatError(ChatError), + DataLengthLessThan5, + EmptyMessage, +} + +impl std::fmt::Display for StreamError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + StreamError::ChatError(error) => write!(f, "{}", serde_json::to_string(error).unwrap()), + StreamError::DataLengthLessThan5 => write!(f, "data length less than 5"), + StreamError::EmptyMessage => write!(f, "empty message"), + } + } +} diff --git a/src/chat/stream.rs b/src/chat/stream.rs new file mode 100644 index 0000000..218a7f2 --- /dev/null +++ b/src/chat/stream.rs @@ -0,0 +1,127 @@ +use crate::aiserver::v1::StreamChatResponse; +use flate2::read::GzDecoder; +use prost::Message; +use std::io::Read; + +use super::error::{ChatError, StreamError}; + +// 解压gzip数据 +fn decompress_gzip(data: &[u8]) -> Option> { + let mut decoder = GzDecoder::new(data); + let mut decompressed = Vec::new(); + + match decoder.read_to_end(&mut decompressed) { + Ok(_) => Some(decompressed), + Err(_) => { + // println!("gzip解压失败: {}", e); + None + } + } +} + +pub enum StreamMessage { + // 调试 + Debug(String), + // 流开始标志 b"\0\0\0\0\0" + StreamStart, + // 消息内容 + Content(Vec), + // 流结束标志 b"\x02\0\0\0\x02{}" + StreamEnd, +} + +pub fn parse_stream_data(data: &[u8]) -> Result { + if data.len() < 5 { + return Err(StreamError::DataLengthLessThan5); + } + + // 检查是否为流开始标志 + // if data == b"\0\0\0\0\0" { + // return Ok(StreamMessage::StreamStart); + // } + + // 检查是否为流结束标志 + // if data == b"\x02\0\0\0\x02{}" { + // return Ok(StreamMessage::StreamEnd); + // } + + let mut messages = Vec::new(); + let mut offset = 0; + + while offset + 5 <= data.len() { + // 获取消息类型和长度 + let msg_type = data[offset]; + let msg_len = u32::from_be_bytes([ + data[offset + 1], + data[offset + 2], + data[offset + 3], + data[offset + 4], + ]) as usize; + + // 流开始 + if msg_type == 0 && msg_len == 0 { + return Ok(StreamMessage::StreamStart); + } + + // 检查剩余数据长度是否足够 + if offset + 5 + msg_len > data.len() { + break; + } + + let msg_data = &data[offset + 5..offset + 5 + msg_len]; + + match msg_type { + // 文本消息 + 0 => { + if let Ok(response) = StreamChatResponse::decode(msg_data) { + if !response.text.is_empty() { + messages.push(response.text); + } else { + // println!("[text] StreamChatResponse: {:?}", response); + return Ok(StreamMessage::Debug( + response.filled_prompt.unwrap_or_default(), + )); + } + } + } + // gzip压缩消息 + 1 => { + if let Some(text) = decompress_gzip(msg_data) { + let response = StreamChatResponse::decode(&text[..]).unwrap_or_default(); + if !response.text.is_empty() { + messages.push(response.text); + } else { + // println!("[gzip] StreamChatResponse: {:?}", response); + return Ok(StreamMessage::Debug( + response.filled_prompt.unwrap_or_default(), + )); + } + } + } + // JSON字符串 + 2 => { + if msg_len == 2 { + return Ok(StreamMessage::StreamEnd); + } + if let Ok(text) = String::from_utf8(msg_data.to_vec()) { + // println!("JSON消息: {}", text); + if let Ok(error) = serde_json::from_str::(&text) { + return Err(StreamError::ChatError(error)); + } + // 未预计 + // messages.push(text); + } + } + // 其他类型暂不处理 + t => eprintln!("收到未知消息类型: {},请尝试联系开发者以获取支持", t), + } + + offset += 5 + msg_len; + } + + if messages.is_empty() { + Err(StreamError::EmptyMessage) + } else { + Ok(StreamMessage::Content(messages)) + } +} diff --git a/src/lib.rs b/src/lib.rs index de59635..df1ec42 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,29 +1,40 @@ use base64::{engine::general_purpose::STANDARD as BASE64, Engine as _}; -use flate2::read::GzDecoder; -use prost::Message; -use rand::{thread_rng, Rng}; +use image::guess_format; +use prost::Message as _; +use rand::Rng; use sha2::{Digest, Sha256}; -use std::io::Read; use uuid::Uuid; -pub mod proto { - include!(concat!(env!("OUT_DIR"), "/cursor.rs")); -} +mod aiserver; +use aiserver::v1::*; -use proto::{ChatMessage, ResMessage}; +pub mod message; +use message::*; -#[derive(Debug)] -pub struct ChatInput { - pub role: String, - pub content: String, -} +pub mod app; +use app::{models::*,constant::*}; -fn process_chat_inputs(inputs: Vec) -> (String, Vec) { +pub mod chat; + +async fn process_chat_inputs(inputs: Vec) -> (String, Vec) { // 收集 system 和 developer 指令 let instructions = inputs .iter() - .filter(|input| input.role == "system" || input.role == "developer") - .map(|input| input.content.clone()) + .filter(|input| input.role == Role::System) + .map(|input| match &input.content { + MessageContent::Text(text) => text.clone(), + MessageContent::Vision(contents) => contents + .iter() + .filter_map(|content| { + if content.content_type == "text" { + content.text.clone() + } else { + None + } + }) + .collect::>() + .join("\n"), + }) .collect::>() .join("\n\n"); @@ -35,19 +46,48 @@ fn process_chat_inputs(inputs: Vec) -> (String, Vec = inputs + let mut chat_inputs: Vec = inputs .into_iter() - .filter(|input| input.role == "user" || input.role == "assistant") + .filter(|input| input.role == Role::User || input.role == Role::Assistant) .collect(); // 处理空对话情况 if chat_inputs.is_empty() { return ( instructions, - vec![proto::chat_message::Message { - role: 1, // user - content: " ".to_string(), - message_id: Uuid::new_v4().to_string(), + vec![ConversationMessage { + text: " ".to_string(), + r#type: conversation_message::MessageType::Human as i32, + attached_code_chunks: vec![], + codebase_context_chunks: vec![], + commits: vec![], + pull_requests: vec![], + git_diffs: vec![], + assistant_suggested_diffs: vec![], + interpreter_results: vec![], + images: vec![], + attached_folders: vec![], + approximate_lint_errors: vec![], + bubble_id: Uuid::new_v4().to_string(), + server_bubble_id: None, + attached_folders_new: vec![], + lints: vec![], + user_responses_to_suggested_code_blocks: vec![], + relevant_files: vec![], + tool_results: vec![], + notepads: vec![], + is_capability_iteration: Some(false), + capabilities: vec![], + edit_trail_contexts: vec![], + suggested_code_blocks: vec![], + diffs_for_compressing_files: vec![], + multi_file_linter_errors: vec![], + diff_histories: vec![], + recently_viewed_files: vec![], + recent_locations_history: vec![], + is_agentic: false, + file_diff_trajectories: vec![], + conversation_summary: None, }], ); } @@ -55,13 +95,13 @@ fn process_chat_inputs(inputs: Vec) -> (String, Vec) -> (String, Vec) -> (String, Vec (text, vec![]), + MessageContent::Vision(contents) => { + let mut text_parts = Vec::new(); + let mut images = Vec::new(); + + for content in contents { + match content.content_type.as_str() { + "text" => { + if let Some(text) = content.text { + text_parts.push(text); + } + } + "image_url" => { + if let Some(image_url) = &content.image_url { + let url = image_url.url.clone(); + let result = + tokio::spawn(async move { fetch_image_data(&url).await }); + if let Ok(Ok((image_data, dimensions))) = result.await { + images.push(ImageProto { + data: image_data, + dimension: dimensions, + }); + } + } + } + _ => {} + } + } + (text_parts.join("\n"), images) + } + }; + + messages.push(ConversationMessage { + text, + r#type: if input.role == Role::User { + conversation_message::MessageType::Human as i32 + } else { + conversation_message::MessageType::Ai as i32 + }, + attached_code_chunks: vec![], + codebase_context_chunks: vec![], + commits: vec![], + pull_requests: vec![], + git_diffs: vec![], + assistant_suggested_diffs: vec![], + interpreter_results: vec![], + images, + attached_folders: vec![], + approximate_lint_errors: vec![], + bubble_id: Uuid::new_v4().to_string(), + server_bubble_id: None, + attached_folders_new: vec![], + lints: vec![], + user_responses_to_suggested_code_blocks: vec![], + relevant_files: vec![], + tool_results: vec![], + notepads: vec![], + is_capability_iteration: Some(false), + capabilities: vec![], + edit_trail_contexts: vec![], + suggested_code_blocks: vec![], + diffs_for_compressing_files: vec![], + multi_file_linter_errors: vec![], + diff_histories: vec![], + recently_viewed_files: vec![], + recent_locations_history: vec![], + is_agentic: false, + file_diff_trajectories: vec![], + conversation_summary: None, + }); + } (instructions, messages) } +async fn fetch_image_data( + url: &str, +) -> Result<(Vec, Option), Box> { + // 在进入异步操作前获取并释放锁 + let vision_ability = AppConfig::get_vision_ability(); + + match vision_ability { + VisionAbility::None => Err("图片功能已禁用".into()), + + VisionAbility::Base64 => { + if !url.starts_with("data:image/") { + return Err("仅支持 base64 编码的图片".into()); + } + process_base64_image(url) + } + + VisionAbility::All => { + if url.starts_with("data:image/") { + process_base64_image(url) + } else { + process_http_image(url).await + } + } + } +} + +// 处理 base64 编码的图片 +fn process_base64_image( + url: &str, +) -> Result<(Vec, Option), Box> { + let parts: Vec<&str> = url.split("base64,").collect(); + if parts.len() != 2 { + return Err("无效的 base64 图片格式".into()); + } + + // 检查图片格式 + let format = parts[0].to_lowercase(); + if !format.contains("png") + && !format.contains("jpeg") + && !format.contains("jpg") + && !format.contains("webp") + && !format.contains("gif") + { + return Err("不支持的图片格式,仅支持 PNG、JPEG、WEBP 和非动态 GIF".into()); + } + + let image_data = BASE64.decode(parts[1])?; + + // 检查是否为动态 GIF + if format.contains("gif") { + if let Ok(frames) = gif::DecodeOptions::new().read_info(std::io::Cursor::new(&image_data)) { + if frames.into_iter().count() > 1 { + return Err("不支持动态 GIF".into()); + } + } + } + + // 获取图片尺寸 + let dimensions = if let Ok(img) = image::load_from_memory(&image_data) { + Some(image_proto::Dimension { + width: img.width() as i32, + height: img.height() as i32, + }) + } else { + None + }; + + Ok((image_data, dimensions)) +} + +// 处理 HTTP 图片 URL +async fn process_http_image( + url: &str, +) -> Result<(Vec, Option), Box> { + let response = reqwest::get(url).await?; + let image_data = response.bytes().await?.to_vec(); + let format = guess_format(&image_data)?; + + // 检查图片格式 + match format { + image::ImageFormat::Png | image::ImageFormat::Jpeg | image::ImageFormat::WebP => { + // 这些格式都支持 + } + image::ImageFormat::Gif => { + if let Ok(frames) = + gif::DecodeOptions::new().read_info(std::io::Cursor::new(&image_data)) + { + if frames.into_iter().count() > 1 { + return Err("不支持动态 GIF".into()); + } + } + } + _ => return Err("不支持的图片格式,仅支持 PNG、JPEG、WEBP 和非动态 GIF".into()), + } + + // 获取图片尺寸 + let dimensions = if let Ok(img) = image::load_from_memory_with_format(&image_data, format) { + Some(image_proto::Dimension { + width: img.width() as i32, + height: img.height() as i32, + }) + } else { + None + }; + + Ok((image_data, dimensions)) +} + pub async fn encode_chat_message( - inputs: Vec, + inputs: Vec, model_name: &str, ) -> Result, Box> { - let (instructions, messages) = process_chat_inputs(inputs); + // 在进入异步操作前获取并释放锁 + let enable_slow_pool = { + if AppConfig::get_slow_pool() { + Some(true) + } else { + None + } + }; - let chat = ChatMessage { - messages, - instructions: Some(proto::chat_message::Instructions { - content: instructions, - }), - project_path: "/path/to/project".to_string(), - model: Some(proto::chat_message::Model { - name: model_name.to_string(), - empty: String::new(), + let (instructions, messages) = process_chat_inputs(inputs).await; + + let explicit_context = if !instructions.trim().is_empty() { + Some(ExplicitContext { + context: instructions, + repo_context: None, + }) + } else { + None + }; + + let chat = GetChatRequest { + current_file: None, + conversation: messages, + repositories: vec![], + explicit_context, + workspace_root_path: None, + code_blocks: vec![], + model_details: Some(ModelDetails { + model_name: Some(model_name.to_string()), + api_key: None, + enable_ghost_mode: None, + azure_state: None, + enable_slow_pool, + openai_api_base_url: None, }), + documentation_identifiers: vec![], request_id: Uuid::new_v4().to_string(), - summary: String::new(), + linter_errors: None, + summary: None, + summary_up_until_index: None, + allow_long_file_scan: None, + is_bash: None, conversation_id: Uuid::new_v4().to_string(), + can_handle_filenames_after_language_ids: None, + use_web: None, + quotes: vec![], + debug_info: None, + workspace_id: None, + external_links: vec![], + commit_notes: vec![], + long_context_mode: if LONG_CONTEXT_MODELS.contains(&model_name) { + Some(true) + } else { + None + }, + is_eval: None, + desired_max_tokens: None, + context_ast: None, + is_composer: None, + runnable_code_blocks: None, + should_cache: None, }; let mut encoded = Vec::new(); @@ -140,78 +400,6 @@ pub async fn encode_chat_message( Ok(hex::decode(len_prefix + &content)?) } -pub async fn decode_response(data: &[u8]) -> Result> { - match decode_proto_messages(data) { - Ok(decoded) if !decoded.is_empty() => Ok(decoded), - _ => decompress_response(data).await - } -} - -fn decode_proto_messages(data: &[u8]) -> Result> { - let hex_str = hex::encode(data); - let mut pos = 0; - let mut messages = Vec::new(); - - while pos + 10 <= hex_str.len() { - let msg_len = i64::from_str_radix(&hex_str[pos..pos + 10], 16)?; - pos += 10; - - if pos + (msg_len * 2) as usize > hex_str.len() { - break; - } - - let msg_data = &hex_str[pos..pos + (msg_len * 2) as usize]; - pos += (msg_len * 2) as usize; - - let buffer = hex::decode(msg_data)?; - let response = ResMessage::decode(&buffer[..])?; - messages.push(response.msg); - } - - Ok(messages.join("")) -} - -async fn decompress_response(data: &[u8]) -> Result> { - if data.len() <= 5 { - return Ok(String::new()); - } - - let mut decoder = GzDecoder::new(&data[5..]); - let mut text = String::new(); - - match decoder.read_to_string(&mut text) { - Ok(_) => { - if !text.contains("<|BEGIN_SYSTEM|>") { - Ok(text) - } else { - Ok(String::new()) - } - }, - Err(e) => Err(Box::new(e)) - } -} - -pub fn generate_random_id( - size: usize, - dict_type: Option<&str>, - custom_chars: Option<&str>, -) -> String { - let charset = match (dict_type, custom_chars) { - (_, Some(chars)) => chars, - (Some("alphabet"), _) => "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", - (Some("max"), _) => "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-", - _ => "0123456789", - }; - - let mut rng = thread_rng(); - (0..size) - .map(|_| { - let idx = rng.gen_range(0..charset.len()); - charset.chars().nth(idx).unwrap() - }) - .collect() -} - pub fn generate_hash() -> String { let random_bytes = rand::thread_rng().gen::<[u8; 32]>(); let mut hasher = Sha256::new(); @@ -219,7 +407,7 @@ pub fn generate_hash() -> String { hex::encode(hasher.finalize()) } -fn obfuscate_bytes(bytes: &mut Vec) { +fn obfuscate_bytes(bytes: &mut [u8]) { let mut prev: u8 = 165; for (idx, byte) in bytes.iter_mut().enumerate() { let old_value = *byte; diff --git a/src/main.rs b/src/main.rs index 1faa6e4..6544e9a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,124 +1,49 @@ use axum::{ body::Body, - extract::State, + extract::{Path, State}, http::{HeaderMap, StatusCode}, response::{IntoResponse, Response}, routing::{get, post}, Json, Router, }; use bytes::Bytes; -use chrono::{DateTime, Local, Utc}; -use futures::StreamExt; -use reqwest::Client; -use serde::{Deserialize, Serialize}; -use std::sync::{ - atomic::{AtomicUsize, Ordering}, - LazyLock, +use chrono::Local; +use cursor_api::{ + app::{ + client::build_client, + constant::*, + models::*, + token::{ + get_user_info, get_user_usage, handle_get_tokeninfo, handle_update_tokeninfo, + handle_update_tokeninfo_post, load_tokens, + }, + utils::{parse_bool_from_env, parse_string_from_env}, + }, + chat::{error::StreamError, stream::parse_stream_data}, }; -use std::{convert::Infallible, sync::Arc}; +use cursor_api::{chat::stream::StreamMessage, message::*}; +use futures::{Stream, StreamExt}; +use std::{ + convert::Infallible, + sync::{atomic::AtomicBool, Arc}, +}; +use std::{ + pin::Pin, + sync::atomic::{AtomicUsize, Ordering}, +}; +use sysinfo::{CpuRefreshKind, MemoryRefreshKind, RefreshKind, System}; use tokio::sync::Mutex; use tower_http::cors::CorsLayer; use uuid::Uuid; -struct AppConfig { - auth_token: String, - token_file: String, - token_list_file: String, - route_prefix: String, - version: String, - start_time: DateTime, -} - -static APP_CONFIG: LazyLock = LazyLock::new(|| { - // 加载环境变量 - if let Err(e) = dotenvy::dotenv() { - eprintln!("警告: 无法加载 .env 文件: {}", e); - } - - let auth_token = std::env::var("AUTH_TOKEN").unwrap_or_else(|_| "".to_string()); - if auth_token.is_empty() { - eprintln!("错误: AUTH_TOKEN 未设置"); - std::process::exit(1); - } - - AppConfig { - auth_token, - token_file: std::env::var("TOKEN_FILE").unwrap_or_else(|_| ".token".to_string()), - token_list_file: std::env::var("TOKEN_LIST_FILE") - .unwrap_or_else(|_| ".token-list".to_string()), - route_prefix: std::env::var("ROUTE_PREFIX").unwrap_or_default(), - version: env!("CARGO_PKG_VERSION").to_string(), - start_time: Local::now(), - } -}); - -struct AppState { - total_requests: u64, - active_requests: u64, - request_logs: Vec, - token_infos: Vec, -} - -// 模型定义 -#[derive(Serialize, Deserialize, Clone)] -struct Model { - id: String, - created: i64, - object: String, - owned_by: String, -} - -// 请求日志 -#[derive(Serialize, Clone)] -struct RequestLog { - timestamp: DateTime, - model: String, - checksum: String, - auth_token: String, - stream: bool, - status: String, - error: Option, -} - -// 聊天请求 -#[derive(Deserialize)] -struct ChatRequest { - model: String, - messages: Vec, - #[serde(default)] - stream: bool, -} - -// 添加用于请求的消息结构体 -#[derive(Serialize, Deserialize)] -struct Message { - role: String, - content: String, -} - // 支持的模型列表 mod models; use models::AVAILABLE_MODELS; -// 用于存储 token 信息 -struct TokenInfo { - token: String, - checksum: String, -} - -// TokenUpdateRequest 结构体 -#[derive(Deserialize)] -struct TokenUpdateRequest { - tokens: String, - #[serde(default)] - token_list: Option, -} - // 自定义错误类型 enum ChatError { ModelNotSupported(String), EmptyMessages, - StreamNotSupported(String), NoTokens, RequestFailed(String), Unauthorized, @@ -135,10 +60,6 @@ impl ChatError { "empty_messages", "Message array cannot be empty".to_string(), ), - ChatError::StreamNotSupported(model) => ( - "stream_not_supported", - format!("Streaming is not supported for model '{}'", model), - ), ChatError::NoTokens => ("no_tokens", "No available tokens".to_string()), ChatError::RequestFailed(err) => ("request_failed", format!("Request failed: {}", err)), ChatError::Unauthorized => ("unauthorized", "Invalid authorization token".to_string()), @@ -147,7 +68,7 @@ impl ChatError { serde_json::json!({ "error": { "code": code, - "message": message + MESSAGE: message } }) } @@ -155,34 +76,65 @@ impl ChatError { #[tokio::main] async fn main() { + // 设置自定义 panic hook + std::panic::set_hook(Box::new(|info| { + // std::env::set_var("RUST_BACKTRACE", "1"); + if let Some(msg) = info.payload().downcast_ref::() { + eprintln!("{}", msg); + } else if let Some(msg) = info.payload().downcast_ref::<&str>() { + eprintln!("{}", msg); + } + })); + + // 加载环境变量 + dotenvy::dotenv().ok(); + + // 初始化全局配置 + AppConfig::init( + parse_bool_from_env("ENABLE_STREAM_CHECK", true), + parse_bool_from_env("INCLUDE_STOP_REASON_STREAM", true), + VisionAbility::from_str(parse_string_from_env("VISION_ABILITY", "base64").as_str()) + .unwrap_or_default(), + parse_bool_from_env("ENABLE_SLOW_POOL", false), + parse_bool_from_env("PASS_ANY_CLAUDE", false), + std::env::var("AUTH_TOKEN").expect("AUTH_TOKEN must be set"), + parse_string_from_env("TOKEN_FILE", ".token"), + parse_string_from_env("TOKEN_LIST_FILE", ".token-list"), + parse_string_from_env("ROUTE_PREFIX", ""), + ); + // 加载 tokens let token_infos = load_tokens(); - // 初始化需要互斥访问的状态 - let state = Arc::new(Mutex::new(AppState { - total_requests: 0, - active_requests: 0, - request_logs: Vec::new(), - token_infos, - })); + // 初始化应用状态 + let state = Arc::new(Mutex::new(AppState::new(token_infos))); + + let route_prefix = AppConfig::get_route_prefix(); // 设置路由 let app = Router::new() - .route("/", get(handle_root)) - .route("/tokeninfo", get(handle_tokeninfo_page)) + .route(ROUTER_ROOT_PATH, get(handle_root)) + .route(ROUTER_HEALTH_PATH, get(handle_health)) + .route(ROUTER_TOKENINFO_PATH, get(handle_tokeninfo_page)) + .route(&format!("{}/v1/models", route_prefix), get(handle_models)) + .route(ROUTER_GET_CHECKSUM, get(handle_get_checksum)) + .route(ROUTER_GET_USER_INFO_PATH, get(get_user_info)) + .route(ROUTER_UPDATE_TOKENINFO_PATH, get(handle_update_tokeninfo)) + .route(ROUTER_GET_TOKENINFO_PATH, post(handle_get_tokeninfo)) .route( - &format!("{}/v1/models", APP_CONFIG.route_prefix), - get(handle_models), + ROUTER_UPDATE_TOKENINFO_PATH, + post(handle_update_tokeninfo_post), ) - .route("/checksum", get(handle_checksum)) - .route("/update-tokeninfo", get(handle_update_tokeninfo)) - .route("/get-tokeninfo", post(handle_get_tokeninfo)) - .route("/update-tokeninfo", post(handle_update_tokeninfo_post)) .route( - &format!("{}/v1/chat/completions", APP_CONFIG.route_prefix), + &format!("{}/v1/chat/completions", route_prefix), post(handle_chat), ) - .route("/logs", get(handle_logs)) + .route(ROUTER_LOGS_PATH, get(handle_logs)) + .route(ROUTER_LOGS_PATH, post(handle_logs_post)) + .route(ROUTER_ENV_EXAMPLE_PATH, get(handle_env_example)) + .route(ROUTER_CONFIG_PATH, get(handle_config_page)) + .route(ROUTER_CONFIG_PATH, post(handle_config_update)) + .route("/static/:path", get(handle_static)) .layer(CorsLayer::permissive()) .with_state(state); @@ -190,142 +142,112 @@ async fn main() { let port = std::env::var("PORT").unwrap_or_else(|_| "3000".to_string()); let addr = format!("0.0.0.0:{}", port); println!("服务器运行在端口 {}", port); + println!("当前版本: v{}", PKG_VERSION); + if !std::env::args().any(|arg| arg == "--no-instruction") { + println!(include_str!("../start_instruction")); + } let listener = tokio::net::TcpListener::bind(addr).await.unwrap(); axum::serve(listener, app).await.unwrap(); } -// Token 加载函数 -fn load_tokens() -> Vec { - // 读取 .token 文件并解析 - let tokens = match std::fs::read_to_string(&APP_CONFIG.token_file) { - Ok(content) => { - let normalized = content.replace("\r\n", "\n"); - // 如果内容被规范化,则更新文件 - if normalized != content { - if let Err(e) = std::fs::write(&APP_CONFIG.token_file, &normalized) { - eprintln!("警告: 无法更新规范化的token文件: {}", e); - } - } - - normalized - .lines() - .filter_map(|line| { - let line = line.trim(); - if line.is_empty() { - return None; - } - - // 处理 alias::token 格式 - match line.split("::").collect::>() { - parts if parts.len() == 1 => Some(line.to_string()), - parts if parts.len() == 2 => Some(parts[1].to_string()), - _ => { - eprintln!("警告: 忽略无效的token行: {}", line); - None - } - } - }) - .collect::>() - } - Err(e) => { - eprintln!("警告: 无法读取token文件 '{}': {}", APP_CONFIG.token_file, e); - Vec::new() - } - }; - - // 读取现有的 token-list - let mut token_map: std::collections::HashMap = - match std::fs::read_to_string(&APP_CONFIG.token_list_file) { - Ok(content) => content - .lines() - .filter_map(|line| { - let line = line.trim(); - if line.is_empty() { - return None; - } - - let parts: Vec<&str> = line.split(',').collect(); - match parts[..] { - [token, checksum] => Some((token.to_string(), checksum.to_string())), - _ => { - eprintln!("警告: 忽略无效的token-list行: {}", line); - None - } - } - }) - .collect(), - Err(e) => { - eprintln!("警告: 无法读取token-list文件: {}", e); - std::collections::HashMap::new() - } - }; - - // 为新 token 生成 checksum - for token in tokens { - if !token_map.contains_key(&token) { - let checksum = cursor_api::generate_checksum( - &cursor_api::generate_hash(), - Some(&cursor_api::generate_hash()), - ); - token_map.insert(token, checksum); - } +// 根路由处理 +async fn handle_root() -> impl IntoResponse { + match AppConfig::get_page_content(ROUTER_ROOT_PATH).unwrap_or_default() { + PageContent::Default => Response::builder() + .status(StatusCode::TEMPORARY_REDIRECT) + .header("Location", ROUTER_HEALTH_PATH) + .body(Body::empty()) + .unwrap(), + PageContent::Text(content) => Response::builder() + .header(HEADER_NAME_CONTENT_TYPE, CONTENT_TYPE_TEXT_PLAIN_WITH_UTF8) + .body(Body::from(content.clone())) + .unwrap(), + PageContent::Html(content) => Response::builder() + .header(HEADER_NAME_CONTENT_TYPE, CONTENT_TYPE_TEXT_HTML_WITH_UTF8) + .body(Body::from(content.clone())) + .unwrap(), } - - // 更新 token-list 文件 - let token_list_content = token_map - .iter() - .map(|(token, checksum)| format!("{},{}", token, checksum)) - .collect::>() - .join("\n"); - - if let Err(e) = std::fs::write(&APP_CONFIG.token_list_file, token_list_content) { - eprintln!("警告: 无法更新token-list文件: {}", e); - } - - // 转换为 TokenInfo vector - token_map - .into_iter() - .map(|(token, checksum)| TokenInfo { token, checksum }) - .collect() } -// 根路由处理 -async fn handle_root(State(state): State>>) -> Json { +async fn handle_health(State(state): State>>) -> Json { + let start_time = APP_CONFIG.read().unwrap().start_time; + let route_prefix = AppConfig::get_route_prefix(); + + // 创建系统信息实例,只监控 CPU 和内存 + let mut sys = System::new_with_specifics( + RefreshKind::nothing() + .with_memory(MemoryRefreshKind::everything()) + .with_cpu(CpuRefreshKind::everything()), + ); + + std::thread::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL); + + // 刷新 CPU 和内存信息 + sys.refresh_memory(); + sys.refresh_cpu_usage(); + + let pid = std::process::id() as usize; + let process = sys.process(pid.into()); + + // 获取内存信息 + let memory = process.map(|p| p.memory()).unwrap_or(0); + + // 获取 CPU 使用率 + let cpu_usage = sys.global_cpu_usage(); + let state = state.lock().await; - let uptime = (Local::now() - APP_CONFIG.start_time).num_seconds(); + let uptime = (Local::now() - start_time).num_seconds(); Json(serde_json::json!({ - "status": "healthy", - "version": APP_CONFIG.version, + STATUS: "healthy", + "version": PKG_VERSION, "uptime": uptime, "stats": { - "started": APP_CONFIG.start_time, + "started": start_time, "totalRequests": state.total_requests, "activeRequests": state.active_requests, - "memory": { - "heapTotal": 0, - "heapUsed": 0, - "rss": 0 + "system": { + "memory": { + "rss": memory // 物理内存使用量(字节) + }, + "cpu": { + "usage": cpu_usage // CPU 使用率(百分比) + } } }, "models": AVAILABLE_MODELS.iter().map(|m| &m.id).collect::>(), "endpoints": [ - &format!("{}/v1/chat/completions", APP_CONFIG.route_prefix), - &format!("{}/v1/models", APP_CONFIG.route_prefix), - "/checksum", - "/tokeninfo", - "/update-tokeninfo", - "/get-tokeninfo" + &format!("{}/v1/chat/completions", route_prefix), + &format!("{}/v1/models", route_prefix), + ROUTER_GET_CHECKSUM, + ROUTER_TOKENINFO_PATH, + ROUTER_UPDATE_TOKENINFO_PATH, + ROUTER_GET_TOKENINFO_PATH, + ROUTER_LOGS_PATH, + ROUTER_GET_USER_INFO_PATH, + ROUTER_ENV_EXAMPLE_PATH, + ROUTER_CONFIG_PATH, + "/static" ] })) } async fn handle_tokeninfo_page() -> impl IntoResponse { - Response::builder() - .header("Content-Type", "text/html") - .body(include_str!("../static/tokeninfo.min.html").to_string()) - .unwrap() + match AppConfig::get_page_content(ROUTER_TOKENINFO_PATH).unwrap_or_default() { + PageContent::Default => Response::builder() + .header(HEADER_NAME_CONTENT_TYPE, CONTENT_TYPE_TEXT_HTML_WITH_UTF8) + .body(include_str!("../static/tokeninfo.min.html").to_string()) + .unwrap(), + PageContent::Text(content) => Response::builder() + .header(HEADER_NAME_CONTENT_TYPE, CONTENT_TYPE_TEXT_PLAIN_WITH_UTF8) + .body(content.clone()) + .unwrap(), + PageContent::Html(content) => Response::builder() + .header(HEADER_NAME_CONTENT_TYPE, CONTENT_TYPE_TEXT_HTML_WITH_UTF8) + .body(content.clone()) + .unwrap(), + } } // 模型列表处理 @@ -336,8 +258,7 @@ async fn handle_models() -> Json { })) } -// Checksum 处理 -async fn handle_checksum() -> Json { +async fn handle_get_checksum() -> Json { let checksum = cursor_api::generate_checksum( &cursor_api::generate_hash(), Some(&cursor_api::generate_hash()), @@ -347,109 +268,57 @@ async fn handle_checksum() -> Json { })) } -// 更新 TokenInfo 处理 -async fn handle_update_tokeninfo( - State(state): State>>, -) -> Json { - // 重新加载 tokens - let token_infos = load_tokens(); - - // 更新应用状态 - { - let mut state = state.lock().await; - state.token_infos = token_infos; - } - - Json(serde_json::json!({ - "status": "success", - "message": "Token list has been reloaded" - })) -} - -// 获取 TokenInfo 处理 -async fn handle_get_tokeninfo( - State(_state): State>>, - headers: HeaderMap, -) -> Result, StatusCode> { - // 验证 AUTH_TOKEN - let auth_header = headers - .get("authorization") - .and_then(|h| h.to_str().ok()) - .and_then(|h| h.strip_prefix("Bearer ")) - .ok_or(StatusCode::UNAUTHORIZED)?; - - if auth_header != APP_CONFIG.auth_token { - return Err(StatusCode::UNAUTHORIZED); - } - - // 读取文件内容 - let tokens = std::fs::read_to_string(&APP_CONFIG.token_file).unwrap_or_else(|_| String::new()); - let token_list = - std::fs::read_to_string(&APP_CONFIG.token_list_file).unwrap_or_else(|_| String::new()); - - Ok(Json(serde_json::json!({ - "status": "success", - "token_file": APP_CONFIG.token_file, - "token_list_file": APP_CONFIG.token_list_file, - "tokens": tokens, - "token_list": token_list - }))) -} - -async fn handle_update_tokeninfo_post( - State(state): State>>, - headers: HeaderMap, - Json(request): Json, -) -> Result, StatusCode> { - // 验证 AUTH_TOKEN - let auth_header = headers - .get("authorization") - .and_then(|h| h.to_str().ok()) - .and_then(|h| h.strip_prefix("Bearer ")) - .ok_or(StatusCode::UNAUTHORIZED)?; - - if auth_header != APP_CONFIG.auth_token { - return Err(StatusCode::UNAUTHORIZED); - } - - // 写入 .token 文件 - std::fs::write(&APP_CONFIG.token_file, &request.tokens) - .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; - - // 如果提供了 token_list,则写入 - if let Some(token_list) = request.token_list { - std::fs::write(&APP_CONFIG.token_list_file, token_list) - .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; - } - - // 重新加载 tokens - let token_infos = load_tokens(); - let token_infos_len = token_infos.len(); - - // 更新应用状态 - { - let mut state = state.lock().await; - state.token_infos = token_infos; - } - - Ok(Json(serde_json::json!({ - "status": "success", - "message": "Token files have been updated and reloaded", - "token_file": APP_CONFIG.token_file, - "token_list_file": APP_CONFIG.token_list_file, - "token_count": token_infos_len - }))) -} - // 日志处理 -async fn handle_logs(State(state): State>>) -> Json { +async fn handle_logs() -> impl IntoResponse { + match AppConfig::get_page_content(ROUTER_LOGS_PATH).unwrap_or_default() { + PageContent::Default => Response::builder() + .header(HEADER_NAME_CONTENT_TYPE, CONTENT_TYPE_TEXT_HTML_WITH_UTF8) + .body(Body::from( + include_str!("../static/logs.min.html").to_string(), + )) + .unwrap(), + PageContent::Text(content) => Response::builder() + .header(HEADER_NAME_CONTENT_TYPE, CONTENT_TYPE_TEXT_PLAIN_WITH_UTF8) + .body(Body::from(content.clone())) + .unwrap(), + PageContent::Html(content) => Response::builder() + .header(HEADER_NAME_CONTENT_TYPE, CONTENT_TYPE_TEXT_HTML_WITH_UTF8) + .body(Body::from(content.clone())) + .unwrap(), + } +} + +async fn handle_logs_post( + State(state): State>>, + headers: HeaderMap, +) -> Result, StatusCode> { + let auth_token = AppConfig::get_auth_token(); + + // 验证 AUTH_TOKEN + let auth_header = headers + .get(HEADER_NAME_AUTHORIZATION) + .and_then(|h| h.to_str().ok()) + .and_then(|h| h.strip_prefix(AUTHORIZATION_BEARER_PREFIX)) + .ok_or(StatusCode::UNAUTHORIZED)?; + + if auth_header != auth_token { + return Err(StatusCode::UNAUTHORIZED); + } + let state = state.lock().await; - Json(serde_json::json!({ + Ok(Json(serde_json::json!({ "total": state.request_logs.len(), "logs": state.request_logs, - "timestamp": Utc::now(), - "status": "success" - })) + "timestamp": Local::now(), + STATUS: STATUS_SUCCESS + }))) +} + +async fn handle_env_example() -> impl IntoResponse { + Response::builder() + .header(HEADER_NAME_CONTENT_TYPE, CONTENT_TYPE_TEXT_PLAIN_WITH_UTF8) + .body(include_str!("../.env.example").to_string()) + .unwrap() } // 聊天处理函数的签名 @@ -458,11 +327,15 @@ async fn handle_chat( headers: HeaderMap, Json(request): Json, ) -> Result, (StatusCode, Json)> { + let allow_claude = AppConfig::get_allow_claude(); + // 验证模型是否支持 - if !AVAILABLE_MODELS.iter().any(|m| m.id == request.model) { + let model_supported = AVAILABLE_MODELS.iter().any(|m| m.id == request.model); + + if !(model_supported || allow_claude && request.model.starts_with("claude")) { return Err(( StatusCode::BAD_REQUEST, - Json(ChatError::ModelNotSupported(request.model.clone()).to_json()), + Json(ChatError::ModelNotSupported(request.model).to_json()), )); } @@ -476,26 +349,18 @@ async fn handle_chat( )); } - // 验证 O1 模型不支持流式输出 - if request.model.starts_with("o1") && request.stream { - return Err(( - StatusCode::BAD_REQUEST, - Json(ChatError::StreamNotSupported(request.model.clone()).to_json()), - )); - } - // 获取并处理认证令牌 let auth_token = headers - .get("authorization") + .get(axum::http::header::AUTHORIZATION) .and_then(|h| h.to_str().ok()) - .and_then(|h| h.strip_prefix("Bearer ")) + .and_then(|h| h.strip_prefix(AUTHORIZATION_BEARER_PREFIX)) .ok_or(( StatusCode::UNAUTHORIZED, Json(ChatError::Unauthorized.to_json()), ))?; // 验证 AuthToken - if auth_token != APP_CONFIG.auth_token { + if auth_token != AppConfig::get_auth_token() { return Err(( StatusCode::UNAUTHORIZED, Json(ChatError::Unauthorized.to_json()), @@ -503,7 +368,7 @@ async fn handle_chat( } // 完整的令牌处理逻辑和对应的 checksum - let (auth_token, checksum) = { + let (auth_token, checksum, alias) = { static CURRENT_KEY_INDEX: AtomicUsize = AtomicUsize::new(0); let state_guard = state.lock().await; let token_infos = &state_guard.token_infos; @@ -517,19 +382,47 @@ async fn handle_chat( let index = CURRENT_KEY_INDEX.fetch_add(1, Ordering::SeqCst) % token_infos.len(); let token_info = &token_infos[index]; - (token_info.token.clone(), token_info.checksum.clone()) + ( + token_info.token.clone(), + token_info.checksum.clone(), + token_info.alias.clone(), + ) }; // 更新请求日志 { + let state_clone = state.clone(); let mut state = state.lock().await; state.total_requests += 1; state.active_requests += 1; + + // 创建一个后台任务来获取使用情况 + let auth_token_clone = auth_token.clone(); + let checksum_clone = checksum.clone(); + + tokio::spawn(async move { + let usage = get_user_usage(&auth_token_clone, &checksum_clone).await; + let mut state = state_clone.lock().await; + // 根据时间戳找到对应的日志 + if let Some(log) = state + .request_logs + .iter_mut() + .find(|log| log.timestamp == request_time) + { + log.token_info.usage = usage; + } + }); + state.request_logs.push(RequestLog { timestamp: request_time, model: request.model.clone(), - checksum: checksum.clone(), - auth_token: auth_token.clone(), + token_info: TokenInfo { + token: auth_token.clone(), + checksum: checksum.clone(), + alias: alias.clone(), + usage: None, + }, + prompt: None, stream: request.stream, status: "pending".to_string(), error: None, @@ -540,18 +433,8 @@ async fn handle_chat( } } - // 消息转换 - let chat_inputs: Vec = request - .messages - .into_iter() - .map(|m| cursor_api::ChatInput { - role: m.role, - content: m.content, - }) - .collect(); - // 将消息转换为hex格式 - let hex_data = cursor_api::encode_chat_message(chat_inputs, &request.model) + let hex_data = cursor_api::encode_chat_message(request.messages, &request.model) .await .map_err(|_| { ( @@ -563,25 +446,8 @@ async fn handle_chat( })?; // 构建请求客户端 - let client = Client::new(); - let request_id = Uuid::new_v4().to_string(); - let response = client - .post("https://api2.cursor.sh/aiserver.v1.AiService/StreamChat") - .header("Content-Type", "application/connect+proto") - .header("Authorization", format!("Bearer {}", auth_token)) - .header("connect-accept-encoding", "gzip,br") - .header("connect-protocol-version", "1") - .header("user-agent", "connect-es/1.4.0") - .header("x-amzn-trace-id", format!("Root={}", &request_id)) - .header("x-cursor-checksum", &checksum) - .header("x-cursor-client-version", "0.42.5") - .header("x-cursor-timezone", "Asia/Shanghai") - .header("x-ghost-mode", "false") - .header("x-request-id", &request_id) - .header("Host", "api2.cursor.sh") - .body(hex_data) - .send() - .await; + let client = build_client(&auth_token, &checksum, CURSOR_API2_STREAM_CHAT); + let response = client.body(hex_data).send().await; // 处理请求结果 let response = match response { @@ -589,7 +455,7 @@ async fn handle_chat( // 更新请求日志为成功 { let mut state = state.lock().await; - state.request_logs.last_mut().unwrap().status = "success".to_string(); + state.request_logs.last_mut().unwrap().status = STATUS_SUCCESS.to_string(); } resp } @@ -598,13 +464,13 @@ async fn handle_chat( { let mut state = state.lock().await; if let Some(last_log) = state.request_logs.last_mut() { - last_log.status = "failed".to_string(); + last_log.status = STATUS_FAILED.to_string(); last_log.error = Some(e.to_string()); } } return Err(( StatusCode::INTERNAL_SERVER_ERROR, - Json(ChatError::RequestFailed(format!("Request failed: {}", e)).to_json()), + Json(ChatError::RequestFailed(e.to_string()).to_json()), )); } }; @@ -616,47 +482,219 @@ async fn handle_chat( } if request.stream { - let response_id = format!("chatcmpl-{}", Uuid::new_v4()); + let response_id = format!("chatcmpl-{}", Uuid::new_v4().simple()); + let full_text = Arc::new(Mutex::new(String::with_capacity(1024))); + let is_start = Arc::new(AtomicBool::new(true)); - let stream = response.bytes_stream().then(move |chunk| { + let stream = { + // 创建新的 stream + let mut stream = response.bytes_stream(); + + let enable_stream_check = AppConfig::get_stream_check(); + + if enable_stream_check { + // 检查第一个 chunk + match stream.next().await { + Some(first_chunk) => { + let chunk = first_chunk.map_err(|e| { + let error_message = format!("Failed to read response chunk: {}", e); + // 理论上,若程序正常,必定成功,因为前面判断过了 + ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(ChatError::RequestFailed(error_message).to_json()), + ) + })?; + + match parse_stream_data(&chunk) { + Err(StreamError::ChatError(error)) => { + let error_respone = error.to_error_response(); + // 更新请求日志为失败 + { + let mut state = state.lock().await; + if let Some(last_log) = state.request_logs.last_mut() { + last_log.status = STATUS_FAILED.to_string(); + last_log.error = Some(error_respone.native_code()); + } + } + return Err(( + error_respone.status_code(), + Json(error_respone.to_json()), + )); + } + Ok(_) | Err(_) => { + // 创建一个包含第一个 chunk 的 stream + Box::pin( + futures::stream::once(async move { Ok(chunk) }).chain(stream), + ) + as Pin< + Box< + dyn Stream> + Send, + >, + > + } + } + } + None => { + // Box::pin(stream) + // as Pin> + Send>> + // 更新请求日志为失败 + { + let mut state = state.lock().await; + if let Some(last_log) = state.request_logs.last_mut() { + last_log.status = STATUS_FAILED.to_string(); + last_log.error = Some("Empty stream response".to_string()); + } + } + return Err(( + StatusCode::INTERNAL_SERVER_ERROR, + Json( + ChatError::RequestFailed("Empty stream response".to_string()) + .to_json(), + ), + )); + } + } + } else { + Box::pin(stream) + as Pin> + Send>> + } + } + .then(move |chunk| { let response_id = response_id.clone(); let model = request.model.clone(); + let is_start = is_start.clone(); + let full_text = full_text.clone(); + let state = state.clone(); async move { let chunk = chunk.unwrap_or_default(); - let text = match cursor_api::decode_response(&chunk).await { - Ok(text) if text.is_empty() => return Ok(Bytes::from("data: [DONE]\n\n")), - Ok(text) => text, - Err(_) => return Ok(Bytes::new()), - }; + match parse_stream_data(&chunk) { + Ok(StreamMessage::Content(texts)) => { + let mut response_data = String::new(); - let data = serde_json::json!({ - "id": &response_id, - "object": "chat.completion.chunk", - "created": chrono::Utc::now().timestamp(), - "model": model, - "choices": [{ - "index": 0, - "delta": { - "content": text + for text in texts { + let mut text_guard = full_text.lock().await; + text_guard.push_str(&text); + let is_first = is_start.load(Ordering::SeqCst); + + let response = ChatResponse { + id: response_id.clone(), + object: OBJECT_CHAT_COMPLETION_CHUNK.to_string(), + created: chrono::Utc::now().timestamp(), + model: if is_first { Some(model.clone()) } else { None }, + choices: vec![Choice { + index: 0, + message: None, + delta: Some(Delta { + role: if is_first { + is_start.store(false, Ordering::SeqCst); + Some(Role::Assistant) + } else { + None + }, + content: Some(text), + }), + finish_reason: None, + }], + usage: None, + }; + + response_data.push_str(&format!( + "data: {}\n\n", + serde_json::to_string(&response).unwrap() + )); } - }] - }); - Ok::<_, Infallible>(Bytes::from(format!("data: {}\n\n", data.to_string()))) + Ok::<_, Infallible>(Bytes::from(response_data)) + } + Ok(StreamMessage::StreamStart) => { + // 发送初始响应,包含模型信息 + let response = ChatResponse { + id: response_id.clone(), + object: OBJECT_CHAT_COMPLETION_CHUNK.to_string(), + created: chrono::Utc::now().timestamp(), + model: { + is_start.store(true, Ordering::SeqCst); + Some(model.clone()) + }, + choices: vec![Choice { + index: 0, + message: None, + delta: Some(Delta { + role: Some(Role::Assistant), + content: Some(String::new()), + }), + finish_reason: None, + }], + usage: None, + }; + + Ok(Bytes::from(format!( + "data: {}\n\n", + serde_json::to_string(&response).unwrap() + ))) + } + Ok(StreamMessage::StreamEnd) => { + // 根据配置决定是否发送最后的 finish_reason + let include_finish_reason = + parse_bool_from_env("INCLUDE_STOP_FINISH_REASON_STREAM", true); + + if include_finish_reason { + let response = ChatResponse { + id: response_id.clone(), + object: OBJECT_CHAT_COMPLETION_CHUNK.to_string(), + created: chrono::Utc::now().timestamp(), + model: None, + choices: vec![Choice { + index: 0, + message: None, + delta: Some(Delta { + role: None, + content: None, + }), + finish_reason: Some(FINISH_REASON_STOP.to_string()), + }], + usage: None, + }; + Ok(Bytes::from(format!( + "data: {}\n\ndata: [DONE]\n\n", + serde_json::to_string(&response).unwrap() + ))) + } else { + Ok(Bytes::from("data: [DONE]\n\n")) + } + } + Ok(StreamMessage::Debug(debug_prompt)) => { + if let Ok(mut state) = state.try_lock() { + if let Some(last_log) = state.request_logs.last_mut() { + last_log.prompt = Some(debug_prompt.clone()); + } + } + Ok(Bytes::new()) + } + Err(StreamError::ChatError(error)) => { + eprintln!("Stream error occurred: {}", error.to_json()); + Ok(Bytes::new()) + } + Err(e) => { + eprintln!("[警告] Stream error: {}", e); + Ok(Bytes::new()) + } + } } }); Ok(Response::builder() - .header("Content-Type", "text/event-stream") .header("Cache-Control", "no-cache") .header("Connection", "keep-alive") + .header(HEADER_NAME_CONTENT_TYPE, "text/event-stream") .body(Body::from_stream(stream)) .unwrap()) } else { // 非流式响应 - let mut full_text = String::new(); + let mut full_text = String::with_capacity(1024); // 预分配合适的容量 let mut stream = response.bytes_stream(); + let mut prompt = None; while let Some(chunk) = stream.next().await { let chunk = chunk.map_err(|e| { @@ -668,43 +706,339 @@ async fn handle_chat( ), ) })?; - full_text.push_str( - &cursor_api::decode_response(&chunk) - .await - .unwrap_or_default(), - ); + + match parse_stream_data(&chunk) { + Ok(StreamMessage::Content(texts)) => { + for text in texts { + full_text.push_str(&text); + } + } + Ok(StreamMessage::Debug(debug_prompt)) => { + prompt = Some(debug_prompt); + } + Ok(StreamMessage::StreamStart) | Ok(StreamMessage::StreamEnd) => {} + Err(StreamError::ChatError(error)) => { + return Err(( + StatusCode::from_u16(error.error.details[0].debug.status_code()) + .unwrap_or(StatusCode::INTERNAL_SERVER_ERROR), + Json(error.to_json()), + )); + } + Err(_) => continue, + } } - // 处理文本 - full_text = full_text - .replace( - regex::Regex::new(r"^.*<\|END_USER\|>").unwrap().as_str(), - "", - ) - .replace(regex::Regex::new(r"^\n[a-zA-Z]?").unwrap().as_str(), "") - .trim() - .to_string(); - - let response_data = serde_json::json!({ - "id": format!("chatcmpl-{}", Uuid::new_v4()), - "object": "chat.completion", - "created": chrono::Utc::now().timestamp(), - "model": request.model, - "choices": [{ - "index": 0, - "message": { - "role": "assistant", - "content": full_text - }, - "finish_reason": "stop" - }], - "usage": { - "prompt_tokens": 0, - "completion_tokens": 0, - "total_tokens": 0 + // 检查响应是否为空 + if full_text.is_empty() { + // 更新请求日志为失败 + { + let mut state = state.lock().await; + if let Some(last_log) = state.request_logs.last_mut() { + last_log.status = STATUS_FAILED.to_string(); + last_log.error = Some("Empty response received".to_string()); + if let Some(p) = prompt { + last_log.prompt = Some(p); + } + } } - }); + return Err(( + StatusCode::INTERNAL_SERVER_ERROR, + Json(ChatError::RequestFailed("Empty response received".to_string()).to_json()), + )); + } - Ok(Response::new(Body::from(response_data.to_string()))) + // 更新请求日志提示词 + { + let mut state = state.lock().await; + if let Some(last_log) = state.request_logs.last_mut() { + last_log.prompt = prompt; + } + } + + let response_data = ChatResponse { + id: format!("chatcmpl-{}", Uuid::new_v4().simple()), + object: OBJECT_CHAT_COMPLETION.to_string(), + created: chrono::Utc::now().timestamp(), + model: Some(request.model), + choices: vec![Choice { + index: 0, + message: Some(Message { + role: Role::Assistant, + content: MessageContent::Text(full_text), + }), + delta: None, + finish_reason: Some(FINISH_REASON_STOP.to_string()), + }], + usage: Some(Usage { + prompt_tokens: 0, + completion_tokens: 0, + total_tokens: 0, + }), + }; + + Ok(Response::builder() + .header(HEADER_NAME_CONTENT_TYPE, "application/json") + .body(Body::from(serde_json::to_string(&response_data).unwrap())) + .unwrap()) + } +} + +// 配置页面处理函数 +async fn handle_config_page() -> impl IntoResponse { + match AppConfig::get_page_content(ROUTER_CONFIG_PATH).unwrap_or_default() { + PageContent::Default => Response::builder() + .header(HEADER_NAME_CONTENT_TYPE, CONTENT_TYPE_TEXT_HTML_WITH_UTF8) + .body(include_str!("../static/config.min.html").to_string()) + .unwrap(), + PageContent::Text(content) => Response::builder() + .header(HEADER_NAME_CONTENT_TYPE, CONTENT_TYPE_TEXT_PLAIN_WITH_UTF8) + .body(content.clone()) + .unwrap(), + PageContent::Html(content) => Response::builder() + .header(HEADER_NAME_CONTENT_TYPE, CONTENT_TYPE_TEXT_HTML_WITH_UTF8) + .body(content.clone()) + .unwrap(), + } +} + +// 配置更新处理函数 +async fn handle_config_update( + State(_state): State>>, + headers: HeaderMap, + Json(request): Json, +) -> Result, (StatusCode, Json)> { + // 验证 AUTH_TOKEN + let auth_token = AppConfig::get_auth_token(); + + let auth_header = headers + .get(HEADER_NAME_AUTHORIZATION) + .and_then(|h| h.to_str().ok()) + .and_then(|h| h.strip_prefix(AUTHORIZATION_BEARER_PREFIX)) + .ok_or(( + StatusCode::UNAUTHORIZED, + Json(serde_json::json!({ + "error": "未提供认证令牌" + })), + ))?; + + if auth_header != auth_token { + return Err(( + StatusCode::UNAUTHORIZED, + Json(serde_json::json!({ + "error": "无效的认证令牌" + })), + )); + } + + match request.action.as_str() { + "get" => Ok(Json(serde_json::json!({ + STATUS: STATUS_SUCCESS, + "data": { + "page_content": AppConfig::get_page_content(&request.path), + "enable_stream_check": AppConfig::get_stream_check(), + "include_stop_stream": AppConfig::get_stop_stream(), + "vision_ability": AppConfig::get_vision_ability(), + "enable_slow_pool": AppConfig::get_slow_pool(), + "enable_all_claude": AppConfig::get_allow_claude(), + } + }))), + + "update" => { + // 处理页面内容更新 + if !request.path.is_empty() && request.content.is_some() { + let content = request.content.unwrap(); + + if let Err(e) = AppConfig::update_page_content(&request.path, content) { + return Err(( + StatusCode::INTERNAL_SERVER_ERROR, + Json(serde_json::json!({ + "error": format!("更新页面内容失败: {}", e) + })), + )); + } + } + + // 处理 enable_stream_check 更新 + if let Some(enable_stream_check) = request.enable_stream_check { + if let Err(e) = AppConfig::update_stream_check(enable_stream_check) { + return Err(( + StatusCode::INTERNAL_SERVER_ERROR, + Json(serde_json::json!({ + "error": format!("更新 enable_stream_check 失败: {}", e) + })), + )); + } + } + + // 处理 include_stop_stream 更新 + if let Some(include_stop_stream) = request.include_stop_stream { + if let Err(e) = AppConfig::update_stop_stream(include_stop_stream) { + return Err(( + StatusCode::INTERNAL_SERVER_ERROR, + Json(serde_json::json!({ + "error": format!("更新 include_stop_stream 失败: {}", e) + })), + )); + } + } + + // 处理 vision_ability 更新 + if let Some(vision_ability) = request.vision_ability { + if let Err(e) = AppConfig::update_vision_ability(vision_ability) { + return Err(( + StatusCode::INTERNAL_SERVER_ERROR, + Json(serde_json::json!({ + "error": format!("更新 vision_ability 失败: {}", e) + })), + )); + } + } + + // 处理 enable_slow_pool 更新 + if let Some(enable_slow_pool) = request.enable_slow_pool { + if let Err(e) = AppConfig::update_slow_pool(enable_slow_pool) { + return Err(( + StatusCode::INTERNAL_SERVER_ERROR, + Json(serde_json::json!({ + "error": format!("更新 enable_slow_pool 失败: {}", e) + })), + )); + } + } + + // 处理 enable_all_claude 更新 + if let Some(enable_all_claude) = request.enable_all_claude { + if let Err(e) = AppConfig::update_allow_claude(enable_all_claude) { + return Err(( + StatusCode::INTERNAL_SERVER_ERROR, + Json(serde_json::json!({ + "error": format!("更新 enable_all_claude 失败: {}", e) + })), + )); + } + } + + Ok(Json(serde_json::json!({ + STATUS: STATUS_SUCCESS, + MESSAGE: "配置已更新" + }))) + } + + "reset" => { + // 重置页面内容 + if !request.path.is_empty() { + if let Err(e) = AppConfig::reset_page_content(&request.path) { + return Err(( + StatusCode::INTERNAL_SERVER_ERROR, + Json(serde_json::json!({ + "error": format!("重置页面内容失败: {}", e) + })), + )); + } + } + + // 重置 enable_stream_check + if request.enable_stream_check.is_some() { + if let Err(e) = AppConfig::reset_stream_check() { + return Err(( + StatusCode::INTERNAL_SERVER_ERROR, + Json(serde_json::json!({ + "error": format!("重置 enable_stream_check 失败: {}", e) + })), + )); + } + } + + // 重置 include_stop_stream + if request.include_stop_stream.is_some() { + if let Err(e) = AppConfig::reset_stop_stream() { + return Err(( + StatusCode::INTERNAL_SERVER_ERROR, + Json(serde_json::json!({ + "error": format!("重置 include_stop_stream 失败: {}", e) + })), + )); + } + } + + // 重置 vision_ability + if request.vision_ability.is_some() { + if let Err(e) = AppConfig::reset_vision_ability() { + return Err(( + StatusCode::INTERNAL_SERVER_ERROR, + Json(serde_json::json!({ + "error": format!("重置 vision_ability 失败: {}", e) + })), + )); + } + } + + // 重置 enable_slow_pool + if request.enable_slow_pool.is_some() { + if let Err(e) = AppConfig::reset_slow_pool() { + return Err(( + StatusCode::INTERNAL_SERVER_ERROR, + Json(serde_json::json!({ + "error": format!("重置 enable_slow_pool 失败: {}", e) + })), + )); + } + } + + // 重置 enable_all_claude + if request.enable_all_claude.is_some() { + if let Err(e) = AppConfig::reset_allow_claude() { + return Err(( + StatusCode::INTERNAL_SERVER_ERROR, + Json(serde_json::json!({ + "error": format!("重置 enable_slow_pool 失败: {}", e) + })), + )); + } + } + Ok(Json(serde_json::json!({ + STATUS: STATUS_SUCCESS, + MESSAGE: "配置已重置" + }))) + } + + _ => Err(( + StatusCode::BAD_REQUEST, + Json(serde_json::json!({ + "error": "无效的操作类型" + })), + )), + } +} + +async fn handle_static(Path(path): Path) -> impl IntoResponse { + match path.as_str() { + "shared-styles.css" => { + match AppConfig::get_page_content(ROUTER_SHARED_STYLES_PATH).unwrap_or_default() { + PageContent::Default => Response::builder() + .header(HEADER_NAME_CONTENT_TYPE, "text/css;charset=utf-8") + .body(include_str!("../static/shared-styles.min.css").to_string()) + .unwrap(), + PageContent::Text(content) | PageContent::Html(content) => Response::builder() + .header(HEADER_NAME_CONTENT_TYPE, "text/css;charset=utf-8") + .body(content.clone()) + .unwrap(), + } + } + "shared.js" => match AppConfig::get_page_content(ROUTER_SHARED_JS_PATH).unwrap_or_default() + { + PageContent::Default => Response::builder() + .header(HEADER_NAME_CONTENT_TYPE, "text/javascript;charset=utf-8") + .body(include_str!("../static/shared.min.js").to_string()) + .unwrap(), + PageContent::Text(content) | PageContent::Html(content) => Response::builder() + .header(HEADER_NAME_CONTENT_TYPE, "text/javascript;charset=utf-8") + .body(content.clone()) + .unwrap(), + }, + _ => Response::builder() + .status(StatusCode::NOT_FOUND) + .body("Not found".to_string()) + .unwrap(), } } diff --git a/src/message.rs b/src/message.rs new file mode 100644 index 0000000..2c299e6 --- /dev/null +++ b/src/message.rs @@ -0,0 +1,78 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +#[serde(untagged)] +pub enum MessageContent { + Text(String), + Vision(Vec), +} + +#[derive(Serialize, Deserialize)] +pub struct VisionMessageContent { + #[serde(rename = "type")] + pub content_type: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub text: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub image_url: Option, +} + +#[derive(Serialize, Deserialize)] +pub struct ImageUrl { + pub url: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub detail: Option, +} + +#[derive(Serialize, Deserialize)] +pub struct Message { + pub role: Role, + pub content: MessageContent, +} + +#[derive(Serialize, Deserialize, PartialEq)] +pub enum Role { + #[serde(rename = "system", alias = "developer")] + System, + #[serde(rename = "user", alias = "human")] + User, + #[serde(rename = "assistant", alias = "ai")] + Assistant, +} + +#[derive(Serialize)] +pub struct ChatResponse { + pub id: String, + pub object: String, + pub created: i64, + #[serde(skip_serializing_if = "Option::is_none")] + pub model: Option, + pub choices: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + pub usage: Option, +} + +#[derive(Serialize)] +pub struct Choice { + pub index: i32, + #[serde(skip_serializing_if = "Option::is_none")] + pub message: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub delta: Option, + pub finish_reason: Option, +} + +#[derive(Serialize)] +pub struct Delta { + #[serde(skip_serializing_if = "Option::is_none")] + pub role: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub content: Option, +} + +#[derive(Serialize)] +pub struct Usage { + pub prompt_tokens: i32, + pub completion_tokens: i32, + pub total_tokens: i32, +} diff --git a/src/models.rs b/src/models.rs index aeab6b2..d8ea513 100644 --- a/src/models.rs +++ b/src/models.rs @@ -1,133 +1,141 @@ -use std::sync::LazyLock; use crate::Model; +use std::sync::LazyLock; -const MODEL_OBJECT: &str = "model"; -const ANTHROPIC: &str = "anthropic"; -const CURSOR: &str = "cursor"; -const GOOGLE: &str = "google"; -const OPENAI: &str = "openai"; +use super::{ANTHROPIC, CURSOR, GOOGLE, MODEL_OBJECT, OPENAI}; pub static AVAILABLE_MODELS: LazyLock> = LazyLock::new(|| { vec![ Model { - id: "cursor-small".into(), + id: "claude-3.5-sonnet".into(), created: 1706659200, object: MODEL_OBJECT.into(), - owned_by: CURSOR.into() + owned_by: ANTHROPIC.into(), }, Model { - id: "claude-3-opus".into(), + id: "gpt-3.5".into(), created: 1706659200, object: MODEL_OBJECT.into(), - owned_by: ANTHROPIC.into() - }, - Model { - id: "cursor-fast".into(), - created: 1706659200, - object: MODEL_OBJECT.into(), - owned_by: CURSOR.into() - }, - Model { - id: "gpt-3.5-turbo".into(), - created: 1706659200, - object: MODEL_OBJECT.into(), - owned_by: OPENAI.into() - }, - Model { - id: "gpt-4-turbo-2024-04-09".into(), - created: 1706659200, - object: MODEL_OBJECT.into(), - owned_by: OPENAI.into() + owned_by: OPENAI.into(), }, Model { id: "gpt-4".into(), created: 1706659200, object: MODEL_OBJECT.into(), - owned_by: OPENAI.into() + owned_by: OPENAI.into(), + }, + Model { + id: "gpt-4o".into(), + created: 1706659200, + object: MODEL_OBJECT.into(), + owned_by: OPENAI.into(), + }, + Model { + id: "claude-3-opus".into(), + created: 1706659200, + object: MODEL_OBJECT.into(), + owned_by: ANTHROPIC.into(), + }, + Model { + id: "cursor-fast".into(), + created: 1706659200, + object: MODEL_OBJECT.into(), + owned_by: CURSOR.into(), + }, + Model { + id: "cursor-small".into(), + created: 1706659200, + object: MODEL_OBJECT.into(), + owned_by: CURSOR.into(), + }, + Model { + id: "gpt-3.5-turbo".into(), + created: 1706659200, + object: MODEL_OBJECT.into(), + owned_by: OPENAI.into(), + }, + Model { + id: "gpt-4-turbo-2024-04-09".into(), + created: 1706659200, + object: MODEL_OBJECT.into(), + owned_by: OPENAI.into(), }, Model { id: "gpt-4o-128k".into(), created: 1706659200, object: MODEL_OBJECT.into(), - owned_by: OPENAI.into() + owned_by: OPENAI.into(), }, Model { id: "gemini-1.5-flash-500k".into(), created: 1706659200, object: MODEL_OBJECT.into(), - owned_by: GOOGLE.into() + owned_by: GOOGLE.into(), }, Model { id: "claude-3-haiku-200k".into(), created: 1706659200, object: MODEL_OBJECT.into(), - owned_by: ANTHROPIC.into() + owned_by: ANTHROPIC.into(), }, Model { id: "claude-3-5-sonnet-200k".into(), created: 1706659200, object: MODEL_OBJECT.into(), - owned_by: ANTHROPIC.into() - }, - Model { - id: "claude-3-5-sonnet-20240620".into(), - created: 1706659200, - object: MODEL_OBJECT.into(), - owned_by: ANTHROPIC.into() + owned_by: ANTHROPIC.into(), }, Model { id: "claude-3-5-sonnet-20241022".into(), created: 1706659200, object: MODEL_OBJECT.into(), - owned_by: ANTHROPIC.into() + owned_by: ANTHROPIC.into(), }, Model { id: "gpt-4o-mini".into(), created: 1706659200, object: MODEL_OBJECT.into(), - owned_by: OPENAI.into() + owned_by: OPENAI.into(), }, Model { id: "o1-mini".into(), created: 1706659200, object: MODEL_OBJECT.into(), - owned_by: OPENAI.into() + owned_by: OPENAI.into(), }, Model { id: "o1-preview".into(), created: 1706659200, object: MODEL_OBJECT.into(), - owned_by: OPENAI.into() + owned_by: OPENAI.into(), }, Model { id: "o1".into(), created: 1706659200, object: MODEL_OBJECT.into(), - owned_by: OPENAI.into() + owned_by: OPENAI.into(), }, Model { id: "claude-3.5-haiku".into(), created: 1706659200, object: MODEL_OBJECT.into(), - owned_by: ANTHROPIC.into() + owned_by: ANTHROPIC.into(), }, Model { id: "gemini-exp-1206".into(), created: 1706659200, object: MODEL_OBJECT.into(), - owned_by: GOOGLE.into() + owned_by: GOOGLE.into(), }, Model { id: "gemini-2.0-flash-thinking-exp".into(), created: 1706659200, object: MODEL_OBJECT.into(), - owned_by: GOOGLE.into() + owned_by: GOOGLE.into(), }, Model { id: "gemini-2.0-flash-exp".into(), created: 1706659200, object: MODEL_OBJECT.into(), - owned_by: GOOGLE.into() - } + owned_by: GOOGLE.into(), + }, ] -}); \ No newline at end of file +}); diff --git a/start_instruction b/start_instruction new file mode 100644 index 0000000..cad93bf --- /dev/null +++ b/start_instruction @@ -0,0 +1,6 @@ +当前版本已稳定,若发现响应出现缺字漏字,与本程序无关。 +若发现首字慢,与本程序无关。 +若发现响应出现乱码,也与本程序无关。 +属于官方的问题,请不要像作者反馈。 +本程序拥有堪比客户端原本的速度,甚至可能更快。 +本程序的性能是非常厉害的。 \ No newline at end of file diff --git a/static/config.html b/static/config.html new file mode 100644 index 0000000..529a79e --- /dev/null +++ b/static/config.html @@ -0,0 +1,226 @@ + + + + + + + 配置管理 + + + + + + +

配置管理

+ +
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + + +
+
+ +
+ + + + + \ No newline at end of file diff --git a/static/logs.html b/static/logs.html new file mode 100644 index 0000000..8401fe5 --- /dev/null +++ b/static/logs.html @@ -0,0 +1,382 @@ + + + + + + + 请求日志查看 + + + + + + + +

请求日志查看

+ +
+
+ + +
+
+
+ +
+
+ + +
+
+
+ +
+
+
+

总请求数

+
-
+
+
+

活跃请求数

+
-
+
+
+

最后更新

+
-
+
+
+ +
+ + + + + + + + + + + + + +
时间模型Token信息Prompt流式响应状态错误信息
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/static/shared-styles.css b/static/shared-styles.css new file mode 100644 index 0000000..8e8a885 --- /dev/null +++ b/static/shared-styles.css @@ -0,0 +1,169 @@ +:root { + --primary-color: #2196F3; + --primary-dark: #1976D2; + --success-color: #4CAF50; + --error-color: #F44336; + --background-color: #F5F5F5; + --card-background: #FFFFFF; + --border-radius: 8px; + --spacing: 20px; +} + +body { + font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + max-width: 1200px; + margin: 0 auto; + padding: var(--spacing); + background: var(--background-color); + color: #333; + line-height: 1.6; +} + +.container { + background: var(--card-background); + padding: var(--spacing); + border-radius: var(--border-radius); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + margin-bottom: var(--spacing); +} + +h1, +h2, +h3 { + color: #1a1a1a; + margin-top: 0; +} + +.form-group { + margin-bottom: 15px; +} + +label { + display: block; + margin-bottom: 8px; + font-weight: 500; +} + +input[type="text"], +input[type="password"], +select, +textarea { + width: 100%; + padding: 8px 12px; + border: 1px solid #ddd; + border-radius: 4px; + font-size: 14px; + transition: border-color 0.2s; +} + +input[type="text"]:focus, +input[type="password"]:focus, +select:focus, +textarea:focus { + border-color: var(--primary-color); + outline: none; + box-shadow: 0 0 0 2px rgba(33, 150, 243, 0.1); +} + +textarea { + min-height: 150px; + font-family: monospace; + resize: vertical; +} + +.button-group { + display: flex; + gap: 10px; + margin: var(--spacing) 0; +} + +button { + background: var(--primary-color); + color: white; + padding: 8px 16px; + border: none; + border-radius: 4px; + cursor: pointer; + font-weight: 500; + transition: background-color 0.2s, transform 0.1s; +} + +button:hover { + background: var(--primary-dark); +} + +button:active { + transform: translateY(1px); +} + +button.secondary { + background: #757575; +} + +button.secondary:hover { + background: #616161; +} + +.message { + padding: 12px; + border-radius: var(--border-radius); + margin: 10px 0; +} + +.success { + background: #E8F5E9; + color: #2E7D32; + border: 1px solid #A5D6A7; +} + +.error { + background: #FFEBEE; + color: #C62828; + border: 1px solid #FFCDD2; +} + +table { + width: 100%; + border-collapse: collapse; + margin-top: var(--spacing); + background: var(--card-background); + border-radius: var(--border-radius); + overflow: hidden; +} + +th, +td { + padding: 12px; + text-align: left; + border-bottom: 1px solid #eee; +} + +th { + background: var(--primary-color); + color: white; + font-weight: 500; +} + +tr:nth-child(even) { + background: #f8f9fa; +} + +tr:hover { + background: #f1f3f4; +} + +/* 响应式设计 */ +@media (max-width: 768px) { + body { + padding: 10px; + } + + .button-group { + flex-direction: column; + } + + table { + display: block; + overflow-x: auto; + } +} \ No newline at end of file diff --git a/static/shared.js b/static/shared.js new file mode 100644 index 0000000..144771b --- /dev/null +++ b/static/shared.js @@ -0,0 +1,252 @@ +// Token 管理功能 +function saveAuthToken(token) { + const expiryTime = new Date().getTime() + (24 * 60 * 60 * 1000); // 24小时后过期 + localStorage.setItem('authToken', token); + localStorage.setItem('authTokenExpiry', expiryTime); +} + +function getAuthToken() { + const token = localStorage.getItem('authToken'); + const expiry = localStorage.getItem('authTokenExpiry'); + + if (!token || !expiry) { + return null; + } + + if (new Date().getTime() > parseInt(expiry)) { + localStorage.removeItem('authToken'); + localStorage.removeItem('authTokenExpiry'); + return null; + } + + return token; +} + +// 消息显示功能 +function showMessage(elementId, text, isError = false) { + const msg = document.getElementById(elementId); + msg.className = `message ${isError ? 'error' : 'success'}`; + msg.textContent = text; +} + +function showGlobalMessage(text, isError = false) { + showMessage('message', text, isError); +} + +// Token 输入框自动填充和事件绑定 +function initializeTokenHandling(inputId) { + document.addEventListener('DOMContentLoaded', () => { + const authToken = getAuthToken(); + if (authToken) { + document.getElementById(inputId).value = authToken; + } + }); + + document.getElementById(inputId).addEventListener('change', (e) => { + if (e.target.value) { + saveAuthToken(e.target.value); + } else { + localStorage.removeItem('authToken'); + localStorage.removeItem('authTokenExpiry'); + } + }); +} + +// API 请求通用处理 +async function makeAuthenticatedRequest(url, options = {}) { + const tokenId = options.tokenId || 'authToken'; + const token = document.getElementById(tokenId).value; + + if (!token) { + showGlobalMessage('请输入 AUTH_TOKEN', true); + return null; + } + + const defaultOptions = { + method: 'POST', + headers: { + 'Authorization': `Bearer ${token}`, + 'Content-Type': 'application/json' + } + }; + + try { + const response = await fetch(url, { ...defaultOptions, ...options }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + return await response.json(); + } catch (error) { + showGlobalMessage(`请求失败: ${error.message}`, true); + return null; + } +} + +/** + * 从字符串解析布尔值 + * @param {string} str - 要解析的字符串 + * @param {boolean|null} defaultValue - 解析失败时的默认值 + * @returns {boolean|null} 解析结果,如果无法解析则返回默认值 + */ +function parseBooleanFromString(str, defaultValue = null) { + if (typeof str !== 'string') { + return defaultValue; + } + + const lowercaseStr = str.toLowerCase().trim(); + + if (lowercaseStr === 'true' || lowercaseStr === '1') { + return true; + } else if (lowercaseStr === 'false' || lowercaseStr === '0') { + return false; + } else { + return defaultValue; + } +} + +/** + * 将布尔值转换为字符串 + * @param {boolean|undefined|null} value - 要转换的布尔值 + * @param {string} defaultValue - 转换失败时的默认值 + * @returns {string} 转换结果,如果输入无效则返回默认值 + */ +function parseStringFromBoolean(value, defaultValue = null) { + if (typeof value !== 'boolean') { + return defaultValue; + } + + return value ? 'true' : 'false'; +} + +/** + * 解析对话内容 + * @param {string} promptStr - 原始prompt字符串 + * @returns {Array<{role: string, content: string}>} 解析后的对话数组 + */ +function parsePrompt(promptStr) { + if (!promptStr) return []; + + const messages = []; + const lines = promptStr.split('\n'); + let currentRole = ''; + let currentContent = ''; + + const roleMap = { + 'BEGIN_SYSTEM': 'system', + 'BEGIN_USER': 'user', + 'BEGIN_ASSISTANT': 'assistant' + }; + + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + + // 检查是否是角色标记行 + let foundRole = false; + for (const [marker, role] of Object.entries(roleMap)) { + if (line.includes(marker)) { + // 保存之前的消息(如果有) + if (currentRole && currentContent.trim()) { + messages.push({ + role: currentRole, + content: currentContent.trim() + }); + } + // 设置新角色 + currentRole = role; + currentContent = ''; + foundRole = true; + break; + } + } + + // 如果不是角色标记行且不是END标记行,则添加到当前内容 + if (!foundRole && !line.includes('END_')) { + currentContent += line + '\n'; + } + } + + // 添加最后一条消息 + if (currentRole && currentContent.trim()) { + messages.push({ + role: currentRole, + content: currentContent.trim() + }); + } + + return messages; +} + +/** + * 格式化对话内容为HTML表格 + * @param {Array<{role: string, content: string}>} messages - 对话消息数组 + * @returns {string} HTML表格字符串 + */ +function formatPromptToTable(messages) { + if (!messages || messages.length === 0) { + return '

无对话内容

'; + } + + const roleLabels = { + 'system': '系统', + 'user': '用户', + 'assistant': '助手' + }; + + function escapeHtml(content) { + // 先转义HTML特殊字符 + const escaped = content + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, '''); + + // 将HTML标签文本用引号包裹,使其更易读 + // return escaped.replace(/<(\/?[^>]+)>/g, '"<$1>"'); + return escaped; + } + + return ` + + + + + + + + + ${messages.map(msg => ` + + + + + `).join('')} + +
角色内容
${roleLabels[msg.role] || msg.role}${escapeHtml(msg.content).replace(/\n/g, '
')}
+ `; +} + +/** + * 安全地显示prompt对话框 + * @param {string} promptStr - 原始prompt字符串 + */ +function showPromptModal(promptStr) { + try { + const modal = document.getElementById('promptModal'); + const content = document.getElementById('promptContent'); + + if (!modal || !content) { + console.error('Modal elements not found'); + return; + } + + const messages = parsePrompt(promptStr); + content.innerHTML = formatPromptToTable(messages); + modal.style.display = 'block'; + } catch (e) { + console.error('显示prompt对话框失败:', e); + console.error('原始prompt:', promptStr); + } +} \ No newline at end of file diff --git a/static/tokeninfo.html b/static/tokeninfo.html index 5bdaf72..0dd5b26 100644 --- a/static/tokeninfo.html +++ b/static/tokeninfo.html @@ -5,70 +5,36 @@ Token 信息管理 + + + @@ -77,97 +43,70 @@

Token 信息管理

-

认证

- +
+ + +
-
-

Token 配置

-
- - +
+
+

Token 配置

+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ 快捷键: Ctrl + S 保存更改 +
- -

Token 文件内容

- - -

Token List 文件内容

-