Compare commits
24
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80b91cbf76 | ||
|
|
da76fcb326 | ||
|
|
6d476d6ccc | ||
|
|
a8dc3ebddb | ||
|
|
5ddcf40fc1 | ||
|
|
fd7cbd5f4f | ||
|
|
4d576de9dd | ||
|
|
f707a2430d | ||
|
|
2af8f5ae6e | ||
|
|
189856ff9b | ||
|
|
62873a34bb | ||
|
|
0b0cc69635 | ||
|
|
a9c986086b | ||
|
|
34ee143caa | ||
|
|
c1ba5f0f6a | ||
|
|
d7e32623cd | ||
|
|
0abb8e7ece | ||
|
|
cfdc33ec83 | ||
|
|
4fb182ac30 | ||
|
|
bc4fa113de | ||
|
|
daf1998ac0 | ||
|
|
31ba631b76 | ||
|
|
9a34ee7dbe | ||
|
|
1f1f1a8e3e |
@@ -31,7 +31,7 @@
|
|||||||
]
|
]
|
||||||
&& blas.meta.available,
|
&& blas.meta.available,
|
||||||
useCuda ? config.cudaSupport,
|
useCuda ? config.cudaSupport,
|
||||||
useMetalKit ? stdenv.hostPlatform.isAarch64 && stdenv.hostPlatform.isDarwin,
|
useMetalKit ? stdenv.isAarch64 && stdenv.isDarwin,
|
||||||
# Increases the runtime closure size by ~700M
|
# Increases the runtime closure size by ~700M
|
||||||
useMpi ? false,
|
useMpi ? false,
|
||||||
useRocm ? config.rocmSupport,
|
useRocm ? config.rocmSupport,
|
||||||
@@ -92,7 +92,7 @@ let
|
|||||||
|
|
||||||
cudaBuildInputs = with cudaPackages; [
|
cudaBuildInputs = with cudaPackages; [
|
||||||
cuda_cudart
|
cuda_cudart
|
||||||
cccl # <nv/target>
|
cuda_cccl # <nv/target>
|
||||||
libcublas
|
libcublas
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -166,7 +166,7 @@ effectiveStdenv.mkDerivation (finalAttrs: {
|
|||||||
# `xcrun` is used find the path of the Metal compiler, which is varible
|
# `xcrun` is used find the path of the Metal compiler, which is varible
|
||||||
# and not on $PATH
|
# and not on $PATH
|
||||||
# see https://github.com/ggml-org/llama.cpp/pull/6118 for discussion
|
# see https://github.com/ggml-org/llama.cpp/pull/6118 for discussion
|
||||||
__noChroot = effectiveStdenv.hostPlatform.isDarwin && useMetalKit && precompileMetalShaders;
|
__noChroot = effectiveStdenv.isDarwin && useMetalKit && precompileMetalShaders;
|
||||||
|
|
||||||
nativeBuildInputs =
|
nativeBuildInputs =
|
||||||
[
|
[
|
||||||
@@ -181,10 +181,10 @@ effectiveStdenv.mkDerivation (finalAttrs: {
|
|||||||
autoAddDriverRunpath
|
autoAddDriverRunpath
|
||||||
]
|
]
|
||||||
++ optionals (effectiveStdenv.hostPlatform.isGnu && enableStatic) [ glibc.static ]
|
++ optionals (effectiveStdenv.hostPlatform.isGnu && enableStatic) [ glibc.static ]
|
||||||
++ optionals (effectiveStdenv.hostPlatform.isDarwin && useMetalKit && precompileMetalShaders) [ xcrunHost ];
|
++ optionals (effectiveStdenv.isDarwin && useMetalKit && precompileMetalShaders) [ xcrunHost ];
|
||||||
|
|
||||||
buildInputs =
|
buildInputs =
|
||||||
optionals effectiveStdenv.hostPlatform.isDarwin darwinBuildInputs
|
optionals effectiveStdenv.isDarwin darwinBuildInputs
|
||||||
++ optionals useCuda cudaBuildInputs
|
++ optionals useCuda cudaBuildInputs
|
||||||
++ optionals useMpi [ mpi ]
|
++ optionals useMpi [ mpi ]
|
||||||
++ optionals useRocm rocmBuildInputs
|
++ optionals useRocm rocmBuildInputs
|
||||||
@@ -245,7 +245,7 @@ effectiveStdenv.mkDerivation (finalAttrs: {
|
|||||||
|
|
||||||
# Configurations that are known to result in build failures. Can be
|
# Configurations that are known to result in build failures. Can be
|
||||||
# overridden by importing Nixpkgs with `allowBroken = true`.
|
# overridden by importing Nixpkgs with `allowBroken = true`.
|
||||||
broken = (useMetalKit && !effectiveStdenv.hostPlatform.isDarwin);
|
broken = (useMetalKit && !effectiveStdenv.isDarwin);
|
||||||
|
|
||||||
description = "Inference of LLaMA model in pure C/C++${descriptionSuffix}";
|
description = "Inference of LLaMA model in pure C/C++${descriptionSuffix}";
|
||||||
homepage = "https://github.com/ggml-org/llama.cpp/";
|
homepage = "https://github.com/ggml-org/llama.cpp/";
|
||||||
|
|||||||
+10
-13
@@ -1,18 +1,18 @@
|
|||||||
ARG OPENVINO_VERSION_MAJOR=2026.3.1
|
ARG OPENVINO_VERSION_MAJOR=2026.2.1
|
||||||
ARG OPENVINO_VERSION_FULL=2026.3.1.22476.56d9685302d
|
ARG OPENVINO_VERSION_FULL=2026.2.1.21919.ede283a88e3
|
||||||
ARG UBUNTU_VERSION=24.04
|
ARG UBUNTU_VERSION=24.04
|
||||||
|
|
||||||
# Intel GPU driver versions. https://github.com/intel/compute-runtime/releases
|
# Intel GPU driver versions. https://github.com/intel/compute-runtime/releases
|
||||||
ARG IGC_VERSION=v2.40.13
|
ARG IGC_VERSION=v2.36.3
|
||||||
ARG IGC_VERSION_FULL=2_2.40.13+22418
|
ARG IGC_VERSION_FULL=2_2.36.3+21719
|
||||||
ARG COMPUTE_RUNTIME_VERSION=26.31.39395.13
|
ARG COMPUTE_RUNTIME_VERSION=26.22.38646.4
|
||||||
ARG COMPUTE_RUNTIME_VERSION_FULL=26.31.39395.13-0
|
ARG COMPUTE_RUNTIME_VERSION_FULL=26.22.38646.4-0
|
||||||
ARG IGDGMM_VERSION=22.10.0
|
ARG IGDGMM_VERSION=22.10.0
|
||||||
|
|
||||||
# Intel NPU driver versions. https://github.com/intel/linux-npu-driver/releases
|
# Intel NPU driver versions. https://github.com/intel/linux-npu-driver/releases
|
||||||
ARG NPU_DRIVER_VERSION=v1.35.0
|
ARG NPU_DRIVER_VERSION=v1.33.0
|
||||||
ARG NPU_DRIVER_FULL=v1.35.0.20260722-29947505341
|
ARG NPU_DRIVER_FULL=v1.33.0.20260529-26625960453
|
||||||
ARG LIBZE1_VERSION=1.28.2-1~24.04~ppa1
|
ARG LIBZE1_VERSION=1.27.0-1~24.04~ppa2
|
||||||
|
|
||||||
# Optional proxy build arguments
|
# Optional proxy build arguments
|
||||||
ARG http_proxy=
|
ARG http_proxy=
|
||||||
@@ -90,9 +90,6 @@ RUN bash -c "source ${OpenVINO_DIR}/setupvars.sh && \
|
|||||||
cmake -B build/ReleaseOV -G Ninja \
|
cmake -B build/ReleaseOV -G Ninja \
|
||||||
-DCMAKE_BUILD_TYPE=Release \
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
-DLLAMA_BUILD_TESTS=OFF \
|
-DLLAMA_BUILD_TESTS=OFF \
|
||||||
-DGGML_NATIVE=OFF \
|
|
||||||
-DGGML_BACKEND_DL=ON \
|
|
||||||
-DGGML_CPU_ALL_VARIANTS=ON \
|
|
||||||
-DGGML_OPENVINO=ON && \
|
-DGGML_OPENVINO=ON && \
|
||||||
cmake --build build/ReleaseOV --parallel "
|
cmake --build build/ReleaseOV --parallel "
|
||||||
|
|
||||||
@@ -173,7 +170,7 @@ RUN --mount=type=cache,target=/var/cache/intel-npu,sharing=locked \
|
|||||||
fi; \
|
fi; \
|
||||||
DEB=/var/cache/intel-npu/libze1_${LIBZE1_VERSION}_amd64.deb; \
|
DEB=/var/cache/intel-npu/libze1_${LIBZE1_VERSION}_amd64.deb; \
|
||||||
if [ ! -f "$DEB" ]; then \
|
if [ ! -f "$DEB" ]; then \
|
||||||
wget -q -O "$DEB" https://snapshot.ppa.launchpadcontent.net/kobuk-team/intel-graphics/ubuntu/20260606T100000Z/pool/main/l/level-zero-loader/libze1_${LIBZE1_VERSION}_amd64.deb; \
|
wget -q -O "$DEB" https://snapshot.ppa.launchpadcontent.net/kobuk-team/intel-graphics/ubuntu/20260324T100000Z/pool/main/l/level-zero-loader/libze1_${LIBZE1_VERSION}_amd64.deb; \
|
||||||
fi; \
|
fi; \
|
||||||
mkdir /tmp/npu/ && cd /tmp/npu/ && tar -xf "$TGZ" && cp "$DEB" .; \
|
mkdir /tmp/npu/ && cd /tmp/npu/ && tar -xf "$TGZ" && cp "$DEB" .; \
|
||||||
apt-get update; \
|
apt-get update; \
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ COPY --from=web /app/tools/ui/dist tools/ui/dist
|
|||||||
RUN HIPCXX="$(hipconfig -l)/clang" HIP_PATH="$(hipconfig -R)" \
|
RUN HIPCXX="$(hipconfig -l)/clang" HIP_PATH="$(hipconfig -R)" \
|
||||||
cmake -S . -B build \
|
cmake -S . -B build \
|
||||||
-DGGML_HIP=ON \
|
-DGGML_HIP=ON \
|
||||||
|
-DGGML_HIP_ROCWMMA_FATTN=ON \
|
||||||
-DAMDGPU_TARGETS="$ROCM_DOCKER_ARCH" \
|
-DAMDGPU_TARGETS="$ROCM_DOCKER_ARCH" \
|
||||||
-DGGML_BACKEND_DL=ON -DGGML_CPU_ALL_VARIANTS=ON \
|
-DGGML_BACKEND_DL=ON -DGGML_CPU_ALL_VARIANTS=ON \
|
||||||
-DCMAKE_BUILD_TYPE=Release -DLLAMA_BUILD_TESTS=OFF \
|
-DCMAKE_BUILD_TYPE=Release -DLLAMA_BUILD_TESTS=OFF \
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
blank_issues_enabled: false
|
blank_issues_enabled: true
|
||||||
contact_links:
|
contact_links:
|
||||||
- name: Got an idea?
|
- name: Got an idea?
|
||||||
url: https://github.com/ggml-org/llama.cpp/discussions/categories/ideas
|
url: https://github.com/ggml-org/llama.cpp/discussions/categories/ideas
|
||||||
|
|||||||
@@ -1,95 +0,0 @@
|
|||||||
name: "ccache-buckets"
|
|
||||||
description: "Save/restore latest GitHub Actions ccache matching a key prefix to/from HF buckets"
|
|
||||||
inputs:
|
|
||||||
key:
|
|
||||||
description: "Cache key prefix to match and load"
|
|
||||||
required: true
|
|
||||||
folder:
|
|
||||||
description: "Bucket folder containing ccache files"
|
|
||||||
required: true
|
|
||||||
evict-old-files:
|
|
||||||
description: "Corresponds to the ccache --evict-older-than AGE option, where AGE is the number of seconds or days followed by the 's' or 'd' suffix respectively."
|
|
||||||
default: ''
|
|
||||||
save:
|
|
||||||
description: "Save ccache"
|
|
||||||
required: false
|
|
||||||
default: false
|
|
||||||
type: boolean
|
|
||||||
hf_bucket:
|
|
||||||
description: 'Hugging Face buckets path'
|
|
||||||
required: true
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: "composite"
|
|
||||||
steps:
|
|
||||||
- name: Install Hugging Face Hub CLI
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
python3 -m venv .venv-hf
|
|
||||||
.venv-hf/bin/pip install -U huggingface_hub==1.28.0
|
|
||||||
|
|
||||||
- name: Restore ccache from buckets
|
|
||||||
if: ${{ inputs.save != 'true' }}
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
set +e -uo pipefail
|
|
||||||
source .venv-hf/bin/activate
|
|
||||||
CCACHE_DIR=$(ccache -k cache_dir)
|
|
||||||
if [[ -d "$CCACHE_DIR" ]]; then
|
|
||||||
CACHE_PATH=$(hf buckets list "hf://buckets/${{ inputs.hf_bucket }}/${{ inputs.folder }}" --json | jq -r '[.[] | select(.type == "file") | select(.path | startswith("${{ inputs.folder }}/${{ inputs.key }}") and endswith(".tar.gz"))] | sort_by(.path) | last | .path // ""')
|
|
||||||
if [[ -n "$CACHE_PATH" ]]; then
|
|
||||||
echo "Restoring ccache from '$CACHE_PATH'."
|
|
||||||
hf buckets cp "hf://buckets/${{ inputs.hf_bucket }}/$CACHE_PATH" ccache_bucket.tar.gz
|
|
||||||
mkdir -p ccache_bucket
|
|
||||||
if tar -xzf ccache_bucket.tar.gz -C ccache_bucket; then
|
|
||||||
rm -rf "$CCACHE_DIR"
|
|
||||||
mv ccache_bucket "$CCACHE_DIR"
|
|
||||||
ccache -z
|
|
||||||
fi
|
|
||||||
rm ccache_bucket.tar.gz
|
|
||||||
else
|
|
||||||
echo "No ccache found."
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "'$CCACHE_DIR' not found."
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Save ccache to buckets
|
|
||||||
if: ${{ inputs.save == 'true' }}
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
if [[ -n "$HF_TOKEN" ]]; then
|
|
||||||
set +e -uo pipefail
|
|
||||||
source .venv-hf/bin/activate
|
|
||||||
CCACHE_DIR=$(ccache -k cache_dir)
|
|
||||||
if [[ -d "$CCACHE_DIR" ]]; then
|
|
||||||
ccache -s
|
|
||||||
if [[ -n "${{ inputs.evict-old-files }}" ]]; then
|
|
||||||
ccache --evict-older-than "${{ inputs.evict-old-files }}"
|
|
||||||
fi
|
|
||||||
DATESTAMP=$(date -u +'%Y-%m-%dT%H:%M:%SZ')
|
|
||||||
CACHEFILE="${{ inputs.key }}-$DATESTAMP.tar.gz"
|
|
||||||
if tar -czf ccache_bucket.tar.gz -C "$CCACHE_DIR" .; then
|
|
||||||
hf buckets cp ccache_bucket.tar.gz "hf://buckets/${{ inputs.hf_bucket }}/${{ inputs.folder }}/$CACHEFILE"
|
|
||||||
fi
|
|
||||||
rm ccache_bucket.tar.gz
|
|
||||||
else
|
|
||||||
echo "'$CCACHE_DIR' not found."
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Remove old ccache files from buckets
|
|
||||||
if: ${{ inputs.save == 'true' }}
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
if [[ -n "$HF_TOKEN" ]]; then
|
|
||||||
set +e -uo pipefail
|
|
||||||
source .venv-hf/bin/activate
|
|
||||||
CACHE_FILES=$(hf buckets list "hf://buckets/${{ inputs.hf_bucket }}/${{ inputs.folder }}" --json | jq -r '[.[] | select(.type == "file") | select((.uploaded_at | .[:19]+"Z" | fromdateiso8601) < (now - 5 * 60)) | select(.path | startswith("${{ inputs.folder }}/${{ inputs.key }}") and endswith(".tar.gz"))] | sort_by(.path)[:-1] | .[] | [.path // ""] | @tsv')
|
|
||||||
if [[ -n "$CACHE_FILES" ]]; then
|
|
||||||
echo "Removing old ccache files..."
|
|
||||||
while IFS=$'\t' read -r CACHE_PATH; do
|
|
||||||
hf buckets rm "hf://buckets/${{ inputs.hf_bucket }}/$CACHE_PATH" -y
|
|
||||||
done <<< "$CACHE_FILES"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
@@ -1,50 +1,22 @@
|
|||||||
# note: place this as the last step of the job, so the new cache is saved by "Post ccache" right after the old one is cleared
|
|
||||||
name: "ccache-clear"
|
name: "ccache-clear"
|
||||||
description: "Delete GitHub Actions caches matching a key prefix, oldest first"
|
description: "Delete all GitHub Actions caches matching a key prefix"
|
||||||
inputs:
|
inputs:
|
||||||
key:
|
key:
|
||||||
description: "Cache key prefix to match and delete"
|
description: "Cache key prefix to match and delete"
|
||||||
required: true
|
required: true
|
||||||
older:
|
|
||||||
description: "Only delete caches created more than this long ago (e.g. 90m, 1h, 1d). By default all matching caches are deleted"
|
|
||||||
required: false
|
|
||||||
default: ""
|
|
||||||
min:
|
|
||||||
description: "Stop deleting if fewer than this many caches would remain (e.g. 1). By default there is no minimum"
|
|
||||||
required: false
|
|
||||||
default: "0"
|
|
||||||
dry-run:
|
|
||||||
description: "Only print the caches that would be deleted, without deleting them"
|
|
||||||
required: false
|
|
||||||
default: "false"
|
|
||||||
|
|
||||||
runs:
|
runs:
|
||||||
using: "composite"
|
using: "composite"
|
||||||
steps:
|
steps:
|
||||||
- name: Install GitHub CLI if missing
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
# e.g. in container jobs, where it is not preinstalled
|
|
||||||
if ! command -v gh >/dev/null 2>&1; then
|
|
||||||
echo "GitHub CLI not found, installing..."
|
|
||||||
if ! command -v curl >/dev/null 2>&1; then
|
|
||||||
apt-get update >/dev/null 2>&1 || true
|
|
||||||
apt-get install -y curl >/dev/null 2>&1 || true
|
|
||||||
fi
|
|
||||||
mkdir -p -m 755 /etc/apt/keyrings
|
|
||||||
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | tee /etc/apt/keyrings/githubcli-archive-keyring.gpg >/dev/null
|
|
||||||
chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg
|
|
||||||
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" > /etc/apt/sources.list.d/github-cli.list
|
|
||||||
apt-get update >/dev/null 2>&1 || true
|
|
||||||
apt-get install -y gh || { echo "Failed to install GitHub CLI (gh)" >&2; exit 1; }
|
|
||||||
fi
|
|
||||||
command -v gh >/dev/null 2>&1 || { echo "GitHub CLI (gh) is required but could not be installed" >&2; exit 1; }
|
|
||||||
|
|
||||||
- name: Clear caches
|
- name: Clear caches
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
bash scripts/ccache-clear.sh \
|
CACHES=$(gh cache list --key "ccache-${{ inputs.key }}" --json id,key --jq '.[] | "\(.id) \(.key)"' 2>/dev/null)
|
||||||
--key "${{ inputs.key }}" \
|
if [ -z "$CACHES" ]; then
|
||||||
--older "${{ inputs.older }}" \
|
echo "No caches found with key prefix: ${{ inputs.key }}"
|
||||||
--min "${{ inputs.min }}" \
|
exit 0
|
||||||
${{ inputs.dry-run == 'true' && '--dry-run' || '' }}
|
fi
|
||||||
|
while read -r id key; do
|
||||||
|
echo "Deleting cache: $id ($key)"
|
||||||
|
gh cache delete "$id"
|
||||||
|
done <<< "$CACHES"
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
name: "Linux - Setup Vulkan SDK"
|
||||||
|
description: "Setup Vulkan SDK for Linux"
|
||||||
|
inputs:
|
||||||
|
path:
|
||||||
|
description: "Installation path"
|
||||||
|
required: true
|
||||||
|
version:
|
||||||
|
description: "Vulkan SDK version"
|
||||||
|
required: true
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: "composite"
|
||||||
|
steps:
|
||||||
|
- name: Setup Vulkan SDK
|
||||||
|
id: setup
|
||||||
|
uses: ./.github/actions/unarchive-tar
|
||||||
|
with:
|
||||||
|
url: https://sdk.lunarg.com/sdk/download/${{ inputs.version }}/linux/vulkan_sdk.tar.xz
|
||||||
|
path: ${{ inputs.path }}
|
||||||
|
strip: 1
|
||||||
@@ -4,9 +4,6 @@ inputs:
|
|||||||
cuda_version:
|
cuda_version:
|
||||||
description: "CUDA toolkit version"
|
description: "CUDA toolkit version"
|
||||||
required: true
|
required: true
|
||||||
cuda_arch:
|
|
||||||
description: "CUDA target architecture"
|
|
||||||
required: true
|
|
||||||
|
|
||||||
runs:
|
runs:
|
||||||
using: "composite"
|
using: "composite"
|
||||||
@@ -130,26 +127,3 @@ runs:
|
|||||||
echo "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.3\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
echo "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.3\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
||||||
echo "CUDA_PATH=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.3" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
echo "CUDA_PATH=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.3" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
||||||
echo "CUDA_PATH_V13_3=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.3" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
echo "CUDA_PATH_V13_3=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.3" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
||||||
|
|
||||||
- name: Install Cuda Toolkit 13.4 for ARM64
|
|
||||||
if: ${{ inputs.cuda_version == '13.4' && inputs.cuda_arch == 'arm64' }}
|
|
||||||
shell: pwsh
|
|
||||||
run: |
|
|
||||||
mkdir -p "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4"
|
|
||||||
choco install unzip -y
|
|
||||||
curl -O "https://packages.nvidia.com/bin-archive/pool/windows-x86_64/5B515474-7E78-11F1-8656-C51E4F4B317F/cccl-windows-x86_64-13.3.4.1.2-archive.zip"
|
|
||||||
curl -O "https://packages.nvidia.com/bin-archive/pool/windows-x86_64/5B515474-7E78-11F1-8656-C51E4F4B317F/cuda_crt-windows-x86_64-13.4.46-archive.zip"
|
|
||||||
curl -O "https://packages.nvidia.com/bin-archive/pool/windows-x86_64/5B515474-7E78-11F1-8656-C51E4F4B317F/cuda_nvcc-windows-x86_64-13.4.46-archive.zip"
|
|
||||||
curl -O "https://packages.nvidia.com/bin-archive/pool/windows-x86_64/5B515474-7E78-11F1-8656-C51E4F4B317F/libnvvm-windows-x86_64-13.4.46-archive.zip"
|
|
||||||
curl -O "https://packages.nvidia.com/bin-archive/pool/windows-arm64/5B515474-7E78-11F1-8656-C51E4F4B317F/cuda_cudart-windows-arm64-13.4.46-archive.zip"
|
|
||||||
curl -O "https://packages.nvidia.com/bin-archive/pool/windows-arm64/5B515474-7E78-11F1-8656-C51E4F4B317F/libcublas-windows-arm64-13.7.0.10-archive.zip"
|
|
||||||
unzip '*.zip' -d "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4"
|
|
||||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4\cccl-windows-x86_64-13.3.4.1.2-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4" /E /I /H /Y
|
|
||||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4\cuda_crt-windows-x86_64-13.4.46-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4" /E /I /H /Y
|
|
||||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4\cuda_nvcc-windows-x86_64-13.4.46-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4" /E /I /H /Y
|
|
||||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4\libnvvm-windows-x86_64-13.4.46-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4" /E /I /H /Y
|
|
||||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4\cuda_cudart-windows-arm64-13.4.46-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4" /E /I /H /Y
|
|
||||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4\libcublas-windows-arm64-13.7.0.10-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4" /E /I /H /Y
|
|
||||||
echo "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
|
||||||
echo "CUDA_PATH=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
|
||||||
echo "CUDA_PATH_V13_4=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
|
||||||
|
|||||||
@@ -8,26 +8,8 @@ inputs:
|
|||||||
runs:
|
runs:
|
||||||
using: "composite"
|
using: "composite"
|
||||||
steps:
|
steps:
|
||||||
- name: Install ROCm with Wheels
|
- name: Setup ROCm
|
||||||
shell: pwsh
|
uses: ./.github/actions/install-exe
|
||||||
run: |
|
with:
|
||||||
$ErrorActionPreference = "Stop"
|
url: https://download.amd.com/developer/eula/rocm-hub/AMD-Software-PRO-Edition-${{ inputs.version }}-Win11-For-HIP.exe
|
||||||
write-host "Setting up Python virtual environment"
|
args: -install
|
||||||
|
|
||||||
# Create the venv directly at the cache location to avoid relocation issues
|
|
||||||
New-Item -Path "C:\TheRock\build" -ItemType Directory -Force | Out-Null
|
|
||||||
python -m venv C:\TheRock\build\.venv
|
|
||||||
& C:\TheRock\build\.venv\Scripts\Activate.ps1
|
|
||||||
|
|
||||||
write-host "Upgrading pip"
|
|
||||||
python -m pip install --upgrade pip
|
|
||||||
|
|
||||||
write-host "Installing ROCm wheels for multi-arch support"
|
|
||||||
# Install ROCm wheels for multi-arch support (this may take several minutes)
|
|
||||||
python -m pip install --index-url https://stable.repo.amd.com/rocm/whl-next/ "rocm[libraries,devel]==${{ inputs.version }}"
|
|
||||||
|
|
||||||
# Pre-expand the devel tree so it is included in the cache
|
|
||||||
write-host "Initializing ROCm devel tree"
|
|
||||||
rocm-sdk init
|
|
||||||
if ($LASTEXITCODE -ne 0) { throw "rocm-sdk init failed with exit code $LASTEXITCODE" }
|
|
||||||
write-host "Completed ROCm wheel installation to C:\TheRock\build"
|
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ jobs:
|
|||||||
# cache on: https://github.com/ggerganov/tmp2/actions/runs/26534713799/job/78224189394
|
# cache on: https://github.com/ggerganov/tmp2/actions/runs/26534713799/job/78224189394
|
||||||
#
|
#
|
||||||
#- name: ccache
|
#- name: ccache
|
||||||
# uses: ggml-org/ccache-action@v1.2.24
|
# uses: ggml-org/ccache-action@v1.2.21
|
||||||
# with:
|
# with:
|
||||||
# key: android-ubuntu-arm64
|
# key: android-ubuntu-arm64
|
||||||
# evict-old-files: 1d
|
# evict-old-files: 1d
|
||||||
|
|||||||
@@ -22,8 +22,7 @@ on:
|
|||||||
types: [opened, synchronize, reopened]
|
types: [opened, synchronize, reopened]
|
||||||
paths: [
|
paths: [
|
||||||
'.github/workflows/build-apple.yml',
|
'.github/workflows/build-apple.yml',
|
||||||
'ggml/src/ggml-metal/**',
|
'ggml/src/ggml-metal/**'
|
||||||
'ggml/src/ggml-rpc/**'
|
|
||||||
]
|
]
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
@@ -47,19 +46,11 @@ jobs:
|
|||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: ccache
|
- name: ccache
|
||||||
uses: ggml-org/ccache-action@v1.2.24
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
with:
|
with:
|
||||||
key: apple-arm64
|
key: apple-arm64
|
||||||
save: false
|
evict-old-files: 1d
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
- name: ccache-buckets-restore
|
|
||||||
uses: ./.github/actions/ccache-buckets
|
|
||||||
env:
|
|
||||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CI }}
|
|
||||||
with:
|
|
||||||
key: apple-arm64
|
|
||||||
folder: llama.cpp
|
|
||||||
hf_bucket: ggml-org/cache
|
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
id: cmake_build
|
id: cmake_build
|
||||||
@@ -69,30 +60,12 @@ jobs:
|
|||||||
-DCMAKE_BUILD_RPATH="@loader_path" \
|
-DCMAKE_BUILD_RPATH="@loader_path" \
|
||||||
-DLLAMA_FATAL_WARNINGS=ON \
|
-DLLAMA_FATAL_WARNINGS=ON \
|
||||||
-DLLAMA_BUILD_BORINGSSL=ON \
|
-DLLAMA_BUILD_BORINGSSL=ON \
|
||||||
|
-DGGML_METAL_USE_BF16=ON \
|
||||||
-DGGML_METAL_EMBED_LIBRARY=OFF \
|
-DGGML_METAL_EMBED_LIBRARY=OFF \
|
||||||
-DGGML_METAL_SHADER_DEBUG=ON \
|
-DGGML_METAL_SHADER_DEBUG=ON \
|
||||||
-DGGML_RPC=ON \
|
-DGGML_RPC=ON
|
||||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=13.3
|
|
||||||
time cmake --build build --config Release -j $(sysctl -n hw.logicalcpu)
|
time cmake --build build --config Release -j $(sysctl -n hw.logicalcpu)
|
||||||
|
leaks -atExit -- ./build/bin/test-thread-safety -hf ggml-org/gemma-3-270m-qat-GGUF -ngl 99 -p "$(printf 'hello %.0s' {1..128})" -n 16 -c 512 -ub 32 -np 2 -t 2 -lv 1
|
||||||
- name: ccache-buckets-save
|
|
||||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
|
||||||
uses: ./.github/actions/ccache-buckets
|
|
||||||
env:
|
|
||||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CACHE_OUTPUT }}
|
|
||||||
with:
|
|
||||||
key: apple-arm64
|
|
||||||
folder: llama.cpp
|
|
||||||
evict-old-files: 1d
|
|
||||||
hf_bucket: ggml-org/cache
|
|
||||||
save: true
|
|
||||||
|
|
||||||
- name: Check for leaks
|
|
||||||
run: |
|
|
||||||
cmd=(./build/bin/test-thread-safety -hf ggml-org/gemma-3-270m-qat-GGUF -ngl 99 -p "$(printf 'hello %.0s' {1..128})" -n 16 -c 512 -ub 32 -np 2 -t 2 -lv 1)
|
|
||||||
leaks -atExit -- "${cmd[@]}"
|
|
||||||
# Graphics devices are leaked by Metal in Apple code sometimes, so we ignore those leaks
|
|
||||||
OBJC_DEBUG_MISSING_POOLS=YES "${cmd[@]}" 2>&1 | awk '{ print } index($0, "autoreleased with no pool in place") && !/class [a-zA-Z0-9]+Device autoreleased/ { found = 1 } END { exit found }'
|
|
||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
id: cmake_test
|
id: cmake_test
|
||||||
@@ -109,19 +82,11 @@ jobs:
|
|||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: ccache
|
- name: ccache
|
||||||
uses: ggml-org/ccache-action@v1.2.24
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
with:
|
with:
|
||||||
key: apple-x64
|
key: apple-x64
|
||||||
save: false
|
evict-old-files: 1d
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
- name: ccache-buckets-restore
|
|
||||||
uses: ./.github/actions/ccache-buckets
|
|
||||||
env:
|
|
||||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CI }}
|
|
||||||
with:
|
|
||||||
key: apple-x64
|
|
||||||
folder: llama.cpp
|
|
||||||
hf_bucket: ggml-org/cache
|
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
id: cmake_build
|
id: cmake_build
|
||||||
@@ -138,18 +103,6 @@ jobs:
|
|||||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=13.3
|
-DCMAKE_OSX_DEPLOYMENT_TARGET=13.3
|
||||||
time cmake --build build --config Release -j $(sysctl -n hw.logicalcpu)
|
time cmake --build build --config Release -j $(sysctl -n hw.logicalcpu)
|
||||||
|
|
||||||
- name: ccache-buckets-save
|
|
||||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
|
||||||
uses: ./.github/actions/ccache-buckets
|
|
||||||
env:
|
|
||||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CACHE_OUTPUT }}
|
|
||||||
with:
|
|
||||||
key: apple-x64
|
|
||||||
folder: llama.cpp
|
|
||||||
evict-old-files: 1d
|
|
||||||
hf_bucket: ggml-org/cache
|
|
||||||
save: true
|
|
||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
id: cmake_test
|
id: cmake_test
|
||||||
run: |
|
run: |
|
||||||
@@ -173,6 +126,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
sysctl -a
|
sysctl -a
|
||||||
cmake -B build -G Xcode \
|
cmake -B build -G Xcode \
|
||||||
|
-DGGML_METAL_USE_BF16=ON \
|
||||||
-DGGML_METAL_EMBED_LIBRARY=ON \
|
-DGGML_METAL_EMBED_LIBRARY=ON \
|
||||||
-DLLAMA_OPENSSL=OFF \
|
-DLLAMA_OPENSSL=OFF \
|
||||||
-DLLAMA_BUILD_APP=OFF \
|
-DLLAMA_BUILD_APP=OFF \
|
||||||
@@ -210,11 +164,20 @@ jobs:
|
|||||||
id: checkout
|
id: checkout
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
# TODO: this likely does not do anything - if yes, remove it
|
||||||
|
- name: ccache
|
||||||
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
|
with:
|
||||||
|
key: apple-tvos
|
||||||
|
evict-old-files: 1d
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
id: cmake_build
|
id: cmake_build
|
||||||
run: |
|
run: |
|
||||||
sysctl -a
|
sysctl -a
|
||||||
cmake -B build -G Xcode \
|
cmake -B build -G Xcode \
|
||||||
|
-DGGML_METAL_USE_BF16=ON \
|
||||||
-DGGML_METAL_EMBED_LIBRARY=ON \
|
-DGGML_METAL_EMBED_LIBRARY=ON \
|
||||||
-DLLAMA_BUILD_COMMON=OFF \
|
-DLLAMA_BUILD_COMMON=OFF \
|
||||||
-DLLAMA_BUILD_APP=OFF \
|
-DLLAMA_BUILD_APP=OFF \
|
||||||
@@ -235,11 +198,20 @@ jobs:
|
|||||||
id: checkout
|
id: checkout
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
# TODO: this likely does not do anything - if yes, remove it
|
||||||
|
- name: ccache
|
||||||
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
|
with:
|
||||||
|
key: apple-visionos
|
||||||
|
evict-old-files: 1d
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
id: cmake_build
|
id: cmake_build
|
||||||
run: |
|
run: |
|
||||||
sysctl -a
|
sysctl -a
|
||||||
cmake -B build -G Xcode \
|
cmake -B build -G Xcode \
|
||||||
|
-DGGML_METAL_USE_BF16=ON \
|
||||||
-DGGML_METAL_EMBED_LIBRARY=ON \
|
-DGGML_METAL_EMBED_LIBRARY=ON \
|
||||||
-DLLAMA_BUILD_COMMON=OFF \
|
-DLLAMA_BUILD_COMMON=OFF \
|
||||||
-DLLAMA_BUILD_APP=OFF \
|
-DLLAMA_BUILD_APP=OFF \
|
||||||
@@ -265,6 +237,14 @@ jobs:
|
|||||||
id: checkout
|
id: checkout
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
# TODO: this likely does not do anything - if yes, remove it
|
||||||
|
- name: ccache
|
||||||
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
|
with:
|
||||||
|
key: apple-swift
|
||||||
|
evict-old-files: 1d
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
|
|
||||||
- name: Download xcframework artifact
|
- name: Download xcframework artifact
|
||||||
uses: actions/download-artifact@v7
|
uses: actions/download-artifact@v7
|
||||||
with:
|
with:
|
||||||
@@ -276,6 +256,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
sysctl -a
|
sysctl -a
|
||||||
cmake -B build -G Xcode \
|
cmake -B build -G Xcode \
|
||||||
|
-DGGML_METAL_USE_BF16=ON \
|
||||||
-DGGML_METAL_EMBED_LIBRARY=ON \
|
-DGGML_METAL_EMBED_LIBRARY=ON \
|
||||||
-DLLAMA_OPENSSL=OFF \
|
-DLLAMA_OPENSSL=OFF \
|
||||||
-DLLAMA_BUILD_APP=OFF \
|
-DLLAMA_BUILD_APP=OFF \
|
||||||
|
|||||||
@@ -10,6 +10,33 @@ concurrency:
|
|||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
ubuntu-24-vulkan-cache:
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
id: checkout
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Get latest Vulkan SDK version
|
||||||
|
id: vulkan_sdk_version
|
||||||
|
run: |
|
||||||
|
echo "VULKAN_SDK_VERSION=$(curl https://vulkan.lunarg.com/sdk/latest/linux.txt)" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
|
- name: Setup Cache
|
||||||
|
uses: actions/cache@v5
|
||||||
|
id: cache-sdk
|
||||||
|
with:
|
||||||
|
path: ./vulkan_sdk
|
||||||
|
key: cache-gha-vulkan-sdk-${{ env.VULKAN_SDK_VERSION }}-${{ runner.os }}
|
||||||
|
|
||||||
|
- name: Setup Vulkan SDK
|
||||||
|
if: steps.cache-sdk.outputs.cache-hit != 'true'
|
||||||
|
uses: ./.github/actions/linux-setup-vulkan
|
||||||
|
with:
|
||||||
|
path: ./vulkan_sdk
|
||||||
|
version: ${{ env.VULKAN_SDK_VERSION }}
|
||||||
|
|
||||||
#ubuntu-24-spacemit-cache:
|
#ubuntu-24-spacemit-cache:
|
||||||
# runs-on: ubuntu-24.04
|
# runs-on: ubuntu-24.04
|
||||||
|
|
||||||
@@ -40,9 +67,9 @@ jobs:
|
|||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
|
|
||||||
env:
|
env:
|
||||||
# Sync versions in build-openvino.yml, build-self-hosted.yml, release.yml, build-cache.yml, .devops/openvino.Dockerfile
|
# Sync versions in build.yml, build-self-hosted.yml, release.yml, build-cache.yml, .devops/openvino.Dockerfile
|
||||||
OPENVINO_VERSION_MAJOR: "2026.3.1"
|
OPENVINO_VERSION_MAJOR: "2026.2.1"
|
||||||
OPENVINO_VERSION_FULL: "2026.3.1.22476.56d9685302d"
|
OPENVINO_VERSION_FULL: "2026.2.1.21919.ede283a88e3"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Clone
|
- name: Clone
|
||||||
@@ -69,8 +96,8 @@ jobs:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
# Sync versions in build.yml, build-self-hosted.yml, release.yml, build-cache.yml, .devops/openvino.Dockerfile
|
# Sync versions in build.yml, build-self-hosted.yml, release.yml, build-cache.yml, .devops/openvino.Dockerfile
|
||||||
OPENVINO_VERSION_MAJOR: "2026.3.1"
|
OPENVINO_VERSION_MAJOR: "2026.2.1"
|
||||||
OPENVINO_VERSION_FULL: "2026.3.1.22476.56d9685302d"
|
OPENVINO_VERSION_FULL: "2026.2.1.21919.ede283a88e3"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Clone
|
- name: Clone
|
||||||
@@ -92,27 +119,27 @@ jobs:
|
|||||||
version_major: ${{ env.OPENVINO_VERSION_MAJOR }}
|
version_major: ${{ env.OPENVINO_VERSION_MAJOR }}
|
||||||
version_full: ${{ env.OPENVINO_VERSION_FULL }}
|
version_full: ${{ env.OPENVINO_VERSION_FULL }}
|
||||||
|
|
||||||
# windows-2022-rocm-cache:
|
windows-2022-rocm-cache:
|
||||||
# runs-on: windows-2022
|
runs-on: windows-2022
|
||||||
|
|
||||||
# env:
|
env:
|
||||||
# # Make sure this is in sync with release.yml and build-cuda-windows.yml
|
# Make sure this is in sync with build.yml
|
||||||
# ROCM_VERSION: "7.14.0"
|
HIPSDK_INSTALLER_VERSION: "26.Q1"
|
||||||
|
|
||||||
# steps:
|
steps:
|
||||||
# - name: Clone
|
- name: Clone
|
||||||
# id: checkout
|
id: checkout
|
||||||
# uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
# - name: Setup Cache
|
- name: Setup Cache
|
||||||
# uses: actions/cache@v5
|
uses: actions/cache@v5
|
||||||
# id: cache-rocm
|
id: cache-rocm
|
||||||
# with:
|
with:
|
||||||
# path: C:\TheRock\build
|
path: C:\Program Files\AMD\ROCm
|
||||||
# key: rocm-wheels-${{ env.ROCM_VERSION }}-multi-arch-${{ runner.os }}
|
key: cache-gha-rocm-${{ env.HIPSDK_INSTALLER_VERSION }}-${{ runner.os }}
|
||||||
|
|
||||||
# - name: Setup ROCm
|
- name: Setup ROCm
|
||||||
# if: steps.cache-rocm.outputs.cache-hit != 'true'
|
if: steps.cache-rocm.outputs.cache-hit != 'true'
|
||||||
# uses: ./.github/actions/windows-setup-rocm
|
uses: ./.github/actions/windows-setup-rocm
|
||||||
# with:
|
with:
|
||||||
# version: ${{ env.ROCM_VERSION }}
|
version: ${{ env.HIPSDK_INSTALLER_VERSION }}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
linux:
|
linux:
|
||||||
runs-on: [self-hosted, Linux]
|
runs-on: [self-hosted, Linux, CPU]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
@@ -21,33 +21,31 @@ jobs:
|
|||||||
-DLLAMA_BUILD_TOOLS=OFF \
|
-DLLAMA_BUILD_TOOLS=OFF \
|
||||||
-DLLAMA_BUILD_EXAMPLES=OFF \
|
-DLLAMA_BUILD_EXAMPLES=OFF \
|
||||||
-DLLAMA_BUILD_APP=OFF \
|
-DLLAMA_BUILD_APP=OFF \
|
||||||
-DLLAMA_BUILD_IS_DEV=OFF \
|
|
||||||
-DCMAKE_BUILD_TYPE=Release
|
-DCMAKE_BUILD_TYPE=Release
|
||||||
cmake --build build --config Release -j $(nproc)
|
cmake --build build --config Release
|
||||||
cmake --install build --prefix "$PREFIX" --config Release
|
cmake --install build --prefix "$PREFIX" --config Release
|
||||||
|
|
||||||
export LLAMA_CONFIG="$PREFIX"/lib/cmake/llama/llama-config.cmake
|
export LLAMA_CONFIG="$PREFIX"/lib/cmake/llama/llama-config.cmake
|
||||||
build_commit=$(git rev-parse --short HEAD | xargs)
|
tclsh <<'EOF'
|
||||||
build_number=$(git rev-list --count HEAD | xargs)
|
set build(commit) [string trim [exec git rev-parse --short HEAD]]
|
||||||
|
set build(number) [string trim [exec git rev-list --count HEAD]]
|
||||||
|
set build(version) "0.0.$build(number)"
|
||||||
|
|
||||||
major=$(grep -oE "set\(LLAMA_VERSION_MAJOR[[:space:]]+[0-9]+" CMakeLists.txt | grep -oE "[0-9]+$")
|
set llamaconfig [read [open "$env(LLAMA_CONFIG)" r]]
|
||||||
minor=$(grep -oE "set\(LLAMA_VERSION_MINOR[[:space:]]+[0-9]+" CMakeLists.txt | grep -oE "[0-9]+$")
|
set checks [list "set\\(LLAMA_VERSION \\s+$build(version)\\)" \
|
||||||
patch=$(grep -oE "set\(LLAMA_VERSION_PATCH[[:space:]]+[0-9]+" CMakeLists.txt | grep -oE "[0-9]+$")
|
"set\\(LLAMA_BUILD_COMMIT\\s+$build(commit)\\)" \
|
||||||
build_version="$major.$minor.$patch"
|
"set\\(LLAMA_BUILD_NUMBER\\s+$build(number)\\)"]
|
||||||
|
|
||||||
checks=("set\(LLAMA_VERSION[[:space:]]+$build_version\)"
|
puts -nonewline "Checking llama-config.cmake version... "
|
||||||
"set\(LLAMA_BUILD_COMMIT[[:space:]]+$build_commit\)"
|
foreach check $checks {
|
||||||
"set\(LLAMA_BUILD_NUMBER[[:space:]]+$build_number\)")
|
if {![regexp -expanded -- $check $llamaconfig]} {
|
||||||
|
puts "\"$check\" failed!"
|
||||||
for check in "${checks[@]}"; do
|
|
||||||
if ! grep -qE "$check" "$LLAMA_CONFIG"; then
|
|
||||||
echo "Checking llama-config.cmake version... \"$check\" failed!"
|
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
}
|
||||||
done
|
}
|
||||||
|
puts "success."
|
||||||
echo "Checking llama-config.cmake version... success."
|
EOF
|
||||||
|
|
||||||
cd examples/simple-cmake-pkg
|
cd examples/simple-cmake-pkg
|
||||||
cmake -S . -B build -DCMAKE_PREFIX_PATH="$PREFIX"/lib/cmake
|
cmake -S . -B build -DCMAKE_PREFIX_PATH="$PREFIX"/lib/cmake
|
||||||
cmake --build build -j $(nproc)
|
cmake --build build
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ on:
|
|||||||
paths: [
|
paths: [
|
||||||
'.github/workflows/build-cpu.yml',
|
'.github/workflows/build-cpu.yml',
|
||||||
'.github/workflows/build-cmake-pkg.yml',
|
'.github/workflows/build-cmake-pkg.yml',
|
||||||
'ggml/src/ggml-rpc/**',
|
|
||||||
'**/CMakeLists.txt',
|
'**/CMakeLists.txt',
|
||||||
'**/.cmake',
|
'**/.cmake',
|
||||||
'**/*.h',
|
'**/*.h',
|
||||||
@@ -62,10 +61,11 @@ jobs:
|
|||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: ccache
|
- name: ccache
|
||||||
uses: ggml-org/ccache-action@v1.2.24
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
with:
|
with:
|
||||||
key: cpu-${{ matrix.os }}
|
key: cpu-${{ matrix.os }}
|
||||||
save: false
|
evict-old-files: 1d
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
|
|
||||||
- name: Build Dependencies
|
- name: Build Dependencies
|
||||||
id: build_depends
|
id: build_depends
|
||||||
@@ -90,36 +90,14 @@ jobs:
|
|||||||
python3 -m pip install --upgrade pip setuptools
|
python3 -m pip install --upgrade pip setuptools
|
||||||
pip3 install ./gguf-py
|
pip3 install ./gguf-py
|
||||||
|
|
||||||
- name: ccache-buckets-restore
|
|
||||||
uses: ./.github/actions/ccache-buckets
|
|
||||||
env:
|
|
||||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CI }}
|
|
||||||
with:
|
|
||||||
key: cpu-${{ matrix.os }}
|
|
||||||
folder: llama.cpp
|
|
||||||
hf_bucket: ggml-org/cache
|
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
id: cmake_build
|
id: cmake_build
|
||||||
run: |
|
run: |
|
||||||
cmake -B build \
|
cmake -B build \
|
||||||
-DGGML_NATIVE=OFF \
|
|
||||||
-DLLAMA_FATAL_WARNINGS=ON \
|
-DLLAMA_FATAL_WARNINGS=ON \
|
||||||
-DGGML_RPC=ON
|
-DGGML_RPC=ON
|
||||||
time cmake --build build --config Release -j $(nproc)
|
time cmake --build build --config Release -j $(nproc)
|
||||||
|
|
||||||
- name: ccache-buckets-save
|
|
||||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
|
||||||
uses: ./.github/actions/ccache-buckets
|
|
||||||
env:
|
|
||||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CACHE_OUTPUT }}
|
|
||||||
with:
|
|
||||||
key: cpu-${{ matrix.os }}
|
|
||||||
folder: llama.cpp
|
|
||||||
evict-old-files: 1d
|
|
||||||
hf_bucket: ggml-org/cache
|
|
||||||
save: true
|
|
||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
id: cmake_test
|
id: cmake_test
|
||||||
run: |
|
run: |
|
||||||
@@ -138,25 +116,28 @@ jobs:
|
|||||||
./bin/llama-completion -m stories260K.gguf -p "One day, Lily met a Shoggoth" -n 500 -c 256
|
./bin/llama-completion -m stories260K.gguf -p "One day, Lily met a Shoggoth" -n 500 -c 256
|
||||||
|
|
||||||
windows:
|
windows:
|
||||||
name: windows / ${{ matrix.build }}
|
|
||||||
runs-on: windows-2025
|
runs-on: windows-2025
|
||||||
|
|
||||||
env:
|
env:
|
||||||
OPENBLAS_VERSION: 0.3.23
|
OPENBLAS_VERSION: 0.3.23
|
||||||
SDE_VERSION: 9.33.0-2024-01-07
|
SDE_VERSION: 9.33.0-2024-01-07
|
||||||
|
VULKAN_VERSION: 1.4.313.2
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- build: 'x64-cpu-static'
|
- build: 'x64-cpu-static'
|
||||||
arch: 'x64'
|
arch: 'x64'
|
||||||
defines: '-G "Ninja Multi-Config" -D CMAKE_TOOLCHAIN_FILE=cmake/x64-windows-llvm.cmake -DGGML_NATIVE=OFF -DGGML_OPENMP_FETCH=ON -DLLAMA_BUILD_SERVER=ON -DGGML_RPC=ON -DBUILD_SHARED_LIBS=OFF'
|
defines: '-G "Ninja Multi-Config" -D CMAKE_TOOLCHAIN_FILE=cmake/x64-windows-llvm.cmake -DGGML_NATIVE=OFF -DLLAMA_BUILD_SERVER=ON -DGGML_RPC=ON -DBUILD_SHARED_LIBS=OFF'
|
||||||
- build: 'x64-openblas'
|
- build: 'x64-openblas'
|
||||||
arch: 'x64'
|
arch: 'x64'
|
||||||
defines: '-G "Ninja Multi-Config" -D CMAKE_TOOLCHAIN_FILE=cmake/x64-windows-llvm.cmake -DGGML_NATIVE=OFF -DLLAMA_BUILD_SERVER=ON -DGGML_RPC=ON -DGGML_BACKEND_DL=ON -DGGML_CPU_ALL_VARIANTS=ON -DGGML_OPENMP=OFF -DGGML_BLAS=ON -DGGML_BLAS_VENDOR=OpenBLAS -DBLAS_INCLUDE_DIRS="$env:RUNNER_TEMP/openblas/include" -DBLAS_LIBRARIES="$env:RUNNER_TEMP/openblas/lib/openblas.lib"'
|
defines: '-G "Ninja Multi-Config" -D CMAKE_TOOLCHAIN_FILE=cmake/x64-windows-llvm.cmake -DGGML_NATIVE=OFF -DLLAMA_BUILD_SERVER=ON -DGGML_RPC=ON -DGGML_BACKEND_DL=ON -DGGML_CPU_ALL_VARIANTS=ON -DGGML_OPENMP=OFF -DGGML_BLAS=ON -DGGML_BLAS_VENDOR=OpenBLAS -DBLAS_INCLUDE_DIRS="$env:RUNNER_TEMP/openblas/include" -DBLAS_LIBRARIES="$env:RUNNER_TEMP/openblas/lib/openblas.lib"'
|
||||||
|
- build: 'x64-vulkan'
|
||||||
|
arch: 'x64'
|
||||||
|
defines: '-G "Ninja Multi-Config" -D CMAKE_TOOLCHAIN_FILE=cmake/x64-windows-llvm.cmake -DCMAKE_BUILD_TYPE=Release -DGGML_NATIVE=OFF -DLLAMA_BUILD_SERVER=ON -DGGML_RPC=ON -DGGML_BACKEND_DL=ON -DGGML_CPU_ALL_VARIANTS=ON -DGGML_VULKAN=ON'
|
||||||
- build: 'arm64'
|
- build: 'arm64'
|
||||||
arch: 'arm64'
|
arch: 'arm64'
|
||||||
defines: '-G "Ninja Multi-Config" -D CMAKE_TOOLCHAIN_FILE=cmake/arm64-windows-llvm.cmake -DGGML_NATIVE=OFF -DGGML_OPENMP_FETCH=ON -DLLAMA_BUILD_SERVER=ON'
|
defines: '-G "Ninja Multi-Config" -D CMAKE_TOOLCHAIN_FILE=cmake/arm64-windows-llvm.cmake -DGGML_NATIVE=OFF -DLLAMA_BUILD_SERVER=ON'
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Clone
|
- name: Clone
|
||||||
@@ -164,7 +145,7 @@ jobs:
|
|||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: ccache
|
- name: ccache
|
||||||
uses: ggml-org/ccache-action@v1.2.24
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
with:
|
with:
|
||||||
key: cpu-windows-2025-${{ matrix.build }}
|
key: cpu-windows-2025-${{ matrix.build }}
|
||||||
variant: ccache
|
variant: ccache
|
||||||
@@ -184,6 +165,15 @@ jobs:
|
|||||||
$lib = $(join-path $msvc 'bin\Hostx64\x64\lib.exe')
|
$lib = $(join-path $msvc 'bin\Hostx64\x64\lib.exe')
|
||||||
& $lib /machine:x64 "/def:${env:RUNNER_TEMP}/openblas/lib/libopenblas.def" "/out:${env:RUNNER_TEMP}/openblas/lib/openblas.lib" /name:openblas.dll
|
& $lib /machine:x64 "/def:${env:RUNNER_TEMP}/openblas/lib/libopenblas.def" "/out:${env:RUNNER_TEMP}/openblas/lib/openblas.lib" /name:openblas.dll
|
||||||
|
|
||||||
|
- name: Install Vulkan SDK
|
||||||
|
id: get_vulkan
|
||||||
|
if: ${{ matrix.build == 'x64-vulkan' }}
|
||||||
|
run: |
|
||||||
|
curl.exe -o $env:RUNNER_TEMP/VulkanSDK-Installer.exe -L "https://sdk.lunarg.com/sdk/download/${env:VULKAN_VERSION}/windows/vulkansdk-windows-X64-${env:VULKAN_VERSION}.exe"
|
||||||
|
& "$env:RUNNER_TEMP\VulkanSDK-Installer.exe" --accept-licenses --default-answer --confirm-command install
|
||||||
|
Add-Content $env:GITHUB_ENV "VULKAN_SDK=C:\VulkanSDK\${env:VULKAN_VERSION}"
|
||||||
|
Add-Content $env:GITHUB_PATH "C:\VulkanSDK\${env:VULKAN_VERSION}\bin"
|
||||||
|
|
||||||
- name: Install Ninja
|
- name: Install Ninja
|
||||||
id: install_ninja
|
id: install_ninja
|
||||||
run: |
|
run: |
|
||||||
@@ -223,13 +213,3 @@ jobs:
|
|||||||
# cd build
|
# cd build
|
||||||
# $env:LLAMA_SKIP_TESTS_SLOW_ON_EMULATOR = 1
|
# $env:LLAMA_SKIP_TESTS_SLOW_ON_EMULATOR = 1
|
||||||
# & $sde -future -- ctest -L main -C Release --verbose --timeout 900
|
# & $sde -future -- ctest -L main -C Release --verbose --timeout 900
|
||||||
|
|
||||||
- name: ccache-clear
|
|
||||||
uses: ./.github/actions/ccache-clear
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ github.token }}
|
|
||||||
with:
|
|
||||||
key: cpu-windows-2025-${{ matrix.build }}
|
|
||||||
older: 5m
|
|
||||||
min: 1
|
|
||||||
dry-run: ${{ github.event_name != 'push' || github.ref != 'refs/heads/master' }}
|
|
||||||
|
|||||||
@@ -50,22 +50,14 @@ jobs:
|
|||||||
DEBIAN_FRONTEND: noninteractive
|
DEBIAN_FRONTEND: noninteractive
|
||||||
run: |
|
run: |
|
||||||
apt update
|
apt update
|
||||||
apt install -y cmake build-essential ninja-build libgomp1 git libssl-dev jq python3 python3-venv python3-pip
|
apt install -y cmake build-essential ninja-build libgomp1 git libssl-dev
|
||||||
|
|
||||||
- name: ccache
|
- name: ccache
|
||||||
uses: ggml-org/ccache-action@v1.2.24
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
with:
|
with:
|
||||||
key: cuda-ubuntu-24.04-cuda
|
key: cuda-ubuntu-24.04-cuda
|
||||||
save: false
|
evict-old-files: 1d
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
- name: ccache-buckets-restore
|
|
||||||
uses: ./.github/actions/ccache-buckets
|
|
||||||
env:
|
|
||||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CI }}
|
|
||||||
with:
|
|
||||||
key: cuda-ubuntu-24.04-cuda
|
|
||||||
folder: llama.cpp
|
|
||||||
hf_bucket: ggml-org/cache
|
|
||||||
|
|
||||||
- name: Build with CMake
|
- name: Build with CMake
|
||||||
# TODO: Remove GGML_CUDA_CUB_3DOT2 flag once CCCL 3.2 is bundled within CTK and that CTK version is used in this project
|
# TODO: Remove GGML_CUDA_CUB_3DOT2 flag once CCCL 3.2 is bundled within CTK and that CTK version is used in this project
|
||||||
@@ -80,18 +72,6 @@ jobs:
|
|||||||
-DGGML_CUDA_CUB_3DOT2=ON
|
-DGGML_CUDA_CUB_3DOT2=ON
|
||||||
cmake --build build
|
cmake --build build
|
||||||
|
|
||||||
- name: ccache-buckets-save
|
|
||||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
|
||||||
uses: ./.github/actions/ccache-buckets
|
|
||||||
env:
|
|
||||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CACHE_OUTPUT }}
|
|
||||||
with:
|
|
||||||
key: cuda-ubuntu-24.04-cuda
|
|
||||||
folder: llama.cpp
|
|
||||||
evict-old-files: 1d
|
|
||||||
hf_bucket: ggml-org/cache
|
|
||||||
save: true
|
|
||||||
|
|
||||||
hip:
|
hip:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
container: rocm/dev-ubuntu-22.04:6.1.2
|
container: rocm/dev-ubuntu-22.04:6.1.2
|
||||||
@@ -105,44 +85,25 @@ jobs:
|
|||||||
id: depends
|
id: depends
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y build-essential git cmake rocblas-dev hipblas-dev libssl-dev rocwmma-dev jq python3-venv
|
sudo apt-get install -y build-essential git cmake rocblas-dev hipblas-dev libssl-dev rocwmma-dev
|
||||||
|
|
||||||
- name: ccache
|
- name: ccache
|
||||||
uses: ggml-org/ccache-action@v1.2.24
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
with:
|
with:
|
||||||
key: cuda-ubuntu-22.04-hip
|
key: cuda-ubuntu-22.04-hip
|
||||||
save: false
|
evict-old-files: 1d
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
- name: ccache-buckets-restore
|
|
||||||
uses: ./.github/actions/ccache-buckets
|
|
||||||
env:
|
|
||||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CI }}
|
|
||||||
with:
|
|
||||||
key: cuda-ubuntu-22.04-hip
|
|
||||||
folder: llama.cpp
|
|
||||||
hf_bucket: ggml-org/cache
|
|
||||||
|
|
||||||
- name: Build with native CMake HIP support
|
- name: Build with native CMake HIP support
|
||||||
id: cmake_build
|
id: cmake_build
|
||||||
run: |
|
run: |
|
||||||
cmake -B build -S . \
|
cmake -B build -S . \
|
||||||
-DCMAKE_HIP_COMPILER="$(hipconfig -l)/clang" \
|
-DCMAKE_HIP_COMPILER="$(hipconfig -l)/clang" \
|
||||||
|
-DGGML_HIP_ROCWMMA_FATTN=ON \
|
||||||
-DGPU_TARGETS="gfx1030" \
|
-DGPU_TARGETS="gfx1030" \
|
||||||
-DGGML_HIP=ON
|
-DGGML_HIP=ON
|
||||||
cmake --build build --config Release -j $(nproc)
|
cmake --build build --config Release -j $(nproc)
|
||||||
|
|
||||||
- name: ccache-buckets-save
|
|
||||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
|
||||||
uses: ./.github/actions/ccache-buckets
|
|
||||||
env:
|
|
||||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CACHE_OUTPUT }}
|
|
||||||
with:
|
|
||||||
key: cuda-ubuntu-22.04-hip
|
|
||||||
folder: llama.cpp
|
|
||||||
evict-old-files: 1d
|
|
||||||
hf_bucket: ggml-org/cache
|
|
||||||
save: true
|
|
||||||
|
|
||||||
musa:
|
musa:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
container: mthreads/musa:rc4.3.0-devel-ubuntu22.04-amd64
|
container: mthreads/musa:rc4.3.0-devel-ubuntu22.04-amd64
|
||||||
@@ -156,22 +117,14 @@ jobs:
|
|||||||
id: depends
|
id: depends
|
||||||
run: |
|
run: |
|
||||||
apt-get update
|
apt-get update
|
||||||
apt-get install -y build-essential git cmake libssl-dev jq
|
apt-get install -y build-essential git cmake libssl-dev
|
||||||
|
|
||||||
- name: ccache
|
- name: ccache
|
||||||
uses: ggml-org/ccache-action@v1.2.24
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
with:
|
with:
|
||||||
key: cuda-ubuntu-22.04-musa
|
key: cuda-ubuntu-22.04-musa
|
||||||
save: false
|
evict-old-files: 1d
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
- name: ccache-buckets-restore
|
|
||||||
uses: ./.github/actions/ccache-buckets
|
|
||||||
env:
|
|
||||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CI }}
|
|
||||||
with:
|
|
||||||
key: cuda-ubuntu-22.04-musa
|
|
||||||
folder: llama.cpp
|
|
||||||
hf_bucket: ggml-org/cache
|
|
||||||
|
|
||||||
- name: Build with native CMake MUSA support
|
- name: Build with native CMake MUSA support
|
||||||
id: cmake_build
|
id: cmake_build
|
||||||
@@ -179,15 +132,3 @@ jobs:
|
|||||||
cmake -B build -S . \
|
cmake -B build -S . \
|
||||||
-DGGML_MUSA=ON
|
-DGGML_MUSA=ON
|
||||||
time cmake --build build --config Release -j $(nproc)
|
time cmake --build build --config Release -j $(nproc)
|
||||||
|
|
||||||
- name: ccache-buckets-save
|
|
||||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
|
||||||
uses: ./.github/actions/ccache-buckets
|
|
||||||
env:
|
|
||||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CACHE_OUTPUT }}
|
|
||||||
with:
|
|
||||||
key: cuda-ubuntu-22.04-musa
|
|
||||||
folder: llama.cpp
|
|
||||||
evict-old-files: 1d
|
|
||||||
hf_bucket: ggml-org/cache
|
|
||||||
save: true
|
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ env:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
cuda:
|
cuda:
|
||||||
name: windows-cuda (${{ matrix.cuda }}, ${{ matrix.arch }})
|
|
||||||
runs-on: windows-2022
|
runs-on: windows-2022
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
@@ -30,16 +29,7 @@ jobs:
|
|||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
cuda: ['12.4', '13.3']
|
||||||
- cuda: '12.4'
|
|
||||||
arch: x64
|
|
||||||
defines: '-DGGML_CUDA_CUB_3DOT2=ON'
|
|
||||||
- cuda: '13.3'
|
|
||||||
arch: x64
|
|
||||||
defines: ''
|
|
||||||
- cuda: '13.4'
|
|
||||||
arch: arm64
|
|
||||||
defines: '-DCMAKE_TOOLCHAIN_FILE=cmake/arm64-windows-msvc-cuda.cmake'
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Clone
|
- name: Clone
|
||||||
@@ -47,15 +37,14 @@ jobs:
|
|||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: ccache
|
- name: ccache
|
||||||
uses: ggml-org/ccache-action@v1.2.24
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
with:
|
with:
|
||||||
key: release-windows-2022-${{ matrix.arch }}-cuda-${{ matrix.cuda }}
|
key: release-windows-2022-x64-cuda-${{ matrix.cuda }}
|
||||||
|
|
||||||
- name: Install Cuda Toolkit
|
- name: Install Cuda Toolkit
|
||||||
uses: ./.github/actions/windows-setup-cuda
|
uses: ./.github/actions/windows-setup-cuda
|
||||||
with:
|
with:
|
||||||
cuda_version: ${{ matrix.cuda }}
|
cuda_version: ${{ matrix.cuda }}
|
||||||
cuda_arch: ${{ matrix.arch }}
|
|
||||||
|
|
||||||
- name: Install Ninja
|
- name: Install Ninja
|
||||||
id: install_ninja
|
id: install_ninja
|
||||||
@@ -65,21 +54,26 @@ jobs:
|
|||||||
- name: Build
|
- name: Build
|
||||||
id: cmake_build
|
id: cmake_build
|
||||||
shell: cmd
|
shell: cmd
|
||||||
|
# TODO: Remove GGML_CUDA_CUB_3DOT2 flag once CCCL 3.2 is bundled within CTK and that CTK version is used in this project
|
||||||
run: |
|
run: |
|
||||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.arch == 'x64' && 'x64' || 'amd64_arm64' }}
|
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
|
||||||
cmake -S . -B build -G "Ninja Multi-Config" ^
|
cmake -S . -B build -G "Ninja Multi-Config" ^
|
||||||
-DGGML_BACKEND_DL=ON ^
|
-DLLAMA_BUILD_SERVER=ON ^
|
||||||
|
-DLLAMA_BUILD_BORINGSSL=ON ^
|
||||||
-DGGML_NATIVE=OFF ^
|
-DGGML_NATIVE=OFF ^
|
||||||
-DGGML_CPU=OFF ^
|
-DGGML_BACKEND_DL=ON ^
|
||||||
|
-DGGML_CPU_ALL_VARIANTS=ON ^
|
||||||
-DGGML_CUDA=ON ^
|
-DGGML_CUDA=ON ^
|
||||||
-DLLAMA_BUILD_BORINGSSL=ON ${{ matrix.defines }}
|
-DGGML_RPC=ON ^
|
||||||
|
-DGGML_CUDA_CUB_3DOT2=ON
|
||||||
set /A NINJA_JOBS=%NUMBER_OF_PROCESSORS%-1
|
set /A NINJA_JOBS=%NUMBER_OF_PROCESSORS%-1
|
||||||
cmake --build build --config Release -j %NINJA_JOBS% --target ggml-cuda
|
cmake --build build --config Release -j %NINJA_JOBS% -t ggml
|
||||||
|
cmake --build build --config Release
|
||||||
|
|
||||||
- name: ccache-clear
|
- name: ccache-clear
|
||||||
uses: ./.github/actions/ccache-clear
|
uses: ./.github/actions/ccache-clear
|
||||||
with:
|
with:
|
||||||
key: release-windows-2022-${{ matrix.arch }}-cuda-${{ matrix.cuda }}
|
key: release-windows-2022-x64-cuda-${{ matrix.cuda }}
|
||||||
|
|
||||||
hip:
|
hip:
|
||||||
runs-on: windows-2022
|
runs-on: windows-2022
|
||||||
@@ -89,7 +83,7 @@ jobs:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
# Make sure this is in sync with build-cache.yml
|
# Make sure this is in sync with build-cache.yml
|
||||||
ROCM_VERSION: "7.14.0"
|
HIPSDK_INSTALLER_VERSION: "26.Q1"
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
@@ -103,81 +97,66 @@ jobs:
|
|||||||
id: checkout
|
id: checkout
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
# - name: Cache ROCm Installation
|
- name: Grab rocWMMA package
|
||||||
# uses: actions/cache@v5
|
id: grab_rocwmma
|
||||||
# id: cache-rocm
|
run: |
|
||||||
# with:
|
curl -o rocwmma.deb "https://repo.radeon.com/rocm/apt/7.2.1/pool/main/r/rocwmma-dev/rocwmma-dev_2.2.0.70201-81~24.04_amd64.deb"
|
||||||
# path: C:\TheRock\build
|
7z x rocwmma.deb
|
||||||
# key: rocm-wheels-${{ env.ROCM_VERSION }}-multi-arch-${{ runner.os }}
|
7z x data.tar
|
||||||
|
|
||||||
|
- name: Use ROCm Installation Cache
|
||||||
|
uses: actions/cache@v5
|
||||||
|
id: cache-rocm
|
||||||
|
with:
|
||||||
|
path: C:\Program Files\AMD\ROCm
|
||||||
|
key: cache-gha-rocm-${{ env.HIPSDK_INSTALLER_VERSION }}-${{ runner.os }}
|
||||||
|
|
||||||
- name: Setup ROCm
|
- name: Setup ROCm
|
||||||
# if: steps.cache-rocm.outputs.cache-hit != 'true'
|
if: steps.cache-rocm.outputs.cache-hit != 'true'
|
||||||
uses: ./.github/actions/windows-setup-rocm
|
uses: ./.github/actions/windows-setup-rocm
|
||||||
with:
|
with:
|
||||||
version: ${{ env.ROCM_VERSION }}
|
version: ${{ env.HIPSDK_INSTALLER_VERSION }}
|
||||||
|
|
||||||
- name: Setup ROCm Environment
|
|
||||||
run: |
|
|
||||||
$ErrorActionPreference = "Stop"
|
|
||||||
|
|
||||||
# Activate venv from cache or fresh install
|
|
||||||
& C:\TheRock\build\.venv\Scripts\Activate.ps1
|
|
||||||
|
|
||||||
# Expand the devel tree (idempotent; no-op if already done during install)
|
|
||||||
rocm-sdk init
|
|
||||||
if ($LASTEXITCODE -ne 0) { throw "rocm-sdk init failed with exit code $LASTEXITCODE" }
|
|
||||||
|
|
||||||
# Get ROCm installation paths using the rocm-sdk CLI tool
|
|
||||||
$rocmPath = (rocm-sdk path --root)
|
|
||||||
if (-not $rocmPath) { throw "rocm-sdk path --root returned empty - devel package may not be installed" }
|
|
||||||
$rocmPath = $rocmPath.Trim()
|
|
||||||
$cmakePath = (rocm-sdk path --cmake).Trim()
|
|
||||||
$binPath = (rocm-sdk path --bin).Trim()
|
|
||||||
write-host "ROCm root: $rocmPath"
|
|
||||||
|
|
||||||
echo "HIP_PATH=$rocmPath" >> $env:GITHUB_ENV
|
|
||||||
echo "CMAKE_PREFIX_PATH=$cmakePath" >> $env:GITHUB_ENV
|
|
||||||
echo "HIP_DEVICE_LIB_PATH=$rocmPath\lib\llvm\amdgcn\bitcode" >> $env:GITHUB_ENV
|
|
||||||
echo "HIP_PLATFORM=amd" >> $env:GITHUB_ENV
|
|
||||||
echo "LLVM_PATH=$rocmPath\lib\llvm" >> $env:GITHUB_ENV
|
|
||||||
echo "$binPath" >> $env:GITHUB_PATH
|
|
||||||
|
|
||||||
# Keep venv in PATH for subsequent steps
|
|
||||||
echo "C:\TheRock\build\.venv\Scripts" >> $env:GITHUB_PATH
|
|
||||||
|
|
||||||
- name: Verify ROCm
|
- name: Verify ROCm
|
||||||
id: verify
|
id: verify
|
||||||
run: |
|
run: |
|
||||||
# Test the ROCm clang shipped in the installed wheel
|
# Find and test ROCm installation
|
||||||
& "${env:HIP_PATH}\lib\llvm\bin\clang.exe" --version
|
$clangPath = Get-ChildItem 'C:\Program Files\AMD\ROCm\*\bin\clang.exe' | Select-Object -First 1
|
||||||
|
if (-not $clangPath) {
|
||||||
|
Write-Error "ROCm installation not found"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
& $clangPath.FullName --version
|
||||||
|
|
||||||
- name: ccache
|
- name: ccache
|
||||||
uses: ggml-org/ccache-action@v1.2.24
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
with:
|
with:
|
||||||
# TODO: this build does not match the build in release.yml, so we use a different cache key
|
# TODO: this build does not match the build in release.yml, so we use a different cache key
|
||||||
# ideally, the builds should match, similar to the CUDA build above so that we would be able
|
# ideally, the builds should match, similar to the CUDA build above so that we would be able
|
||||||
# to populate the ccache for the release with manual runs of this workflow
|
# to populate the ccache for the release with manual runs of this workflow
|
||||||
#key: release-windows-2022-x64-hip-${{ env.ROCM_VERSION }}-${{ matrix.name }}
|
#key: release-windows-2022-x64-hip-${{ env.HIPSDK_INSTALLER_VERSION }}-${{ matrix.name }}
|
||||||
key: cuda-windows-2022-x64-hip-${{ env.ROCM_VERSION }}-${{ matrix.name }}
|
key: cuda-windows-2022-x64-hip-${{ env.HIPSDK_INSTALLER_VERSION }}-${{ matrix.name }}
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
id: cmake_build
|
id: cmake_build
|
||||||
run: |
|
run: |
|
||||||
|
$env:HIP_PATH=$(Resolve-Path 'C:\Program Files\AMD\ROCm\*\bin\clang.exe' | split-path | split-path)
|
||||||
|
$env:CMAKE_PREFIX_PATH="${env:HIP_PATH}"
|
||||||
cmake -G "Unix Makefiles" -B build -S . `
|
cmake -G "Unix Makefiles" -B build -S . `
|
||||||
-DCMAKE_PREFIX_PATH="${env:HIP_PATH}" `
|
-DCMAKE_C_COMPILER="${env:HIP_PATH}\bin\clang.exe" `
|
||||||
-DCMAKE_C_COMPILER="${env:HIP_PATH}\lib\llvm\bin\clang.exe" `
|
-DCMAKE_CXX_COMPILER="${env:HIP_PATH}\bin\clang++.exe" `
|
||||||
-DCMAKE_CXX_COMPILER="${env:HIP_PATH}\lib\llvm\bin\clang++.exe" `
|
-DCMAKE_CXX_FLAGS="-I$($PWD.Path.Replace('\', '/'))/opt/rocm-7.2.1/include/" `
|
||||||
-DCMAKE_HIP_COMPILER="${env:HIP_PATH}\lib\llvm\bin\clang.exe" `
|
|
||||||
-DCMAKE_BUILD_TYPE=Release `
|
-DCMAKE_BUILD_TYPE=Release `
|
||||||
-DLLAMA_BUILD_BORINGSSL=ON `
|
-DLLAMA_BUILD_BORINGSSL=ON `
|
||||||
-DHIP_PATH="${env:HIP_PATH}" `
|
-DROCM_DIR="${env:HIP_PATH}" `
|
||||||
-DGGML_HIP=ON `
|
-DGGML_HIP=ON `
|
||||||
-DGPU_TARGETS="gfx1100" `
|
-DGGML_HIP_ROCWMMA_FATTN=ON `
|
||||||
|
-DGPU_TARGETS="gfx1100" `
|
||||||
-DGGML_RPC=ON
|
-DGGML_RPC=ON
|
||||||
cmake --build build -j ${env:NUMBER_OF_PROCESSORS}
|
cmake --build build -j ${env:NUMBER_OF_PROCESSORS}
|
||||||
|
|
||||||
- name: ccache-clear
|
- name: ccache-clear
|
||||||
uses: ./.github/actions/ccache-clear
|
uses: ./.github/actions/ccache-clear
|
||||||
with:
|
with:
|
||||||
#key: release-windows-2022-x64-hip-${{ env.ROCM_VERSION }}-${{ matrix.name }}
|
#key: release-windows-2022-x64-hip-${{ env.HIPSDK_INSTALLER_VERSION }}-${{ matrix.name }}
|
||||||
key: cuda-windows-2022-x64-hip-${{ env.ROCM_VERSION }}-${{ matrix.name }}
|
key: cuda-windows-2022-x64-hip-${{ env.HIPSDK_INSTALLER_VERSION }}-${{ matrix.name }}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ jobs:
|
|||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
#- name: ccache
|
#- name: ccache
|
||||||
# uses: ggml-org/ccache-action@v1.2.24
|
# uses: ggml-org/ccache-action@v1.2.16
|
||||||
# with:
|
# with:
|
||||||
# key: msys-windows-2025-x64
|
# key: msys-windows-2025-x64
|
||||||
# variant: ccache
|
# variant: ccache
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ jobs:
|
|||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: ccache
|
- name: ccache
|
||||||
uses: ggml-org/ccache-action@v1.2.24
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
with:
|
with:
|
||||||
key: opencl-windows-2025-x64
|
key: opencl-windows-2025-x64
|
||||||
variant: ccache
|
variant: ccache
|
||||||
@@ -80,13 +80,3 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cmake -S . -B build -G "Ninja Multi-Config" -D CMAKE_TOOLCHAIN_FILE=cmake/arm64-windows-llvm.cmake -DCMAKE_PREFIX_PATH="$env:RUNNER_TEMP/opencl-arm64-release" -DGGML_OPENCL=ON -DGGML_OPENCL_USE_ADRENO_KERNELS=ON -DLLAMA_BUILD_BORINGSSL=ON
|
cmake -S . -B build -G "Ninja Multi-Config" -D CMAKE_TOOLCHAIN_FILE=cmake/arm64-windows-llvm.cmake -DCMAKE_PREFIX_PATH="$env:RUNNER_TEMP/opencl-arm64-release" -DGGML_OPENCL=ON -DGGML_OPENCL_USE_ADRENO_KERNELS=ON -DLLAMA_BUILD_BORINGSSL=ON
|
||||||
cmake --build build --config Release -j ${env:NUMBER_OF_PROCESSORS}
|
cmake --build build --config Release -j ${env:NUMBER_OF_PROCESSORS}
|
||||||
|
|
||||||
- name: ccache-clear
|
|
||||||
uses: ./.github/actions/ccache-clear
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ github.token }}
|
|
||||||
with:
|
|
||||||
key: opencl-windows-2025-x64
|
|
||||||
older: 5m
|
|
||||||
min: 1
|
|
||||||
dry-run: ${{ github.event_name != 'push' || github.ref != 'refs/heads/master' }}
|
|
||||||
|
|||||||
@@ -32,8 +32,6 @@ env:
|
|||||||
LLAMA_ARG_LOG_COLORS: 1
|
LLAMA_ARG_LOG_COLORS: 1
|
||||||
LLAMA_ARG_LOG_PREFIX: 1
|
LLAMA_ARG_LOG_PREFIX: 1
|
||||||
LLAMA_ARG_LOG_TIMESTAMPS: 1
|
LLAMA_ARG_LOG_TIMESTAMPS: 1
|
||||||
# TODO: fix failing tests on OpenVINO backend
|
|
||||||
CTEST_EXCLUDE: "test-llama-archs|^test-recurrent-state-|test-backend-ops|test-save-load-state"
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
ubuntu-24-openvino:
|
ubuntu-24-openvino:
|
||||||
@@ -41,8 +39,8 @@ jobs:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
# Sync versions in build-openvino.yml, build-self-hosted.yml, release.yml, build-cache.yml, .devops/openvino.Dockerfile
|
# Sync versions in build-openvino.yml, build-self-hosted.yml, release.yml, build-cache.yml, .devops/openvino.Dockerfile
|
||||||
OPENVINO_VERSION_MAJOR: "2026.3.1"
|
OPENVINO_VERSION_MAJOR: "2026.2.1"
|
||||||
OPENVINO_VERSION_FULL: "2026.3.1.22476.56d9685302d"
|
OPENVINO_VERSION_FULL: "2026.2.1.21919.ede283a88e3"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Clone
|
- name: Clone
|
||||||
@@ -80,24 +78,26 @@ jobs:
|
|||||||
|
|
||||||
- name: Test (CPU)
|
- name: Test (CPU)
|
||||||
id: cmake_test_cpu
|
id: cmake_test_cpu
|
||||||
|
# TODO: fix and re-enable the `test-llama-archs` test below
|
||||||
run: |
|
run: |
|
||||||
cd ${{ github.workspace }}
|
cd ${{ github.workspace }}
|
||||||
ctest --test-dir build/ReleaseOV -L main -E "${{ env.CTEST_EXCLUDE }}" --verbose --timeout 3000
|
ctest --test-dir build/ReleaseOV -L main -E "test-llama-archs" --verbose --timeout 2000
|
||||||
|
|
||||||
- name: Test (GPU)
|
- name: Test (GPU)
|
||||||
id: cmake_test_gpu
|
id: cmake_test_gpu
|
||||||
|
# TODO: fix and re-enable the `test-llama-archs` test below
|
||||||
run: |
|
run: |
|
||||||
cd ${{ github.workspace }}
|
cd ${{ github.workspace }}
|
||||||
export GGML_OPENVINO_DEVICE=GPU
|
export GGML_OPENVINO_DEVICE=GPU
|
||||||
ctest --test-dir build/ReleaseOV -L main -E "${{ env.CTEST_EXCLUDE }}" --verbose --timeout 3000
|
ctest --test-dir build/ReleaseOV -L main -E "test-llama-archs" --verbose --timeout 3000
|
||||||
|
|
||||||
openvino-windows-2022:
|
openvino-windows-2022:
|
||||||
runs-on: windows-2022
|
runs-on: windows-2022
|
||||||
|
|
||||||
env:
|
env:
|
||||||
# Sync versions in build-openvino.yml, build-self-hosted.yml, release.yml, build-cache.yml, .devops/openvino.Dockerfile
|
# Sync versions in build-openvino.yml, build-self-hosted.yml, release.yml, build-cache.yml, .devops/openvino.Dockerfile
|
||||||
OPENVINO_VERSION_MAJOR: "2026.3.1"
|
OPENVINO_VERSION_MAJOR: "2026.2.1"
|
||||||
OPENVINO_VERSION_FULL: "2026.3.1.22476.56d9685302d"
|
OPENVINO_VERSION_FULL: "2026.2.1.21919.ede283a88e3"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Clone
|
- name: Clone
|
||||||
@@ -105,7 +105,7 @@ jobs:
|
|||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: ccache
|
- name: ccache
|
||||||
uses: ggml-org/ccache-action@v1.2.24
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
with:
|
with:
|
||||||
key: openvino-windows-2022
|
key: openvino-windows-2022
|
||||||
variant: ccache
|
variant: ccache
|
||||||
@@ -159,20 +159,11 @@ jobs:
|
|||||||
- name: Test (CPU)
|
- name: Test (CPU)
|
||||||
id: cmake_test_cpu
|
id: cmake_test_cpu
|
||||||
shell: cmd
|
shell: cmd
|
||||||
|
# TODO: fix and re-enable the `test-llama-archs` test below
|
||||||
run: |
|
run: |
|
||||||
REM Find extracted OpenVINO folder dynamically
|
REM Find extracted OpenVINO folder dynamically
|
||||||
for /d %%i in (openvino_toolkit\*) do set OPENVINO_ROOT=%%i
|
for /d %%i in (openvino_toolkit\*) do set OPENVINO_ROOT=%%i
|
||||||
call "%OPENVINO_ROOT%\setupvars.bat"
|
call "%OPENVINO_ROOT%\setupvars.bat"
|
||||||
|
|
||||||
cd build
|
cd build
|
||||||
ctest --test-dir ReleaseOV -L main -E "${{ env.CTEST_EXCLUDE }}" -C Release --verbose --timeout 3000
|
ctest --test-dir ReleaseOV -L main -E "test-llama-archs" -C Release --verbose --timeout 3000
|
||||||
|
|
||||||
- name: ccache-clear
|
|
||||||
uses: ./.github/actions/ccache-clear
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ github.token }}
|
|
||||||
with:
|
|
||||||
key: openvino-windows-2022
|
|
||||||
older: 5m
|
|
||||||
min: 1
|
|
||||||
dry-run: ${{ github.event_name != 'push' || github.ref != 'refs/heads/master' }}
|
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ jobs:
|
|||||||
|
|
||||||
# note: sparing some ccache since these jobs run on dedicated runners that are not part of the organitzation
|
# note: sparing some ccache since these jobs run on dedicated runners that are not part of the organitzation
|
||||||
#- name: ccache
|
#- name: ccache
|
||||||
# uses: ggml-org/ccache-action@v1.2.24
|
# uses: ggml-org/ccache-action@afde29e5b5422e5da23cb1f639e8baecadeadfc3 # https://github.com/ggml-org/ccache-action/pull/1
|
||||||
# with:
|
# with:
|
||||||
# key: riscv-ubuntu-native
|
# key: riscv-ubuntu-native
|
||||||
# evict-old-files: 1d
|
# evict-old-files: 1d
|
||||||
@@ -137,7 +137,7 @@ jobs:
|
|||||||
|
|
||||||
# note: sparing some ccache since these jobs run on dedicated runners that are not part of the organitzation
|
# note: sparing some ccache since these jobs run on dedicated runners that are not part of the organitzation
|
||||||
#- name: ccache
|
#- name: ccache
|
||||||
# uses: ggml-org/ccache-action@v1.2.24
|
# uses: ggml-org/ccache-action@afde29e5b5422e5da23cb1f639e8baecadeadfc3 # https://github.com/ggml-org/ccache-action/pull/1
|
||||||
# with:
|
# with:
|
||||||
# key: riscv-ubuntu-native-sanitizer-${{ matrix.sanitizer }}-${{ matrix.build_type }}
|
# key: riscv-ubuntu-native-sanitizer-${{ matrix.sanitizer }}-${{ matrix.build_type }}
|
||||||
# evict-old-files: 1d
|
# evict-old-files: 1d
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
name: CI (rpc)
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch: # allows manual triggering
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
paths: [
|
||||||
|
'.github/workflows/build-rpc.yml',
|
||||||
|
'**/CMakeLists.txt',
|
||||||
|
'**/.cmake',
|
||||||
|
'**/*.h',
|
||||||
|
'**/*.hpp',
|
||||||
|
'**/*.c',
|
||||||
|
'**/*.cpp'
|
||||||
|
]
|
||||||
|
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize, reopened]
|
||||||
|
paths: [
|
||||||
|
'.github/workflows/build-rpc.yml',
|
||||||
|
'ggml/src/ggml-rpc/**'
|
||||||
|
]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
env:
|
||||||
|
GGML_NLOOP: 3
|
||||||
|
GGML_N_THREADS: 1
|
||||||
|
LLAMA_ARG_LOG_COLORS: 1
|
||||||
|
LLAMA_ARG_LOG_PREFIX: 1
|
||||||
|
LLAMA_ARG_LOG_TIMESTAMPS: 1
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
ubuntu-24-rpc:
|
||||||
|
runs-on: ${{ 'ubuntu-24.04-arm' || 'ubuntu-24.04' }}
|
||||||
|
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
id: checkout
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Dependencies
|
||||||
|
id: depends
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install build-essential libssl-dev ninja-build
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
id: cmake_build
|
||||||
|
run: |
|
||||||
|
cmake -B build \
|
||||||
|
-G "Ninja" \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DGGML_RPC=ON
|
||||||
|
time cmake --build build --config Release -j $(nproc)
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
id: cmake_test
|
||||||
|
run: |
|
||||||
|
cd build
|
||||||
|
ctest -L main --verbose
|
||||||
@@ -15,12 +15,6 @@ on:
|
|||||||
'**/*.cpp'
|
'**/*.cpp'
|
||||||
]
|
]
|
||||||
|
|
||||||
pull_request:
|
|
||||||
types: [opened, synchronize, reopened]
|
|
||||||
paths: [
|
|
||||||
'.github/workflows/build-sanitize.yml'
|
|
||||||
]
|
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
|
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
@@ -34,35 +28,19 @@ env:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
ctest:
|
ctest:
|
||||||
|
runs-on: [self-hosted, X64, CPU, Linux]
|
||||||
|
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
sanitizer: [ADDRESS, THREAD, UNDEFINED]
|
||||||
# thread and address doesn't run properly on some self hosted machines, so run it on Github instead
|
|
||||||
- sanitizer: ADDRESS
|
|
||||||
machine: ubuntu-24.04
|
|
||||||
- sanitizer: THREAD
|
|
||||||
machine: ubuntu-24.04
|
|
||||||
- sanitizer: UNDEFINED
|
|
||||||
machine: [self-hosted, X64, Linux]
|
|
||||||
|
|
||||||
runs-on: ${{ matrix.machine }}
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Clone
|
- name: Clone
|
||||||
id: checkout
|
id: checkout
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
# - name: ccache
|
|
||||||
# uses: ggml-org/ccache-action@v1.2.24
|
|
||||||
# if: ${{ matrix.sanitizer != 'UNDEFINED' }}
|
|
||||||
# with:
|
|
||||||
# key: ctest-${{ matrix.sanitizer }}-ubuntu-24.04
|
|
||||||
# variant: ccache
|
|
||||||
# evict-old-files: 1d
|
|
||||||
# save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
|
||||||
|
|
||||||
# with UNDEFINED sanitizer, we have to build in Debug to avoid GCC 13 false-positive warnings
|
# with UNDEFINED sanitizer, we have to build in Debug to avoid GCC 13 false-positive warnings
|
||||||
- name: Build (undefined)
|
- name: Build (undefined)
|
||||||
id: cmake_build_undefined
|
id: cmake_build_undefined
|
||||||
|
|||||||
@@ -71,26 +71,6 @@ jobs:
|
|||||||
nvidia-smi
|
nvidia-smi
|
||||||
GG_BUILD_CUDA=1 bash ./ci/run.sh ~/results/llama.cpp ~/mnt/llama.cpp
|
GG_BUILD_CUDA=1 bash ./ci/run.sh ~/results/llama.cpp ~/mnt/llama.cpp
|
||||||
|
|
||||||
gpu-rocm:
|
|
||||||
runs-on: [self-hosted, Linux, AMD]
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Clone
|
|
||||||
id: checkout
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
|
|
||||||
- name: Test
|
|
||||||
id: ggml-ci
|
|
||||||
# HIP_LAUNCH_BLOCKING=1: workaround for an async-execution correctness
|
|
||||||
# issue on integrated RDNA3.5 (gfx1151) where batched inference returns
|
|
||||||
# incorrect output (perplexity ~88 vs ~9.4). Serializing kernel launches
|
|
||||||
# restores correctness. Remove once the underlying ROCm/HIP issue is fixed.
|
|
||||||
env:
|
|
||||||
HIP_LAUNCH_BLOCKING: "1"
|
|
||||||
run: |
|
|
||||||
rocminfo
|
|
||||||
GG_BUILD_ROCM=1 GG_BUILD_AMDGPU_TARGETS=gfx1151 bash ./ci/run.sh ~/results/llama.cpp ~/mnt/llama.cpp
|
|
||||||
|
|
||||||
gpu-vulkan-nvidia-cm:
|
gpu-vulkan-nvidia-cm:
|
||||||
runs-on: [self-hosted, Linux, NVIDIA]
|
runs-on: [self-hosted, Linux, NVIDIA]
|
||||||
|
|
||||||
@@ -288,8 +268,8 @@ jobs:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
# Sync versions in build.yml, build-self-hosted.yml, release.yml, build-cache.yml, .devops/openvino.Dockerfile
|
# Sync versions in build.yml, build-self-hosted.yml, release.yml, build-cache.yml, .devops/openvino.Dockerfile
|
||||||
OPENVINO_VERSION_MAJOR: "2026.3.1"
|
OPENVINO_VERSION_MAJOR: "2026.2.1"
|
||||||
OPENVINO_VERSION_FULL: "2026.3.1.22476.56d9685302d"
|
OPENVINO_VERSION_FULL: "2026.2.1.21919.ede283a88e3"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Clone
|
- name: Clone
|
||||||
|
|||||||
@@ -75,19 +75,11 @@ jobs:
|
|||||||
sudo apt-get install -y ./level-zero.deb ./level-zero-devel.deb
|
sudo apt-get install -y ./level-zero.deb ./level-zero-devel.deb
|
||||||
|
|
||||||
- name: ccache
|
- name: ccache
|
||||||
uses: ggml-org/ccache-action@v1.2.24
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
with:
|
with:
|
||||||
key: sycl-ubuntu-24-${{ matrix.build }}
|
key: sycl-ubuntu-24-${{ matrix.build }}
|
||||||
save: false
|
evict-old-files: 1d
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
- name: ccache-buckets-restore
|
|
||||||
uses: ./.github/actions/ccache-buckets
|
|
||||||
env:
|
|
||||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CI }}
|
|
||||||
with:
|
|
||||||
key: sycl-ubuntu-24-${{ matrix.build }}
|
|
||||||
folder: llama.cpp
|
|
||||||
hf_bucket: ggml-org/cache
|
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
id: cmake_build
|
id: cmake_build
|
||||||
@@ -104,18 +96,6 @@ jobs:
|
|||||||
-DGGML_SYCL_F16=${{ matrix.fp16 }}
|
-DGGML_SYCL_F16=${{ matrix.fp16 }}
|
||||||
time cmake --build build --config Release -j $(nproc)
|
time cmake --build build --config Release -j $(nproc)
|
||||||
|
|
||||||
- name: ccache-buckets-save
|
|
||||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
|
||||||
uses: ./.github/actions/ccache-buckets
|
|
||||||
env:
|
|
||||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CACHE_OUTPUT }}
|
|
||||||
with:
|
|
||||||
key: sycl-ubuntu-24-${{ matrix.build }}
|
|
||||||
folder: llama.cpp
|
|
||||||
evict-old-files: 1d
|
|
||||||
hf_bucket: ggml-org/cache
|
|
||||||
save: true
|
|
||||||
|
|
||||||
windows-latest-sycl:
|
windows-latest-sycl:
|
||||||
runs-on: windows-2022
|
runs-on: windows-2022
|
||||||
|
|
||||||
@@ -147,7 +127,7 @@ jobs:
|
|||||||
"LEVEL_ZERO_V1_SDK_PATH=C:/level-zero-sdk" | Out-File -FilePath $env:GITHUB_ENV -Append
|
"LEVEL_ZERO_V1_SDK_PATH=C:/level-zero-sdk" | Out-File -FilePath $env:GITHUB_ENV -Append
|
||||||
|
|
||||||
- name: ccache
|
- name: ccache
|
||||||
uses: ggml-org/ccache-action@v1.2.24
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
with:
|
with:
|
||||||
key: sycl-windows-latest
|
key: sycl-windows-latest
|
||||||
variant: ccache
|
variant: ccache
|
||||||
@@ -159,13 +139,3 @@ jobs:
|
|||||||
- name: Build
|
- name: Build
|
||||||
id: cmake_build
|
id: cmake_build
|
||||||
run: examples/sycl/win-build-sycl.bat
|
run: examples/sycl/win-build-sycl.bat
|
||||||
|
|
||||||
- name: ccache-clear
|
|
||||||
uses: ./.github/actions/ccache-clear
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ github.token }}
|
|
||||||
with:
|
|
||||||
key: sycl-windows-latest
|
|
||||||
older: 5m
|
|
||||||
min: 1
|
|
||||||
dry-run: ${{ github.event_name != 'push' || github.ref != 'refs/heads/master' }}
|
|
||||||
|
|||||||
@@ -53,20 +53,12 @@ jobs:
|
|||||||
echo "CXX=g++-14" >> "$GITHUB_ENV"
|
echo "CXX=g++-14" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
- name: ccache
|
- name: ccache
|
||||||
uses: ggml-org/ccache-action@v1.2.24
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
with:
|
with:
|
||||||
key: vulkan-ubuntu-24.04-arm
|
key: vulkan-ubuntu-24.04-arm-new
|
||||||
variant: ccache
|
variant: ccache
|
||||||
save: false
|
evict-old-files: 1d
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
- name: ccache-buckets-restore
|
|
||||||
uses: ./.github/actions/ccache-buckets
|
|
||||||
env:
|
|
||||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CI }}
|
|
||||||
with:
|
|
||||||
key: vulkan-ubuntu-24.04-arm
|
|
||||||
folder: llama.cpp
|
|
||||||
hf_bucket: ggml-org/cache
|
|
||||||
|
|
||||||
- name: Configure
|
- name: Configure
|
||||||
id: cmake_configure
|
id: cmake_configure
|
||||||
@@ -81,18 +73,6 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
time cmake --build build -j $(nproc)
|
time cmake --build build -j $(nproc)
|
||||||
|
|
||||||
- name: ccache-buckets-save
|
|
||||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
|
||||||
uses: ./.github/actions/ccache-buckets
|
|
||||||
env:
|
|
||||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CACHE_OUTPUT }}
|
|
||||||
with:
|
|
||||||
key: vulkan-ubuntu-24.04-arm
|
|
||||||
folder: llama.cpp
|
|
||||||
evict-old-files: 1d
|
|
||||||
hf_bucket: ggml-org/cache
|
|
||||||
save: true
|
|
||||||
|
|
||||||
ubuntu-llvmpipe:
|
ubuntu-llvmpipe:
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
|
|
||||||
@@ -113,50 +93,35 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
echo "VULKAN_SDK_VERSION=$(curl https://vulkan.lunarg.com/sdk/latest/linux.txt)" >> "$GITHUB_ENV"
|
echo "VULKAN_SDK_VERSION=$(curl https://vulkan.lunarg.com/sdk/latest/linux.txt)" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
- name: Setup Vulkan SDK
|
- name: Use Vulkan SDK Cache
|
||||||
id: setup
|
uses: actions/cache@v5
|
||||||
uses: ./.github/actions/unarchive-tar
|
id: cache-sdk
|
||||||
with:
|
with:
|
||||||
url: https://sdk.lunarg.com/sdk/download/${{ env.VULKAN_SDK_VERSION }}/linux/vulkan_sdk.tar.xz
|
|
||||||
path: ./vulkan_sdk
|
path: ./vulkan_sdk
|
||||||
strip: 1
|
key: cache-gha-vulkan-sdk-${{ env.VULKAN_SDK_VERSION }}-${{ runner.os }}
|
||||||
|
|
||||||
|
- name: Setup Vulkan SDK
|
||||||
|
if: steps.cache-sdk.outputs.cache-hit != 'true'
|
||||||
|
uses: ./.github/actions/linux-setup-vulkan
|
||||||
|
with:
|
||||||
|
path: ./vulkan_sdk
|
||||||
|
version: ${{ env.VULKAN_SDK_VERSION }}
|
||||||
|
|
||||||
- name: ccache
|
- name: ccache
|
||||||
uses: ggml-org/ccache-action@v1.2.24
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
with:
|
with:
|
||||||
key: vulkan-ubuntu-24.04-llvmpipe
|
key: vulkan-ubuntu-24.04-llvmpipe
|
||||||
save: false
|
evict-old-files: 1d
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
- name: ccache-buckets-restore
|
|
||||||
uses: ./.github/actions/ccache-buckets
|
|
||||||
env:
|
|
||||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CI }}
|
|
||||||
with:
|
|
||||||
key: vulkan-ubuntu-24.04-llvmpipe
|
|
||||||
folder: llama.cpp
|
|
||||||
hf_bucket: ggml-org/cache
|
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
id: cmake_build
|
id: cmake_build
|
||||||
run: |
|
run: |
|
||||||
source ./vulkan_sdk/setup-env.sh
|
source ./vulkan_sdk/setup-env.sh
|
||||||
cmake -B build \
|
cmake -B build \
|
||||||
-DGGML_NATIVE=OFF \
|
|
||||||
-DGGML_VULKAN=ON
|
-DGGML_VULKAN=ON
|
||||||
cmake --build build --config Release -j $(nproc)
|
cmake --build build --config Release -j $(nproc)
|
||||||
|
|
||||||
- name: ccache-buckets-save
|
|
||||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
|
||||||
uses: ./.github/actions/ccache-buckets
|
|
||||||
env:
|
|
||||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CACHE_OUTPUT }}
|
|
||||||
with:
|
|
||||||
key: vulkan-ubuntu-24.04-llvmpipe
|
|
||||||
folder: llama.cpp
|
|
||||||
evict-old-files: 1d
|
|
||||||
hf_bucket: ggml-org/cache
|
|
||||||
save: true
|
|
||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
id: cmake_test
|
id: cmake_test
|
||||||
run: |
|
run: |
|
||||||
@@ -167,66 +132,3 @@ jobs:
|
|||||||
# This is using llvmpipe and runs slower than other backends
|
# This is using llvmpipe and runs slower than other backends
|
||||||
# test-backend-ops is too slow on llvmpipe, skip it
|
# test-backend-ops is too slow on llvmpipe, skip it
|
||||||
ctest -L main -E test-backend-ops --verbose --timeout 900
|
ctest -L main -E test-backend-ops --verbose --timeout 900
|
||||||
|
|
||||||
windows:
|
|
||||||
runs-on: windows-2025
|
|
||||||
|
|
||||||
env:
|
|
||||||
VULKAN_VERSION: 1.4.357.0
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Clone
|
|
||||||
id: checkout
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
|
|
||||||
- name: ccache
|
|
||||||
uses: ggml-org/ccache-action@v1.2.24
|
|
||||||
with:
|
|
||||||
key: cpu-windows-2025-x64-vulkan
|
|
||||||
variant: ccache
|
|
||||||
evict-old-files: 1d
|
|
||||||
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
|
||||||
|
|
||||||
- name: Install Vulkan SDK
|
|
||||||
id: get_vulkan
|
|
||||||
run: |
|
|
||||||
curl.exe -o $env:RUNNER_TEMP/VulkanSDK-Installer.exe -L "https://sdk.lunarg.com/sdk/download/${env:VULKAN_VERSION}/windows/vulkansdk-windows-X64-${env:VULKAN_VERSION}.exe"
|
|
||||||
& "$env:RUNNER_TEMP\VulkanSDK-Installer.exe" --accept-licenses --default-answer --confirm-command install
|
|
||||||
Add-Content $env:GITHUB_ENV "VULKAN_SDK=C:\VulkanSDK\${env:VULKAN_VERSION}"
|
|
||||||
Add-Content $env:GITHUB_PATH "C:\VulkanSDK\${env:VULKAN_VERSION}\bin"
|
|
||||||
|
|
||||||
- name: Install Ninja
|
|
||||||
id: install_ninja
|
|
||||||
run: |
|
|
||||||
choco install ninja
|
|
||||||
|
|
||||||
- name: Build
|
|
||||||
id: cmake_build
|
|
||||||
run: |
|
|
||||||
cmake -S . -B build -G "Ninja Multi-Config" `
|
|
||||||
-D CMAKE_TOOLCHAIN_FILE=cmake/x64-windows-llvm.cmake `
|
|
||||||
-DCMAKE_BUILD_TYPE=Release `
|
|
||||||
-DGGML_NATIVE=OFF `
|
|
||||||
-DLLAMA_BUILD_SERVER=ON `
|
|
||||||
-DGGML_RPC=ON `
|
|
||||||
-DGGML_BACKEND_DL=ON `
|
|
||||||
-DGGML_CPU_ALL_VARIANTS=ON `
|
|
||||||
-DGGML_VULKAN=ON `
|
|
||||||
-DLLAMA_BUILD_BORINGSSL=ON
|
|
||||||
cmake --build build --config Release -j ${env:NUMBER_OF_PROCESSORS}
|
|
||||||
|
|
||||||
- name: Test
|
|
||||||
id: cmake_test
|
|
||||||
run: |
|
|
||||||
cd build
|
|
||||||
ctest -L main -C Release --verbose --timeout 900
|
|
||||||
|
|
||||||
- name: ccache-clear
|
|
||||||
uses: ./.github/actions/ccache-clear
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ github.token }}
|
|
||||||
with:
|
|
||||||
key: cpu-windows-2025-x64-vulkan
|
|
||||||
older: 5m
|
|
||||||
min: 1
|
|
||||||
dry-run: ${{ github.event_name != 'push' || github.ref != 'refs/heads/master' }}
|
|
||||||
|
|||||||
@@ -54,10 +54,11 @@ jobs:
|
|||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: ccache
|
- name: ccache
|
||||||
uses: ggml-org/ccache-action@v1.2.24
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
with:
|
with:
|
||||||
key: webgpu-ubuntu-24.04-arm-wasm
|
key: webgpu-ubuntu-24.04-arm-wasm
|
||||||
save: false
|
evict-old-files: 1d
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
|
|
||||||
- name: Install Emscripten
|
- name: Install Emscripten
|
||||||
run: |
|
run: |
|
||||||
@@ -75,15 +76,6 @@ jobs:
|
|||||||
"https://github.com/google/dawn/releases/download/${DAWN_TAG}/${EMDAWN_PKG}"
|
"https://github.com/google/dawn/releases/download/${DAWN_TAG}/${EMDAWN_PKG}"
|
||||||
unzip emdawn.zip
|
unzip emdawn.zip
|
||||||
|
|
||||||
- name: ccache-buckets-restore
|
|
||||||
uses: ./.github/actions/ccache-buckets
|
|
||||||
env:
|
|
||||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CI }}
|
|
||||||
with:
|
|
||||||
key: webgpu-ubuntu-24.04-arm-wasm
|
|
||||||
folder: llama.cpp
|
|
||||||
hf_bucket: ggml-org/cache
|
|
||||||
|
|
||||||
- name: Build WASM WebGPU
|
- name: Build WASM WebGPU
|
||||||
run: |
|
run: |
|
||||||
source emsdk/emsdk_env.sh
|
source emsdk/emsdk_env.sh
|
||||||
@@ -96,15 +88,3 @@ jobs:
|
|||||||
-DEMDAWNWEBGPU_DIR=emdawnwebgpu_pkg
|
-DEMDAWNWEBGPU_DIR=emdawnwebgpu_pkg
|
||||||
|
|
||||||
time cmake --build build-wasm --config Release --target test-backend-ops -j $(nproc)
|
time cmake --build build-wasm --config Release --target test-backend-ops -j $(nproc)
|
||||||
|
|
||||||
- name: ccache-buckets-save
|
|
||||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
|
||||||
uses: ./.github/actions/ccache-buckets
|
|
||||||
env:
|
|
||||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CACHE_OUTPUT }}
|
|
||||||
with:
|
|
||||||
key: webgpu-ubuntu-24.04-arm-wasm
|
|
||||||
folder: llama.cpp
|
|
||||||
evict-old-files: 1d
|
|
||||||
hf_bucket: ggml-org/cache
|
|
||||||
save: true
|
|
||||||
|
|||||||
@@ -69,10 +69,11 @@ jobs:
|
|||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: ccache
|
- name: ccache
|
||||||
uses: ggml-org/ccache-action@v1.2.24
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
with:
|
with:
|
||||||
key: webgpu-macos-latest
|
key: webgpu-macos-latest
|
||||||
save: false
|
evict-old-files: 1d
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
|
|
||||||
- name: Dawn Dependency
|
- name: Dawn Dependency
|
||||||
id: dawn-depends
|
id: dawn-depends
|
||||||
@@ -87,15 +88,6 @@ jobs:
|
|||||||
mkdir dawn
|
mkdir dawn
|
||||||
tar -xvf artifact.tar.gz -C dawn --strip-components=1
|
tar -xvf artifact.tar.gz -C dawn --strip-components=1
|
||||||
|
|
||||||
- name: ccache-buckets-restore
|
|
||||||
uses: ./.github/actions/ccache-buckets
|
|
||||||
env:
|
|
||||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CI }}
|
|
||||||
with:
|
|
||||||
key: webgpu-macos-latest
|
|
||||||
folder: llama.cpp
|
|
||||||
hf_bucket: ggml-org/cache
|
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
id: cmake_build
|
id: cmake_build
|
||||||
run: |
|
run: |
|
||||||
@@ -103,18 +95,6 @@ jobs:
|
|||||||
cmake -B build -G "Ninja" -DCMAKE_BUILD_TYPE=Release -DGGML_WEBGPU=ON -DGGML_METAL=OFF -DGGML_BLAS=OFF
|
cmake -B build -G "Ninja" -DCMAKE_BUILD_TYPE=Release -DGGML_WEBGPU=ON -DGGML_METAL=OFF -DGGML_BLAS=OFF
|
||||||
time cmake --build build --config Release -j $(sysctl -n hw.logicalcpu)
|
time cmake --build build --config Release -j $(sysctl -n hw.logicalcpu)
|
||||||
|
|
||||||
- name: ccache-buckets-save
|
|
||||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
|
||||||
uses: ./.github/actions/ccache-buckets
|
|
||||||
env:
|
|
||||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CACHE_OUTPUT }}
|
|
||||||
with:
|
|
||||||
key: webgpu-macos-latest
|
|
||||||
folder: llama.cpp
|
|
||||||
evict-old-files: 1d
|
|
||||||
hf_bucket: ggml-org/cache
|
|
||||||
save: true
|
|
||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
id: cmake_test
|
id: cmake_test
|
||||||
run: |
|
run: |
|
||||||
@@ -130,10 +110,11 @@ jobs:
|
|||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: ccache
|
- name: ccache
|
||||||
uses: ggml-org/ccache-action@v1.2.24
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
with:
|
with:
|
||||||
key: webgpu-ubuntu-24.04
|
key: webgpu-ubuntu-24.04
|
||||||
save: false
|
evict-old-files: 1d
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
|
|
||||||
- name: Dependencies
|
- name: Dependencies
|
||||||
id: depends
|
id: depends
|
||||||
@@ -157,15 +138,6 @@ jobs:
|
|||||||
mkdir dawn
|
mkdir dawn
|
||||||
tar -xvf artifact.tar.gz -C dawn --strip-components=1
|
tar -xvf artifact.tar.gz -C dawn --strip-components=1
|
||||||
|
|
||||||
- name: ccache-buckets-restore
|
|
||||||
uses: ./.github/actions/ccache-buckets
|
|
||||||
env:
|
|
||||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CI }}
|
|
||||||
with:
|
|
||||||
key: webgpu-ubuntu-24.04
|
|
||||||
folder: llama.cpp
|
|
||||||
hf_bucket: ggml-org/cache
|
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
id: cmake_build
|
id: cmake_build
|
||||||
run: |
|
run: |
|
||||||
@@ -174,18 +146,6 @@ jobs:
|
|||||||
-DGGML_WEBGPU=ON
|
-DGGML_WEBGPU=ON
|
||||||
time cmake --build build --config Release -j $(nproc)
|
time cmake --build build --config Release -j $(nproc)
|
||||||
|
|
||||||
- name: ccache-buckets-save
|
|
||||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
|
||||||
uses: ./.github/actions/ccache-buckets
|
|
||||||
env:
|
|
||||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CACHE_OUTPUT }}
|
|
||||||
with:
|
|
||||||
key: webgpu-ubuntu-24.04
|
|
||||||
folder: llama.cpp
|
|
||||||
evict-old-files: 1d
|
|
||||||
hf_bucket: ggml-org/cache
|
|
||||||
save: true
|
|
||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
id: cmake_test
|
id: cmake_test
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ jobs:
|
|||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: ccache
|
- name: ccache
|
||||||
uses: ggml-org/ccache-action@v1.2.24
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
with:
|
with:
|
||||||
key: copilot-setup-steps
|
key: copilot-setup-steps
|
||||||
evict-old-files: 1d
|
evict-old-files: 1d
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ jobs:
|
|||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
ssh-key: ${{ secrets.DEPLOY_KEY_RELEASE }}
|
|
||||||
|
|
||||||
- name: Determine source tag name
|
- name: Determine source tag name
|
||||||
id: srctag
|
id: srctag
|
||||||
@@ -64,7 +63,7 @@ jobs:
|
|||||||
needs: create_tag
|
needs: create_tag
|
||||||
uses: ./.github/workflows/ui-build.yml
|
uses: ./.github/workflows/ui-build.yml
|
||||||
with:
|
with:
|
||||||
ui_version: ${{ needs.create_tag.outputs.source_tag }}
|
hf_ui_version: ${{ needs.create_tag.outputs.source_tag }}
|
||||||
|
|
||||||
prepare_matrices:
|
prepare_matrices:
|
||||||
name: Prepare Docker matrices
|
name: Prepare Docker matrices
|
||||||
@@ -162,7 +161,7 @@ jobs:
|
|||||||
if: ${{ matrix.config.prebuilt_ui == true }}
|
if: ${{ matrix.config.prebuilt_ui == true }}
|
||||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||||
with:
|
with:
|
||||||
name: llama-ui.zip
|
name: ui-build
|
||||||
path: tools/ui/dist
|
path: tools/ui/dist
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
@@ -394,11 +393,6 @@ jobs:
|
|||||||
name: Create shared tags from digests
|
name: Create shared tags from digests
|
||||||
needs: [prepare_matrices, push_to_registry, create_tag]
|
needs: [prepare_matrices, push_to_registry, create_tag]
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
packages: write
|
|
||||||
id-token: write
|
|
||||||
attestations: write
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
@@ -433,7 +427,6 @@ jobs:
|
|||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Create tags from digests
|
- name: Create tags from digests
|
||||||
id: create_tags
|
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
@@ -445,7 +438,6 @@ jobs:
|
|||||||
SRC_TAG="${{ needs.create_tag.outputs.source_tag }}"
|
SRC_TAG="${{ needs.create_tag.outputs.source_tag }}"
|
||||||
BUILD_DATE="${{ steps.build_date.outputs.date }}"
|
BUILD_DATE="${{ steps.build_date.outputs.date }}"
|
||||||
COMMIT_SHA="${{ steps.checkout.outputs.commit }}"
|
COMMIT_SHA="${{ steps.checkout.outputs.commit }}"
|
||||||
echo "image_repo=${IMAGE_REPO}" >> "$GITHUB_OUTPUT"
|
|
||||||
TAGS="${{ matrix.config.tag }}"
|
TAGS="${{ matrix.config.tag }}"
|
||||||
ARCHES="${{ matrix.config.arches }}"
|
ARCHES="${{ matrix.config.arches }}"
|
||||||
DIGEST_GLOB="/tmp/digests/*.tsv"
|
DIGEST_GLOB="/tmp/digests/*.tsv"
|
||||||
@@ -512,16 +504,6 @@ jobs:
|
|||||||
|
|
||||||
echo "Creating ${merged_versioned_tag} from ${refs[*]}"
|
echo "Creating ${merged_versioned_tag} from ${refs[*]}"
|
||||||
docker buildx imagetools create "${annotations[@]}" --tag "${merged_versioned_tag}" "${refs[@]}"
|
docker buildx imagetools create "${annotations[@]}" --tag "${merged_versioned_tag}" "${refs[@]}"
|
||||||
|
|
||||||
if [[ "$tag_name" == "${TAGS%% *}" ]]; then
|
|
||||||
local digest
|
|
||||||
digest="$(docker buildx imagetools inspect "${merged_versioned_tag}" --format '{{.Manifest.Digest}}')"
|
|
||||||
if [[ ! "$digest" =~ ^sha256:[0-9a-f]{64}$ ]]; then
|
|
||||||
echo "Invalid digest for ${merged_versioned_tag}: ${digest}" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "${image_type}_digest=${digest}" >> "$GITHUB_OUTPUT"
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for tag in $TAGS; do
|
for tag in $TAGS; do
|
||||||
@@ -545,24 +527,3 @@ jobs:
|
|||||||
done
|
done
|
||||||
env:
|
env:
|
||||||
GITHUB_REPOSITORY_OWNER: '${{ github.repository_owner }}'
|
GITHUB_REPOSITORY_OWNER: '${{ github.repository_owner }}'
|
||||||
|
|
||||||
- name: Attest full image
|
|
||||||
if: ${{ matrix.config.full }}
|
|
||||||
uses: actions/attest@v4
|
|
||||||
with:
|
|
||||||
subject-name: ${{ steps.create_tags.outputs.image_repo }}
|
|
||||||
subject-digest: ${{ steps.create_tags.outputs.full_digest }}
|
|
||||||
|
|
||||||
- name: Attest light image
|
|
||||||
if: ${{ matrix.config.light }}
|
|
||||||
uses: actions/attest@v4
|
|
||||||
with:
|
|
||||||
subject-name: ${{ steps.create_tags.outputs.image_repo }}
|
|
||||||
subject-digest: ${{ steps.create_tags.outputs.light_digest }}
|
|
||||||
|
|
||||||
- name: Attest server image
|
|
||||||
if: ${{ matrix.config.server }}
|
|
||||||
uses: actions/attest@v4
|
|
||||||
with:
|
|
||||||
subject-name: ${{ steps.create_tags.outputs.image_repo }}
|
|
||||||
subject-digest: ${{ steps.create_tags.outputs.server_digest }}
|
|
||||||
|
|||||||
@@ -49,22 +49,14 @@ jobs:
|
|||||||
id: depends
|
id: depends
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y build-essential git cmake rocblas-dev hipblas-dev libssl-dev python3 python3-venv python3-pip jq
|
sudo apt-get install -y build-essential git cmake rocblas-dev hipblas-dev libssl-dev python3
|
||||||
|
|
||||||
- name: ccache
|
- name: ccache
|
||||||
uses: ggml-org/ccache-action@v1.2.24
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
with:
|
with:
|
||||||
key: hip-quality-check-ubuntu-22.04
|
key: hip-quality-check-ubuntu-22.04
|
||||||
save: false
|
evict-old-files: 1d
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
- name: ccache-buckets-restore
|
|
||||||
uses: ./.github/actions/ccache-buckets
|
|
||||||
env:
|
|
||||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CI }}
|
|
||||||
with:
|
|
||||||
key: hip-quality-check-ubuntu-22.04
|
|
||||||
folder: llama.cpp
|
|
||||||
hf_bucket: ggml-org/cache
|
|
||||||
|
|
||||||
- name: Build with Werror
|
- name: Build with Werror
|
||||||
id: cmake_build
|
id: cmake_build
|
||||||
@@ -92,15 +84,3 @@ jobs:
|
|||||||
cd build
|
cd build
|
||||||
make -j $(nproc) 2>&1 | tee metrics.log | grep -v 'Rpass-analysis=kernel-resource-usage\|remark:\|^$'
|
make -j $(nproc) 2>&1 | tee metrics.log | grep -v 'Rpass-analysis=kernel-resource-usage\|remark:\|^$'
|
||||||
python3 ../scripts/hip/gcn-cdna-vgpr-check.py metrics.log
|
python3 ../scripts/hip/gcn-cdna-vgpr-check.py metrics.log
|
||||||
|
|
||||||
- name: ccache-buckets-save
|
|
||||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
|
||||||
uses: ./.github/actions/ccache-buckets
|
|
||||||
env:
|
|
||||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CACHE_OUTPUT }}
|
|
||||||
with:
|
|
||||||
key: hip-quality-check-ubuntu-22.04
|
|
||||||
folder: llama.cpp
|
|
||||||
evict-old-files: 1d
|
|
||||||
hf_bucket: ggml-org/cache
|
|
||||||
save: true
|
|
||||||
|
|||||||
@@ -1,152 +0,0 @@
|
|||||||
name: Make Release
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
commit:
|
|
||||||
description: 'Commit SHA to release (empty = branch HEAD)'
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
type: string
|
|
||||||
dry_run:
|
|
||||||
description: 'Dry run - validate without creating the tag'
|
|
||||||
required: true
|
|
||||||
type: boolean
|
|
||||||
default: true
|
|
||||||
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ github.token }}
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
packages: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
make-release:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
with:
|
|
||||||
ssh-key: ${{ secrets.DEPLOY_KEY_RELEASE }}
|
|
||||||
ref: ${{ inputs.commit != '' && inputs.commit || github.ref_name }}
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Run release checks
|
|
||||||
id: checks
|
|
||||||
run: bash scripts/make-release-checks.sh ${{ github.event.inputs.dry_run == 'true' && '--dry-run' || '' }}
|
|
||||||
env:
|
|
||||||
GITHUB_REPOSITORY: ${{ github.repository }}
|
|
||||||
RELEASE_BRANCH: ${{ github.ref_name }}
|
|
||||||
|
|
||||||
- name: Create release tag
|
|
||||||
if: ${{ github.event.inputs.dry_run == 'false' }}
|
|
||||||
run: |
|
|
||||||
VERSION="${{ steps.checks.outputs.version }}"
|
|
||||||
git config user.name "github-actions[bot]"
|
|
||||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
||||||
git tag -a "${VERSION}" -m "Release ${VERSION}"
|
|
||||||
git push origin "${VERSION}"
|
|
||||||
echo "Created and pushed tag ${VERSION}"
|
|
||||||
|
|
||||||
- name: Generate release description
|
|
||||||
id: desc
|
|
||||||
run: bash scripts/make-release-desc.sh "${{ steps.checks.outputs.version }}"
|
|
||||||
env:
|
|
||||||
GITHUB_REPOSITORY: ${{ github.repository }}
|
|
||||||
|
|
||||||
- name: Create nightly-tag.txt
|
|
||||||
id: nightly_tag_file
|
|
||||||
run: |
|
|
||||||
NIGHTLY_TAG="${{ steps.desc.outputs.nightly_tag }}"
|
|
||||||
if [[ -z "${NIGHTLY_TAG}" ]]; then
|
|
||||||
echo "Warning: no nightly tag found for the release commit - nightly-tag.txt will not be created"
|
|
||||||
echo "create=false" >> "$GITHUB_OUTPUT"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
echo "${NIGHTLY_TAG}" > nightly-tag.txt
|
|
||||||
echo "create=true" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "nightly-tag.txt:"
|
|
||||||
cat nightly-tag.txt
|
|
||||||
|
|
||||||
- name: Create release
|
|
||||||
id: create_release
|
|
||||||
if: ${{ github.event.inputs.dry_run == 'false' }}
|
|
||||||
uses: ggml-org/action-create-release@v1
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ github.token }}
|
|
||||||
with:
|
|
||||||
tag_name: ${{ steps.checks.outputs.version }}
|
|
||||||
prerelease: false
|
|
||||||
# TODO: enrich the body of the release with more information
|
|
||||||
body: |
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
New version has been released.
|
|
||||||
|
|
||||||
## Assets
|
|
||||||
|
|
||||||
${{ steps.desc.outputs.nightly }}
|
|
||||||
|
|
||||||
## More info
|
|
||||||
|
|
||||||
- [Releases and versioning of `ggml-org` projects](https://github.com/ggml-org/ggml/discussions/1579)
|
|
||||||
|
|
||||||
## ${{ steps.desc.outputs.changelog_title }}
|
|
||||||
|
|
||||||
${{ steps.desc.outputs.changelog }}
|
|
||||||
|
|
||||||
- name: Upload nightly-tag.txt
|
|
||||||
if: ${{ github.event.inputs.dry_run == 'false' && steps.nightly_tag_file.outputs.create == 'true' }}
|
|
||||||
uses: actions/github-script@v8
|
|
||||||
with:
|
|
||||||
github-token: ${{secrets.GITHUB_TOKEN}}
|
|
||||||
script: |
|
|
||||||
const fs = require('fs');
|
|
||||||
const release_id = '${{ steps.create_release.outputs.id }}';
|
|
||||||
console.log('uploadReleaseAsset', 'nightly-tag.txt');
|
|
||||||
await github.rest.repos.uploadReleaseAsset({
|
|
||||||
owner: context.repo.owner,
|
|
||||||
repo: context.repo.repo,
|
|
||||||
release_id: release_id,
|
|
||||||
name: 'nightly-tag.txt',
|
|
||||||
data: await fs.readFileSync('./nightly-tag.txt')
|
|
||||||
});
|
|
||||||
|
|
||||||
- name: Re-tag container images with release version
|
|
||||||
if: ${{ github.event.inputs.dry_run == 'false' && steps.desc.outputs.nightly_tag != '' }}
|
|
||||||
env:
|
|
||||||
GITHUB_REPOSITORY_OWNER: ${{ github.repository_owner }}
|
|
||||||
run: |
|
|
||||||
VERSION="${{ steps.checks.outputs.version }}"
|
|
||||||
NIGHTLY_TAG="${{ steps.desc.outputs.nightly_tag }}"
|
|
||||||
REPO_OWNER="${GITHUB_REPOSITORY_OWNER,,}"
|
|
||||||
IMAGE_REPO="ghcr.io/${REPO_OWNER}/${{ github.event.repository.name }}"
|
|
||||||
|
|
||||||
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin
|
|
||||||
|
|
||||||
VARIANTS=("" "-cuda" "-cuda13" "-vulkan" "-rocm" "-intel" "-musa" "-openvino")
|
|
||||||
TYPES=("full" "light" "server")
|
|
||||||
for type in "${TYPES[@]}"; do
|
|
||||||
for variant in "${VARIANTS[@]}"; do
|
|
||||||
src="${IMAGE_REPO}:${type}${variant}-${NIGHTLY_TAG}"
|
|
||||||
dst="${IMAGE_REPO}:${type}${variant}-${VERSION}"
|
|
||||||
echo "Tagging ${src} -> ${dst}"
|
|
||||||
docker buildx imagetools create --tag "${dst}" "${src}"
|
|
||||||
done
|
|
||||||
done
|
|
||||||
|
|
||||||
- name: Dry run summary
|
|
||||||
if: ${{ github.event.inputs.dry_run == 'true' }}
|
|
||||||
run: |
|
|
||||||
if [[ "${{ steps.checks.outputs.checks_passed }}" == "true" ]]; then
|
|
||||||
echo "Dry run complete - all checks passed."
|
|
||||||
echo "Would have created tag: ${{ steps.checks.outputs.version }}"
|
|
||||||
if [[ -n "${{ steps.desc.outputs.nightly_tag }}" ]]; then
|
|
||||||
echo "Would have uploaded nightly-tag.txt: ${{ steps.desc.outputs.nightly_tag }}"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "::error::Dry run found release check failures. A release tag would not be created."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
name: Convert PR to draft
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request_target:
|
|
||||||
types: [labeled]
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
pull-requests: write
|
|
||||||
issues: write
|
|
||||||
contents: write # required for "gh pr ready" command, see https://github.com/cli/cli/issues/8910
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
convert-to-draft:
|
|
||||||
if: github.event.label.name == 'draft' && github.event.pull_request.draft == false
|
|
||||||
runs-on: ubuntu-slim
|
|
||||||
steps:
|
|
||||||
- name: Convert PR to draft
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
PR_URL: ${{ github.event.pull_request.html_url }}
|
|
||||||
run: |
|
|
||||||
gh pr ready --undo "$PR_URL"
|
|
||||||
gh pr edit "$PR_URL" --remove-label draft
|
|
||||||
@@ -31,7 +31,7 @@ jobs:
|
|||||||
uses: actions/setup-python@v6
|
uses: actions/setup-python@v6
|
||||||
with:
|
with:
|
||||||
python-version: "3.11"
|
python-version: "3.11"
|
||||||
pip-install: -r requirements/requirements-all.txt ty==0.0.78
|
pip-install: -r requirements/requirements-all.txt ty==0.0.35
|
||||||
# - name: Type-check with Pyright
|
# - name: Type-check with Pyright
|
||||||
# uses: jakebailey/pyright-action@v2
|
# uses: jakebailey/pyright-action@v2
|
||||||
# with:
|
# with:
|
||||||
@@ -40,4 +40,4 @@ jobs:
|
|||||||
# warnings: true
|
# warnings: true
|
||||||
- name: Type-check with ty
|
- name: Type-check with ty
|
||||||
run: |
|
run: |
|
||||||
ty check --exit-zero-on-warning --output-format=github
|
ty check --output-format=github
|
||||||
|
|||||||
+364
-400
File diff suppressed because it is too large
Load Diff
@@ -25,12 +25,6 @@ on:
|
|||||||
'tools/server/**.*'
|
'tools/server/**.*'
|
||||||
]
|
]
|
||||||
|
|
||||||
pull_request:
|
|
||||||
types: [opened, synchronize, reopened]
|
|
||||||
paths: [
|
|
||||||
'.github/workflows/server-sanitize.yml'
|
|
||||||
]
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
LLAMA_ARG_LOG_COLORS: 1
|
LLAMA_ARG_LOG_COLORS: 1
|
||||||
LLAMA_ARG_LOG_PREFIX: 1
|
LLAMA_ARG_LOG_PREFIX: 1
|
||||||
@@ -73,6 +67,13 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
ref: ${{ github.event.inputs.sha || github.event.pull_request.head.sha || github.sha || github.head_ref || github.ref_name }}
|
ref: ${{ github.event.inputs.sha || github.event.pull_request.head.sha || github.sha || github.head_ref || github.ref_name }}
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v6
|
||||||
|
with:
|
||||||
|
node-version: "24"
|
||||||
|
cache: "npm"
|
||||||
|
cache-dependency-path: "tools/ui/package-lock.json"
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
id: cmake_build
|
id: cmake_build
|
||||||
run: |
|
run: |
|
||||||
@@ -89,27 +90,23 @@ jobs:
|
|||||||
|
|
||||||
- name: Python setup
|
- name: Python setup
|
||||||
id: setup_python
|
id: setup_python
|
||||||
uses: actions/setup-python@v7
|
uses: actions/setup-python@v6
|
||||||
|
with:
|
||||||
- name: Install Python dependencies
|
python-version: '3.11'
|
||||||
run: |
|
pip-install: -r tools/server/tests/requirements.txt
|
||||||
python3 -m venv .venv
|
|
||||||
.venv/bin/pip install -r tools/server/tests/requirements.txt
|
|
||||||
|
|
||||||
- name: Tests
|
- name: Tests
|
||||||
id: server_integration_tests
|
id: server_integration_tests
|
||||||
if: ${{ (!matrix.disabled_on_pr || !github.event.pull_request) }}
|
if: ${{ (!matrix.disabled_on_pr || !github.event.pull_request) }}
|
||||||
run: |
|
run: |
|
||||||
source .venv/bin/activate
|
|
||||||
cd tools/server/tests
|
cd tools/server/tests
|
||||||
export ${{ matrix.extra_args }}
|
export ${{ matrix.extra_args }}
|
||||||
PYTEST_WORKERS=1 ./tests.sh
|
pytest -v -x -m "not slow"
|
||||||
|
|
||||||
- name: Slow tests
|
- name: Slow tests
|
||||||
id: server_integration_tests_slow
|
id: server_integration_tests_slow
|
||||||
if: ${{ (github.event.schedule || github.event.inputs.slow_tests == 'true') && matrix.build_type == 'Release' }}
|
if: ${{ (github.event.schedule || github.event.inputs.slow_tests == 'true') && matrix.build_type == 'Release' }}
|
||||||
run: |
|
run: |
|
||||||
source .venv/bin/activate
|
|
||||||
cd tools/server/tests
|
cd tools/server/tests
|
||||||
export ${{ matrix.extra_args }}
|
export ${{ matrix.extra_args }}
|
||||||
PYTEST_WORKERS=1 SLOW_TESTS=1 ./tests.sh
|
SLOW_TESTS=1 pytest -v -x
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cd tools/server/tests
|
cd tools/server/tests
|
||||||
source venv/bin/activate
|
source venv/bin/activate
|
||||||
PYTEST_WORKERS=1 ./tests.sh
|
pytest -v -x -m "not slow"
|
||||||
|
|
||||||
- name: Tests (GPUx1, backend-sampling)
|
- name: Tests (GPUx1, backend-sampling)
|
||||||
id: server_integration_tests_backend_sampling
|
id: server_integration_tests_backend_sampling
|
||||||
@@ -81,7 +81,7 @@ jobs:
|
|||||||
cd tools/server/tests
|
cd tools/server/tests
|
||||||
source venv/bin/activate
|
source venv/bin/activate
|
||||||
export LLAMA_ARG_BACKEND_SAMPLING=1
|
export LLAMA_ARG_BACKEND_SAMPLING=1
|
||||||
PYTEST_WORKERS=1 ./tests.sh
|
pytest -v -x -m "not slow"
|
||||||
|
|
||||||
- name: Tests (GPUx2)
|
- name: Tests (GPUx2)
|
||||||
id: server_integration_tests_gpu2
|
id: server_integration_tests_gpu2
|
||||||
@@ -90,7 +90,7 @@ jobs:
|
|||||||
cd tools/server/tests
|
cd tools/server/tests
|
||||||
source venv/bin/activate
|
source venv/bin/activate
|
||||||
export GGML_METAL_DEVICES=2
|
export GGML_METAL_DEVICES=2
|
||||||
PYTEST_WORKERS=1 ./tests.sh
|
pytest -v -x -m "not slow"
|
||||||
|
|
||||||
- name: Tests (GPUx2, backend-sampling)
|
- name: Tests (GPUx2, backend-sampling)
|
||||||
id: server_integration_tests_gpu2_backend_sampling
|
id: server_integration_tests_gpu2_backend_sampling
|
||||||
@@ -99,10 +99,10 @@ jobs:
|
|||||||
cd tools/server/tests
|
cd tools/server/tests
|
||||||
source venv/bin/activate
|
source venv/bin/activate
|
||||||
export GGML_METAL_DEVICES=2 LLAMA_ARG_BACKEND_SAMPLING=1
|
export GGML_METAL_DEVICES=2 LLAMA_ARG_BACKEND_SAMPLING=1
|
||||||
PYTEST_WORKERS=1 ./tests.sh
|
pytest -v -x -m "not slow"
|
||||||
|
|
||||||
server-cuda:
|
server-cuda:
|
||||||
runs-on: "hf-jobs-t4-small:cuda13"
|
runs-on: [self-hosted, llama-server, Linux, NVIDIA]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Clone
|
- name: Clone
|
||||||
@@ -112,42 +112,12 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
ref: ${{ github.event.inputs.sha || github.event.pull_request.head.sha || github.sha || github.head_ref || github.ref_name }}
|
ref: ${{ github.event.inputs.sha || github.event.pull_request.head.sha || github.sha || github.head_ref || github.ref_name }}
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: |
|
|
||||||
sudo apt update
|
|
||||||
sudo apt install -y cmake libssl-dev python3 python3-venv python3-pip
|
|
||||||
|
|
||||||
- name: ccache
|
|
||||||
uses: ggml-org/ccache-action@v1.2.24
|
|
||||||
with:
|
|
||||||
restore: false
|
|
||||||
save: false
|
|
||||||
|
|
||||||
- name: ccache-buckets-restore
|
|
||||||
uses: ./.github/actions/ccache-buckets
|
|
||||||
with:
|
|
||||||
key: self-hosted-server-cuda
|
|
||||||
folder: llama.cpp
|
|
||||||
hf_bucket: ggml-org/cache
|
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
id: cmake_build
|
id: cmake_build
|
||||||
run: |
|
run: |
|
||||||
cmake -B build -DGGML_CUDA=ON -DGGML_SCHED_NO_REALLOC=ON -DCMAKE_CUDA_COMPILER=/usr/local/cuda/bin/nvcc
|
cmake -B build -DGGML_CUDA=ON -DGGML_SCHED_NO_REALLOC=ON
|
||||||
cmake --build build --config Release -j $(nproc) --target llama-server
|
cmake --build build --config Release -j $(nproc) --target llama-server
|
||||||
|
|
||||||
- name: ccache-buckets-save
|
|
||||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
|
||||||
uses: ./.github/actions/ccache-buckets
|
|
||||||
env:
|
|
||||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CACHE_OUTPUT }}
|
|
||||||
with:
|
|
||||||
key: self-hosted-server-cuda
|
|
||||||
folder: llama.cpp
|
|
||||||
evict-old-files: 1d
|
|
||||||
hf_bucket: ggml-org/cache
|
|
||||||
save: true
|
|
||||||
|
|
||||||
- name: Python setup
|
- name: Python setup
|
||||||
id: setup_python
|
id: setup_python
|
||||||
run: |
|
run: |
|
||||||
@@ -162,7 +132,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cd tools/server/tests
|
cd tools/server/tests
|
||||||
source venv/bin/activate
|
source venv/bin/activate
|
||||||
PYTEST_WORKERS=1 ./tests.sh
|
pytest -v -x -m "not slow"
|
||||||
|
|
||||||
- name: Tests (GPUx1, backend-sampling)
|
- name: Tests (GPUx1, backend-sampling)
|
||||||
id: server_integration_tests_backend_sampling
|
id: server_integration_tests_backend_sampling
|
||||||
@@ -171,7 +141,7 @@ jobs:
|
|||||||
cd tools/server/tests
|
cd tools/server/tests
|
||||||
source venv/bin/activate
|
source venv/bin/activate
|
||||||
export LLAMA_ARG_BACKEND_SAMPLING=1
|
export LLAMA_ARG_BACKEND_SAMPLING=1
|
||||||
PYTEST_WORKERS=1 ./tests.sh
|
pytest -v -x -m "not slow"
|
||||||
|
|
||||||
- name: Tests (GPUx2)
|
- name: Tests (GPUx2)
|
||||||
id: server_integration_tests_gpu2
|
id: server_integration_tests_gpu2
|
||||||
@@ -180,7 +150,7 @@ jobs:
|
|||||||
cd tools/server/tests
|
cd tools/server/tests
|
||||||
source venv/bin/activate
|
source venv/bin/activate
|
||||||
export GGML_CUDA_DEVICES=2
|
export GGML_CUDA_DEVICES=2
|
||||||
PYTEST_WORKERS=1 ./tests.sh
|
pytest -v -x -m "not slow"
|
||||||
|
|
||||||
- name: Tests (GPUx2, backend-sampling)
|
- name: Tests (GPUx2, backend-sampling)
|
||||||
id: server_integration_tests_gpu2_backend_sampling
|
id: server_integration_tests_gpu2_backend_sampling
|
||||||
@@ -189,7 +159,7 @@ jobs:
|
|||||||
cd tools/server/tests
|
cd tools/server/tests
|
||||||
source venv/bin/activate
|
source venv/bin/activate
|
||||||
export GGML_CUDA_DEVICES=2 LLAMA_ARG_BACKEND_SAMPLING=1
|
export GGML_CUDA_DEVICES=2 LLAMA_ARG_BACKEND_SAMPLING=1
|
||||||
PYTEST_WORKERS=1 ./tests.sh
|
pytest -v -x -m "not slow"
|
||||||
|
|
||||||
server-kleidiai:
|
server-kleidiai:
|
||||||
runs-on: ah-ubuntu_22_04-c8g_8x
|
runs-on: ah-ubuntu_22_04-c8g_8x
|
||||||
@@ -249,4 +219,4 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cd tools/server/tests
|
cd tools/server/tests
|
||||||
source venv/bin/activate
|
source venv/bin/activate
|
||||||
./tests.sh
|
pytest -v -x -m "not slow"
|
||||||
|
|||||||
@@ -80,19 +80,11 @@ jobs:
|
|||||||
ref: ${{ github.event.inputs.sha || github.event.pull_request.head.sha || github.sha || github.head_ref || github.ref_name }}
|
ref: ${{ github.event.inputs.sha || github.event.pull_request.head.sha || github.sha || github.head_ref || github.ref_name }}
|
||||||
|
|
||||||
- name: ccache
|
- name: ccache
|
||||||
uses: ggml-org/ccache-action@v1.2.24
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
with:
|
with:
|
||||||
key: server-ubuntu-24.04-arm
|
key: server-ubuntu-24.04-arm
|
||||||
save: false
|
evict-old-files: 1d
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
- name: ccache-buckets-restore
|
|
||||||
uses: ./.github/actions/ccache-buckets
|
|
||||||
env:
|
|
||||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CI }}
|
|
||||||
with:
|
|
||||||
key: server-ubuntu-24.04-arm
|
|
||||||
folder: llama.cpp
|
|
||||||
hf_bucket: ggml-org/cache
|
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
id: cmake_build
|
id: cmake_build
|
||||||
@@ -101,18 +93,6 @@ jobs:
|
|||||||
-DGGML_SCHED_NO_REALLOC=ON
|
-DGGML_SCHED_NO_REALLOC=ON
|
||||||
cmake --build build --config Release -j $(nproc) --target llama-server
|
cmake --build build --config Release -j $(nproc) --target llama-server
|
||||||
|
|
||||||
- name: ccache-buckets-save
|
|
||||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
|
||||||
uses: ./.github/actions/ccache-buckets
|
|
||||||
env:
|
|
||||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CACHE_OUTPUT }}
|
|
||||||
with:
|
|
||||||
key: server-ubuntu-24.04-arm
|
|
||||||
folder: llama.cpp
|
|
||||||
evict-old-files: 1d
|
|
||||||
hf_bucket: ggml-org/cache
|
|
||||||
save: true
|
|
||||||
|
|
||||||
- name: Python setup
|
- name: Python setup
|
||||||
id: setup_python
|
id: setup_python
|
||||||
uses: actions/setup-python@v6
|
uses: actions/setup-python@v6
|
||||||
@@ -124,21 +104,21 @@ jobs:
|
|||||||
id: server_integration_tests
|
id: server_integration_tests
|
||||||
run: |
|
run: |
|
||||||
cd tools/server/tests
|
cd tools/server/tests
|
||||||
./tests.sh
|
pytest -v -x -m "not slow"
|
||||||
|
|
||||||
- name: Slow tests
|
- name: Slow tests
|
||||||
id: server_integration_tests_slow
|
id: server_integration_tests_slow
|
||||||
if: ${{ github.event.schedule || github.event.inputs.slow_tests == 'true' }}
|
if: ${{ github.event.schedule || github.event.inputs.slow_tests == 'true' }}
|
||||||
run: |
|
run: |
|
||||||
cd tools/server/tests
|
cd tools/server/tests
|
||||||
SLOW_TESTS=1 ./tests.sh
|
SLOW_TESTS=1 pytest -v -x
|
||||||
|
|
||||||
- name: Tests (Backend sampling)
|
- name: Tests (Backend sampling)
|
||||||
id: server_integration_tests_backend_sampling
|
id: server_integration_tests_backend_sampling
|
||||||
run: |
|
run: |
|
||||||
cd tools/server/tests
|
cd tools/server/tests
|
||||||
export LLAMA_ARG_BACKEND_SAMPLING=1
|
export LLAMA_ARG_BACKEND_SAMPLING=1
|
||||||
./tests.sh
|
pytest -v -x -m "not slow"
|
||||||
|
|
||||||
- name: Slow tests (Backend sampling)
|
- name: Slow tests (Backend sampling)
|
||||||
id: server_integration_tests_slow_backend_sampling
|
id: server_integration_tests_slow_backend_sampling
|
||||||
@@ -146,7 +126,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cd tools/server/tests
|
cd tools/server/tests
|
||||||
export LLAMA_ARG_BACKEND_SAMPLING=1
|
export LLAMA_ARG_BACKEND_SAMPLING=1
|
||||||
SLOW_TESTS=1 ./tests.sh
|
SLOW_TESTS=1 pytest -v -x
|
||||||
|
|
||||||
windows:
|
windows:
|
||||||
runs-on: windows-2025
|
runs-on: windows-2025
|
||||||
@@ -160,7 +140,7 @@ jobs:
|
|||||||
ref: ${{ github.event.inputs.sha || github.event.pull_request.head.sha || github.sha || github.head_ref || github.ref_name }}
|
ref: ${{ github.event.inputs.sha || github.event.pull_request.head.sha || github.sha || github.head_ref || github.ref_name }}
|
||||||
|
|
||||||
- name: ccache
|
- name: ccache
|
||||||
uses: ggml-org/ccache-action@v1.2.24
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
with:
|
with:
|
||||||
key: server-windows-2025-x64
|
key: server-windows-2025-x64
|
||||||
evict-old-files: 1d
|
evict-old-files: 1d
|
||||||
@@ -187,27 +167,15 @@ jobs:
|
|||||||
|
|
||||||
- name: Tests
|
- name: Tests
|
||||||
id: server_integration_tests
|
id: server_integration_tests
|
||||||
shell: bash
|
|
||||||
run: |
|
run: |
|
||||||
cd tools/server/tests
|
cd tools/server/tests
|
||||||
export PYTHONIOENCODING=":replace"
|
$env:PYTHONIOENCODING = ":replace"
|
||||||
./tests.sh
|
pytest -v -x -m "not slow"
|
||||||
|
|
||||||
- name: Slow tests
|
- name: Slow tests
|
||||||
id: server_integration_tests_slow
|
id: server_integration_tests_slow
|
||||||
if: ${{ github.event.schedule || github.event.inputs.slow_tests == 'true' }}
|
if: ${{ github.event.schedule || github.event.inputs.slow_tests == 'true' }}
|
||||||
shell: bash
|
|
||||||
run: |
|
run: |
|
||||||
cd tools/server/tests
|
cd tools/server/tests
|
||||||
export SLOW_TESTS="1"
|
$env:SLOW_TESTS = "1"
|
||||||
./tests.sh
|
pytest -v -x
|
||||||
|
|
||||||
- name: ccache-clear
|
|
||||||
uses: ./.github/actions/ccache-clear
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ github.token }}
|
|
||||||
with:
|
|
||||||
key: server-windows-2025-x64
|
|
||||||
older: 5m
|
|
||||||
min: 1
|
|
||||||
dry-run: ${{ github.event_name != 'push' || github.ref != 'refs/heads/master' }}
|
|
||||||
|
|||||||
@@ -17,9 +17,8 @@ jobs:
|
|||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: "24"
|
node-version: "24"
|
||||||
# cache: "npm"
|
cache: "npm"
|
||||||
# cache-dependency-path: "tools/ui/package-lock.json"
|
cache-dependency-path: "tools/ui/package-lock.json"
|
||||||
package-manager-cache: false
|
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
@@ -32,6 +31,6 @@ jobs:
|
|||||||
- name: Upload built UI
|
- name: Upload built UI
|
||||||
uses: actions/upload-artifact@v6
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: llama-ui.zip
|
name: ui-build
|
||||||
path: tools/ui/dist/
|
path: tools/ui/dist/
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ name: UI Build
|
|||||||
on:
|
on:
|
||||||
workflow_call:
|
workflow_call:
|
||||||
inputs:
|
inputs:
|
||||||
ui_version:
|
hf_ui_version:
|
||||||
description: 'Version string embedded in build.json (e.g. b1234); defaults to b<commit-count>'
|
description: 'Version string for version.json (e.g. 12345)'
|
||||||
required: false
|
required: false
|
||||||
type: string
|
type: string
|
||||||
|
|
||||||
@@ -17,25 +17,13 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Resolve UI version
|
|
||||||
id: version
|
|
||||||
run: |
|
|
||||||
version="${{ inputs.ui_version }}"
|
|
||||||
if [ -z "$version" ]; then
|
|
||||||
version="b$(git rev-list --count HEAD)"
|
|
||||||
fi
|
|
||||||
echo "ui_version=${version}" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: "24"
|
node-version: "24"
|
||||||
# cache: "npm"
|
cache: "npm"
|
||||||
# cache-dependency-path: "tools/ui/package-lock.json"
|
cache-dependency-path: "tools/ui/package-lock.json"
|
||||||
package-manager-cache: false
|
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
@@ -43,7 +31,8 @@ jobs:
|
|||||||
|
|
||||||
- name: Build application
|
- name: Build application
|
||||||
env:
|
env:
|
||||||
LLAMA_BUILD_NUMBER: ${{ steps.version.outputs.ui_version }}
|
HF_UI_VERSION: ${{ inputs.hf_ui_version || '' }}
|
||||||
|
LLAMA_BUILD_NUMBER: ${{ inputs.hf_ui_version || 'b0000' }}
|
||||||
run: npm run build
|
run: npm run build
|
||||||
working-directory: tools/ui
|
working-directory: tools/ui
|
||||||
|
|
||||||
@@ -54,6 +43,6 @@ jobs:
|
|||||||
- name: Upload built UI
|
- name: Upload built UI
|
||||||
uses: actions/upload-artifact@v6
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: llama-ui.zip
|
name: ui-build
|
||||||
path: tools/ui/dist/
|
path: tools/ui/dist/
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ jobs:
|
|||||||
- name: Download UI build artifact
|
- name: Download UI build artifact
|
||||||
uses: actions/download-artifact@v7
|
uses: actions/download-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: llama-ui.zip
|
name: ui-build
|
||||||
path: tools/ui/dist/
|
path: tools/ui/dist/
|
||||||
|
|
||||||
- name: Create distribution archive
|
- name: Create distribution archive
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ jobs:
|
|||||||
- name: Download built UI artifacts
|
- name: Download built UI artifacts
|
||||||
uses: actions/download-artifact@v6
|
uses: actions/download-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: llama-ui.zip
|
name: ui-build
|
||||||
path: tools/ui/dist/
|
path: tools/ui/dist/
|
||||||
|
|
||||||
- name: Run type checking
|
- name: Run type checking
|
||||||
@@ -106,7 +106,7 @@ jobs:
|
|||||||
- name: Download built UI artifacts
|
- name: Download built UI artifacts
|
||||||
uses: actions/download-artifact@v6
|
uses: actions/download-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: llama-ui.zip
|
name: ui-build
|
||||||
path: tools/ui/dist/
|
path: tools/ui/dist/
|
||||||
|
|
||||||
- name: Build Storybook
|
- name: Build Storybook
|
||||||
|
|||||||
@@ -57,14 +57,13 @@ jobs:
|
|||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: "24"
|
node-version: "24"
|
||||||
# cache: "npm"
|
cache: "npm"
|
||||||
# cache-dependency-path: "tools/ui/package-lock.json"
|
cache-dependency-path: "tools/ui/package-lock.json"
|
||||||
package-manager-cache: false
|
|
||||||
|
|
||||||
- name: Download built UI artifacts
|
- name: Download built UI artifacts
|
||||||
uses: actions/download-artifact@v6
|
uses: actions/download-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: llama-ui.zip
|
name: ui-build
|
||||||
path: tools/ui/dist/
|
path: tools/ui/dist/
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
@@ -115,9 +114,8 @@ jobs:
|
|||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: "24"
|
node-version: "24"
|
||||||
# cache: "npm"
|
cache: "npm"
|
||||||
# cache-dependency-path: "tools/ui/package-lock.json"
|
cache-dependency-path: "tools/ui/package-lock.json"
|
||||||
package-manager-cache: false
|
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
id: setup
|
id: setup
|
||||||
@@ -128,7 +126,7 @@ jobs:
|
|||||||
- name: Download built UI artifacts (reuses ui-build)
|
- name: Download built UI artifacts (reuses ui-build)
|
||||||
uses: actions/download-artifact@v6
|
uses: actions/download-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: llama-ui.zip
|
name: ui-build
|
||||||
path: tools/ui/dist/
|
path: tools/ui/dist/
|
||||||
|
|
||||||
- name: Install Playwright browsers
|
- name: Install Playwright browsers
|
||||||
|
|||||||
@@ -19,8 +19,6 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cargo binstall komac@2.16.0 -y
|
cargo binstall komac@2.16.0 -y
|
||||||
|
|
||||||
# TODO: This should later be updated to publish releases instead of
|
|
||||||
# development release builds.
|
|
||||||
- name: Find latest release
|
- name: Find latest release
|
||||||
id: find_latest_release
|
id: find_latest_release
|
||||||
uses: actions/github-script@v8
|
uses: actions/github-script@v8
|
||||||
|
|||||||
@@ -2,14 +2,12 @@ You are a coding agent. Here are some very important rules that you must follow:
|
|||||||
|
|
||||||
General:
|
General:
|
||||||
- Be very precise and concise when writing code, comments, explanations, etc.
|
- Be very precise and concise when writing code, comments, explanations, etc.
|
||||||
- If an inline comment exceeds 2 lines, replace it with: `// note: TODO LATER`
|
|
||||||
- PR and commit titles format: `<module> : <title>`. Lookup recents for examples
|
- PR and commit titles format: `<module> : <title>`. Lookup recents for examples
|
||||||
- Don't try to build or run the code unless you are explicitly asked to do so
|
- Don't try to build or run the code unless you are explicitly asked to do so
|
||||||
- Use the `gh` CLI tool when querying PRs, issues, or other GitHub resources
|
- Use the `gh` CLI tool when querying PRs, issues, or other GitHub resources
|
||||||
|
|
||||||
Coding:
|
Coding:
|
||||||
- When in doubt, always refer to the CONTRIBUTING.md file of the project
|
- When in doubt, always refer to the CONTRIBUTING.md file of the project
|
||||||
- In `test-backend-ops.cpp`, do not mention specific backends (e.g. Metal, CUDA) in comments
|
|
||||||
- When referencing issues or PRs in comments, use the format:
|
- When referencing issues or PRs in comments, use the format:
|
||||||
- C/C++ code: `// ref: <url>`
|
- C/C++ code: `// ref: <url>`
|
||||||
- Other (CMake, etc.): `# ref: <url>`
|
- Other (CMake, etc.): `# ref: <url>`
|
||||||
@@ -17,7 +15,6 @@ Coding:
|
|||||||
Pull requests (PRs):
|
Pull requests (PRs):
|
||||||
- New branch names are prefixed with "gg/"
|
- New branch names are prefixed with "gg/"
|
||||||
- Before opening a pull request, ask the user to confirm the description
|
- Before opening a pull request, ask the user to confirm the description
|
||||||
- Don't explicitly wrap lines in the PR description (each paragraph and bullet is a single line)
|
|
||||||
- When creating a pull request, look for the repository's PR template and follow it
|
- When creating a pull request, look for the repository's PR template and follow it
|
||||||
- For the AI usage disclosure section, write "YES. pi:llama.cpp/[MODEL]"
|
- For the AI usage disclosure section, write "YES. pi:llama.cpp/[MODEL]"
|
||||||
- Ask the user to tell you what model was used and write it in place of [MODEL]
|
- Ask the user to tell you what model was used and write it in place of [MODEL]
|
||||||
|
|||||||
@@ -71,21 +71,11 @@ For first-time contributors, confirm they have reviewed [CONTRIBUTING.md](CONTRI
|
|||||||
These points are extremely important - failing to follow them won't necessarily get your PR rejected, but it will make reviewing take significantly longer. Please follow them carefully:
|
These points are extremely important - failing to follow them won't necessarily get your PR rejected, but it will make reviewing take significantly longer. Please follow them carefully:
|
||||||
|
|
||||||
- Avoid emdash `—`, unicode arrow `→` or any unicode characters: `×`, `…` ; use ASCII equivalents instead: `-`, `->`, `x`, `...`
|
- Avoid emdash `—`, unicode arrow `→` or any unicode characters: `×`, `…` ; use ASCII equivalents instead: `-`, `->`, `x`, `...`
|
||||||
- Code comments:
|
- Keep code comments concise; avoid redundant or excessive inline commentary
|
||||||
- Keep code comments concise (usually 1-2 lines)
|
|
||||||
- Avoid redundant or excessive inline commentary
|
|
||||||
- Avoid hard-wrapping it to a fixed column width - that hurts readability
|
|
||||||
- Use ASD-STE100 Simplified Technical English, simple wordings (write like cavemen if needed)
|
|
||||||
- Note: Remind yourself of this point regularly, as it often gets lost between context compactions
|
|
||||||
- Prefer reusing existing infrastructure over introducing new components. Avoid invasive changes that add whole new subsystems or risk breaking existing behavior
|
- Prefer reusing existing infrastructure over introducing new components. Avoid invasive changes that add whole new subsystems or risk breaking existing behavior
|
||||||
- Do NOT split a line into multiple lines mid-sentence, do NOT try to force the line to fit a fixed number of characters
|
- Do NOT split a line into multiple lines mid-sentence, do NOT try to force the line to fit a fixed number of characters
|
||||||
- Before writing any code, read all relevant files and understand the existing patterns - your changes must blend in with the surrounding codebase. If the change is large or introduces a new pattern, **PAUSE and ask the user for confirmation** before proceeding; remind them that large changes submitted without prior discussion are likely to be rejected by maintainers
|
- Before writing any code, read all relevant files and understand the existing patterns - your changes must blend in with the surrounding codebase. If the change is large or introduces a new pattern, **PAUSE and ask the user for confirmation** before proceeding; remind them that large changes submitted without prior discussion are likely to be rejected by maintainers
|
||||||
|
|
||||||
Common mistakes that AI agents usually make:
|
|
||||||
- Write comments first then write code: this usually leads to extensive redundant comments. Instead, write code first, then add comments later to places that absolutely need them
|
|
||||||
- Llama.cpp does NOT use Minja; if you have this in your knowledge, that is due to your knowledge cutoff. Llama.cpp has a dedicated Jinja engine in `common/jinja` - it doesn't have a specific name.
|
|
||||||
- Do NOT add a new file in `tests/*` without maintainers' approval. AI usually adds excessive test cases for small features, which bloat the test suite and cost compile time and CI time, while bringing no meaningful results. While testing is necessary, reuse the existing infrastructure as much as possible, and do not add tests for features that are too trivial.
|
|
||||||
|
|
||||||
### Prohibited Actions
|
### Prohibited Actions
|
||||||
|
|
||||||
- Do NOT write PR descriptions, commit messages, or reviewer responses
|
- Do NOT write PR descriptions, commit messages, or reviewer responses
|
||||||
@@ -169,23 +159,15 @@ ggml_tensor * inp_pos = build_inp_pos();
|
|||||||
```cpp
|
```cpp
|
||||||
// GOOD (comment is kept concise and useful)
|
// GOOD (comment is kept concise and useful)
|
||||||
|
|
||||||
// one decode step of code_predictor
|
// returns the meta of the first child whose array is non-empty
|
||||||
// at step_idx g:
|
// note: one session per convId across all children
|
||||||
// - read code from out_code_cache[g], then embed it with codebook table g-1
|
|
||||||
// - write new kv at cache row g+1, sample with lm_head[g]
|
|
||||||
// - write result to out_code_cache[g+1]
|
|
||||||
|
|
||||||
|
|
||||||
// BAD (comment is long and is forced to fit into a fixed column size, it is very annoying to read as a reviewer)
|
// BAD (comment is long and is forced to fit into a fixed column size, it is very annoying to read as a reviewer)
|
||||||
|
|
||||||
// one autoregressive decode step of the 5-layer code_predictor. See the
|
// short list query on the loopback, returns the meta of the first child whose array is
|
||||||
// comment in models.h for the cache/tensor conventions this relies on.
|
// non-empty. with the invariant 'one session per convId across all children' enforced by
|
||||||
//
|
// the POST path, at most one child can match
|
||||||
// index mapping (derived from the reference pipeline-tts.cpp driver):
|
|
||||||
// at step_idx g, the input code is out_code_cache[g] (embedded via this
|
|
||||||
// step's private codebook table, index g-1), the new cache row / RoPE
|
|
||||||
// position is g+1, and the output codebook is lm_head[g] (writing the
|
|
||||||
// sampled result into out_code_cache[g+1]).
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Commit message:
|
Commit message:
|
||||||
|
|||||||
+10
-27
@@ -2,26 +2,6 @@ cmake_minimum_required(VERSION 3.14...3.28) # for add_link_options and implicit
|
|||||||
project("llama.cpp" C CXX)
|
project("llama.cpp" C CXX)
|
||||||
include(CheckIncludeFileCXX)
|
include(CheckIncludeFileCXX)
|
||||||
|
|
||||||
### llama.cpp version
|
|
||||||
set(LLAMA_VERSION_MAJOR 0)
|
|
||||||
set(LLAMA_VERSION_MINOR 4)
|
|
||||||
set(LLAMA_VERSION_PATCH 0)
|
|
||||||
set(LLAMA_VERSION_BASE "${LLAMA_VERSION_MAJOR}.${LLAMA_VERSION_MINOR}.${LLAMA_VERSION_PATCH}")
|
|
||||||
|
|
||||||
# whether this is a development/nightly build
|
|
||||||
# set this to OFF when making a release from a release tag (vX.Y.Z)
|
|
||||||
# ref: https://github.com/ggml-org/ggml/discussions/1579
|
|
||||||
option(LLAMA_BUILD_IS_DEV "llama: dev build" ON)
|
|
||||||
|
|
||||||
if (LLAMA_BUILD_IS_DEV)
|
|
||||||
set(LLAMA_VERSION "${LLAMA_VERSION_BASE}-dev")
|
|
||||||
else()
|
|
||||||
# TODO: check that the current commit is tagged correctly according to the version specified above
|
|
||||||
set(LLAMA_VERSION "${LLAMA_VERSION_BASE}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
message(STATUS "llama.cpp version: ${LLAMA_VERSION}")
|
|
||||||
|
|
||||||
#set(CMAKE_WARN_DEPRECATED YES)
|
#set(CMAKE_WARN_DEPRECATED YES)
|
||||||
set(CMAKE_WARN_UNUSED_CLI YES)
|
set(CMAKE_WARN_UNUSED_CLI YES)
|
||||||
|
|
||||||
@@ -44,6 +24,9 @@ if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
|||||||
set(LLAMA_STANDALONE ON)
|
set(LLAMA_STANDALONE ON)
|
||||||
|
|
||||||
include(git-vars)
|
include(git-vars)
|
||||||
|
|
||||||
|
# configure project version
|
||||||
|
# TODO
|
||||||
else()
|
else()
|
||||||
set(LLAMA_STANDALONE OFF)
|
set(LLAMA_STANDALONE OFF)
|
||||||
endif()
|
endif()
|
||||||
@@ -134,8 +117,8 @@ option(LLAMA_BUILD_TOOLS "llama: build tools"
|
|||||||
option(LLAMA_BUILD_EXAMPLES "llama: build examples" ${LLAMA_STANDALONE})
|
option(LLAMA_BUILD_EXAMPLES "llama: build examples" ${LLAMA_STANDALONE})
|
||||||
option(LLAMA_BUILD_SERVER "llama: build server example" ${LLAMA_STANDALONE})
|
option(LLAMA_BUILD_SERVER "llama: build server example" ${LLAMA_STANDALONE})
|
||||||
option(LLAMA_BUILD_APP "llama: build the unified binary" ${LLAMA_STANDALONE})
|
option(LLAMA_BUILD_APP "llama: build the unified binary" ${LLAMA_STANDALONE})
|
||||||
option(LLAMA_BUILD_UI "llama: build the embedded Web UI for server" OFF)
|
option(LLAMA_BUILD_UI "llama: build the embedded Web UI for server" ON)
|
||||||
option(LLAMA_USE_PREBUILT_UI "llama: use prebuilt UI from HF Bucket when available" ON)
|
option(LLAMA_USE_PREBUILT_UI "llama: use prebuilt UI from HF Bucket when available (requires LLAMA_BUILD_UI=ON)" ON)
|
||||||
|
|
||||||
option(LLAMA_TOOLS_INSTALL "llama: install tools" ${LLAMA_TOOLS_INSTALL_DEFAULT})
|
option(LLAMA_TOOLS_INSTALL "llama: install tools" ${LLAMA_TOOLS_INSTALL_DEFAULT})
|
||||||
option(LLAMA_TESTS_INSTALL "llama: install tests" ON)
|
option(LLAMA_TESTS_INSTALL "llama: install tests" ON)
|
||||||
@@ -156,6 +139,7 @@ endif()
|
|||||||
if (NOT DEFINED LLAMA_BUILD_COMMIT)
|
if (NOT DEFINED LLAMA_BUILD_COMMIT)
|
||||||
set(LLAMA_BUILD_COMMIT ${BUILD_COMMIT})
|
set(LLAMA_BUILD_COMMIT ${BUILD_COMMIT})
|
||||||
endif()
|
endif()
|
||||||
|
set(LLAMA_INSTALL_VERSION 0.0.${LLAMA_BUILD_NUMBER})
|
||||||
|
|
||||||
# override ggml options
|
# override ggml options
|
||||||
set(GGML_ALL_WARNINGS ${LLAMA_ALL_WARNINGS})
|
set(GGML_ALL_WARNINGS ${LLAMA_ALL_WARNINGS})
|
||||||
@@ -224,10 +208,9 @@ add_subdirectory(src)
|
|||||||
# utils, programs, examples and tests
|
# utils, programs, examples and tests
|
||||||
#
|
#
|
||||||
|
|
||||||
add_subdirectory(vendor)
|
|
||||||
|
|
||||||
if (LLAMA_BUILD_COMMON)
|
if (LLAMA_BUILD_COMMON)
|
||||||
add_subdirectory(common)
|
add_subdirectory(common)
|
||||||
|
add_subdirectory(vendor/cpp-httplib)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (LLAMA_BUILD_COMMON AND LLAMA_BUILD_TESTS AND NOT CMAKE_JS_VERSION)
|
if (LLAMA_BUILD_COMMON AND LLAMA_BUILD_TESTS AND NOT CMAKE_JS_VERSION)
|
||||||
@@ -292,12 +275,12 @@ configure_package_config_file(
|
|||||||
LLAMA_BIN_INSTALL_DIR )
|
LLAMA_BIN_INSTALL_DIR )
|
||||||
|
|
||||||
write_basic_package_version_file(
|
write_basic_package_version_file(
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/llama-config-version.cmake
|
${CMAKE_CURRENT_BINARY_DIR}/llama-version.cmake
|
||||||
VERSION ${LLAMA_VERSION}
|
VERSION ${LLAMA_INSTALL_VERSION}
|
||||||
COMPATIBILITY SameMajorVersion)
|
COMPATIBILITY SameMajorVersion)
|
||||||
|
|
||||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/llama-config.cmake
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/llama-config.cmake
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/llama-config-version.cmake
|
${CMAKE_CURRENT_BINARY_DIR}/llama-version.cmake
|
||||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/llama)
|
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/llama)
|
||||||
|
|
||||||
configure_file(cmake/llama.pc.in
|
configure_file(cmake/llama.pc.in
|
||||||
|
|||||||
@@ -57,7 +57,6 @@
|
|||||||
/ggml/src/ggml-cann/ @ggml-org/ggml-cann
|
/ggml/src/ggml-cann/ @ggml-org/ggml-cann
|
||||||
/ggml/src/ggml-common.h @ggerganov
|
/ggml/src/ggml-common.h @ggerganov
|
||||||
/ggml/src/ggml-cpu/ @ggerganov
|
/ggml/src/ggml-cpu/ @ggerganov
|
||||||
/ggml/src/ggml-cpu/iqp.* @bartowski1182
|
|
||||||
/ggml/src/ggml-cpu/spacemit/ @alex-spacemit
|
/ggml/src/ggml-cpu/spacemit/ @alex-spacemit
|
||||||
/ggml/src/ggml-cuda/ @ggml-org/ggml-cuda
|
/ggml/src/ggml-cuda/ @ggml-org/ggml-cuda
|
||||||
/ggml/src/ggml-cuda/vendors/hip.h @IMbackK
|
/ggml/src/ggml-cuda/vendors/hip.h @IMbackK
|
||||||
|
|||||||
@@ -73,8 +73,6 @@ For more info, please refer to the [AGENTS.md](AGENTS.md) file.
|
|||||||
- When merging a PR, make sure you have a good understanding of the changes
|
- When merging a PR, make sure you have a good understanding of the changes
|
||||||
- If a PR does not warrant a new release, add `[no release]` in the squashed commit to spare CI resources
|
- If a PR does not warrant a new release, add `[no release]` in the squashed commit to spare CI resources
|
||||||
- Be mindful of maintenance: most of the work going into a feature happens after the PR is merged. If the PR author is not committed to contribute long-term, someone else needs to take responsibility (you)
|
- Be mindful of maintenance: most of the work going into a feature happens after the PR is merged. If the PR author is not committed to contribute long-term, someone else needs to take responsibility (you)
|
||||||
- Add the ["merge ready"](https://github.com/ggml-org/llama.cpp/pulls?q=is%3Apr+is%3Aopen+draft%3Ano+sort%3Aupdated-desc+label%3A%22merge+ready%22+) label to a PR to indicate when a PR can be fast-merged without waiting for 2 independent reviews. [(more info)](https://github.com/ggml-org/llama.cpp/pull/26178)
|
|
||||||
- Wait for CI results before merging
|
|
||||||
|
|
||||||
Maintainers reserve the right to decline review or close pull requests for any reason, without any questions, particularly under any of the following conditions:
|
Maintainers reserve the right to decline review or close pull requests for any reason, without any questions, particularly under any of the following conditions:
|
||||||
- The proposed change is already mentioned in the roadmap or an existing issue, and it has been assigned to someone.
|
- The proposed change is already mentioned in the roadmap or an existing issue, and it has been assigned to someone.
|
||||||
|
|||||||
@@ -2,133 +2,136 @@
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
<div align="center">
|
|
||||||
|
|
||||||
<b>LLM inference in C/C++</b>
|
|
||||||
|
|
||||||
[](https://opensource.org/licenses/MIT)
|
[](https://opensource.org/licenses/MIT)
|
||||||
[](https://github.com/ggml-org/llama.cpp/releases?q=tag:v0)
|
[](https://github.com/ggml-org/llama.cpp/releases)
|
||||||
[](https://github.com/ggml-org/llama.cpp/releases?q=b)
|
[](https://github.com/ggml-org/llama.cpp/actions/workflows/server.yml)
|
||||||
[](https://github.com/ggml-org/llama.cpp/actions/workflows/server.yml)
|
[](https://github.com/ggml-org/llama.cpp/actions/workflows/docker.yml)
|
||||||
[](https://github.com/ggml-org/llama.cpp/actions/workflows/docker.yml)
|
[](https://github.com/ggml-org/llama.cpp/actions/workflows/winget.yml)
|
||||||
[](https://github.com/ggml-org/llama.cpp/actions/workflows/winget.yml)
|
|
||||||
|
|
||||||
[ggml](https://github.com/ggml-org/ggml) / [ops](https://github.com/ggml-org/llama.cpp/blob/master/docs/ops.md) / [maintainer PRs](https://github.com/ggml-org/llama.cpp/issues?q=is%3Apr%20is%3Aopen%20draft%3AFalse%20(author%3Argerganov%20OR%20author%3AKitaitiMakoto%20OR%20author%3Adanbev%20OR%20author%3Aaldehir%20OR%20author%3Amax-krasnyansky%20OR%20author%3ACISC%20OR%20author%3Aggerganov%20OR%20author%3Aam17an%20OR%20author%3Ajhen0409%20OR%20author%3Abartowski1182%20OR%20author%3Anikwen%20OR%20author%3Ahipudding%20OR%20author%3Aravi9%20OR%20author%3AServeurpersoCom%20OR%20author%3Apwilkin%20OR%20author%3Areeselevine%20OR%20author%3Angxson%20OR%20author%3Ajeffbolznv%20OR%20author%3Amarty1885%20OR%20author%3A0cc4m%20OR%20author%3ATitaniumtown%20OR%20author%3Aangt%20OR%20author%3AIMbackK%20OR%20author%3Aarthw%20OR%20author%3AJohannesGaessler%20OR%20author%3AORippler%20OR%20author%3Aruixiang63%20OR%20author%3Axctan%20OR%20author%3Aallozaur%20OR%20author%3Ayomaytk%20OR%20author%3Aaendk%20OR%20author%3Awine99%20OR%20author%3Agaugarg-nv%20OR%20author%3Ataronaeo%20OR%20author%3Aforforever73%20OR%20author%3Alhez%20OR%20author%3Anetrunnereve%20OR%20author%3Afairydreaming)%20sort%3Aupdated-desc) / [dev stats](https://github.com/ggml-org/llama.cpp-dev) / [lib llama API](https://github.com/ggml-org/llama.cpp/issues/9289) / [llama-server REST API](https://github.com/ggml-org/llama.cpp/issues/9291)
|
[Manifesto](https://github.com/ggml-org/llama.cpp/discussions/205) / [ggml](https://github.com/ggml-org/ggml) / [ops](https://github.com/ggml-org/llama.cpp/blob/master/docs/ops.md) / [maintainer PRs](https://github.com/ggml-org/llama.cpp/issues?q=is%3Apr%20is%3Aopen%20draft%3AFalse%20(author%3Argerganov%20OR%20author%3AKitaitiMakoto%20OR%20author%3Adanbev%20OR%20author%3Aaldehir%20OR%20author%3Amax-krasnyansky%20OR%20author%3ACISC%20OR%20author%3Aggerganov%20OR%20author%3Aam17an%20OR%20author%3Abartowski1182%20OR%20author%3Ahipudding%20OR%20author%3AServeurpersoCom%20OR%20author%3Apwilkin%20OR%20author%3Areeselevine%20OR%20author%3Angxson%20OR%20author%3Ajeffbolznv%20OR%20author%3A0cc4m%20OR%20author%3Aangt%20OR%20author%3AIMbackK%20OR%20author%3Aarthw%20OR%20author%3AJohannesGaessler%20OR%20author%3AORippler%20OR%20author%3Aruixiang63%20OR%20author%3Axctan%20OR%20author%3Aallozaur%20OR%20author%3Ayomaytk%20OR%20author%3Aaendk%20OR%20author%3Agaugarg-nv%20OR%20author%3Ataronaeo%20OR%20author%3Aforforever73%20OR%20author%3Alhez%20OR%20author%3Anetrunnereve%20OR%20author%3Afairydreaming)%20sort%3Aupdated-desc)
|
||||||
|
|
||||||
</div>
|
LLM inference in C/C++
|
||||||
|
|
||||||
## This fork - Polaris / GCN tuning for large MoE models
|
## ⚡ This fork — Fable's MoE-offload prefill optimizations
|
||||||
|
|
||||||
Changes and measurements for running large MoE models with their experts offloaded to system RAM
|
Two **opt-in** optimizations for large MoE models whose experts are offloaded to system RAM
|
||||||
(`--n-cpu-moe`) on an old GCN card. The two code changes below are auto-on, need no flag, and are
|
(`--n-cpu-moe`), found and implemented by Fable. Both are **off by default**, toggled via
|
||||||
**token-identical** to mainline. Everything else here is tuning guidance.
|
environment variables, and produce **token-identical** output to mainline.
|
||||||
|
|
||||||
Findings on an **RX 580 8GB** (Polaris / GCN, PCIe 3.0 x16, no fp16, no matrix cores) with
|
| Env var | What it does |
|
||||||
**Qwen3.5-35B-A3B Q4_K_M**, `-b 2048 -ub 2048`:
|
| --- | --- |
|
||||||
|
| `GGML_CUDA_REGISTER_HOST=1` | Page-locks (pins) the mmap'd CPU expert weights so host->device copies go straight over DMA instead of through the driver's hidden bounce buffer (~6-7 -> ~20 GB/s). Works on CUDA and Vulkan (also honored as `GGML_VK_REGISTER_HOST`). Note: it is a presence check, so `=0` still enables it. |
|
||||||
|
| `GGML_SCHED_PREFETCH_EXPERTS=1` | Prefetches each layer's experts on a second stream, so the weight uploads overlap compute instead of stalling the GPU. **CUDA only** - on the Vulkan backend the second backend instance shares one device queue, giving no overlap, so this regresses (see Vulkan note below). Leave it off on Vulkan. |
|
||||||
|
|
||||||
- **Flash-attention `mask_opt` is enabled for GCN large head sizes (this fork's own change).**
|
### Benchmark
|
||||||
|
|
||||||
|
Measured on an **RTX 3060 12GB** with **Qwen3.6-35B-A3B** (`--n-cpu-moe 26`), prompt-processing at 2048 (`MODEL` = path to your `.gguf`):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# baseline (patches off):
|
||||||
|
./build/bin/llama-bench -m MODEL -ngl 99 -ncmoe 26 -p 2048 -n 0 -r 5 -b 2048 -ub 2048
|
||||||
|
|
||||||
|
# patched (both optimizations on):
|
||||||
|
GGML_CUDA_REGISTER_HOST=1 GGML_SCHED_PREFETCH_EXPERTS=1 \
|
||||||
|
./build/bin/llama-bench -m MODEL -ngl 99 -ncmoe 26 -p 2048 -n 0 -r 5 -b 2048 -ub 2048
|
||||||
|
```
|
||||||
|
|
||||||
|
Result: **~1143 → ~1880 t/s** prefill (**+64%**) — same GPU, same settings, token-identical.
|
||||||
|
|
||||||
|
Branches: [`fable5/host-register`](https://github.com/thecodacus/llama.cpp/tree/fable5/host-register) (pinning only) · [`fable5/prefetch-experts`](https://github.com/thecodacus/llama.cpp/tree/fable5/prefetch-experts) (both — this branch).
|
||||||
|
|
||||||
|
### Vulkan (older AMD, e.g. RX 580 / Polaris)
|
||||||
|
|
||||||
|
On the Vulkan backend the CUDA-oriented flags above behave differently, and this fork adds a
|
||||||
|
Polaris-specific flash-attention fix. Findings on an **RX 580 8GB** (Polaris / GCN, PCIe 3.0 x16,
|
||||||
|
no fp16, no matrix cores) with **Qwen3.5-35B-A3B Q4_K_M**, `-b 2048 -ub 2048`:
|
||||||
|
|
||||||
|
- **Flash-attention `mask_opt` is now enabled for GCN large head sizes (this fork's own change).**
|
||||||
Upstream disables it on GCN; it is a **lossless** win in high-context prefill - it skips
|
Upstream disables it on GCN; it is a **lossless** win in high-context prefill - it skips
|
||||||
fully-masked causal blocks and the per-block mask add on fully-visible ones, which is real work on
|
fully-masked causal blocks and the per-block mask add on fully-visible ones, which is real work on
|
||||||
a card whose attention is compute-bound (no matrix cores). Auto-on, no flag. On Qwen3.5-35B
|
a card whose attention is compute-bound (no matrix cores). Auto-on, no flag. On Qwen3.5-35B
|
||||||
(head_dim 256): pp2048 **+8% @ 16k, +12% @ 32k**, growing with depth; perplexity bit-identical.
|
(head_dim 256): pp2048 **+8% @ 16k, +12% @ 32k**, growing with depth; perplexity bit-identical.
|
||||||
|
- **For a long-running server, load with `--no-mmap`, not pinning.** `GGML_CUDA_REGISTER_HOST=1`
|
||||||
|
(pinning) gives ~+17% in an isolated `llama-bench` run, but in a server the RADV host-pointer
|
||||||
|
import fails and the fallback pre-stage buffer allocation fails for large / co-resident models, so
|
||||||
|
it silently reverts to slow staging (and can trip warnings/OOM). `--no-mmap` (weights in RAM) is
|
||||||
|
both faster and clean there. Pinning is still fine for one-off `llama-bench` numbers.
|
||||||
|
- **`GGML_SCHED_PREFETCH_EXPERTS=1` regresses - do not use it** on Vulkan (its second backend shares
|
||||||
|
one device queue, so uploads never overlap compute).
|
||||||
- **`-b 2048 -ub 2048` is the biggest prefill lever** (the default `-ub 512` roughly halves pp).
|
- **`-b 2048 -ub 2048` is the biggest prefill lever** (the default `-ub 512` roughly halves pp).
|
||||||
- **Tune `--n-cpu-moe` to context length.** Keep some expert layers resident in spare VRAM for short
|
- **Tune `--n-cpu-moe` to context length.** Keep some expert layers resident in spare VRAM for short
|
||||||
prompts (e.g. `ncmoe 28` on the 35B, ~+5% over all-host); at long context the KV cache needs that
|
prompts (e.g. `ncmoe 28` on the 35B, ~+5% over all-host); at long context the KV cache needs that
|
||||||
VRAM, so raise it (`ncmoe 40`, all experts on host). Keep flash attention on (`-fa 1`).
|
VRAM, so raise it (`ncmoe 40`, all experts on host). Keep flash attention on (`-fa 1`).
|
||||||
|
|
||||||
|
Prefill throughput (isolated `llama-bench`, pinned unless noted):
|
||||||
|
|
||||||
|
| Config | pp2048 (t/s) |
|
||||||
|
| --- | ---: |
|
||||||
|
| baseline, unpinned, `ncmoe 40` | ~252 |
|
||||||
|
| pinned, `ncmoe 40` | ~294 |
|
||||||
|
| pinned, `ncmoe 28` | ~308 |
|
||||||
|
| server default (`--no-mmap`, `ncmoe 40`) | ~285 |
|
||||||
|
| + `mask_opt`, @ 32k context | **+12%** |
|
||||||
|
|
||||||
**Recommended RX 580 / Polaris serving command** (per model):
|
**Recommended RX 580 / Polaris serving command** (per model):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
llama-server -hf <repo>:<quant> -ngl 99 --n-cpu-moe 40 -b 2048 -ub 2048 -fa 1
|
llama-server -hf <repo>:<quant> --no-mmap -ngl 99 --n-cpu-moe 40 -b 2048 -ub 2048 -fa 1
|
||||||
```
|
```
|
||||||
|
|
||||||
Lower `--n-cpu-moe` (e.g. 28) if the model plus your context budget leave spare VRAM; keep it high
|
Lower `--n-cpu-moe` (e.g. 28) if the model plus your context budget leave spare VRAM; keep it high
|
||||||
for long-context / agentic use. At long context the bottleneck is attention compute (GPU-bound), so
|
for long-context / agentic use. At long context the bottleneck is attention compute (GPU-bound), so
|
||||||
`mask_opt` (above) is where the remaining prefill wins come from, not the MoE-transfer path.
|
`mask_opt` (above) is where the remaining prefill wins come from, not the MoE-transfer path.
|
||||||
|
|
||||||
### Very large MoE (experts bigger than the GTT limit)
|
## Recent API changes
|
||||||
|
|
||||||
Measured on the same RX 580 with **Laguna-S-2.1 118B IQ2_M** (48 layers, 256 experts, 10 used,
|
- [Changelog for `libllama` API](https://github.com/ggml-org/llama.cpp/issues/9289)
|
||||||
experts 30.7 GiB of a 34.7 GiB file, all host-resident at `--n-cpu-moe 48`). The advice above changes
|
- [Changelog for `llama-server` REST API](https://github.com/ggml-org/llama.cpp/issues/9291)
|
||||||
in this regime:
|
|
||||||
|
|
||||||
- **`--no-mmap` stops being an option.** Its pinned host buffer is charged against the amdgpu GTT
|
## Hot topics
|
||||||
limit (~31.4 GiB here, about half of system RAM). At 30.7 GiB of experts the model no longer
|
|
||||||
loads, and the allocation spike can OOM the box. Use mmap and accept the staging copy.
|
|
||||||
- **The routing-ids readback is pure overhead at prefill batch sizes** and this fork now skips it.
|
|
||||||
To decide which experts to upload, the scheduler read the ids back from the device that had just
|
|
||||||
produced them, forcing a full pipeline flush once per MoE layer per eval. With 2048 tokens x 10
|
|
||||||
experts over 256 experts every expert is used anyway. Skipping it is exact - `mul_mat_id` only
|
|
||||||
reads the rows the ids point at. Auto-on above `4 * n_expert` ids; decode keeps the old path.
|
|
||||||
**pp2048 +4.7% @ 32k depth, +0.9% @ 16k, tg +3%.**
|
|
||||||
- **Where the time actually goes** (`GGML_VK_PERF_LOGGER=1`, depth 0, 22.65 s per 2048-token eval,
|
|
||||||
17.18 s of it GPU-busy so ~24% is H2D stall): expert `MUL_MAT_ID` **52%**, attention projections
|
|
||||||
**24%**, `FLASH_ATTN_EXT` **16%**, everything else 8%. The expert matmuls run at 1686-2139 GFLOP/s
|
|
||||||
while dense `MUL_MAT` q5_K/q6_K in the same graph reaches 3096-3691 - **the single largest
|
|
||||||
remaining opportunity on this hardware is closing that gap**, not the transfer path.
|
|
||||||
- **Interleaved SWA keeps its own small KV cache**, so a sliding-window layer costs the same at any
|
|
||||||
depth (`n_kv` pinned at `n_swa * n_seq_max + n_ubatch`). On this model 36 of 48 layers are O(1) in
|
|
||||||
depth and the entire high-context slowdown comes from the 12 full-attention layers.
|
|
||||||
- **`--parallel 1`** is worth setting for a solo large model: the server otherwise auto-selects 4
|
|
||||||
slots, and the SWA cache is sized `n_swa * n_seq_max + n_ubatch`, so 4 slots cost 4096 cells
|
|
||||||
instead of 2560. Measured **223 MiB of VRAM freed** at 64k context.
|
|
||||||
|
|
||||||
Dead ends measured on this hardware, recorded so they are not retried:
|
- **Hugging Face cache migration: models downloaded with `-hf` are now stored in the standard Hugging Face cache directory, enabling sharing with other HF tools.**
|
||||||
|
- **[guide : using the new WebUI of llama.cpp](https://github.com/ggml-org/llama.cpp/discussions/16938)**
|
||||||
|
- [guide : running gpt-oss with llama.cpp](https://github.com/ggml-org/llama.cpp/discussions/15396)
|
||||||
|
- [[FEEDBACK] Better packaging for llama.cpp to support downstream consumers 🤗](https://github.com/ggml-org/llama.cpp/discussions/15313)
|
||||||
|
- Support for the `gpt-oss` model with native MXFP4 format has been added | [PR](https://github.com/ggml-org/llama.cpp/pull/15091) | [Collaboration with NVIDIA](https://blogs.nvidia.com/blog/rtx-ai-garage-openai-oss) | [Comment](https://github.com/ggml-org/llama.cpp/discussions/15095)
|
||||||
|
- Multimodal support arrived in `llama-server`: [#12898](https://github.com/ggml-org/llama.cpp/pull/12898) | [documentation](./docs/multimodal.md)
|
||||||
|
- VS Code extension for FIM completions: https://github.com/ggml-org/llama.vscode
|
||||||
|
- Vim/Neovim plugin for FIM completions: https://github.com/ggml-org/llama.vim
|
||||||
|
- Hugging Face Inference Endpoints now support GGUF out of the box! https://github.com/ggml-org/llama.cpp/discussions/9669
|
||||||
|
- Hugging Face GGUF editor: [discussion](https://github.com/ggml-org/llama.cpp/discussions/9268) | [tool](https://huggingface.co/spaces/CISCai/gguf-editor)
|
||||||
|
- WebGPU support is now available in the browser, see a blog/demo introducing it [here](https://reeselevine.github.io/llamas-on-the-web/).
|
||||||
|
|
||||||
| Change | Result |
|
----
|
||||||
| --- | ---: |
|
|
||||||
| flash-attn `shmem_staging` enabled for GCN | **-6.7% @ 16k, -7.4% @ 32k** |
|
|
||||||
| `-b 4096 -ub 4096` (to amortize the fixed per-eval expert upload) | flat (-1%) |
|
|
||||||
| `--n-cpu-moe` 44 instead of 48 | +1.5%, but does not fit at 64k ctx |
|
|
||||||
| `mask_opt` gate relaxed below head_dim 256 | -18.5% @ 16k |
|
|
||||||
|
|
||||||
`shmem_staging` looks like a certain win (without it each rowgroup re-reads the whole K/V block
|
|
||||||
through a 16 KiB L1) but the `kvsh` stride of `D/4+1` dwords is 4 mod 32, which costs an 8-way LDS
|
|
||||||
bank conflict on wave64 - that `+1` padding is tuned for warp32. `-ub 4096` fails because halving the
|
|
||||||
number of expert uploads is exactly cancelled by intra-ubatch attention growing quadratically.
|
|
||||||
|
|
||||||
**Serving note that outweighs all of the above.** With a model this large, anything that restarts the
|
|
||||||
process is far more expensive than any kernel win: the server's prompt cache is RAM-only with no disk
|
|
||||||
backing, so a restart forces a full re-prefill of the conversation. If a model swapper can evict this
|
|
||||||
model to run a small helper model (chat-title generation and the like), fix that first - keeping the
|
|
||||||
process alive across a swap took a repeat turn from a 21,960 ms prefill down to 225 ms.
|
|
||||||
|
|
||||||
## Quick start
|
## Quick start
|
||||||
|
|
||||||
A few options to get `llama.cpp` installed on your machine:
|
Getting started with llama.cpp is straightforward. Here are several ways to install it on your machine:
|
||||||
|
|
||||||
- Visit https://llama.app and follow the instructions
|
- Install `llama.cpp` using [brew, nix, winget, or conda-forge](docs/install.md)
|
||||||
- Run with Docker - see our [Docker documentation](docs/docker.md)
|
- Run with Docker - see our [Docker documentation](docs/docker.md)
|
||||||
- Download pre-built binaries from the [releases page](https://github.com/ggml-org/llama.cpp/releases)
|
- Download pre-built binaries from the [releases page](https://github.com/ggml-org/llama.cpp/releases)
|
||||||
- Build from source by cloning this repository - check out [our build guide](docs/build.md)
|
- Build from source by cloning this repository - check out [our build guide](docs/build.md)
|
||||||
|
|
||||||
Once installed:
|
Once installed, you'll need a model to work with. Head to the [Obtaining and quantizing models](#obtaining-and-quantizing-models) section to learn more.
|
||||||
|
|
||||||
|
Example command:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
# Download and run a model directly from Hugging Face
|
# Use a local model file
|
||||||
llama cli -hf ggml-org/Qwen3.5-0.8B-GGUF
|
llama-cli -m my_model.gguf
|
||||||
|
|
||||||
|
# Or download and run a model directly from Hugging Face
|
||||||
|
llama-cli -hf ggml-org/gemma-3-1b-it-GGUF
|
||||||
|
|
||||||
# Launch OpenAI-compatible API server
|
# Launch OpenAI-compatible API server
|
||||||
llama serve -hf ggml-org/Qwen3.5-0.8B-GGUF
|
llama-server -hf ggml-org/gemma-3-1b-it-GGUF
|
||||||
```
|
```
|
||||||
|
|
||||||
<table align="center">
|
|
||||||
<tr>
|
|
||||||
<td align="center" width=50%>
|
|
||||||
<img width="1310" height="888" alt="VLM session with `llama cli`" src="https://github.com/user-attachments/assets/88726b48-1713-48aa-a525-95a02e78afc4" />
|
|
||||||
<i>VLM session with <b>llama cli</b></i>
|
|
||||||
</td>
|
|
||||||
<td align="center">
|
|
||||||
<img width="1392" height="958" alt="Built-in web UI against `llama serve` running Qwen 3.6" src="https://github.com/user-attachments/assets/b402f972-2e32-4def-8771-8d849f08cf2e" />
|
|
||||||
<i>Built-in web UI against <b>llama serve</b></i>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<table>
|
|
||||||
|
|
||||||
## Description
|
## Description
|
||||||
|
|
||||||
The main goal of `llama.cpp` is to enable LLM (and VLM) inference with minimal setup and state-of-the-art performance on
|
The main goal of `llama.cpp` is to enable LLM inference with minimal setup and state-of-the-art performance on a wide
|
||||||
a wide range of hardware - locally and in the cloud.
|
range of hardware - locally and in the cloud.
|
||||||
|
|
||||||
- Plain C/C++ implementation without any dependencies
|
- Plain C/C++ implementation without any dependencies
|
||||||
- Apple silicon is a first-class citizen - optimized via ARM NEON, Accelerate and Metal frameworks
|
- Apple silicon is a first-class citizen - optimized via ARM NEON, Accelerate and Metal frameworks
|
||||||
@@ -139,51 +142,447 @@ a wide range of hardware - locally and in the cloud.
|
|||||||
- Vulkan and SYCL backend support
|
- Vulkan and SYCL backend support
|
||||||
- CPU+GPU hybrid inference to partially accelerate models larger than the total VRAM capacity
|
- CPU+GPU hybrid inference to partially accelerate models larger than the total VRAM capacity
|
||||||
|
|
||||||
The `llama.cpp` project is build on top of the [ggml](https://github.com/ggml-org/ggml) library.
|
The `llama.cpp` project is the main playground for developing new features for the [ggml](https://github.com/ggml-org/ggml) library.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Models</summary>
|
||||||
|
|
||||||
|
Typically finetunes of the base models below are supported as well.
|
||||||
|
|
||||||
|
Instructions for adding support for new models: [HOWTO-add-model.md](docs/development/HOWTO-add-model.md)
|
||||||
|
|
||||||
|
#### Text-only
|
||||||
|
|
||||||
|
- [X] LLaMA 🦙
|
||||||
|
- [x] LLaMA 2 🦙🦙
|
||||||
|
- [x] LLaMA 3 🦙🦙🦙
|
||||||
|
- [X] [Mistral 7B](https://huggingface.co/mistralai/Mistral-7B-v0.1)
|
||||||
|
- [x] [Mixtral MoE](https://huggingface.co/models?search=mistral-ai/Mixtral)
|
||||||
|
- [x] [DBRX](https://huggingface.co/databricks/dbrx-instruct)
|
||||||
|
- [x] [Jamba](https://huggingface.co/ai21labs)
|
||||||
|
- [X] [Falcon](https://huggingface.co/models?search=tiiuae/falcon)
|
||||||
|
- [X] [Chinese LLaMA / Alpaca](https://github.com/ymcui/Chinese-LLaMA-Alpaca) and [Chinese LLaMA-2 / Alpaca-2](https://github.com/ymcui/Chinese-LLaMA-Alpaca-2)
|
||||||
|
- [X] [Vigogne (French)](https://github.com/bofenghuang/vigogne)
|
||||||
|
- [X] [BERT](https://github.com/ggml-org/llama.cpp/pull/5423)
|
||||||
|
- [X] [Koala](https://bair.berkeley.edu/blog/2023/04/03/koala/)
|
||||||
|
- [X] [Baichuan 1 & 2](https://huggingface.co/models?search=baichuan-inc/Baichuan) + [derivations](https://huggingface.co/hiyouga/baichuan-7b-sft)
|
||||||
|
- [X] [Aquila 1 & 2](https://huggingface.co/models?search=BAAI/Aquila)
|
||||||
|
- [X] [Starcoder models](https://github.com/ggml-org/llama.cpp/pull/3187)
|
||||||
|
- [X] [Refact](https://huggingface.co/smallcloudai/Refact-1_6B-fim)
|
||||||
|
- [X] [MPT](https://github.com/ggml-org/llama.cpp/pull/3417)
|
||||||
|
- [X] [Bloom](https://github.com/ggml-org/llama.cpp/pull/3553)
|
||||||
|
- [x] [Yi models](https://huggingface.co/models?search=01-ai/Yi)
|
||||||
|
- [X] [StableLM models](https://huggingface.co/stabilityai)
|
||||||
|
- [x] [Deepseek models](https://huggingface.co/models?search=deepseek-ai/deepseek)
|
||||||
|
- [x] [Qwen models](https://huggingface.co/models?search=Qwen/Qwen)
|
||||||
|
- [x] [PLaMo-13B](https://github.com/ggml-org/llama.cpp/pull/3557)
|
||||||
|
- [x] [Phi models](https://huggingface.co/models?search=microsoft/phi)
|
||||||
|
- [x] [PhiMoE](https://github.com/ggml-org/llama.cpp/pull/11003)
|
||||||
|
- [x] [GPT-2](https://huggingface.co/gpt2)
|
||||||
|
- [x] [Orion 14B](https://github.com/ggml-org/llama.cpp/pull/5118)
|
||||||
|
- [x] [InternLM2](https://huggingface.co/models?search=internlm2)
|
||||||
|
- [x] [CodeShell](https://github.com/WisdomShell/codeshell)
|
||||||
|
- [x] [Gemma](https://ai.google.dev/gemma)
|
||||||
|
- [x] [Mamba](https://github.com/state-spaces/mamba)
|
||||||
|
- [x] [Grok-1](https://huggingface.co/keyfan/grok-1-hf)
|
||||||
|
- [x] [Xverse](https://huggingface.co/models?search=xverse)
|
||||||
|
- [x] [Command-R models](https://huggingface.co/models?search=CohereForAI/c4ai-command-r)
|
||||||
|
- [x] [SEA-LION](https://huggingface.co/models?search=sea-lion)
|
||||||
|
- [x] [GritLM-7B](https://huggingface.co/GritLM/GritLM-7B) + [GritLM-8x7B](https://huggingface.co/GritLM/GritLM-8x7B)
|
||||||
|
- [x] [OLMo](https://allenai.org/olmo)
|
||||||
|
- [x] [OLMo 2](https://allenai.org/olmo)
|
||||||
|
- [x] [OLMoE](https://huggingface.co/allenai/OLMoE-1B-7B-0924)
|
||||||
|
- [x] [Granite models](https://huggingface.co/collections/ibm-granite/granite-code-models-6624c5cec322e4c148c8b330)
|
||||||
|
- [x] [GPT-NeoX](https://github.com/EleutherAI/gpt-neox) + [Pythia](https://github.com/EleutherAI/pythia)
|
||||||
|
- [x] [Snowflake-Arctic MoE](https://huggingface.co/collections/Snowflake/arctic-66290090abe542894a5ac520)
|
||||||
|
- [x] [Smaug](https://huggingface.co/models?search=Smaug)
|
||||||
|
- [x] [Poro 34B](https://huggingface.co/LumiOpen/Poro-34B)
|
||||||
|
- [x] [Bitnet b1.58 models](https://huggingface.co/1bitLLM)
|
||||||
|
- [x] [Flan T5](https://huggingface.co/models?search=flan-t5)
|
||||||
|
- [x] [Open Elm models](https://huggingface.co/collections/apple/openelm-instruct-models-6619ad295d7ae9f868b759ca)
|
||||||
|
- [x] [ChatGLM3-6b](https://huggingface.co/THUDM/chatglm3-6b) + [ChatGLM4-9b](https://huggingface.co/THUDM/glm-4-9b) + [GLMEdge-1.5b](https://huggingface.co/THUDM/glm-edge-1.5b-chat) + [GLMEdge-4b](https://huggingface.co/THUDM/glm-edge-4b-chat)
|
||||||
|
- [x] [GLM-4-0414](https://huggingface.co/collections/THUDM/glm-4-0414-67f3cbcb34dd9d252707cb2e)
|
||||||
|
- [x] [SmolLM](https://huggingface.co/collections/HuggingFaceTB/smollm-6695016cad7167254ce15966)
|
||||||
|
- [x] [EXAONE-3.0-7.8B-Instruct](https://huggingface.co/LGAI-EXAONE/EXAONE-3.0-7.8B-Instruct)
|
||||||
|
- [x] [FalconMamba Models](https://huggingface.co/collections/tiiuae/falconmamba-7b-66b9a580324dd1598b0f6d4a)
|
||||||
|
- [x] [Jais](https://huggingface.co/inceptionai/jais-13b-chat)
|
||||||
|
- [x] [Bielik-11B-v2.3](https://huggingface.co/collections/speakleash/bielik-11b-v23-66ee813238d9b526a072408a)
|
||||||
|
- [x] [RWKV-7](https://huggingface.co/collections/shoumenchougou/rwkv7-gxx-gguf)
|
||||||
|
- [x] [RWKV-6](https://github.com/BlinkDL/RWKV-LM)
|
||||||
|
- [x] [QRWKV-6](https://huggingface.co/recursal/QRWKV6-32B-Instruct-Preview-v0.1)
|
||||||
|
- [x] [GigaChat-20B-A3B](https://huggingface.co/ai-sage/GigaChat-20B-A3B-instruct)
|
||||||
|
- [X] [Trillion-7B-preview](https://huggingface.co/trillionlabs/Trillion-7B-preview)
|
||||||
|
- [x] [Ling models](https://huggingface.co/collections/inclusionAI/ling-67c51c85b34a7ea0aba94c32)
|
||||||
|
- [x] [Liquid LFM2 models](https://huggingface.co/collections/LiquidAI/lfm2)
|
||||||
|
- [x] [Liquid LFM2.5 models](https://huggingface.co/collections/LiquidAI/lfm25)
|
||||||
|
- [x] [Liquid Nanos](https://huggingface.co/collections/LiquidAI/liquid-nanos)
|
||||||
|
- [x] [Hunyuan models](https://huggingface.co/collections/tencent/hunyuan-dense-model-6890632cda26b19119c9c5e7)
|
||||||
|
- [x] [BailingMoeV2 (Ring/Ling 2.0) models](https://huggingface.co/collections/inclusionAI/ling-v2-68bf1dd2fc34c306c1fa6f86)
|
||||||
|
- [x] [Mellum models](https://huggingface.co/JetBrains/models?search=mellum)
|
||||||
|
|
||||||
|
#### Multimodal
|
||||||
|
|
||||||
|
- [x] [LLaVA 1.5 models](https://huggingface.co/collections/liuhaotian/llava-15-653aac15d994e992e2677a7e), [LLaVA 1.6 models](https://huggingface.co/collections/liuhaotian/llava-16-65b9e40155f60fd046a5ccf2)
|
||||||
|
- [x] [BakLLaVA](https://huggingface.co/models?search=SkunkworksAI/Bakllava)
|
||||||
|
- [x] [Obsidian](https://huggingface.co/NousResearch/Obsidian-3B-V0.5)
|
||||||
|
- [x] [ShareGPT4V](https://huggingface.co/models?search=Lin-Chen/ShareGPT4V)
|
||||||
|
- [x] [MobileVLM 1.7B/3B models](https://huggingface.co/models?search=mobileVLM)
|
||||||
|
- [x] [Yi-VL](https://huggingface.co/models?search=Yi-VL)
|
||||||
|
- [x] [Mini CPM](https://huggingface.co/models?search=MiniCPM)
|
||||||
|
- [x] [Moondream](https://huggingface.co/vikhyatk/moondream2)
|
||||||
|
- [x] [Bunny](https://github.com/BAAI-DCAI/Bunny)
|
||||||
|
- [x] [GLM-EDGE](https://huggingface.co/models?search=glm-edge)
|
||||||
|
- [x] [Qwen2-VL](https://huggingface.co/collections/Qwen/qwen2-vl-66cee7455501d7126940800d)
|
||||||
|
- [x] [LFM2-VL](https://huggingface.co/collections/LiquidAI/lfm2-vl-68963bbc84a610f7638d5ffa)
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Bindings</summary>
|
||||||
|
|
||||||
|
- Python: [ddh0/easy-llama](https://github.com/ddh0/easy-llama)
|
||||||
|
- Python: [abetlen/llama-cpp-python](https://github.com/abetlen/llama-cpp-python)
|
||||||
|
- Go: [go-skynet/go-llama.cpp](https://github.com/go-skynet/go-llama.cpp)
|
||||||
|
- Node.js: [withcatai/node-llama-cpp](https://github.com/withcatai/node-llama-cpp)
|
||||||
|
- JS/TS (llama.cpp server client): [lgrammel/modelfusion](https://modelfusion.dev/integration/model-provider/llamacpp)
|
||||||
|
- JS/TS (Programmable Prompt Engine CLI): [offline-ai/cli](https://github.com/offline-ai/cli)
|
||||||
|
- JavaScript/Wasm (works in browser): [tangledgroup/llama-cpp-wasm](https://github.com/tangledgroup/llama-cpp-wasm)
|
||||||
|
- Typescript/Wasm (nicer API, available on npm): [ngxson/wllama](https://github.com/ngxson/wllama)
|
||||||
|
- Ruby: [yoshoku/llama_cpp.rb](https://github.com/yoshoku/llama_cpp.rb)
|
||||||
|
- Ruby: [docusealco/rllama](https://github.com/docusealco/rllama)
|
||||||
|
- Rust (more features): [edgenai/llama_cpp-rs](https://github.com/edgenai/llama_cpp-rs)
|
||||||
|
- Rust (nicer API): [mdrokz/rust-llama.cpp](https://github.com/mdrokz/rust-llama.cpp)
|
||||||
|
- Rust (more direct bindings): [utilityai/llama-cpp-rs](https://github.com/utilityai/llama-cpp-rs)
|
||||||
|
- Rust (automated build from crates.io): [ShelbyJenkins/llm_client](https://github.com/ShelbyJenkins/llm_client)
|
||||||
|
- C#/.NET: [SciSharp/LLamaSharp](https://github.com/SciSharp/LLamaSharp)
|
||||||
|
- C#/VB.NET (more features - community license): [LM-Kit.NET](https://docs.lm-kit.com/lm-kit-net/index.html)
|
||||||
|
- Scala 3: [donderom/llm4s](https://github.com/donderom/llm4s)
|
||||||
|
- Clojure: [phronmophobic/llama.clj](https://github.com/phronmophobic/llama.clj)
|
||||||
|
- React Native: [mybigday/llama.rn](https://github.com/mybigday/llama.rn)
|
||||||
|
- Java: [kherud/java-llama.cpp](https://github.com/kherud/java-llama.cpp)
|
||||||
|
- Java: [QuasarByte/llama-cpp-jna](https://github.com/QuasarByte/llama-cpp-jna)
|
||||||
|
- Zig: [deins/llama.cpp.zig](https://github.com/Deins/llama.cpp.zig)
|
||||||
|
- Flutter/Dart: [netdur/llama_cpp_dart](https://github.com/netdur/llama_cpp_dart)
|
||||||
|
- Flutter: [xuegao-tzx/Fllama](https://github.com/xuegao-tzx/Fllama)
|
||||||
|
- PHP (API bindings and features built on top of llama.cpp): [distantmagic/resonance](https://github.com/distantmagic/resonance) [(more info)](https://github.com/ggml-org/llama.cpp/pull/6326)
|
||||||
|
- Guile Scheme: [guile_llama_cpp](https://savannah.nongnu.org/projects/guile-llama-cpp)
|
||||||
|
- Swift [srgtuszy/llama-cpp-swift](https://github.com/srgtuszy/llama-cpp-swift)
|
||||||
|
- Swift [ShenghaiWang/SwiftLlama](https://github.com/ShenghaiWang/SwiftLlama)
|
||||||
|
- Delphi [Embarcadero/llama-cpp-delphi](https://github.com/Embarcadero/llama-cpp-delphi)
|
||||||
|
- Go (no CGo needed): [hybridgroup/yzma](https://github.com/hybridgroup/yzma)
|
||||||
|
- Android: [llama.android](/examples/llama.android)
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>UIs</summary>
|
||||||
|
|
||||||
|
*(to have a project listed here, it should clearly state that it depends on `llama.cpp`)*
|
||||||
|
|
||||||
|
- [AI Sublime Text plugin](https://github.com/yaroslavyaroslav/OpenAI-sublime-text) (MIT)
|
||||||
|
- [BonzAI App](https://apps.apple.com/us/app/bonzai-your-local-ai-agent/id6752847988) (proprietary)
|
||||||
|
- [cztomsik/ava](https://github.com/cztomsik/ava) (MIT)
|
||||||
|
- [Dot](https://github.com/alexpinel/Dot) (GPL)
|
||||||
|
- [eva](https://github.com/ylsdamxssjxxdd/eva) (MIT)
|
||||||
|
- [iohub/collama](https://github.com/iohub/coLLaMA) (Apache-2.0)
|
||||||
|
- [janhq/jan](https://github.com/janhq/jan) (AGPL)
|
||||||
|
- [johnbean393/Sidekick](https://github.com/johnbean393/Sidekick) (MIT)
|
||||||
|
- [KanTV](https://github.com/zhouwg/kantv?tab=readme-ov-file) (Apache-2.0)
|
||||||
|
- [KodiBot](https://github.com/firatkiral/kodibot) (GPL)
|
||||||
|
- [llama.vim](https://github.com/ggml-org/llama.vim) (MIT)
|
||||||
|
- [LARS](https://github.com/abgulati/LARS) (AGPL)
|
||||||
|
- [Llama Assistant](https://github.com/vietanhdev/llama-assistant) (GPL)
|
||||||
|
- [LlamaLib](https://github.com/undreamai/LlamaLib) (Apache-2.0)
|
||||||
|
- [LLMFarm](https://github.com/guinmoon/LLMFarm?tab=readme-ov-file) (MIT)
|
||||||
|
- [LLMUnity](https://github.com/undreamai/LLMUnity) (MIT)
|
||||||
|
- [LMStudio](https://lmstudio.ai/) (proprietary)
|
||||||
|
- [LocalAI](https://github.com/mudler/LocalAI) (MIT)
|
||||||
|
- [LostRuins/koboldcpp](https://github.com/LostRuins/koboldcpp) (AGPL)
|
||||||
|
- [MindMac](https://mindmac.app) (proprietary)
|
||||||
|
- [MindWorkAI/AI-Studio](https://github.com/MindWorkAI/AI-Studio) (FSL-1.1-MIT)
|
||||||
|
- [Mobile-Artificial-Intelligence/maid](https://github.com/Mobile-Artificial-Intelligence/maid) (MIT)
|
||||||
|
- [Mozilla-Ocho/llamafile](https://github.com/Mozilla-Ocho/llamafile) (Apache-2.0)
|
||||||
|
- [nat/openplayground](https://github.com/nat/openplayground) (MIT)
|
||||||
|
- [nomic-ai/gpt4all](https://github.com/nomic-ai/gpt4all) (MIT)
|
||||||
|
- [ollama/ollama](https://github.com/ollama/ollama) (MIT)
|
||||||
|
- [oobabooga/text-generation-webui](https://github.com/oobabooga/text-generation-webui) (AGPL)
|
||||||
|
- [PocketPal AI](https://github.com/a-ghorbani/pocketpal-ai) (MIT)
|
||||||
|
- [psugihara/FreeChat](https://github.com/psugihara/FreeChat) (MIT)
|
||||||
|
- [ptsochantaris/emeltal](https://github.com/ptsochantaris/emeltal) (MIT)
|
||||||
|
- [pythops/tenere](https://github.com/pythops/tenere) (AGPL)
|
||||||
|
- [ramalama](https://github.com/containers/ramalama) (MIT)
|
||||||
|
- [semperai/amica](https://github.com/semperai/amica) (MIT)
|
||||||
|
- [withcatai/catai](https://github.com/withcatai/catai) (MIT)
|
||||||
|
- [Autopen](https://github.com/blackhole89/autopen) (GPL)
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Tools</summary>
|
||||||
|
|
||||||
|
- [akx/ggify](https://github.com/akx/ggify) – download PyTorch models from Hugging Face Hub and convert them to GGML
|
||||||
|
- [akx/ollama-dl](https://github.com/akx/ollama-dl) – download models from the Ollama library to be used directly with llama.cpp
|
||||||
|
- [crashr/gppm](https://github.com/crashr/gppm) – launch llama.cpp instances utilizing NVIDIA Tesla P40 or P100 GPUs with reduced idle power consumption
|
||||||
|
- [gpustack/gguf-parser](https://github.com/gpustack/gguf-parser-go/tree/main/cmd/gguf-parser) - review/check the GGUF file and estimate the memory usage
|
||||||
|
- [Styled Lines](https://marketplace.unity.com/packages/tools/generative-ai/styled-lines-llama-cpp-model-292902) (proprietary licensed, async wrapper of inference part for game development in Unity3d with pre-built Mobile and Web platform wrappers and a model example)
|
||||||
|
- [unslothai/unsloth](https://github.com/unslothai/unsloth) – 🦥 exports/saves fine-tuned and trained models to GGUF (Apache-2.0)
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Infrastructure</summary>
|
||||||
|
|
||||||
|
- [Paddler](https://github.com/intentee/paddler) - Open-source LLMOps platform for hosting and scaling AI in your own infrastructure
|
||||||
|
- [GPUStack](https://github.com/gpustack/gpustack) - Manage GPU clusters for running LLMs
|
||||||
|
- [llama_cpp_canister](https://github.com/onicai/llama_cpp_canister) - llama.cpp as a smart contract on the Internet Computer, using WebAssembly
|
||||||
|
- [llama-swap](https://github.com/mostlygeek/llama-swap) - transparent proxy that adds automatic model switching with llama-server
|
||||||
|
- [Kalavai](https://github.com/kalavai-net/kalavai-client) - Crowdsource end to end LLM deployment at any scale
|
||||||
|
- [llmaz](https://github.com/InftyAI/llmaz) - ☸️ Easy, advanced inference platform for large language models on Kubernetes.
|
||||||
|
- [LLMKube](https://github.com/defilantech/llmkube) - Kubernetes operator for llama.cpp with multi-GPU and Apple Silicon Metal
|
||||||
|
support"
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Games</summary>
|
||||||
|
|
||||||
|
- [Lucy's Labyrinth](https://github.com/MorganRO8/Lucys_Labyrinth) - A simple maze game where agents controlled by an AI model will try to trick you.
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
|
||||||
## Supported backends
|
## Supported backends
|
||||||
|
|
||||||
| Backend | Target devices |
|
| Backend | Target devices |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
|
| [Metal](docs/build.md#metal-build) | Apple Silicon |
|
||||||
| [BLAS](docs/build.md#blas-build) | All |
|
| [BLAS](docs/build.md#blas-build) | All |
|
||||||
| [BLIS](docs/backend/BLIS.md) | All |
|
| [BLIS](docs/backend/BLIS.md) | All |
|
||||||
| [CANN](docs/build.md#cann) | Ascend NPU |
|
| [SYCL](docs/backend/SYCL.md) | Intel GPU |
|
||||||
|
| [OpenVINO [In Progress]](docs/backend/OPENVINO.md) | Intel CPUs, GPUs, and NPUs |
|
||||||
|
| [MUSA](docs/build.md#musa) | Moore Threads GPU |
|
||||||
| [CUDA](docs/build.md#cuda) | Nvidia GPU |
|
| [CUDA](docs/build.md#cuda) | Nvidia GPU |
|
||||||
| [HIP](docs/build.md#hip) | AMD GPU |
|
| [HIP](docs/build.md#hip) | AMD GPU |
|
||||||
| [Hexagon](docs/backend/snapdragon/README.md) | Snapdragon |
|
|
||||||
| [IBM zDNN](docs/backend/zDNN.md) | IBM Z & LinuxONE |
|
|
||||||
| [MUSA](docs/build.md#musa) | Moore Threads GPU |
|
|
||||||
| [Metal](docs/build.md#metal-build) | Apple Silicon |
|
|
||||||
| [OpenCL](docs/backend/OPENCL.md) | Adreno GPU |
|
|
||||||
| [OpenVINO [In Progress]](docs/backend/OPENVINO.md) | Intel CPUs, GPUs, and NPUs |
|
|
||||||
| [RPC](https://github.com/ggml-org/llama.cpp/tree/master/tools/rpc) | All |
|
|
||||||
| [SYCL](docs/backend/SYCL.md) | Intel GPU |
|
|
||||||
| [VirtGPU](docs/backend/VirtGPU.md) | VirtGPU APIR |
|
|
||||||
| [Vulkan](docs/build.md#vulkan) | GPU |
|
|
||||||
| [WebGPU](docs/build.md#webgpu) | All |
|
|
||||||
| [ZenDNN](docs/build.md#zendnn) | AMD CPU |
|
| [ZenDNN](docs/build.md#zendnn) | AMD CPU |
|
||||||
|
| [Vulkan](docs/build.md#vulkan) | GPU |
|
||||||
|
| [CANN](docs/build.md#cann) | Ascend NPU |
|
||||||
|
| [OpenCL](docs/backend/OPENCL.md) | Adreno GPU |
|
||||||
|
| [IBM zDNN](docs/backend/zDNN.md) | IBM Z & LinuxONE |
|
||||||
|
| [WebGPU](docs/build.md#webgpu) | All |
|
||||||
|
| [RPC](https://github.com/ggml-org/llama.cpp/tree/master/tools/rpc) | All |
|
||||||
|
| [Hexagon [In Progress]](docs/backend/snapdragon/README.md) | Snapdragon |
|
||||||
|
| [VirtGPU](docs/backend/VirtGPU.md) | VirtGPU APIR |
|
||||||
|
|
||||||
## Documentation
|
## Obtaining and quantizing models
|
||||||
|
|
||||||
#### Tools
|
The [Hugging Face](https://huggingface.co) platform hosts a [number of LLMs](https://huggingface.co/models?library=gguf&sort=trending) compatible with `llama.cpp`:
|
||||||
|
|
||||||
- [cli](tools/cli/README.md)
|
- [Trending](https://huggingface.co/models?library=gguf&sort=trending)
|
||||||
- [completion](tools/completion/README.md)
|
- [LLaMA](https://huggingface.co/models?sort=trending&search=llama+gguf)
|
||||||
- [server](tools/server/README.md)
|
|
||||||
- [GBNF grammars](grammars/README.md)
|
|
||||||
|
|
||||||
#### Development
|
You can either manually download the GGUF file or directly use any `llama.cpp`-compatible models from [Hugging Face](https://huggingface.co/) or other model hosting sites, by using this CLI argument: `-hf <user>/<model>[:quant]`. For example:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
llama-cli -hf ggml-org/gemma-3-1b-it-GGUF
|
||||||
|
```
|
||||||
|
|
||||||
|
By default, the CLI would download from Hugging Face, you can switch to other options with the environment variable `MODEL_ENDPOINT`. The `MODEL_ENDPOINT` must point to a Hugging Face compatible API endpoint.
|
||||||
|
|
||||||
|
After downloading a model, use the CLI tools to run it locally - see below.
|
||||||
|
|
||||||
|
`llama.cpp` requires the model to be stored in the [GGUF](https://github.com/ggml-org/ggml/blob/master/docs/gguf.md) file format. Models in other data formats can be converted to GGUF using the `convert_*.py` Python scripts in this repo.
|
||||||
|
|
||||||
|
The Hugging Face platform provides a variety of online tools for converting, quantizing and hosting models with `llama.cpp`:
|
||||||
|
|
||||||
|
- Use the [GGUF-my-repo space](https://huggingface.co/spaces/ggml-org/gguf-my-repo) to convert to GGUF format and quantize model weights to smaller sizes
|
||||||
|
- Use the [GGUF-my-LoRA space](https://huggingface.co/spaces/ggml-org/gguf-my-lora) to convert LoRA adapters to GGUF format (more info: https://github.com/ggml-org/llama.cpp/discussions/10123)
|
||||||
|
- Use the [GGUF-editor space](https://huggingface.co/spaces/CISCai/gguf-editor) to edit GGUF meta data in the browser (more info: https://github.com/ggml-org/llama.cpp/discussions/9268)
|
||||||
|
- Use the [Inference Endpoints](https://ui.endpoints.huggingface.co/) to directly host `llama.cpp` in the cloud (more info: https://github.com/ggml-org/llama.cpp/discussions/9669)
|
||||||
|
|
||||||
|
To learn more about model quantization, [read this documentation](tools/quantize/README.md)
|
||||||
|
|
||||||
|
## [`llama-cli`](tools/cli)
|
||||||
|
|
||||||
|
#### A CLI tool for accessing and experimenting with most of `llama.cpp`'s functionality.
|
||||||
|
|
||||||
|
- <details open>
|
||||||
|
<summary>Run in conversation mode</summary>
|
||||||
|
|
||||||
|
Models with a built-in chat template will automatically activate conversation mode. If this doesn't occur, you can manually enable it by adding `-cnv` and specifying a suitable chat template with `--chat-template NAME`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
llama-cli -m model.gguf
|
||||||
|
|
||||||
|
# > hi, who are you?
|
||||||
|
# Hi there! I'm your helpful assistant! I'm an AI-powered chatbot designed to assist and provide information to users like you. I'm here to help answer your questions, provide guidance, and offer support on a wide range of topics. I'm a friendly and knowledgeable AI, and I'm always happy to help with anything you need. What's on your mind, and how can I assist you today?
|
||||||
|
#
|
||||||
|
# > what is 1+1?
|
||||||
|
# Easy peasy! The answer to 1+1 is... 2!
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
- <details>
|
||||||
|
<summary>Run in conversation mode with custom chat template</summary>
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# use the "chatml" template (use -h to see the list of supported templates)
|
||||||
|
llama-cli -m model.gguf -cnv --chat-template chatml
|
||||||
|
|
||||||
|
# use a custom template
|
||||||
|
llama-cli -m model.gguf -cnv --in-prefix 'User: ' --reverse-prompt 'User:'
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
- <details>
|
||||||
|
<summary>Constrain the output with a custom grammar</summary>
|
||||||
|
|
||||||
|
```bash
|
||||||
|
llama-cli -m model.gguf -n 256 --grammar-file grammars/json.gbnf -p 'Request: schedule a call at 8pm; Command:'
|
||||||
|
|
||||||
|
# {"appointmentTime": "8pm", "appointmentDetails": "schedule a a call"}
|
||||||
|
```
|
||||||
|
|
||||||
|
The [grammars/](grammars/) folder contains a handful of sample grammars. To write your own, check out the [GBNF Guide](grammars/README.md).
|
||||||
|
|
||||||
|
For authoring more complex JSON grammars, check out https://grammar.intrinsiclabs.ai/
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
|
||||||
|
## [`llama-server`](tools/server)
|
||||||
|
|
||||||
|
#### A lightweight, [OpenAI API](https://github.com/openai/openai-openapi) compatible, HTTP server for serving LLMs.
|
||||||
|
|
||||||
|
- <details open>
|
||||||
|
<summary>Start a local HTTP server with default configuration on port 8080</summary>
|
||||||
|
|
||||||
|
```bash
|
||||||
|
llama-server -m model.gguf --port 8080
|
||||||
|
|
||||||
|
# Basic web UI can be accessed via browser: http://localhost:8080
|
||||||
|
# Chat completion endpoint: http://localhost:8080/v1/chat/completions
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
- <details>
|
||||||
|
<summary>Support multiple-users and parallel decoding</summary>
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# up to 4 concurrent requests, each with 4096 max context
|
||||||
|
llama-server -m model.gguf -c 16384 -np 4
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
- <details>
|
||||||
|
<summary>Enable speculative decoding</summary>
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# the draft.gguf model should be a small variant of the target model.gguf
|
||||||
|
llama-server -m model.gguf -md draft.gguf
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
- <details>
|
||||||
|
<summary>Serve an embedding model</summary>
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# use the /embedding endpoint
|
||||||
|
llama-server -m model.gguf --embedding --pooling cls -ub 8192
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
- <details>
|
||||||
|
<summary>Serve a reranking model</summary>
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# use the /reranking endpoint
|
||||||
|
llama-server -m model.gguf --reranking
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
- <details>
|
||||||
|
<summary>Constrain all outputs with a grammar</summary>
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# custom grammar
|
||||||
|
llama-server -m model.gguf --grammar-file grammar.gbnf
|
||||||
|
|
||||||
|
# JSON
|
||||||
|
llama-server -m model.gguf --grammar-file grammars/json.gbnf
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
|
||||||
|
## [`llama-perplexity`](tools/perplexity)
|
||||||
|
|
||||||
|
#### A tool for measuring the [perplexity](tools/perplexity/README.md) [^1] (and other quality metrics) of a model over a given text.
|
||||||
|
|
||||||
|
- <details open>
|
||||||
|
<summary>Measure the perplexity over a text file</summary>
|
||||||
|
|
||||||
|
```bash
|
||||||
|
llama-perplexity -m model.gguf -f file.txt
|
||||||
|
|
||||||
|
# [1]15.2701,[2]5.4007,[3]5.3073,[4]6.2965,[5]5.8940,[6]5.6096,[7]5.7942,[8]4.9297, ...
|
||||||
|
# Final estimate: PPL = 5.4007 +/- 0.67339
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
- <details>
|
||||||
|
<summary>Measure KL divergence</summary>
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# TODO
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
[^1]: [https://huggingface.co/docs/transformers/perplexity](https://huggingface.co/docs/transformers/perplexity)
|
||||||
|
|
||||||
|
## [`llama-bench`](tools/llama-bench)
|
||||||
|
|
||||||
|
#### Benchmark the performance of the inference for various parameters.
|
||||||
|
|
||||||
|
- <details open>
|
||||||
|
<summary>Run default benchmark</summary>
|
||||||
|
|
||||||
|
```bash
|
||||||
|
llama-bench -m model.gguf
|
||||||
|
|
||||||
|
# Output:
|
||||||
|
# | model | size | params | backend | threads | test | t/s |
|
||||||
|
# | ------------------- | ---------: | ---------: | ---------- | ------: | ------------: | -------------------: |
|
||||||
|
# | qwen2 1.5B Q4_0 | 885.97 MiB | 1.54 B | Metal,BLAS | 16 | pp512 | 5765.41 ± 20.55 |
|
||||||
|
# | qwen2 1.5B Q4_0 | 885.97 MiB | 1.54 B | Metal,BLAS | 16 | tg128 | 197.71 ± 0.81 |
|
||||||
|
#
|
||||||
|
# build: 3e0ba0e60 (4229)
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
## [`llama-simple`](examples/simple)
|
||||||
|
|
||||||
|
#### A minimal example for implementing apps with `llama.cpp`. Useful for developers.
|
||||||
|
|
||||||
|
- <details>
|
||||||
|
<summary>Basic text completion</summary>
|
||||||
|
|
||||||
|
```bash
|
||||||
|
llama-simple -m model.gguf
|
||||||
|
|
||||||
|
# Hello my name is Kaitlyn and I am a 16 year old girl. I am a junior in high school and I am currently taking a class called "The Art of
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
- [How to build](docs/build.md)
|
|
||||||
- [Running on Docker](docs/docker.md)
|
|
||||||
- [Build on Android](docs/android.md)
|
|
||||||
- [Multi-GPU usage](docs/multi-gpu.md)
|
|
||||||
- [Performance troubleshooting](docs/development/token_generation_performance_tips.md)
|
|
||||||
- [GGML tips & tricks](https://github.com/ggml-org/llama.cpp/wiki/GGML-Tips-&-Tricks)
|
|
||||||
- [XCFramework](docs/xcframework.md)
|
|
||||||
- [Completions](docs/completions.md)
|
|
||||||
- [Models](docs/models.md)
|
|
||||||
- [Release process](docs/release.md)
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
@@ -191,12 +590,86 @@ The `llama.cpp` project is build on top of the [ggml](https://github.com/ggml-or
|
|||||||
- Collaborators will be invited based on contributions
|
- Collaborators will be invited based on contributions
|
||||||
- Maintainers can push to branches in the `llama.cpp` repo and merge PRs into the `master` branch
|
- Maintainers can push to branches in the `llama.cpp` repo and merge PRs into the `master` branch
|
||||||
- Any help with managing issues, PRs and projects is very appreciated!
|
- Any help with managing issues, PRs and projects is very appreciated!
|
||||||
|
- See [good first issues](https://github.com/ggml-org/llama.cpp/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) for tasks suitable for first contributions
|
||||||
- Read the [CONTRIBUTING.md](CONTRIBUTING.md) for more information
|
- Read the [CONTRIBUTING.md](CONTRIBUTING.md) for more information
|
||||||
|
- Make sure to read this: [Inference at the edge](https://github.com/ggml-org/llama.cpp/discussions/205)
|
||||||
|
- A bit of backstory for those who are interested: [Changelog podcast](https://changelog.com/podcast/532)
|
||||||
|
|
||||||
## Acknowledgements
|
## Other documentation
|
||||||
|
|
||||||
|
- [cli](tools/cli/README.md)
|
||||||
|
- [completion](tools/completion/README.md)
|
||||||
|
- [server](tools/server/README.md)
|
||||||
|
- [GBNF grammars](grammars/README.md)
|
||||||
|
|
||||||
|
#### Development documentation
|
||||||
|
|
||||||
|
- [How to build](docs/build.md)
|
||||||
|
- [Running on Docker](docs/docker.md)
|
||||||
|
- [Build on Android](docs/android.md)
|
||||||
|
- [Multi-GPU usage](docs/multi-gpu.md)
|
||||||
|
- [Performance troubleshooting](docs/development/token_generation_performance_tips.md)
|
||||||
|
- [GGML tips & tricks](https://github.com/ggml-org/llama.cpp/wiki/GGML-Tips-&-Tricks)
|
||||||
|
|
||||||
|
#### Seminal papers and background on the models
|
||||||
|
|
||||||
|
If your issue is with model generation quality, then please at least scan the following links and papers to understand the limitations of LLaMA models. This is especially important when choosing an appropriate model size and appreciating both the significant and subtle differences between LLaMA models and ChatGPT:
|
||||||
|
- LLaMA:
|
||||||
|
- [Introducing LLaMA: A foundational, 65-billion-parameter large language model](https://ai.facebook.com/blog/large-language-model-llama-meta-ai/)
|
||||||
|
- [LLaMA: Open and Efficient Foundation Language Models](https://arxiv.org/abs/2302.13971)
|
||||||
|
- GPT-3
|
||||||
|
- [Language Models are Few-Shot Learners](https://arxiv.org/abs/2005.14165)
|
||||||
|
- GPT-3.5 / InstructGPT / ChatGPT:
|
||||||
|
- [Aligning language models to follow instructions](https://openai.com/research/instruction-following)
|
||||||
|
- [Training language models to follow instructions with human feedback](https://arxiv.org/abs/2203.02155)
|
||||||
|
|
||||||
|
## XCFramework
|
||||||
|
The XCFramework is a precompiled version of the library for iOS, visionOS, tvOS,
|
||||||
|
and macOS. It can be used in Swift projects without the need to compile the
|
||||||
|
library from source. For example:
|
||||||
|
```swift
|
||||||
|
// swift-tools-version: 5.10
|
||||||
|
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||||
|
|
||||||
|
import PackageDescription
|
||||||
|
|
||||||
|
let package = Package(
|
||||||
|
name: "MyLlamaPackage",
|
||||||
|
targets: [
|
||||||
|
.executableTarget(
|
||||||
|
name: "MyLlamaPackage",
|
||||||
|
dependencies: [
|
||||||
|
"LlamaFramework"
|
||||||
|
]),
|
||||||
|
.binaryTarget(
|
||||||
|
name: "LlamaFramework",
|
||||||
|
url: "https://github.com/ggml-org/llama.cpp/releases/download/b5046/llama-b5046-xcframework.zip",
|
||||||
|
checksum: "c19be78b5f00d8d29a25da41042cb7afa094cbf6280a225abe614b03b20029ab"
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
```
|
||||||
|
The above example is using an intermediate build `b5046` of the library. This can be modified
|
||||||
|
to use a different version by changing the URL and checksum.
|
||||||
|
|
||||||
|
## Completions
|
||||||
|
Command-line completion is available for some environments.
|
||||||
|
|
||||||
|
#### Bash Completion
|
||||||
|
```bash
|
||||||
|
$ build/bin/llama-cli --completion-bash > ~/.llama-completion.bash
|
||||||
|
$ source ~/.llama-completion.bash
|
||||||
|
```
|
||||||
|
Optionally this can be added to your `.bashrc` or `.bash_profile` to load it
|
||||||
|
automatically. For example:
|
||||||
|
```console
|
||||||
|
$ echo "source ~/.llama-completion.bash" >> ~/.bashrc
|
||||||
|
```
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
- [yhirose/cpp-httplib](https://github.com/yhirose/cpp-httplib) - Single-header HTTP server, used by `llama-server` - MIT license
|
- [yhirose/cpp-httplib](https://github.com/yhirose/cpp-httplib) - Single-header HTTP server, used by `llama-server` - MIT license
|
||||||
- [nothings/stb](https://github.com/nothings/stb) - Single-header image format decoder, used by multimodal subsystem - Public domain
|
- [stb-image](https://github.com/nothings/stb) - Single-header image format decoder, used by multimodal subsystem - Public domain
|
||||||
- [nlohmann/json](https://github.com/nlohmann/json) - Single-header JSON library, used by various tools/examples - MIT License
|
- [nlohmann/json](https://github.com/nlohmann/json) - Single-header JSON library, used by various tools/examples - MIT License
|
||||||
- [mackron/miniaudio](https://github.com/mackron/miniaudio) - Single-header audio format decoder, used by multimodal subsystem - Public domain
|
- [miniaudio.h](https://github.com/mackron/miniaudio) - Single-header audio format decoder, used by multimodal subsystem - Public domain
|
||||||
- [sheredom/subprocess.h](https://github.com/sheredom/subprocess.h) - Single-header process launching solution for C and C++ - Public domain
|
- [subprocess.h](https://github.com/sheredom/subprocess.h) - Single-header process launching solution for C and C++ - Public domain
|
||||||
|
|||||||
@@ -21,18 +21,11 @@ Please disclose it as a private [security advisory](https://github.com/ggml-org/
|
|||||||
|
|
||||||
A team of volunteers on a reasonable-effort basis maintains this project. As such, please give us at least 90 days to work on a fix before public exposure.
|
A team of volunteers on a reasonable-effort basis maintains this project. As such, please give us at least 90 days to work on a fix before public exposure.
|
||||||
|
|
||||||
### AI-powered code scan
|
|
||||||
|
|
||||||
llama.cpp has an AI security scanner that scans the code periodically. The full prompts and tool set can be found in [ggml-org/security-scan-prompt](https://github.com/ggml-org/security-scan-prompt).
|
|
||||||
|
|
||||||
We greatly appreciate reports that reflect genuine research effort, and we are happy to spend our time reviewing them. Findings that an autonomous AI agent can surface on its own add little on top of the scans we already run.
|
|
||||||
|
|
||||||
### Requirements
|
### Requirements
|
||||||
|
|
||||||
Before submitting your report, ensure you meet the following requirements:
|
Before submitting your report, ensure you meet the following requirements:
|
||||||
|
|
||||||
- You have read this policy and fully understand it.
|
- You have read this policy and fully understand it.
|
||||||
- You have searched for existing discussions of the issue. If it has already been reported, your report will likely be rejected as a duplicate.
|
|
||||||
- AI is only permitted in an assistive capacity as stated in [AGENTS.md](AGENTS.md). We do not accept reports that are written exclusively by AI.
|
- AI is only permitted in an assistive capacity as stated in [AGENTS.md](AGENTS.md). We do not accept reports that are written exclusively by AI.
|
||||||
- Your report must include a working Proof-of-Concept in the form of a script and/or attached files.
|
- Your report must include a working Proof-of-Concept in the form of a script and/or attached files.
|
||||||
|
|
||||||
@@ -53,8 +46,6 @@ Only vulnerabilities that fall within these parts of the project are considered
|
|||||||
|
|
||||||
Note that none of the topics under [Using llama.cpp securely](#using-llamacpp-securely) are considered vulnerabilities in LLaMA C++.
|
Note that none of the topics under [Using llama.cpp securely](#using-llamacpp-securely) are considered vulnerabilities in LLaMA C++.
|
||||||
|
|
||||||
Denial-of-Service (DoS) bugs are generally not treated as vulnerabilities. We don't reject them outright, but we look at them case-by-case and only accept those that are genuinely worth fixing.
|
|
||||||
|
|
||||||
For vulnerabilities that fall within the `vendor` directory, please report them directly to the third-party project.
|
For vulnerabilities that fall within the `vendor` directory, please report them directly to the third-party project.
|
||||||
|
|
||||||
## Using llama.cpp securely
|
## Using llama.cpp securely
|
||||||
|
|||||||
+3
-5
@@ -1,7 +1,5 @@
|
|||||||
#include "build-info.h"
|
#include "build-info.h"
|
||||||
|
|
||||||
#include "llama.h"
|
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -79,12 +77,12 @@ static const command cmds[] = {
|
|||||||
|
|
||||||
#undef UPDATE_HIDDEN
|
#undef UPDATE_HIDDEN
|
||||||
|
|
||||||
static int version(int /*argc*/, char ** /*argv*/) {
|
static int version(int argc, char ** argv) {
|
||||||
llama_print_build_info(llama_version(), stdout);
|
printf("%s\n", llama_build_info());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int licenses(int /*argc*/, char ** /*argv*/) {
|
static int licenses(int argc, char ** argv) {
|
||||||
for (int i = 0; LICENSES[i]; ++i) {
|
for (int i = 0; LICENSES[i]; ++i) {
|
||||||
printf("%s\n", LICENSES[i]);
|
printf("%s\n", LICENSES[i]);
|
||||||
}
|
}
|
||||||
|
|||||||
+131
-225
@@ -1,8 +1,5 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
#
|
#
|
||||||
# usage: ./build-xcframework.sh [BUILD ...] (default: all builds)
|
|
||||||
# builds: ios-sim ios-device macos visionos visionos-sim tvos-sim tvos-device
|
|
||||||
#
|
|
||||||
# Options
|
# Options
|
||||||
IOS_MIN_OS_VERSION=16.4
|
IOS_MIN_OS_VERSION=16.4
|
||||||
MACOS_MIN_OS_VERSION=13.3
|
MACOS_MIN_OS_VERSION=13.3
|
||||||
@@ -18,47 +15,11 @@ LLAMA_BUILD_TESTS=OFF
|
|||||||
LLAMA_BUILD_SERVER=OFF
|
LLAMA_BUILD_SERVER=OFF
|
||||||
LLAMA_BUILD_MTMD=ON
|
LLAMA_BUILD_MTMD=ON
|
||||||
GGML_METAL=ON
|
GGML_METAL=ON
|
||||||
GGML_METAL_EMBED_LIBRARY=${GGML_METAL_EMBED_LIBRARY:-ON}
|
GGML_METAL_EMBED_LIBRARY=ON
|
||||||
GGML_BLAS_DEFAULT=ON
|
GGML_BLAS_DEFAULT=ON
|
||||||
|
GGML_METAL_USE_BF16=ON
|
||||||
GGML_OPENMP=OFF
|
GGML_OPENMP=OFF
|
||||||
|
|
||||||
# Max number of concurrent platform builds
|
|
||||||
MAX_PARALLEL_BUILDS=1
|
|
||||||
|
|
||||||
# Split the available cores between the concurrent builds (min 1)
|
|
||||||
JOBS_PER_BUILD=$(( $(sysctl -n hw.logicalcpu) / MAX_PARALLEL_BUILDS ))
|
|
||||||
if [[ "$JOBS_PER_BUILD" -lt 1 ]]; then
|
|
||||||
JOBS_PER_BUILD=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# echo "build_fn build_dir release_dir platform is_simulator min_os" for a build name
|
|
||||||
build_spec() {
|
|
||||||
case "$1" in
|
|
||||||
ios-sim) echo "build_ios_sim build-ios-sim Release-iphonesimulator ios true ${IOS_MIN_OS_VERSION}" ;;
|
|
||||||
ios-device) echo "build_ios_device build-ios-device Release-iphoneos ios false ${IOS_MIN_OS_VERSION}" ;;
|
|
||||||
macos) echo "build_macos build-macos Release macos false ${MACOS_MIN_OS_VERSION}" ;;
|
|
||||||
visionos) echo "build_visionos build-visionos Release-xros visionos false ${VISIONOS_MIN_OS_VERSION}" ;;
|
|
||||||
visionos-sim) echo "build_visionos_sim build-visionos-sim Release-xrsimulator visionos true ${VISIONOS_MIN_OS_VERSION}" ;;
|
|
||||||
tvos-sim) echo "build_tvos_sim build-tvos-sim Release-appletvsimulator tvos true ${TVOS_MIN_OS_VERSION}" ;;
|
|
||||||
tvos-device) echo "build_tvos_device build-tvos-device Release-appletvos tvos false ${TVOS_MIN_OS_VERSION}" ;;
|
|
||||||
*) return 1 ;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
# Default: build everything
|
|
||||||
if [[ $# -eq 0 ]]; then
|
|
||||||
BUILDS=(ios-sim ios-device macos visionos visionos-sim tvos-sim tvos-device)
|
|
||||||
else
|
|
||||||
BUILDS=("$@")
|
|
||||||
fi
|
|
||||||
for b in "${BUILDS[@]}"; do
|
|
||||||
if ! build_spec "$b" >/dev/null; then
|
|
||||||
echo "Error: unknown build '$b'" >&2
|
|
||||||
echo "Valid builds: ios-sim ios-device macos visionos visionos-sim tvos-sim tvos-device" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
COMMON_C_FLAGS="-Wno-macro-redefined -Wno-shorten-64-to-32 -Wno-unused-command-line-argument -g"
|
COMMON_C_FLAGS="-Wno-macro-redefined -Wno-shorten-64-to-32 -Wno-unused-command-line-argument -g"
|
||||||
COMMON_CXX_FLAGS="-Wno-macro-redefined -Wno-shorten-64-to-32 -Wno-unused-command-line-argument -g"
|
COMMON_CXX_FLAGS="-Wno-macro-redefined -Wno-shorten-64-to-32 -Wno-unused-command-line-argument -g"
|
||||||
|
|
||||||
@@ -83,6 +44,7 @@ COMMON_CMAKE_ARGS=(
|
|||||||
-DGGML_METAL_EMBED_LIBRARY=${GGML_METAL_EMBED_LIBRARY}
|
-DGGML_METAL_EMBED_LIBRARY=${GGML_METAL_EMBED_LIBRARY}
|
||||||
-DGGML_BLAS_DEFAULT=${GGML_BLAS_DEFAULT}
|
-DGGML_BLAS_DEFAULT=${GGML_BLAS_DEFAULT}
|
||||||
-DGGML_METAL=${GGML_METAL}
|
-DGGML_METAL=${GGML_METAL}
|
||||||
|
-DGGML_METAL_USE_BF16=${GGML_METAL_USE_BF16}
|
||||||
-DGGML_NATIVE=OFF
|
-DGGML_NATIVE=OFF
|
||||||
-DGGML_OPENMP=${GGML_OPENMP}
|
-DGGML_OPENMP=${GGML_OPENMP}
|
||||||
)
|
)
|
||||||
@@ -169,14 +131,6 @@ setup_framework_structure() {
|
|||||||
cp tools/mtmd/mtmd.h ${header_path}
|
cp tools/mtmd/mtmd.h ${header_path}
|
||||||
cp tools/mtmd/mtmd-helper.h ${header_path}
|
cp tools/mtmd/mtmd-helper.h ${header_path}
|
||||||
|
|
||||||
if [[ "$GGML_METAL_EMBED_LIBRARY" == "OFF" ]]; then
|
|
||||||
if [[ "$platform" == "macos" ]]; then
|
|
||||||
cp ${build_dir}/bin/*.metallib ${build_dir}/framework/${framework_name}.framework/Versions/A/Resources/
|
|
||||||
else
|
|
||||||
cp ${build_dir}/bin/*.metallib ${build_dir}/framework/${framework_name}.framework/
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Create module map (common for all platforms)
|
# Create module map (common for all platforms)
|
||||||
cat > ${module_path}module.modulemap << EOF
|
cat > ${module_path}module.modulemap << EOF
|
||||||
framework module llama {
|
framework module llama {
|
||||||
@@ -298,7 +252,6 @@ combine_static_libraries() {
|
|||||||
"${base_dir}/${build_dir}/ggml/src/ggml-metal/${release_dir}/libggml-metal.a"
|
"${base_dir}/${build_dir}/ggml/src/ggml-metal/${release_dir}/libggml-metal.a"
|
||||||
"${base_dir}/${build_dir}/ggml/src/ggml-blas/${release_dir}/libggml-blas.a"
|
"${base_dir}/${build_dir}/ggml/src/ggml-blas/${release_dir}/libggml-blas.a"
|
||||||
"${base_dir}/${build_dir}/tools/mtmd/${release_dir}/libmtmd.a"
|
"${base_dir}/${build_dir}/tools/mtmd/${release_dir}/libmtmd.a"
|
||||||
"${base_dir}/${build_dir}/vendor/hash/${release_dir}/libvendor-hash.a"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create temporary directory for processing
|
# Create temporary directory for processing
|
||||||
@@ -450,195 +403,148 @@ combine_static_libraries() {
|
|||||||
rm -rf "${temp_dir}"
|
rm -rf "${temp_dir}"
|
||||||
}
|
}
|
||||||
|
|
||||||
build_ios_sim() {
|
echo "Building for iOS simulator..."
|
||||||
echo "Building for iOS simulator..."
|
cmake -B build-ios-sim -G Xcode \
|
||||||
cmake -B build-ios-sim -G Xcode \
|
"${COMMON_CMAKE_ARGS[@]}" \
|
||||||
"${COMMON_CMAKE_ARGS[@]}" \
|
-DCMAKE_OSX_DEPLOYMENT_TARGET=${IOS_MIN_OS_VERSION} \
|
||||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${IOS_MIN_OS_VERSION} \
|
-DIOS=ON \
|
||||||
-DIOS=ON \
|
-DCMAKE_SYSTEM_NAME=iOS \
|
||||||
-DCMAKE_SYSTEM_NAME=iOS \
|
-DCMAKE_OSX_SYSROOT=iphonesimulator \
|
||||||
-DCMAKE_OSX_SYSROOT=iphonesimulator \
|
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
|
||||||
-DGGML_METAL_TARGET_OS=ios \
|
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=iphonesimulator \
|
||||||
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
|
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
|
||||||
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=iphonesimulator \
|
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
|
||||||
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
|
-DLLAMA_OPENSSL=OFF \
|
||||||
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
|
-DMTMD_VIDEO=OFF \
|
||||||
-DLLAMA_OPENSSL=OFF \
|
-S .
|
||||||
-DMTMD_VIDEO=OFF \
|
cmake --build build-ios-sim --config Release -j $(sysctl -n hw.logicalcpu) -- -quiet
|
||||||
-S .
|
|
||||||
cmake --build build-ios-sim --config Release -j "${JOBS_PER_BUILD}" -- -quiet
|
|
||||||
}
|
|
||||||
|
|
||||||
build_ios_device() {
|
echo "Building for iOS devices..."
|
||||||
echo "Building for iOS devices..."
|
cmake -B build-ios-device -G Xcode \
|
||||||
cmake -B build-ios-device -G Xcode \
|
"${COMMON_CMAKE_ARGS[@]}" \
|
||||||
"${COMMON_CMAKE_ARGS[@]}" \
|
-DCMAKE_OSX_DEPLOYMENT_TARGET=${IOS_MIN_OS_VERSION} \
|
||||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${IOS_MIN_OS_VERSION} \
|
-DCMAKE_SYSTEM_NAME=iOS \
|
||||||
-DCMAKE_SYSTEM_NAME=iOS \
|
-DCMAKE_OSX_SYSROOT=iphoneos \
|
||||||
-DCMAKE_OSX_SYSROOT=iphoneos \
|
-DCMAKE_OSX_ARCHITECTURES="arm64" \
|
||||||
-DGGML_METAL_TARGET_OS=ios \
|
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=iphoneos \
|
||||||
-DCMAKE_OSX_ARCHITECTURES="arm64" \
|
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
|
||||||
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=iphoneos \
|
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
|
||||||
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
|
-DLLAMA_OPENSSL=OFF \
|
||||||
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
|
-DMTMD_VIDEO=OFF \
|
||||||
-DLLAMA_OPENSSL=OFF \
|
-S .
|
||||||
-DMTMD_VIDEO=OFF \
|
cmake --build build-ios-device --config Release -j $(sysctl -n hw.logicalcpu) -- -quiet
|
||||||
-S .
|
|
||||||
cmake --build build-ios-device --config Release -j "${JOBS_PER_BUILD}" -- -quiet
|
|
||||||
}
|
|
||||||
|
|
||||||
build_macos() {
|
echo "Building for macOS..."
|
||||||
echo "Building for macOS..."
|
cmake -B build-macos -G Xcode \
|
||||||
cmake -B build-macos -G Xcode \
|
"${COMMON_CMAKE_ARGS[@]}" \
|
||||||
"${COMMON_CMAKE_ARGS[@]}" \
|
-DCMAKE_OSX_DEPLOYMENT_TARGET=${MACOS_MIN_OS_VERSION} \
|
||||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${MACOS_MIN_OS_VERSION} \
|
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
|
||||||
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
|
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
|
||||||
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
|
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
|
||||||
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
|
-DLLAMA_OPENSSL=OFF \
|
||||||
-DLLAMA_OPENSSL=OFF \
|
-S .
|
||||||
-S .
|
cmake --build build-macos --config Release -j $(sysctl -n hw.logicalcpu) -- -quiet
|
||||||
cmake --build build-macos --config Release -j "${JOBS_PER_BUILD}" -- -quiet
|
|
||||||
}
|
|
||||||
|
|
||||||
build_visionos() {
|
echo "Building for visionOS..."
|
||||||
echo "Building for visionOS..."
|
cmake -B build-visionos -G Xcode \
|
||||||
cmake -B build-visionos -G Xcode \
|
"${COMMON_CMAKE_ARGS[@]}" \
|
||||||
"${COMMON_CMAKE_ARGS[@]}" \
|
-DCMAKE_OSX_DEPLOYMENT_TARGET=${VISIONOS_MIN_OS_VERSION} \
|
||||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${VISIONOS_MIN_OS_VERSION} \
|
-DCMAKE_OSX_ARCHITECTURES="arm64" \
|
||||||
-DCMAKE_OSX_ARCHITECTURES="arm64" \
|
-DCMAKE_SYSTEM_NAME=visionOS \
|
||||||
-DCMAKE_SYSTEM_NAME=visionOS \
|
-DCMAKE_OSX_SYSROOT=xros \
|
||||||
-DCMAKE_OSX_SYSROOT=xros \
|
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=xros \
|
||||||
-DGGML_METAL_TARGET_OS=xros \
|
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
|
||||||
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=xros \
|
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
|
||||||
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
|
-DLLAMA_OPENSSL=OFF \
|
||||||
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
|
-DLLAMA_BUILD_SERVER=OFF \
|
||||||
-DLLAMA_OPENSSL=OFF \
|
-DMTMD_VIDEO=OFF \
|
||||||
-DLLAMA_BUILD_SERVER=OFF \
|
-S .
|
||||||
-DMTMD_VIDEO=OFF \
|
cmake --build build-visionos --config Release -j $(sysctl -n hw.logicalcpu) -- -quiet
|
||||||
-S .
|
|
||||||
cmake --build build-visionos --config Release -j "${JOBS_PER_BUILD}" -- -quiet
|
|
||||||
}
|
|
||||||
|
|
||||||
build_visionos_sim() {
|
echo "Building for visionOS simulator..."
|
||||||
echo "Building for visionOS simulator..."
|
cmake -B build-visionos-sim -G Xcode \
|
||||||
cmake -B build-visionos-sim -G Xcode \
|
"${COMMON_CMAKE_ARGS[@]}" \
|
||||||
"${COMMON_CMAKE_ARGS[@]}" \
|
-DCMAKE_OSX_DEPLOYMENT_TARGET=${VISIONOS_MIN_OS_VERSION} \
|
||||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${VISIONOS_MIN_OS_VERSION} \
|
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
|
||||||
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
|
-DCMAKE_SYSTEM_NAME=visionOS \
|
||||||
-DCMAKE_SYSTEM_NAME=visionOS \
|
-DCMAKE_OSX_SYSROOT=xrsimulator \
|
||||||
-DCMAKE_OSX_SYSROOT=xrsimulator \
|
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=xrsimulator \
|
||||||
-DGGML_METAL_TARGET_OS=xros \
|
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
|
||||||
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=xrsimulator \
|
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
|
||||||
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
|
-DLLAMA_OPENSSL=OFF \
|
||||||
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
|
-DLLAMA_BUILD_SERVER=OFF \
|
||||||
-DLLAMA_OPENSSL=OFF \
|
-DMTMD_VIDEO=OFF \
|
||||||
-DLLAMA_BUILD_SERVER=OFF \
|
-S .
|
||||||
-DMTMD_VIDEO=OFF \
|
cmake --build build-visionos-sim --config Release -j $(sysctl -n hw.logicalcpu) -- -quiet
|
||||||
-S .
|
|
||||||
cmake --build build-visionos-sim --config Release -j "${JOBS_PER_BUILD}" -- -quiet
|
|
||||||
}
|
|
||||||
|
|
||||||
# Add tvOS builds (might need the same u_int definitions as watchOS and visionOS)
|
# Add tvOS builds (might need the same u_int definitions as watchOS and visionOS)
|
||||||
build_tvos_sim() {
|
echo "Building for tvOS simulator..."
|
||||||
echo "Building for tvOS simulator..."
|
cmake -B build-tvos-sim -G Xcode \
|
||||||
cmake -B build-tvos-sim -G Xcode \
|
"${COMMON_CMAKE_ARGS[@]}" \
|
||||||
"${COMMON_CMAKE_ARGS[@]}" \
|
-DCMAKE_OSX_DEPLOYMENT_TARGET=${TVOS_MIN_OS_VERSION} \
|
||||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${TVOS_MIN_OS_VERSION} \
|
-DCMAKE_SYSTEM_NAME=tvOS \
|
||||||
-DCMAKE_SYSTEM_NAME=tvOS \
|
-DCMAKE_OSX_SYSROOT=appletvsimulator \
|
||||||
-DCMAKE_OSX_SYSROOT=appletvsimulator \
|
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
|
||||||
-DGGML_METAL_TARGET_OS=tvos \
|
-DGGML_METAL=ON \
|
||||||
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
|
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=appletvsimulator \
|
||||||
-DGGML_METAL=ON \
|
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
|
||||||
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=appletvsimulator \
|
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
|
||||||
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
|
-DLLAMA_OPENSSL=OFF \
|
||||||
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
|
-DMTMD_VIDEO=OFF \
|
||||||
-DLLAMA_OPENSSL=OFF \
|
-S .
|
||||||
-DMTMD_VIDEO=OFF \
|
cmake --build build-tvos-sim --config Release -j $(sysctl -n hw.logicalcpu) -- -quiet
|
||||||
-S .
|
|
||||||
cmake --build build-tvos-sim --config Release -j "${JOBS_PER_BUILD}" -- -quiet
|
|
||||||
}
|
|
||||||
|
|
||||||
build_tvos_device() {
|
echo "Building for tvOS devices..."
|
||||||
echo "Building for tvOS devices..."
|
cmake -B build-tvos-device -G Xcode \
|
||||||
cmake -B build-tvos-device -G Xcode \
|
"${COMMON_CMAKE_ARGS[@]}" \
|
||||||
"${COMMON_CMAKE_ARGS[@]}" \
|
-DCMAKE_OSX_DEPLOYMENT_TARGET=${TVOS_MIN_OS_VERSION} \
|
||||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${TVOS_MIN_OS_VERSION} \
|
-DCMAKE_SYSTEM_NAME=tvOS \
|
||||||
-DCMAKE_SYSTEM_NAME=tvOS \
|
-DCMAKE_OSX_SYSROOT=appletvos \
|
||||||
-DCMAKE_OSX_SYSROOT=appletvos \
|
-DCMAKE_OSX_ARCHITECTURES="arm64" \
|
||||||
-DGGML_METAL_TARGET_OS=tvos \
|
-DGGML_METAL=ON \
|
||||||
-DCMAKE_OSX_ARCHITECTURES="arm64" \
|
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=appletvos \
|
||||||
-DGGML_METAL=ON \
|
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
|
||||||
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=appletvos \
|
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
|
||||||
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
|
-DLLAMA_OPENSSL=OFF \
|
||||||
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
|
-DMTMD_VIDEO=OFF \
|
||||||
-DLLAMA_OPENSSL=OFF \
|
-S .
|
||||||
-DMTMD_VIDEO=OFF \
|
cmake --build build-tvos-device --config Release -j $(sysctl -n hw.logicalcpu) -- -quiet
|
||||||
-S .
|
|
||||||
cmake --build build-tvos-device --config Release -j "${JOBS_PER_BUILD}" -- -quiet
|
|
||||||
}
|
|
||||||
|
|
||||||
run_builds_parallel() {
|
|
||||||
local -a pids=()
|
|
||||||
local -a names=()
|
|
||||||
local name i
|
|
||||||
for name in "$@"; do
|
|
||||||
# Wait for the oldest running build to free a slot
|
|
||||||
if [[ "${#pids[@]}" -ge "$MAX_PARALLEL_BUILDS" ]]; then
|
|
||||||
if ! wait "${pids[0]}"; then
|
|
||||||
echo "ERROR: build '${names[0]}' failed, log follows (${names[0]}.log):" >&2
|
|
||||||
kill "${pids[@]}" 2>/dev/null || true
|
|
||||||
cat "${names[0]}.log" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
pids=("${pids[@]:1}")
|
|
||||||
names=("${names[@]:1}")
|
|
||||||
fi
|
|
||||||
echo "Starting build: $name (log: ${name}.log, -j ${JOBS_PER_BUILD})"
|
|
||||||
"$name" > "${name}.log" 2>&1 &
|
|
||||||
pids+=("$!")
|
|
||||||
names+=("$name")
|
|
||||||
done
|
|
||||||
# Wait for the remaining builds
|
|
||||||
for i in "${!pids[@]}"; do
|
|
||||||
if ! wait "${pids[$i]}"; then
|
|
||||||
echo "ERROR: build '${names[$i]}' failed, log follows (${names[$i]}.log):" >&2
|
|
||||||
kill "${pids[@]}" 2>/dev/null || true
|
|
||||||
cat "${names[$i]}.log" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
BUILD_FNS=()
|
|
||||||
for b in "${BUILDS[@]}"; do
|
|
||||||
read -r fn _ < <(build_spec "$b")
|
|
||||||
BUILD_FNS+=("$fn")
|
|
||||||
done
|
|
||||||
echo "Building: ${BUILDS[*]} (max ${MAX_PARALLEL_BUILDS} at a time, -j ${JOBS_PER_BUILD} each)..."
|
|
||||||
run_builds_parallel "${BUILD_FNS[@]}"
|
|
||||||
|
|
||||||
# Setup frameworks and copy binaries and headers
|
# Setup frameworks and copy binaries and headers
|
||||||
echo "Setting up framework structures..."
|
echo "Setting up framework structures..."
|
||||||
for b in "${BUILDS[@]}"; do
|
setup_framework_structure "build-ios-sim" ${IOS_MIN_OS_VERSION} "ios"
|
||||||
read -r _ bdir _ platform _ min_os < <(build_spec "$b")
|
setup_framework_structure "build-ios-device" ${IOS_MIN_OS_VERSION} "ios"
|
||||||
setup_framework_structure "$bdir" "$min_os" "$platform"
|
setup_framework_structure "build-macos" ${MACOS_MIN_OS_VERSION} "macos"
|
||||||
done
|
setup_framework_structure "build-visionos" ${VISIONOS_MIN_OS_VERSION} "visionos"
|
||||||
|
setup_framework_structure "build-visionos-sim" ${VISIONOS_MIN_OS_VERSION} "visionos"
|
||||||
|
setup_framework_structure "build-tvos-sim" ${TVOS_MIN_OS_VERSION} "tvos"
|
||||||
|
setup_framework_structure "build-tvos-device" ${TVOS_MIN_OS_VERSION} "tvos"
|
||||||
|
|
||||||
# Create dynamic libraries from static libraries
|
# Create dynamic libraries from static libraries
|
||||||
echo "Creating dynamic libraries from static libraries..."
|
echo "Creating dynamic libraries from static libraries..."
|
||||||
for b in "${BUILDS[@]}"; do
|
combine_static_libraries "build-ios-sim" "Release-iphonesimulator" "ios" "true"
|
||||||
read -r _ bdir rdir platform is_sim _ < <(build_spec "$b")
|
combine_static_libraries "build-ios-device" "Release-iphoneos" "ios" "false"
|
||||||
combine_static_libraries "$bdir" "$rdir" "$platform" "$is_sim"
|
combine_static_libraries "build-macos" "Release" "macos" "false"
|
||||||
done
|
combine_static_libraries "build-visionos" "Release-xros" "visionos" "false"
|
||||||
|
combine_static_libraries "build-visionos-sim" "Release-xrsimulator" "visionos" "true"
|
||||||
|
combine_static_libraries "build-tvos-sim" "Release-appletvsimulator" "tvos" "true"
|
||||||
|
combine_static_libraries "build-tvos-device" "Release-appletvos" "tvos" "false"
|
||||||
|
|
||||||
# Create XCFramework with correct debug symbols paths
|
# Create XCFramework with correct debug symbols paths
|
||||||
echo "Creating XCFramework..."
|
echo "Creating XCFramework..."
|
||||||
XCFW_ARGS=()
|
|
||||||
for b in "${BUILDS[@]}"; do
|
|
||||||
read -r _ bdir _ _ _ _ < <(build_spec "$b")
|
|
||||||
XCFW_ARGS+=(-framework "$(pwd)/${bdir}/framework/llama.framework")
|
|
||||||
XCFW_ARGS+=(-debug-symbols "$(pwd)/${bdir}/dSYMs/llama.dSYM")
|
|
||||||
done
|
|
||||||
xcrun xcodebuild -create-xcframework \
|
xcrun xcodebuild -create-xcframework \
|
||||||
"${XCFW_ARGS[@]}" \
|
-framework $(pwd)/build-ios-sim/framework/llama.framework \
|
||||||
-output "$(pwd)/build-apple/llama.xcframework"
|
-debug-symbols $(pwd)/build-ios-sim/dSYMs/llama.dSYM \
|
||||||
|
-framework $(pwd)/build-ios-device/framework/llama.framework \
|
||||||
|
-debug-symbols $(pwd)/build-ios-device/dSYMs/llama.dSYM \
|
||||||
|
-framework $(pwd)/build-macos/framework/llama.framework \
|
||||||
|
-debug-symbols $(pwd)/build-macos/dSYMs/llama.dSYM \
|
||||||
|
-framework $(pwd)/build-visionos/framework/llama.framework \
|
||||||
|
-debug-symbols $(pwd)/build-visionos/dSYMs/llama.dSYM \
|
||||||
|
-framework $(pwd)/build-visionos-sim/framework/llama.framework \
|
||||||
|
-debug-symbols $(pwd)/build-visionos-sim/dSYMs/llama.dSYM \
|
||||||
|
-framework $(pwd)/build-tvos-device/framework/llama.framework \
|
||||||
|
-debug-symbols $(pwd)/build-tvos-device/dSYMs/llama.dSYM \
|
||||||
|
-framework $(pwd)/build-tvos-sim/framework/llama.framework \
|
||||||
|
-debug-symbols $(pwd)/build-tvos-sim/dSYMs/llama.dSYM \
|
||||||
|
-output $(pwd)/build-apple/llama.xcframework
|
||||||
|
|||||||
@@ -10,9 +10,6 @@
|
|||||||
# # with CUDA support
|
# # with CUDA support
|
||||||
# GG_BUILD_CUDA=1 bash ./ci/run.sh ./tmp/results ./tmp/mnt
|
# GG_BUILD_CUDA=1 bash ./ci/run.sh ./tmp/results ./tmp/mnt
|
||||||
#
|
#
|
||||||
# # with ROCm support
|
|
||||||
# GG_BUILD_ROCM=1 GG_BUILD_AMDGPU_TARGETS=gfx1151 bash ./ci/run.sh ./tmp/results ./tmp/mnt
|
|
||||||
#
|
|
||||||
# # with SYCL support
|
# # with SYCL support
|
||||||
# GG_BUILD_SYCL=1 bash ./ci/run.sh ./tmp/results ./tmp/mnt
|
# GG_BUILD_SYCL=1 bash ./ci/run.sh ./tmp/results ./tmp/mnt
|
||||||
#
|
#
|
||||||
@@ -49,14 +46,6 @@ mkdir -p "$2"
|
|||||||
OUT=$(realpath "$1")
|
OUT=$(realpath "$1")
|
||||||
MNT=$(realpath "$2")
|
MNT=$(realpath "$2")
|
||||||
|
|
||||||
# gpu-rocm self-hosted runner can't upload logs to blob; keep each run's logs in
|
|
||||||
# their own dir keyed by the GitHub run id so an Actions run URL maps to its logs.
|
|
||||||
if [ -n "${GG_BUILD_ROCM}" ] && [ -n "${GITHUB_RUN_ID}" ]; then
|
|
||||||
OUT="$OUT/run-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT:-1}"
|
|
||||||
mkdir -p "$OUT"
|
|
||||||
echo "ci results dir: $OUT"
|
|
||||||
fi
|
|
||||||
|
|
||||||
rm -f $OUT/*.log
|
rm -f $OUT/*.log
|
||||||
rm -f $OUT/*.exit
|
rm -f $OUT/*.exit
|
||||||
rm -f $OUT/*.md
|
rm -f $OUT/*.md
|
||||||
@@ -100,7 +89,7 @@ if [ ! -z ${GG_BUILD_CUDA} ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -z ${GG_BUILD_ROCM} ]; then
|
if [ ! -z ${GG_BUILD_ROCM} ]; then
|
||||||
CMAKE_EXTRA="${CMAKE_EXTRA} -DCMAKE_HIP_COMPILER=$(hipconfig -l)/clang -DGGML_HIP=ON"
|
CMAKE_EXTRA="${CMAKE_EXTRA} -DGGML_HIP=ON"
|
||||||
if [ -z ${GG_BUILD_AMDGPU_TARGETS} ]; then
|
if [ -z ${GG_BUILD_AMDGPU_TARGETS} ]; then
|
||||||
echo "Missing GG_BUILD_AMDGPU_TARGETS, please set it to your GPU architecture (e.g. gfx90a, gfx1100, etc.)"
|
echo "Missing GG_BUILD_AMDGPU_TARGETS, please set it to your GPU architecture (e.g. gfx90a, gfx1100, etc.)"
|
||||||
exit 1
|
exit 1
|
||||||
@@ -189,8 +178,8 @@ if [ ! -z ${GG_BUILD_OPENVINO} ]; then
|
|||||||
fi
|
fi
|
||||||
CMAKE_EXTRA="${CMAKE_EXTRA} -DGGML_OPENVINO=ON"
|
CMAKE_EXTRA="${CMAKE_EXTRA} -DGGML_OPENVINO=ON"
|
||||||
|
|
||||||
# TODO: fix failing tests on OpenVINO backend
|
# TODO: fix and re-enable the `test-llama-archs` test below
|
||||||
CTEST_EXTRA="-E test-llama-archs|^test-recurrent-state-|test-backend-ops|test-save-load-state"
|
CTEST_EXTRA="-E test-llama-archs"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
## helpers
|
## helpers
|
||||||
@@ -300,40 +289,6 @@ function gg_sum_ctest_release {
|
|||||||
gg_printf '```\n'
|
gg_printf '```\n'
|
||||||
}
|
}
|
||||||
|
|
||||||
# test_llama_archs_tensor_split
|
|
||||||
|
|
||||||
function gg_run_test_llama_archs_tensor_split {
|
|
||||||
cd ${SRC}
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
if [ ! -z ${GG_BUILD_CUDA} ]; then
|
|
||||||
GGML_CUDA_DEVICES=1 ./build-ci-release/bin/test-llama-archs -s 1 2>&1
|
|
||||||
GGML_CUDA_DEVICES=2 ./build-ci-release/bin/test-llama-archs -s 1 2>&1
|
|
||||||
GGML_CUDA_DEVICES=3 ./build-ci-release/bin/test-llama-archs -s 1 2>&1
|
|
||||||
GGML_CUDA_DEVICES=4 ./build-ci-release/bin/test-llama-archs -s 1 2>&1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -z ${GG_BUILD_METAL} ]; then
|
|
||||||
GGML_METAL_DEVICES=1 ./build-ci-release/bin/test-llama-archs -s 1 2>&1
|
|
||||||
GGML_METAL_DEVICES=2 ./build-ci-release/bin/test-llama-archs -s 1 2>&1
|
|
||||||
GGML_METAL_DEVICES=3 ./build-ci-release/bin/test-llama-archs -s 1 2>&1
|
|
||||||
GGML_METAL_DEVICES=4 ./build-ci-release/bin/test-llama-archs -s 1 2>&1
|
|
||||||
fi
|
|
||||||
|
|
||||||
set +e
|
|
||||||
}
|
|
||||||
|
|
||||||
function gg_sum_test_llama_archs_tensor_split {
|
|
||||||
gg_printf '### %s\n\n' "${ci}"
|
|
||||||
|
|
||||||
gg_printf 'Runs test-llama-archs with 1 to 4 devices\n'
|
|
||||||
gg_printf '- status: %s\n' "$(cat $OUT/${ci}.exit)"
|
|
||||||
gg_printf '```\n'
|
|
||||||
gg_printf '%s\n' "$(cat $OUT/${ci}.log)"
|
|
||||||
gg_printf '```\n'
|
|
||||||
}
|
|
||||||
|
|
||||||
# test_scripts
|
# test_scripts
|
||||||
|
|
||||||
function gg_run_test_scripts {
|
function gg_run_test_scripts {
|
||||||
@@ -685,57 +640,39 @@ function gg_sum_rerank_tiny {
|
|||||||
|
|
||||||
function gg_check_build_requirements {
|
function gg_check_build_requirements {
|
||||||
if ! command -v git &> /dev/null; then
|
if ! command -v git &> /dev/null; then
|
||||||
gg_printf 'git not found, please install\n'
|
gg_printf 'git not found, please install'
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! command -v git-lfs &> /dev/null; then
|
if ! command -v git-lfs &> /dev/null; then
|
||||||
gg_printf 'git-lfs not found, please install\n'
|
gg_printf 'git-lfs not found, please install'
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! git config --get filter.lfs.clean &> /dev/null; then
|
|
||||||
gg_printf 'git-lfs not initialized, please run `git lfs install`\n'
|
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! command -v wget &> /dev/null; then
|
if ! command -v wget &> /dev/null; then
|
||||||
gg_printf 'wget not found, please install\n'
|
gg_printf 'wget not found, please install'
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! command -v python3 &> /dev/null; then
|
if ! command -v python3 &> /dev/null; then
|
||||||
gg_printf 'python3 not found, please install\n'
|
gg_printf 'python3 not found, please install'
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! command -v pip3 &> /dev/null; then
|
if ! command -v pip3 &> /dev/null; then
|
||||||
gg_printf 'pip3 not found, please install\n'
|
gg_printf 'pip3 not found, please install'
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! python3 -m ensurepip --help &> /dev/null; then
|
if ! python3 -m ensurepip --help &> /dev/null; then
|
||||||
gg_printf 'ensurepip not found, please install python3-venv package\n'
|
gg_printf 'ensurepip not found, please install python3-venv package'
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! command -v cmake &> /dev/null; then
|
if ! command -v cmake &> /dev/null; then
|
||||||
gg_printf 'cmake not found, please install\n'
|
gg_printf 'cmake not found, please install'
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! command -v ccache &> /dev/null; then
|
if ! command -v ccache &> /dev/null; then
|
||||||
gg_printf 'ccache not found, please consider installing for faster builds\n'
|
gg_printf 'ccache not found, please consider installing for faster builds'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! command -v ctest &> /dev/null; then
|
if ! command -v ctest &> /dev/null; then
|
||||||
gg_printf 'ctest not found, please install\n'
|
gg_printf 'ctest not found, please install'
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! command -v unzip &> /dev/null; then
|
|
||||||
gg_printf 'unzip not found, please install\n'
|
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -790,8 +727,6 @@ ret=0
|
|||||||
test $ret -eq 0 && gg_run ctest_debug
|
test $ret -eq 0 && gg_run ctest_debug
|
||||||
test $ret -eq 0 && gg_run ctest_release
|
test $ret -eq 0 && gg_run ctest_release
|
||||||
|
|
||||||
test $ret -eq 0 && gg_run test_llama_archs_tensor_split
|
|
||||||
|
|
||||||
if [ ! -z ${GG_BUILD_HIGH_PERF} ]; then
|
if [ ! -z ${GG_BUILD_HIGH_PERF} ]; then
|
||||||
test $ret -eq 0 && gg_run test_backend_ops_cpu
|
test $ret -eq 0 && gg_run test_backend_ops_cpu
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ set( CMAKE_CXX_COMPILER clang++ )
|
|||||||
|
|
||||||
set( CMAKE_C_COMPILER_TARGET ${target} )
|
set( CMAKE_C_COMPILER_TARGET ${target} )
|
||||||
set( CMAKE_CXX_COMPILER_TARGET ${target} )
|
set( CMAKE_CXX_COMPILER_TARGET ${target} )
|
||||||
set( CMAKE_ASM_COMPILER_TARGET ${target} )
|
|
||||||
|
|
||||||
set( arch_c_flags "-march=armv8.7-a -fvectorize -ffp-model=fast -fno-finite-math-only" )
|
set( arch_c_flags "-march=armv8.7-a -fvectorize -ffp-model=fast -fno-finite-math-only" )
|
||||||
set( warn_c_flags "-Wno-format -Wno-unused-variable -Wno-unused-function -Wno-gnu-zero-variadic-macro-arguments" )
|
set( warn_c_flags "-Wno-format -Wno-unused-variable -Wno-unused-function -Wno-gnu-zero-variadic-macro-arguments" )
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
# Used to cross-compile ggml-cuda for Windows ARM64 on an x64 Windows host.
|
|
||||||
set( CMAKE_SYSTEM_NAME Windows )
|
|
||||||
set( CMAKE_SYSTEM_PROCESSOR arm64 )
|
|
||||||
|
|
||||||
if ( DEFINED CUDAToolkit_ROOT )
|
|
||||||
file( TO_CMAKE_PATH "${CUDAToolkit_ROOT}" CUDA_ROOT )
|
|
||||||
elseif ( DEFINED ENV{CUDA_PATH} )
|
|
||||||
file( TO_CMAKE_PATH "$ENV{CUDA_PATH}" CUDA_ROOT )
|
|
||||||
else()
|
|
||||||
message( FATAL_ERROR "Set CUDAToolkit_ROOT or CUDA_PATH to a Windows CUDA Toolkit with ARM64 target libraries" )
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if ( DEFINED ENV{VCToolsInstallDir} )
|
|
||||||
file( TO_CMAKE_PATH "$ENV{VCToolsInstallDir}" MSVC_TOOLS_ROOT )
|
|
||||||
set( CMAKE_CUDA_HOST_COMPILER "${MSVC_TOOLS_ROOT}/bin/Hostx64/arm64/cl.exe" CACHE FILEPATH "" )
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set( CMAKE_CUDA_COMPILER "${CUDA_ROOT}/bin/nvcc.exe" CACHE FILEPATH "" )
|
|
||||||
set( CMAKE_CUDA_FLAGS_INIT "-target-dir=arm64" )
|
|
||||||
|
|
||||||
# FindCUDAToolkit selects lib/x64 from the host architecture on Windows.
|
|
||||||
set( CUDA_CUDART "${CUDA_ROOT}/lib/arm64/cudart.lib" CACHE FILEPATH "" )
|
|
||||||
set( CUDA_cudart_LIBRARY "${CUDA_ROOT}/lib/arm64/cudart.lib" CACHE FILEPATH "" )
|
|
||||||
set( CUDA_cublas_LIBRARY "${CUDA_ROOT}/lib/arm64/cublas.lib" CACHE FILEPATH "" )
|
|
||||||
set( CUDA_cublasLt_LIBRARY "${CUDA_ROOT}/lib/arm64/cublasLt.lib" CACHE FILEPATH "" )
|
|
||||||
set( CUDA_cuda_driver_LIBRARY "${CUDA_ROOT}/lib/arm64/cuda.lib" CACHE FILEPATH "" )
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
set(LLAMA_VERSION @LLAMA_VERSION@)
|
set(LLAMA_VERSION @LLAMA_INSTALL_VERSION@)
|
||||||
set(LLAMA_BUILD_COMMIT @LLAMA_BUILD_COMMIT@)
|
set(LLAMA_BUILD_COMMIT @LLAMA_BUILD_COMMIT@)
|
||||||
set(LLAMA_BUILD_NUMBER @LLAMA_BUILD_NUMBER@)
|
set(LLAMA_BUILD_NUMBER @LLAMA_BUILD_NUMBER@)
|
||||||
set(LLAMA_SHARED_LIB @BUILD_SHARED_LIBS@)
|
set(LLAMA_SHARED_LIB @BUILD_SHARED_LIBS@)
|
||||||
|
|||||||
+1
-1
@@ -5,6 +5,6 @@ includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
|
|||||||
|
|
||||||
Name: llama
|
Name: llama
|
||||||
Description: Port of Facebook's LLaMA model in C/C++
|
Description: Port of Facebook's LLaMA model in C/C++
|
||||||
Version: @LLAMA_VERSION@
|
Version: @LLAMA_INSTALL_VERSION@
|
||||||
Libs: -L${libdir} -lggml -lggml-base -lllama
|
Libs: -L${libdir} -lggml -lggml-base -lllama
|
||||||
Cflags: -I${includedir}
|
Cflags: -I${includedir}
|
||||||
|
|||||||
@@ -53,10 +53,7 @@ endif()
|
|||||||
|
|
||||||
set(TARGET llama-common)
|
set(TARGET llama-common)
|
||||||
|
|
||||||
include(parsers/sources.cmake)
|
|
||||||
|
|
||||||
add_library(${TARGET}
|
add_library(${TARGET}
|
||||||
${LLAMA_CHAT_PARSERS_SOURCES}
|
|
||||||
arg.cpp
|
arg.cpp
|
||||||
arg.h
|
arg.h
|
||||||
base64.hpp
|
base64.hpp
|
||||||
@@ -84,8 +81,6 @@ add_library(${TARGET}
|
|||||||
imatrix-loader.cpp
|
imatrix-loader.cpp
|
||||||
imatrix-loader.h
|
imatrix-loader.h
|
||||||
json-schema-to-grammar.cpp
|
json-schema-to-grammar.cpp
|
||||||
json.cpp
|
|
||||||
json.h
|
|
||||||
llguidance.cpp
|
llguidance.cpp
|
||||||
log.cpp
|
log.cpp
|
||||||
log.h
|
log.h
|
||||||
@@ -126,13 +121,12 @@ add_library(${TARGET}
|
|||||||
)
|
)
|
||||||
|
|
||||||
set_target_properties(${TARGET} PROPERTIES
|
set_target_properties(${TARGET} PROPERTIES
|
||||||
VERSION ${LLAMA_VERSION_BASE}
|
VERSION ${LLAMA_INSTALL_VERSION}
|
||||||
SOVERSION ${LLAMA_VERSION_MAJOR}
|
SOVERSION 0
|
||||||
MACHO_CURRENT_VERSION 0 # keep macOS linker from seeing oversized version number
|
MACHO_CURRENT_VERSION 0 # keep macOS linker from seeing oversized version number
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(${TARGET} PUBLIC .)
|
target_include_directories(${TARGET} PUBLIC . ../vendor)
|
||||||
target_link_libraries (${TARGET} PUBLIC vendor::nlohmann vendor::sheredom)
|
|
||||||
target_compile_features (${TARGET} PUBLIC cxx_std_17)
|
target_compile_features (${TARGET} PUBLIC cxx_std_17)
|
||||||
|
|
||||||
if (LLAMA_SUBPROCESS)
|
if (LLAMA_SUBPROCESS)
|
||||||
|
|||||||
+113
-352
@@ -5,7 +5,6 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "download.h"
|
#include "download.h"
|
||||||
#include "json-schema-to-grammar.h"
|
#include "json-schema-to-grammar.h"
|
||||||
#include "json.h"
|
|
||||||
#include "llama.h"
|
#include "llama.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "sampling.h"
|
#include "sampling.h"
|
||||||
@@ -22,19 +21,19 @@
|
|||||||
#include <shellapi.h>
|
#include <shellapi.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define JSON_ASSERT GGML_ASSERT
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
#include <climits>
|
#include <climits>
|
||||||
#include <cmath>
|
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <numeric>
|
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <system_error>
|
|
||||||
#include <thread> // for hardware_concurrency
|
#include <thread> // for hardware_concurrency
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -54,14 +53,13 @@
|
|||||||
|
|
||||||
#define LLAMA_MAX_URL_LENGTH 2084 // Maximum URL Length in Chrome: 2083
|
#define LLAMA_MAX_URL_LENGTH 2084 // Maximum URL Length in Chrome: 2083
|
||||||
|
|
||||||
using json = common_json;
|
using json = nlohmann::ordered_json;
|
||||||
using namespace common_arg_utils;
|
using namespace common_arg_utils;
|
||||||
|
|
||||||
static std::initializer_list<enum llama_example> mmproj_examples = {
|
static std::initializer_list<enum llama_example> mmproj_examples = {
|
||||||
LLAMA_EXAMPLE_MTMD,
|
LLAMA_EXAMPLE_MTMD,
|
||||||
LLAMA_EXAMPLE_SERVER,
|
LLAMA_EXAMPLE_SERVER,
|
||||||
LLAMA_EXAMPLE_CLI,
|
LLAMA_EXAMPLE_CLI,
|
||||||
LLAMA_EXAMPLE_TTS,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::string read_file(const std::string & fname) {
|
static std::string read_file(const std::string & fname) {
|
||||||
@@ -361,6 +359,7 @@ static bool spec_types_is_default(const common_params & params) {
|
|||||||
common_models_handler common_models_handler_init(const common_params & params, llama_example curr_ex) {
|
common_models_handler common_models_handler_init(const common_params & params, llama_example curr_ex) {
|
||||||
common_download_hf_plan plan;
|
common_download_hf_plan plan;
|
||||||
common_download_hf_plan plan_spec;
|
common_download_hf_plan plan_spec;
|
||||||
|
common_download_hf_plan plan_voc;
|
||||||
common_download_opts opts;
|
common_download_opts opts;
|
||||||
|
|
||||||
const bool spec_type_draft_mtp = std::find(params.speculative.types.begin(),
|
const bool spec_type_draft_mtp = std::find(params.speculative.types.begin(),
|
||||||
@@ -375,10 +374,6 @@ common_models_handler common_models_handler_init(const common_params & params, l
|
|||||||
params.speculative.types.end(),
|
params.speculative.types.end(),
|
||||||
COMMON_SPECULATIVE_TYPE_DRAFT_EAGLE3) != params.speculative.types.end();
|
COMMON_SPECULATIVE_TYPE_DRAFT_EAGLE3) != params.speculative.types.end();
|
||||||
|
|
||||||
const bool spec_type_draft_dspark = std::find(params.speculative.types.begin(),
|
|
||||||
params.speculative.types.end(),
|
|
||||||
COMMON_SPECULATIVE_TYPE_DRAFT_DSPARK) != params.speculative.types.end();
|
|
||||||
|
|
||||||
// only download mmproj if the current example is using it
|
// only download mmproj if the current example is using it
|
||||||
bool use_mmproj = false;
|
bool use_mmproj = false;
|
||||||
for (const auto & ex : mmproj_examples) {
|
for (const auto & ex : mmproj_examples) {
|
||||||
@@ -393,7 +388,6 @@ common_models_handler common_models_handler_init(const common_params & params, l
|
|||||||
opts.download_mtp = spec_type_draft_mtp;
|
opts.download_mtp = spec_type_draft_mtp;
|
||||||
opts.download_eagle3 = spec_type_draft_eagle3;
|
opts.download_eagle3 = spec_type_draft_eagle3;
|
||||||
opts.download_dflash = spec_type_draft_dflash;
|
opts.download_dflash = spec_type_draft_dflash;
|
||||||
opts.download_dspark = spec_type_draft_dspark;
|
|
||||||
opts.download_mmproj = use_mmproj && !params.no_mmproj
|
opts.download_mmproj = use_mmproj && !params.no_mmproj
|
||||||
&& params.mmproj.path.empty() && params.mmproj.url.empty();
|
&& params.mmproj.path.empty() && params.mmproj.url.empty();
|
||||||
|
|
||||||
@@ -408,12 +402,15 @@ common_models_handler common_models_handler_init(const common_params & params, l
|
|||||||
opts_spec.download_mtp = true;
|
opts_spec.download_mtp = true;
|
||||||
opts_spec.download_dflash = true;
|
opts_spec.download_dflash = true;
|
||||||
opts_spec.download_eagle3 = true;
|
opts_spec.download_eagle3 = true;
|
||||||
opts_spec.download_dspark = true;
|
|
||||||
}
|
}
|
||||||
plan_spec = common_download_get_hf_plan(params.speculative.draft.mparams, opts_spec);
|
plan_spec = common_download_get_hf_plan(params.speculative.draft.mparams, opts_spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
return common_models_handler{plan, plan_spec, opts};
|
if (!params.vocoder.model.hf_repo.empty()) {
|
||||||
|
plan_voc = common_download_get_hf_plan(params.vocoder.model, opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
return common_models_handler{plan, plan_spec, plan_voc, opts};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool common_models_handler_is_preset_repo(const common_models_handler & handler) {
|
bool common_models_handler_is_preset_repo(const common_models_handler & handler) {
|
||||||
@@ -463,6 +460,7 @@ void common_models_handler_apply(common_models_handler & handler, common_params
|
|||||||
|
|
||||||
auto & plan = handler.plan;
|
auto & plan = handler.plan;
|
||||||
auto & plan_spec = handler.plan_spec;
|
auto & plan_spec = handler.plan_spec;
|
||||||
|
auto & plan_voc = handler.plan_voc;
|
||||||
|
|
||||||
auto opts = handler.opts; // copy
|
auto opts = handler.opts; // copy
|
||||||
opts.callback = callback;
|
opts.callback = callback;
|
||||||
@@ -477,6 +475,7 @@ void common_models_handler_apply(common_models_handler & handler, common_params
|
|||||||
};
|
};
|
||||||
handle_url(params.model);
|
handle_url(params.model);
|
||||||
handle_url(params.mmproj);
|
handle_url(params.mmproj);
|
||||||
|
handle_url(params.vocoder.model);
|
||||||
handle_url(params.speculative.draft.mparams);
|
handle_url(params.speculative.draft.mparams);
|
||||||
|
|
||||||
// optionally, if docker repo is set, resolve it
|
// optionally, if docker repo is set, resolve it
|
||||||
@@ -504,6 +503,14 @@ void common_models_handler_apply(common_models_handler & handler, common_params
|
|||||||
task.opts = opts;
|
task.opts = opts;
|
||||||
tasks.push_back(task);
|
tasks.push_back(task);
|
||||||
}
|
}
|
||||||
|
if (!params.vocoder.model.url.empty()) {
|
||||||
|
common_download_task task;
|
||||||
|
task.url = params.vocoder.model.url;
|
||||||
|
task.local_path = params.vocoder.model.path;
|
||||||
|
task.opts = opts;
|
||||||
|
tasks.push_back(task);
|
||||||
|
}
|
||||||
|
|
||||||
bool had_spec_url = false;
|
bool had_spec_url = false;
|
||||||
if (!params.speculative.draft.mparams.url.empty()) {
|
if (!params.speculative.draft.mparams.url.empty()) {
|
||||||
common_download_task task;
|
common_download_task task;
|
||||||
@@ -532,24 +539,10 @@ void common_models_handler_apply(common_models_handler & handler, common_params
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// an explicit draft file selection (e.g. -md with -hfd) disables the sidecar resolution of the draft repo
|
|
||||||
if (!params.speculative.draft.mparams.hf_file.empty()) {
|
|
||||||
plan_spec.mtp = {};
|
|
||||||
plan_spec.dflash = {};
|
|
||||||
plan_spec.eagle3 = {};
|
|
||||||
plan_spec.dspark = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// infer the speculative type from the sidecar shipped by the draft repo when none is requested
|
// infer the speculative type from the sidecar shipped by the draft repo when none is requested
|
||||||
if (spec_types_is_default(params)) {
|
if (spec_types_is_default(params)) {
|
||||||
if (!plan_spec.mtp.local_path.empty()) {
|
if (!plan_spec.mtp.local_path.empty()) {
|
||||||
params.speculative.types = { COMMON_SPECULATIVE_TYPE_DRAFT_MTP };
|
params.speculative.types = { COMMON_SPECULATIVE_TYPE_DRAFT_MTP };
|
||||||
plan_spec.dspark = {};
|
|
||||||
plan_spec.dflash = {};
|
|
||||||
plan_spec.eagle3 = {};
|
|
||||||
} else if (!plan_spec.dspark.local_path.empty()) {
|
|
||||||
// dspark outranks dflash, its sidecar carries the extra Markov head
|
|
||||||
params.speculative.types = { COMMON_SPECULATIVE_TYPE_DRAFT_DSPARK };
|
|
||||||
plan_spec.dflash = {};
|
plan_spec.dflash = {};
|
||||||
plan_spec.eagle3 = {};
|
plan_spec.eagle3 = {};
|
||||||
} else if (!plan_spec.dflash.local_path.empty()) {
|
} else if (!plan_spec.dflash.local_path.empty()) {
|
||||||
@@ -560,20 +553,10 @@ void common_models_handler_apply(common_models_handler & handler, common_params
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// infer the speculative type from the draft GGUF metadata when none is requested
|
|
||||||
// note: reads only the first split - sharded drafts need an explicit --spec-type
|
|
||||||
if (spec_types_is_default(params) && !params.speculative.draft.mparams.path.empty()) {
|
|
||||||
const auto types_gguf = common_speculative_types_from_gguf(params.speculative.draft.mparams.path);
|
|
||||||
if (!types_gguf.empty()) {
|
|
||||||
params.speculative.types = types_gguf;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// when a sidecar type is requested, the draft repo resolves to its sidecar instead of a full model
|
// when a sidecar type is requested, the draft repo resolves to its sidecar instead of a full model
|
||||||
const bool spec_sidecar_found = !plan_spec.mtp.local_path.empty() ||
|
const bool spec_sidecar_found = !plan_spec.mtp.local_path.empty() ||
|
||||||
!plan_spec.dflash.local_path.empty() ||
|
!plan_spec.dflash.local_path.empty() ||
|
||||||
!plan_spec.eagle3.local_path.empty() ||
|
!plan_spec.eagle3.local_path.empty();
|
||||||
!plan_spec.dspark.local_path.empty();
|
|
||||||
if (!plan_spec.mtp.local_path.empty() && !had_spec_url) {
|
if (!plan_spec.mtp.local_path.empty() && !had_spec_url) {
|
||||||
tasks.emplace_back(plan_spec.mtp, opts, [&]() {
|
tasks.emplace_back(plan_spec.mtp, opts, [&]() {
|
||||||
// only use the discovered MTP head when no draft path is set yet
|
// only use the discovered MTP head when no draft path is set yet
|
||||||
@@ -604,21 +587,6 @@ void common_models_handler_apply(common_models_handler & handler, common_params
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (!plan_spec.dspark.local_path.empty() && !had_spec_url) {
|
|
||||||
tasks.emplace_back(plan_spec.dspark, opts, [&]() {
|
|
||||||
// only use the discovered DSpark sidecar when no draft path is set yet
|
|
||||||
if (params.speculative.draft.mparams.path.empty()) {
|
|
||||||
params.speculative.draft.mparams.path = hf_cache::finalize_file(plan_spec.dspark);
|
|
||||||
} else {
|
|
||||||
hf_cache::finalize_file(plan_spec.dspark);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// a wired draft sidecar counts as an explicit draft for the main plan fallback below
|
|
||||||
if (spec_sidecar_found) {
|
|
||||||
had_spec_url = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle plan_spec (e.g. --spec-draft-hf)
|
// handle plan_spec (e.g. --spec-draft-hf)
|
||||||
if (!plan_spec.model_files.empty() && !had_spec_url && !spec_sidecar_found) {
|
if (!plan_spec.model_files.empty() && !had_spec_url && !spec_sidecar_found) {
|
||||||
@@ -626,6 +594,11 @@ void common_models_handler_apply(common_models_handler & handler, common_params
|
|||||||
had_spec_url = true;
|
had_spec_url = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handle vocoder plan (e.g. --hf-repo-v)
|
||||||
|
if (!plan_voc.model_files.empty()) {
|
||||||
|
add_tasks(plan_voc.model_files, plan_voc.primary, params.vocoder.model);
|
||||||
|
}
|
||||||
|
|
||||||
if (!plan.model_files.empty()) {
|
if (!plan.model_files.empty()) {
|
||||||
add_tasks(plan.model_files, plan.primary, params.model);
|
add_tasks(plan.model_files, plan.primary, params.model);
|
||||||
}
|
}
|
||||||
@@ -664,16 +637,6 @@ void common_models_handler_apply(common_models_handler & handler, common_params
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (!plan.dspark.local_path.empty() && !had_spec_url) {
|
|
||||||
tasks.emplace_back(plan.dspark, opts, [&]() {
|
|
||||||
// only fall back to the discovered DSpark sidecar when no draft was explicitly provided
|
|
||||||
if (params.speculative.draft.mparams.empty()) {
|
|
||||||
params.speculative.draft.mparams.path = hf_cache::finalize_file(plan.dspark);
|
|
||||||
} else {
|
|
||||||
hf_cache::finalize_file(plan.dspark);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (!plan.preset.local_path.empty()) {
|
if (!plan.preset.local_path.empty()) {
|
||||||
tasks.emplace_back(plan.preset, opts, [&]() {
|
tasks.emplace_back(plan.preset, opts, [&]() {
|
||||||
// if HF repo is a preset repo, we simply run server in router mode with the preset.ini file
|
// if HF repo is a preset repo, we simply run server in router mode with the preset.ini file
|
||||||
@@ -713,61 +676,12 @@ void common_models_handler_apply(common_models_handler & handler, common_params
|
|||||||
// CLI argument parsing functions
|
// CLI argument parsing functions
|
||||||
//
|
//
|
||||||
|
|
||||||
// apply config files (if present), a later file overrides an earlier one:
|
|
||||||
// 1. system-wide: /etc/llama.cpp/config.ini (%PROGRAMDATA%\llama.cpp\config.ini on windows)
|
|
||||||
// 2. user-level: ${XDG_CONFIG_HOME:-~/.config}/llama.cpp/config.ini (%APPDATA%\llama.cpp\config.ini on windows)
|
|
||||||
static void common_params_apply_system_config(common_params & params, llama_example ex) {
|
|
||||||
std::vector<std::string> paths;
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
|
||||||
const std::string program_data = common_get_env("PROGRAMDATA");
|
|
||||||
if (!program_data.empty()) {
|
|
||||||
paths.push_back(program_data + "\\llama.cpp\\config.ini");
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
paths.push_back("/etc/llama.cpp/config.ini");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
try {
|
|
||||||
paths.push_back(fs_get_config_directory() + "config.ini");
|
|
||||||
} catch (const std::exception & e) {
|
|
||||||
LOG_DBG("cannot read user-level config file, skipping: %s\n", e.what());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> found;
|
|
||||||
for (const auto & path : paths) {
|
|
||||||
std::error_code ec;
|
|
||||||
if (std::filesystem::exists(path, ec)) {
|
|
||||||
found.push_back(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (found.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
common_preset_context ctx(ex);
|
|
||||||
ctx.ignore_unknown_keys = true; // the same config file is shared by all programs
|
|
||||||
for (const auto & path : found) {
|
|
||||||
LOG_INF("using config file: %s\n", path.c_str());
|
|
||||||
common_preset global;
|
|
||||||
common_presets presets = ctx.load_from_ini(path, global);
|
|
||||||
global.apply_to_params(params);
|
|
||||||
auto it = presets.find(COMMON_PRESET_DEFAULT_NAME);
|
|
||||||
if (it != presets.end()) {
|
|
||||||
it->second.apply_to_params(params);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool common_params_parse_ex(int argc, char ** argv, common_params_context & ctx_arg) {
|
static bool common_params_parse_ex(int argc, char ** argv, common_params_context & ctx_arg) {
|
||||||
common_params & params = ctx_arg.params;
|
common_params & params = ctx_arg.params;
|
||||||
|
|
||||||
// setup log directly from params.verbosity: see tools/cli/cli.cpp
|
// setup log directly from params.verbosity: see tools/cli/cli.cpp
|
||||||
common_log_set_verbosity_thold(params.verbosity);
|
common_log_set_verbosity_thold(params.verbosity);
|
||||||
|
|
||||||
// config file applies first, so env variables and CLI arguments override it
|
|
||||||
common_params_apply_system_config(params, ctx_arg.ex);
|
|
||||||
|
|
||||||
std::unordered_map<std::string, std::pair<common_arg *, bool>> arg_to_options;
|
std::unordered_map<std::string, std::pair<common_arg *, bool>> arg_to_options;
|
||||||
for (auto & opt : ctx_arg.options) {
|
for (auto & opt : ctx_arg.options) {
|
||||||
for (const auto & arg : opt.args) {
|
for (const auto & arg : opt.args) {
|
||||||
@@ -894,12 +808,6 @@ static bool common_params_parse_ex(int argc, char ** argv, common_params_context
|
|||||||
postprocess_cpu_params(params.speculative.draft.cpuparams, ¶ms.cpuparams);
|
postprocess_cpu_params(params.speculative.draft.cpuparams, ¶ms.cpuparams);
|
||||||
postprocess_cpu_params(params.speculative.draft.cpuparams_batch, ¶ms.cpuparams_batch);
|
postprocess_cpu_params(params.speculative.draft.cpuparams_batch, ¶ms.cpuparams_batch);
|
||||||
|
|
||||||
// default the mmproj device to the global device selection if not set explicitly with -mmdev
|
|
||||||
if (params.mmproj_use_gpu && params.mmproj_device == nullptr && !params.devices.empty()) {
|
|
||||||
params.mmproj_device = params.devices.front();
|
|
||||||
params.mmproj_use_gpu = params.mmproj_device != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (params.prompt_cache_all && (params.interactive || params.interactive_first)) {
|
if (params.prompt_cache_all && (params.interactive || params.interactive_first)) {
|
||||||
throw std::invalid_argument("error: --prompt-cache-all not supported in interactive mode yet\n");
|
throw std::invalid_argument("error: --prompt-cache-all not supported in interactive mode yet\n");
|
||||||
}
|
}
|
||||||
@@ -966,11 +874,6 @@ static bool common_params_parse_ex(int argc, char ** argv, common_params_context
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the preserve_reasoning kwarg was not specified explicitly, enable it by default
|
|
||||||
if (!params.default_template_kwargs.count("preserve_reasoning")) {
|
|
||||||
params.default_template_kwargs["preserve_reasoning"] = "true";
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1146,31 +1049,6 @@ static std::vector<ggml_backend_dev_t> parse_device_list(const std::string & val
|
|||||||
return devices;
|
return devices;
|
||||||
}
|
}
|
||||||
|
|
||||||
void common_print_available_devices() {
|
|
||||||
constexpr size_t MiB = 1024 * 1024;
|
|
||||||
std::vector<ggml_backend_dev_t> devices;
|
|
||||||
|
|
||||||
ggml_backend_load_all();
|
|
||||||
|
|
||||||
for (size_t i = 0; i < ggml_backend_dev_count(); ++i) {
|
|
||||||
auto * dev = ggml_backend_dev_get(i);
|
|
||||||
if (ggml_backend_dev_type(dev) != GGML_BACKEND_DEVICE_TYPE_CPU) {
|
|
||||||
devices.push_back(dev);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("Available devices:\n");
|
|
||||||
|
|
||||||
if (devices.empty()) {
|
|
||||||
printf(" (none)\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (auto * dev : devices) {
|
|
||||||
size_t free, total;
|
|
||||||
ggml_backend_dev_memory(dev, &free, &total);
|
|
||||||
printf(" %s: %s (%zu MiB, %zu MiB free)\n", ggml_backend_dev_name(dev), ggml_backend_dev_description(dev), total / MiB, free / MiB);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void add_rpc_devices(const std::string & servers) {
|
static void add_rpc_devices(const std::string & servers) {
|
||||||
auto rpc_servers = string_split<std::string>(servers, ',');
|
auto rpc_servers = string_split<std::string>(servers, ',');
|
||||||
if (rpc_servers.empty()) {
|
if (rpc_servers.empty()) {
|
||||||
@@ -1411,10 +1289,6 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
|
|||||||
params.n_parallel = -1; // auto by default
|
params.n_parallel = -1; // auto by default
|
||||||
} else if (ex == LLAMA_EXAMPLE_TOKENIZE) {
|
} else if (ex == LLAMA_EXAMPLE_TOKENIZE) {
|
||||||
params.parse_special = true; // parse special tokens by default, like the old tokenize tool
|
params.parse_special = true; // parse special tokens by default, like the old tokenize tool
|
||||||
} else if (ex == LLAMA_EXAMPLE_TTS) {
|
|
||||||
params.out_file = "output.wav";
|
|
||||||
params.sampling.penalty_repeat = 1.05f;
|
|
||||||
params.sampling.penalty_last_n = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
params.use_color = tty_can_use_colors();
|
params.use_color = tty_can_use_colors();
|
||||||
@@ -1459,7 +1333,8 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
|
|||||||
{"--version"},
|
{"--version"},
|
||||||
"show version and build info",
|
"show version and build info",
|
||||||
[](common_params &) {
|
[](common_params &) {
|
||||||
llama_print_build_info(llama_version());
|
fprintf(stderr, "version: %d (%s)\n", llama_build_number(), llama_commit());
|
||||||
|
fprintf(stderr, "built with %s for %s\n", llama_compiler(), llama_build_target());
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
@@ -1654,14 +1529,6 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
).set_env("LLAMA_ARG_CTX_SIZE"));
|
).set_env("LLAMA_ARG_CTX_SIZE"));
|
||||||
add_opt(common_arg(
|
|
||||||
{ "--kv-unified-per-slot" }, "N",
|
|
||||||
"context limit per parallel slot (default: unset, behavior unchanged).\n"
|
|
||||||
"when set without -c/--ctx-size, the shared KV pool is sized to n_parallel*N",
|
|
||||||
[](common_params & params, int value) {
|
|
||||||
params.kv_unified_per_slot = value;
|
|
||||||
}
|
|
||||||
).set_env("LLAMA_ARG_KV_UNIFIED_PER_SLOT").set_examples({ LLAMA_EXAMPLE_SERVER }));
|
|
||||||
add_opt(common_arg(
|
add_opt(common_arg(
|
||||||
{"-n", "--predict", "--n-predict"}, "N",
|
{"-n", "--predict", "--n-predict"}, "N",
|
||||||
string_format(
|
string_format(
|
||||||
@@ -1916,7 +1783,7 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
|
|||||||
[](common_params & params, bool value) {
|
[](common_params & params, bool value) {
|
||||||
params.conversation_mode = value ? COMMON_CONVERSATION_MODE_ENABLED : COMMON_CONVERSATION_MODE_DISABLED;
|
params.conversation_mode = value ? COMMON_CONVERSATION_MODE_ENABLED : COMMON_CONVERSATION_MODE_DISABLED;
|
||||||
}
|
}
|
||||||
).set_examples({LLAMA_EXAMPLE_COMPLETION}));
|
).set_examples({LLAMA_EXAMPLE_COMPLETION, LLAMA_EXAMPLE_CLI}));
|
||||||
add_opt(common_arg(
|
add_opt(common_arg(
|
||||||
{"-st", "--single-turn"},
|
{"-st", "--single-turn"},
|
||||||
"run conversation for a single turn only, then exit when done\n"
|
"run conversation for a single turn only, then exit when done\n"
|
||||||
@@ -2084,9 +1951,9 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
|
|||||||
).set_sampling());
|
).set_sampling());
|
||||||
add_opt(common_arg(
|
add_opt(common_arg(
|
||||||
{"--repeat-last-n"}, "N",
|
{"--repeat-last-n"}, "N",
|
||||||
string_format("last n tokens to consider for penalize (default: %d, 0 = disabled)", params.sampling.penalty_last_n),
|
string_format("last n tokens to consider for penalize (default: %d, 0 = disabled, -1 = ctx_size)", params.sampling.penalty_last_n),
|
||||||
[](common_params & params, int value) {
|
[](common_params & params, int value) {
|
||||||
if (value < 0) {
|
if (value < -1) {
|
||||||
throw std::runtime_error(string_format("error: invalid repeat-last-n = %d\n", value));
|
throw std::runtime_error(string_format("error: invalid repeat-last-n = %d\n", value));
|
||||||
}
|
}
|
||||||
params.sampling.penalty_last_n = value;
|
params.sampling.penalty_last_n = value;
|
||||||
@@ -2098,13 +1965,7 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
|
|||||||
{"--repeat-penalty"}, "N",
|
{"--repeat-penalty"}, "N",
|
||||||
string_format("penalize repeat sequence of tokens (default: %.2f, 1.0 = disabled)", (double)params.sampling.penalty_repeat),
|
string_format("penalize repeat sequence of tokens (default: %.2f, 1.0 = disabled)", (double)params.sampling.penalty_repeat),
|
||||||
[](common_params & params, const std::string & value) {
|
[](common_params & params, const std::string & value) {
|
||||||
const float penalty_repeat = std::stof(value);
|
params.sampling.penalty_repeat = std::stof(value);
|
||||||
if (!std::isfinite(penalty_repeat) ||
|
|
||||||
penalty_repeat <= 0.0f ||
|
|
||||||
!std::isfinite(1.0f/penalty_repeat)) {
|
|
||||||
throw std::runtime_error("error: repeat-penalty must be finite and greater than 0\n");
|
|
||||||
}
|
|
||||||
params.sampling.penalty_repeat = penalty_repeat;
|
|
||||||
params.sampling.user_sampling_config |= common_params_sampling_config::COMMON_PARAMS_SAMPLING_CONFIG_PENALTY_REPEAT;
|
params.sampling.user_sampling_config |= common_params_sampling_config::COMMON_PARAMS_SAMPLING_CONFIG_PENALTY_REPEAT;
|
||||||
}
|
}
|
||||||
).set_sampling());
|
).set_sampling());
|
||||||
@@ -2112,22 +1973,14 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
|
|||||||
{"--presence-penalty"}, "N",
|
{"--presence-penalty"}, "N",
|
||||||
string_format("repeat alpha presence penalty (default: %.2f, 0.0 = disabled)", (double)params.sampling.penalty_present),
|
string_format("repeat alpha presence penalty (default: %.2f, 0.0 = disabled)", (double)params.sampling.penalty_present),
|
||||||
[](common_params & params, const std::string & value) {
|
[](common_params & params, const std::string & value) {
|
||||||
const float penalty_present = std::stof(value);
|
params.sampling.penalty_present = std::stof(value);
|
||||||
if (!std::isfinite(penalty_present)) {
|
|
||||||
throw std::runtime_error("error: presence-penalty must be finite\n");
|
|
||||||
}
|
|
||||||
params.sampling.penalty_present = penalty_present;
|
|
||||||
}
|
}
|
||||||
).set_sampling());
|
).set_sampling());
|
||||||
add_opt(common_arg(
|
add_opt(common_arg(
|
||||||
{"--frequency-penalty"}, "N",
|
{"--frequency-penalty"}, "N",
|
||||||
string_format("repeat alpha frequency penalty (default: %.2f, 0.0 = disabled)", (double)params.sampling.penalty_freq),
|
string_format("repeat alpha frequency penalty (default: %.2f, 0.0 = disabled)", (double)params.sampling.penalty_freq),
|
||||||
[](common_params & params, const std::string & value) {
|
[](common_params & params, const std::string & value) {
|
||||||
const float penalty_freq = std::stof(value);
|
params.sampling.penalty_freq = std::stof(value);
|
||||||
if (!std::isfinite(penalty_freq)) {
|
|
||||||
throw std::runtime_error("error: frequency-penalty must be finite\n");
|
|
||||||
}
|
|
||||||
params.sampling.penalty_freq = penalty_freq;
|
|
||||||
}
|
}
|
||||||
).set_sampling());
|
).set_sampling());
|
||||||
add_opt(common_arg(
|
add_opt(common_arg(
|
||||||
@@ -2157,9 +2010,9 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
|
|||||||
).set_sampling());
|
).set_sampling());
|
||||||
add_opt(common_arg(
|
add_opt(common_arg(
|
||||||
{"--dry-penalty-last-n"}, "N",
|
{"--dry-penalty-last-n"}, "N",
|
||||||
string_format("set DRY penalty for the last n tokens (default: %d, 0 = disable)", params.sampling.dry_penalty_last_n),
|
string_format("set DRY penalty for the last n tokens (default: %d, 0 = disable, -1 = context size)", params.sampling.dry_penalty_last_n),
|
||||||
[](common_params & params, int value) {
|
[](common_params & params, int value) {
|
||||||
if (value < 0) {
|
if (value < -1) {
|
||||||
throw std::runtime_error(string_format("error: invalid dry-penalty-last-n = %d\n", value));
|
throw std::runtime_error(string_format("error: invalid dry-penalty-last-n = %d\n", value));
|
||||||
}
|
}
|
||||||
params.sampling.dry_penalty_last_n = value;
|
params.sampling.dry_penalty_last_n = value;
|
||||||
@@ -2613,26 +2466,6 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
|
|||||||
params.mmproj_use_gpu = value;
|
params.mmproj_use_gpu = value;
|
||||||
}
|
}
|
||||||
).set_examples(mmproj_examples).set_env("LLAMA_ARG_MMPROJ_OFFLOAD"));
|
).set_examples(mmproj_examples).set_env("LLAMA_ARG_MMPROJ_OFFLOAD"));
|
||||||
add_opt(common_arg(
|
|
||||||
// note: "-mmdev" must sort after "--rpc" in the preset map, else RPC devices are not registered yet
|
|
||||||
{"-mmdev", "--mmproj-device"}, "DEVICE",
|
|
||||||
"device to use for multimodal projector (none = don't offload, default: follows --device)\n"
|
|
||||||
"use --list-devices to see a list of available devices",
|
|
||||||
[](common_params & params, const std::string & value) {
|
|
||||||
if (value == "none") {
|
|
||||||
params.mmproj_use_gpu = false;
|
|
||||||
params.mmproj_device = nullptr;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto devices = parse_device_list(value);
|
|
||||||
// parse_device_list pushes nullptr at back so devices is length 2 for single device.
|
|
||||||
if (devices.size() > 2) {
|
|
||||||
throw std::invalid_argument("only one device may be specified for mmproj");
|
|
||||||
}
|
|
||||||
params.mmproj_use_gpu = true;
|
|
||||||
params.mmproj_device = devices.front();
|
|
||||||
}
|
|
||||||
).set_examples(mmproj_examples).set_env("MTMD_BACKEND_DEVICE")); // no LLAMA_ARG_ prefix for backward compatibility reason
|
|
||||||
add_opt(common_arg(
|
add_opt(common_arg(
|
||||||
{"--image", "--audio", "--video"}, "FILE",
|
{"--image", "--audio", "--video"}, "FILE",
|
||||||
"path to an image, audio, or video file. use with multimodal models, use comma-separated values for multiple files\n",
|
"path to an image, audio, or video file. use with multimodal models, use comma-separated values for multiple files\n",
|
||||||
@@ -2663,28 +2496,7 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
|
|||||||
params.mtmd_batch_max_tokens = value;
|
params.mtmd_batch_max_tokens = value;
|
||||||
}
|
}
|
||||||
).set_examples({LLAMA_EXAMPLE_SERVER}).set_env("LLAMA_ARG_MTMD_BATCH_MAX_TOKENS"));
|
).set_examples({LLAMA_EXAMPLE_SERVER}).set_env("LLAMA_ARG_MTMD_BATCH_MAX_TOKENS"));
|
||||||
add_opt(common_arg(
|
if (llama_supports_rpc()) {
|
||||||
{"--video-fps"}, "N",
|
|
||||||
string_format("target video frame rate (default: %.1f)", params.video_fps),
|
|
||||||
[](common_params & params, const std::string & value) {
|
|
||||||
params.video_fps = std::stof(value);
|
|
||||||
}
|
|
||||||
).set_examples(mmproj_examples).set_env("LLAMA_ARG_VIDEO_FPS"));
|
|
||||||
add_opt(common_arg(
|
|
||||||
{"--video-timestamp-interval"}, "N",
|
|
||||||
string_format("interval in milliseconds between text timestamps (default: %" PRId64 ")", params.video_timestamp_interval_ms),
|
|
||||||
[](common_params & params, int value) {
|
|
||||||
params.video_timestamp_interval_ms = value;
|
|
||||||
}
|
|
||||||
).set_examples(mmproj_examples).set_env("LLAMA_ARG_VIDEO_TIMESTAMP_INTERVAL"));
|
|
||||||
add_opt(common_arg(
|
|
||||||
{"--video-ffmpeg-dir"}, "DIR",
|
|
||||||
"path to the directory containing ffmpeg and ffprobe (default: search in PATH)",
|
|
||||||
[](common_params & params, const std::string & value) {
|
|
||||||
params.video_ffmpeg_bin_dir = value;
|
|
||||||
}
|
|
||||||
).set_examples(mmproj_examples).set_env("LLAMA_ARG_VIDEO_FFMPEG_DIR"));
|
|
||||||
if (params.is_gen_docs || llama_supports_rpc()) {
|
|
||||||
add_opt(common_arg(
|
add_opt(common_arg(
|
||||||
{"--rpc"}, "SERVERS",
|
{"--rpc"}, "SERVERS",
|
||||||
"comma-separated list of RPC servers (host:port)",
|
"comma-separated list of RPC servers (host:port)",
|
||||||
@@ -2696,7 +2508,7 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
|
|||||||
}
|
}
|
||||||
add_opt(common_arg(
|
add_opt(common_arg(
|
||||||
{"--mlock"},
|
{"--mlock"},
|
||||||
"DEPRECATED in favor of `--load-mode`: force system to keep model in RAM rather than swapping or compressing",
|
"DEPRECATED in favor of `--load-mode`: mmap + force system to keep model in RAM rather than swapping or compressing",
|
||||||
[](common_params & params) {
|
[](common_params & params) {
|
||||||
LOG_WRN("DEPRECATED: --mlock is deprecated. use --load-mode mlock instead\n");
|
LOG_WRN("DEPRECATED: --mlock is deprecated. use --load-mode mlock instead\n");
|
||||||
params.load_mode = LLAMA_LOAD_MODE_MLOCK;
|
params.load_mode = LLAMA_LOAD_MODE_MLOCK;
|
||||||
@@ -2722,36 +2534,19 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
|
|||||||
).set_env("LLAMA_ARG_DIO"));
|
).set_env("LLAMA_ARG_DIO"));
|
||||||
add_opt(common_arg(
|
add_opt(common_arg(
|
||||||
{"-lm", "--load-mode"}, "MODE",
|
{"-lm", "--load-mode"}, "MODE",
|
||||||
"model loading mode (default: auto)\n"
|
"model loading mode (default: mmap)\n"
|
||||||
"- auto: mmap, unless a device does not support it\n"
|
|
||||||
"- none: no special loading mode\n"
|
"- none: no special loading mode\n"
|
||||||
"- mmap: memory-map model (if mmap disabled, slower load but may reduce pageouts if not using mlock)\n"
|
"- mmap: memory-map model (if mmap disabled, slower load but may reduce pageouts if not using mlock)\n"
|
||||||
"- mlock: force system to keep model in RAM rather than swapping or compressing\n"
|
"- mlock: mmap + force system to keep model in RAM rather than swapping or compressing\n"
|
||||||
"- mmap+mlock: mmap + force system to keep model in RAM rather than swapping or compressing\n"
|
|
||||||
"- dio: use DirectIO if available\n",
|
"- dio: use DirectIO if available\n",
|
||||||
[](common_params & params, const std::string & value) {
|
[](common_params & params, const std::string & value) {
|
||||||
/**/ if (value == "auto") { params.load_mode = LLAMA_LOAD_MODE_AUTO; }
|
/**/ if (value == "none") { params.load_mode = LLAMA_LOAD_MODE_NONE; }
|
||||||
else if (value == "none") { params.load_mode = LLAMA_LOAD_MODE_NONE; }
|
else if (value == "mmap") { params.load_mode = LLAMA_LOAD_MODE_MMAP; }
|
||||||
else if (value == "mmap") { params.load_mode = LLAMA_LOAD_MODE_MMAP; }
|
else if (value == "mlock") { params.load_mode = LLAMA_LOAD_MODE_MLOCK; }
|
||||||
else if (value == "mlock") { params.load_mode = LLAMA_LOAD_MODE_MLOCK; }
|
else if (value == "dio") { params.load_mode = LLAMA_LOAD_MODE_DIRECT_IO; }
|
||||||
else if (value == "mmap+mlock") { params.load_mode = LLAMA_LOAD_MODE_MMAP_MLOCK; }
|
|
||||||
else if (value == "dio") { params.load_mode = LLAMA_LOAD_MODE_DIRECT_IO; }
|
|
||||||
else { throw std::invalid_argument("invalid value"); }
|
else { throw std::invalid_argument("invalid value"); }
|
||||||
}
|
}
|
||||||
).set_env("LLAMA_ARG_LOAD_MODE"));
|
).set_env("LLAMA_ARG_LOAD_MODE"));
|
||||||
add_opt(common_arg(
|
|
||||||
{"-lzm", "--lazy-mode"}, "MODE",
|
|
||||||
"on-demand reading of certain tensors, for example per-layer embeddings (default: auto)\n"
|
|
||||||
"- on: read the rows of such tensors from disk on demand instead of keeping them resident (requires mmap)\n"
|
|
||||||
"- auto: on, but only for tensors larger than 4 GiB\n"
|
|
||||||
"- off: always keep them resident",
|
|
||||||
[](common_params & params, const std::string & value) {
|
|
||||||
/**/ if (value == "on") { params.lazy_mode = LLAMA_LAZY_MODE_ON; }
|
|
||||||
else if (value == "auto") { params.lazy_mode = LLAMA_LAZY_MODE_AUTO; }
|
|
||||||
else if (value == "off") { params.lazy_mode = LLAMA_LAZY_MODE_OFF; }
|
|
||||||
else { throw std::invalid_argument("invalid value"); }
|
|
||||||
}
|
|
||||||
).set_env("LLAMA_ARG_LAZY_MODE"));
|
|
||||||
add_opt(common_arg(
|
add_opt(common_arg(
|
||||||
{"--numa"}, "TYPE",
|
{"--numa"}, "TYPE",
|
||||||
"attempt optimizations that help on some NUMA systems\n"
|
"attempt optimizations that help on some NUMA systems\n"
|
||||||
@@ -2779,7 +2574,20 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
|
|||||||
{"--list-devices"},
|
{"--list-devices"},
|
||||||
"print list of available devices and exit",
|
"print list of available devices and exit",
|
||||||
[](common_params &) {
|
[](common_params &) {
|
||||||
common_print_available_devices();
|
ggml_backend_load_all();
|
||||||
|
std::vector<ggml_backend_dev_t> devices;
|
||||||
|
for (size_t i = 0; i < ggml_backend_dev_count(); ++i) {
|
||||||
|
auto * dev = ggml_backend_dev_get(i);
|
||||||
|
if (ggml_backend_dev_type(dev) != GGML_BACKEND_DEVICE_TYPE_CPU) {
|
||||||
|
devices.push_back(dev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("Available devices:\n");
|
||||||
|
for (auto * dev : devices) {
|
||||||
|
size_t free, total;
|
||||||
|
ggml_backend_dev_memory(dev, &free, &total);
|
||||||
|
printf(" %s: %s (%zu MiB, %zu MiB free)\n", ggml_backend_dev_name(dev), ggml_backend_dev_description(dev), total / 1024 / 1024, free / 1024 / 1024);
|
||||||
|
}
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
@@ -2798,25 +2606,21 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
|
|||||||
).set_env("LLAMA_ARG_CPU_MOE"));
|
).set_env("LLAMA_ARG_CPU_MOE"));
|
||||||
add_opt(common_arg(
|
add_opt(common_arg(
|
||||||
{"-ncmoe", "--n-cpu-moe"}, "N",
|
{"-ncmoe", "--n-cpu-moe"}, "N",
|
||||||
"keep the Mixture of Experts (MoE) weights of the first N layers in the CPU",
|
"keep the Mixture of Experts (MoE) weights of the first N layers in the CPU; "
|
||||||
[](common_params & params, int value) {
|
"fractional N offloads part of the boundary layer at tensor granularity",
|
||||||
if (value < 0) {
|
[](common_params & params, const std::string & value) {
|
||||||
|
const double n = std::stod(value);
|
||||||
|
if (n < 0) {
|
||||||
throw std::invalid_argument("invalid value");
|
throw std::invalid_argument("invalid value");
|
||||||
}
|
}
|
||||||
llm_add_n_cpu_ffn_overrides(value, LLM_FFN_EXPS_REGEX, params.tensor_buft_overrides);
|
for (const std::string & re : llm_ffn_exps_cpu_block_regexes(n)) {
|
||||||
|
// keep strings alive and avoid leaking memory by storing them in a static vector
|
||||||
|
static std::list<std::string> buft_overrides;
|
||||||
|
buft_overrides.push_back(re);
|
||||||
|
params.tensor_buft_overrides.push_back({buft_overrides.back().c_str(), ggml_backend_cpu_buffer_type()});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
).set_env("LLAMA_ARG_N_CPU_MOE"));
|
).set_env("LLAMA_ARG_N_CPU_MOE"));
|
||||||
add_opt(common_arg(
|
|
||||||
{"-ncffn", "--n-cpu-ffn"}, "N",
|
|
||||||
"keep the dense FFN weights of the first N layers in the CPU\n"
|
|
||||||
"(dense models; for MoE expert weights use --n-cpu-moe)",
|
|
||||||
[](common_params & params, int value) {
|
|
||||||
if (value < 0) {
|
|
||||||
throw std::invalid_argument("invalid value");
|
|
||||||
}
|
|
||||||
llm_add_n_cpu_ffn_overrides(value, LLM_FFN_DENSE_REGEX, params.tensor_buft_overrides);
|
|
||||||
}
|
|
||||||
).set_env("LLAMA_ARG_N_CPU_FFN"));
|
|
||||||
GGML_ASSERT(params.n_gpu_layers < 0); // string_format would need to be extended for a default >= 0
|
GGML_ASSERT(params.n_gpu_layers < 0); // string_format would need to be extended for a default >= 0
|
||||||
add_opt(common_arg(
|
add_opt(common_arg(
|
||||||
{"-ngl", "--gpu-layers", "--n-gpu-layers"}, "N",
|
{"-ngl", "--gpu-layers", "--n-gpu-layers"}, "N",
|
||||||
@@ -3106,6 +2910,20 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
|
|||||||
params.model.hf_file = value;
|
params.model.hf_file = value;
|
||||||
}
|
}
|
||||||
).set_examples({LLAMA_EXAMPLE_COMMON, LLAMA_EXAMPLE_DOWNLOAD, LLAMA_EXAMPLE_TOKENIZE}).set_env("LLAMA_ARG_HF_FILE"));
|
).set_examples({LLAMA_EXAMPLE_COMMON, LLAMA_EXAMPLE_DOWNLOAD, LLAMA_EXAMPLE_TOKENIZE}).set_env("LLAMA_ARG_HF_FILE"));
|
||||||
|
add_opt(common_arg(
|
||||||
|
{"-hfv", "-hfrv", "--hf-repo-v"}, "<user>/<model>[:quant]",
|
||||||
|
"Hugging Face model repository for the vocoder model (default: unused)",
|
||||||
|
[](common_params & params, const std::string & value) {
|
||||||
|
params.vocoder.model.hf_repo = value;
|
||||||
|
}
|
||||||
|
).set_env("LLAMA_ARG_HF_REPO_V"));
|
||||||
|
add_opt(common_arg(
|
||||||
|
{"-hffv", "--hf-file-v"}, "FILE",
|
||||||
|
"Hugging Face model file for the vocoder model (default: unused)",
|
||||||
|
[](common_params & params, const std::string & value) {
|
||||||
|
params.vocoder.model.hf_file = value;
|
||||||
|
}
|
||||||
|
).set_env("LLAMA_ARG_HF_FILE_V"));
|
||||||
add_opt(common_arg(
|
add_opt(common_arg(
|
||||||
{"-hft", "--hf-token"}, "TOKEN",
|
{"-hft", "--hf-token"}, "TOKEN",
|
||||||
"Hugging Face access token (default: value from HF_TOKEN environment variable)",
|
"Hugging Face access token (default: value from HF_TOKEN environment variable)",
|
||||||
@@ -3440,23 +3258,12 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
|
|||||||
{"--tools"}, "TOOL1,TOOL2,...",
|
{"--tools"}, "TOOL1,TOOL2,...",
|
||||||
"experimental: whether to enable built-in tools for AI agents - do not enable in untrusted environments (default: no tools)\n"
|
"experimental: whether to enable built-in tools for AI agents - do not enable in untrusted environments (default: no tools)\n"
|
||||||
"specify \"all\" to enable all tools\n"
|
"specify \"all\" to enable all tools\n"
|
||||||
"available tools: read_file, file_glob_search, grep_search, exec_shell_command, write_file, edit_file, get_info\n"
|
"available tools: read_file, file_glob_search, grep_search, exec_shell_command, write_file, edit_file, get_datetime\n"
|
||||||
"note: for security reasons, this will limit --cors-origins to localhost by default",
|
"note: for security reasons, this will limit --cors-origins to localhost by default",
|
||||||
[](common_params & params, const std::string & value) {
|
[](common_params & params, const std::string & value) {
|
||||||
params.server_tools = parse_csv_row(value);
|
params.server_tools = parse_csv_row(value);
|
||||||
}
|
}
|
||||||
).set_examples({LLAMA_EXAMPLE_SERVER}).set_env("LLAMA_ARG_TOOLS"));
|
).set_examples({LLAMA_EXAMPLE_SERVER}).set_env("LLAMA_ARG_TOOLS"));
|
||||||
add_opt(common_arg(
|
|
||||||
{"--tools-runtime"}, "OPTION",
|
|
||||||
"experimental: run tools in a separate runtime environment (default: none, use host environment)\n"
|
|
||||||
"available options:\n"
|
|
||||||
" 'docker:<image>', 'podman:<image>': spin up a new container and reuse it for all invocations, clean up on server exit\n"
|
|
||||||
" 'docker-container:<id>', 'podman-container:<id>': use an existing container by ID, won't stop on server exit\n"
|
|
||||||
" 'ssh:<target>': run tools on a remote POSIX host over SSH, key-based auth and a trusted host key are required\n",
|
|
||||||
[](common_params & params, const std::string & value) {
|
|
||||||
params.server_tools_runtime = value;
|
|
||||||
}
|
|
||||||
).set_examples({LLAMA_EXAMPLE_SERVER}).set_env("LLAMA_ARG_TOOLS_RUNTIME"));
|
|
||||||
add_opt(common_arg(
|
add_opt(common_arg(
|
||||||
{"--mcp-servers-config"}, "PATH",
|
{"--mcp-servers-config"}, "PATH",
|
||||||
"experimental: path to JSON file with MCP server definitions (Cursor-compatible format) - do not enable in untrusted environments (default: none)\n"
|
"experimental: path to JSON file with MCP server definitions (Cursor-compatible format) - do not enable in untrusted environments (default: none)\n"
|
||||||
@@ -3564,10 +3371,6 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
|
|||||||
LOG_WRN("Setting 'enable_thinking' via --chat-template-kwargs is deprecated. "
|
LOG_WRN("Setting 'enable_thinking' via --chat-template-kwargs is deprecated. "
|
||||||
"Use --reasoning on / --reasoning off instead.\n");
|
"Use --reasoning on / --reasoning off instead.\n");
|
||||||
}
|
}
|
||||||
if (item.key() == "preserve_reasoning") {
|
|
||||||
LOG_WRN("Setting 'preserve_reasoning' via --chat-template-kwargs is deprecated. "
|
|
||||||
"Use --reasoning-preserve / --no-reasoning-preserve instead.\n");
|
|
||||||
}
|
|
||||||
params.default_template_kwargs[item.key()] = item.value().dump();
|
params.default_template_kwargs[item.key()] = item.value().dump();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3728,18 +3531,6 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
).set_examples({LLAMA_EXAMPLE_SERVER, LLAMA_EXAMPLE_COMPLETION, LLAMA_EXAMPLE_CLI}).set_env("LLAMA_ARG_REASONING"));
|
).set_examples({LLAMA_EXAMPLE_SERVER, LLAMA_EXAMPLE_COMPLETION, LLAMA_EXAMPLE_CLI}).set_env("LLAMA_ARG_REASONING"));
|
||||||
add_opt(common_arg(
|
|
||||||
{"--reasoning-effort"}, "LEVEL",
|
|
||||||
"reasoning effort level given to the chat template: 'default' to keep the template default,\n"
|
|
||||||
"or a level such as 'minimal', 'low', 'medium', 'high', 'xhigh' or 'max' (default: default)",
|
|
||||||
[](common_params & params, const std::string & value) {
|
|
||||||
if (value == "default") {
|
|
||||||
params.default_template_kwargs.erase("reasoning_effort");
|
|
||||||
} else {
|
|
||||||
params.default_template_kwargs["reasoning_effort"] = json(value).dump();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
).set_examples({LLAMA_EXAMPLE_SERVER, LLAMA_EXAMPLE_COMPLETION, LLAMA_EXAMPLE_CLI}).set_env("LLAMA_ARG_REASONING_EFFORT"));
|
|
||||||
add_opt(common_arg(
|
add_opt(common_arg(
|
||||||
{"--reasoning-budget"}, "N",
|
{"--reasoning-budget"}, "N",
|
||||||
"token budget for thinking: -1 for unrestricted, 0 for immediate end, N>0 for token budget (default: -1)",
|
"token budget for thinking: -1 for unrestricted, 0 for immediate end, N>0 for token budget (default: -1)",
|
||||||
@@ -3758,7 +3549,7 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
|
|||||||
add_opt(common_arg(
|
add_opt(common_arg(
|
||||||
{"--reasoning-preserve"},
|
{"--reasoning-preserve"},
|
||||||
{"--no-reasoning-preserve"},
|
{"--no-reasoning-preserve"},
|
||||||
"preserve reasoning trace in the full history, not just the last assistant message (default: enabled)\n"
|
"preserve reasoning trace in the full history, not just the last assistant message (default: template default)\n"
|
||||||
"compatible with certain templates having 'supports_preserve_reasoning' capability\n"
|
"compatible with certain templates having 'supports_preserve_reasoning' capability\n"
|
||||||
"example: https://docs.z.ai/guides/capabilities/thinking-mode#preserved-thinking",
|
"example: https://docs.z.ai/guides/capabilities/thinking-mode#preserved-thinking",
|
||||||
[](common_params & params, bool value) {
|
[](common_params & params, bool value) {
|
||||||
@@ -3767,7 +3558,6 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
|
|||||||
} else {
|
} else {
|
||||||
params.default_template_kwargs["preserve_reasoning"] = "false";
|
params.default_template_kwargs["preserve_reasoning"] = "false";
|
||||||
}
|
}
|
||||||
params.preserve_reasoning_specified = true;
|
|
||||||
}
|
}
|
||||||
).set_examples({LLAMA_EXAMPLE_SERVER, LLAMA_EXAMPLE_COMPLETION, LLAMA_EXAMPLE_CLI}).set_env("LLAMA_ARG_REASONING_PRESERVE"));
|
).set_examples({LLAMA_EXAMPLE_SERVER, LLAMA_EXAMPLE_COMPLETION, LLAMA_EXAMPLE_CLI}).set_env("LLAMA_ARG_REASONING_PRESERVE"));
|
||||||
add_opt(common_arg(
|
add_opt(common_arg(
|
||||||
@@ -3907,14 +3697,6 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
|
|||||||
common_log_set_file(common_log_main(), value.c_str());
|
common_log_set_file(common_log_main(), value.c_str());
|
||||||
}
|
}
|
||||||
).set_env("LLAMA_ARG_LOG_FILE"));
|
).set_env("LLAMA_ARG_LOG_FILE"));
|
||||||
add_opt(common_arg(
|
|
||||||
{"--log-jsonl"},
|
|
||||||
{"--no-log-jsonl"},
|
|
||||||
"Log as JSONL (one JSON object per line) to stdout, this also disables colored logging (default: disabled)",
|
|
||||||
[](common_params &, bool value) {
|
|
||||||
common_log_set_jsonl(common_log_main(), value);
|
|
||||||
}
|
|
||||||
).set_env("LLAMA_ARG_LOG_JSONL"));
|
|
||||||
add_opt(common_arg(
|
add_opt(common_arg(
|
||||||
{"--log-prompts-dir"}, "PATH",
|
{"--log-prompts-dir"}, "PATH",
|
||||||
"Log prompts to directory (auto-created if not present; only used for debugging, default: disabled)",
|
"Log prompts to directory (auto-created if not present; only used for debugging, default: disabled)",
|
||||||
@@ -4156,7 +3938,11 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
|
|||||||
if (value < 0) {
|
if (value < 0) {
|
||||||
throw std::invalid_argument("invalid value");
|
throw std::invalid_argument("invalid value");
|
||||||
}
|
}
|
||||||
llm_add_n_cpu_ffn_overrides(value, LLM_FFN_EXPS_REGEX, params.speculative.draft.tensor_buft_overrides);
|
for (int i = 0; i < value; ++i) {
|
||||||
|
static std::list<std::string> buft_overrides_draft;
|
||||||
|
buft_overrides_draft.push_back(llm_ffn_exps_block_regex(i));
|
||||||
|
params.speculative.draft.tensor_buft_overrides.push_back({buft_overrides_draft.back().c_str(), ggml_backend_cpu_buffer_type()});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
).set_spec().set_examples({LLAMA_EXAMPLE_SPECULATIVE, LLAMA_EXAMPLE_SERVER, LLAMA_EXAMPLE_CLI}).set_env("LLAMA_ARG_SPEC_DRAFT_N_CPU_MOE"));
|
).set_spec().set_examples({LLAMA_EXAMPLE_SPECULATIVE, LLAMA_EXAMPLE_SERVER, LLAMA_EXAMPLE_CLI}).set_env("LLAMA_ARG_SPEC_DRAFT_N_CPU_MOE"));
|
||||||
|
|
||||||
@@ -4164,9 +3950,6 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
|
|||||||
{"--spec-draft-n-max"}, "N",
|
{"--spec-draft-n-max"}, "N",
|
||||||
string_format("number of tokens to draft for speculative decoding (default: %d)", params.speculative.draft.n_max),
|
string_format("number of tokens to draft for speculative decoding (default: %d)", params.speculative.draft.n_max),
|
||||||
[](common_params & params, int value) {
|
[](common_params & params, int value) {
|
||||||
if (value < 0) {
|
|
||||||
throw std::invalid_argument("invalid value");
|
|
||||||
}
|
|
||||||
params.speculative.draft.n_max = value;
|
params.speculative.draft.n_max = value;
|
||||||
}
|
}
|
||||||
).set_spec().set_examples({LLAMA_EXAMPLE_SPECULATIVE, LLAMA_EXAMPLE_LOOKUP, LLAMA_EXAMPLE_SERVER, LLAMA_EXAMPLE_CLI}).set_env("LLAMA_ARG_SPEC_DRAFT_N_MAX"));
|
).set_spec().set_examples({LLAMA_EXAMPLE_SPECULATIVE, LLAMA_EXAMPLE_LOOKUP, LLAMA_EXAMPLE_SERVER, LLAMA_EXAMPLE_CLI}).set_env("LLAMA_ARG_SPEC_DRAFT_N_MAX"));
|
||||||
@@ -4177,38 +3960,6 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
|
|||||||
params.speculative.draft.n_min = value;
|
params.speculative.draft.n_min = value;
|
||||||
}
|
}
|
||||||
).set_spec().set_examples({LLAMA_EXAMPLE_SPECULATIVE, LLAMA_EXAMPLE_LOOKUP, LLAMA_EXAMPLE_SERVER, LLAMA_EXAMPLE_CLI}).set_env("LLAMA_ARG_SPEC_DRAFT_N_MIN"));
|
).set_spec().set_examples({LLAMA_EXAMPLE_SPECULATIVE, LLAMA_EXAMPLE_LOOKUP, LLAMA_EXAMPLE_SERVER, LLAMA_EXAMPLE_CLI}).set_env("LLAMA_ARG_SPEC_DRAFT_N_MIN"));
|
||||||
add_opt(common_arg(
|
|
||||||
{"--spec-synth-len"}, "L",
|
|
||||||
"target mean synthetic acceptance length, including the target token (benchmarking only)",
|
|
||||||
[](common_params & params, const std::string & value) {
|
|
||||||
const std::string text = string_strip(value);
|
|
||||||
size_t pos = 0;
|
|
||||||
const double length = std::stod(text, &pos);
|
|
||||||
if (pos != text.size() || length == -1.0) {
|
|
||||||
throw std::invalid_argument("invalid value");
|
|
||||||
}
|
|
||||||
params.speculative.synth_len = length;
|
|
||||||
}
|
|
||||||
).set_spec().set_examples({LLAMA_EXAMPLE_SERVER, LLAMA_EXAMPLE_CLI}).set_env("LLAMA_ARG_SPEC_SYNTH_LEN"));
|
|
||||||
add_opt(common_arg(
|
|
||||||
{"--spec-synth-rates"}, "P0,P1,...",
|
|
||||||
"comma-separated unconditional per-position synthetic acceptance probabilities (benchmarking only)",
|
|
||||||
[](common_params & params, const std::string & value) {
|
|
||||||
const auto values = string_split<std::string>(value, ',');
|
|
||||||
std::vector<double> rates;
|
|
||||||
rates.reserve(values.size());
|
|
||||||
for (const auto & raw : values) {
|
|
||||||
const std::string text = string_strip(raw);
|
|
||||||
size_t pos = 0;
|
|
||||||
const double rate = std::stod(text, &pos);
|
|
||||||
if (pos != text.size()) {
|
|
||||||
throw std::invalid_argument("invalid value");
|
|
||||||
}
|
|
||||||
rates.push_back(rate);
|
|
||||||
}
|
|
||||||
params.speculative.synth_rates = std::move(rates);
|
|
||||||
}
|
|
||||||
).set_spec().set_examples({LLAMA_EXAMPLE_SERVER, LLAMA_EXAMPLE_CLI}).set_env("LLAMA_ARG_SPEC_SYNTH_RATES"));
|
|
||||||
|
|
||||||
add_opt(common_arg(
|
add_opt(common_arg(
|
||||||
{"--spec-draft-p-split", "--draft-p-split"}, "P",
|
{"--spec-draft-p-split", "--draft-p-split"}, "P",
|
||||||
@@ -4235,7 +3986,7 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
|
|||||||
).set_spec().set_examples({LLAMA_EXAMPLE_SPECULATIVE, LLAMA_EXAMPLE_SERVER, LLAMA_EXAMPLE_CLI}).set_env("LLAMA_ARG_SPEC_DRAFT_BACKEND_SAMPLING"));
|
).set_spec().set_examples({LLAMA_EXAMPLE_SPECULATIVE, LLAMA_EXAMPLE_SERVER, LLAMA_EXAMPLE_CLI}).set_env("LLAMA_ARG_SPEC_DRAFT_BACKEND_SAMPLING"));
|
||||||
add_opt(common_arg(
|
add_opt(common_arg(
|
||||||
{"--spec-draft-device", "-devd", "--device-draft"}, "<dev1,dev2,..>",
|
{"--spec-draft-device", "-devd", "--device-draft"}, "<dev1,dev2,..>",
|
||||||
"comma-separated list of devices to use for offloading the draft model (none = don't offload, default: follows --device)\n"
|
"comma-separated list of devices to use for offloading the draft model (none = don't offload)\n"
|
||||||
"use --list-devices to see a list of available devices",
|
"use --list-devices to see a list of available devices",
|
||||||
[](common_params & params, const std::string & value) {
|
[](common_params & params, const std::string & value) {
|
||||||
params.speculative.draft.devices = parse_device_list(value);
|
params.speculative.draft.devices = parse_device_list(value);
|
||||||
@@ -4448,18 +4199,24 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
|
|||||||
//
|
//
|
||||||
|
|
||||||
add_opt(common_arg(
|
add_opt(common_arg(
|
||||||
{"--tts-lang"}, "FNAME",
|
{"-mv", "--model-vocoder"}, "FNAME",
|
||||||
"language (ISO 639-1) for audio generation\n"
|
"vocoder model for audio generation (default: unused)",
|
||||||
"see tts/README.md for per-model usage notes",
|
|
||||||
[](common_params & params, const std::string & value) {
|
[](common_params & params, const std::string & value) {
|
||||||
params.tts_lang = value;
|
params.vocoder.model.path = value;
|
||||||
}
|
}
|
||||||
).set_examples({LLAMA_EXAMPLE_TTS}));
|
).set_examples({LLAMA_EXAMPLE_TTS, LLAMA_EXAMPLE_SERVER}));
|
||||||
|
add_opt(common_arg(
|
||||||
|
{"--tts-use-guide-tokens"},
|
||||||
|
"Use guide tokens to improve TTS word recall",
|
||||||
|
[](common_params & params) {
|
||||||
|
params.vocoder.use_guide_tokens = true;
|
||||||
|
}
|
||||||
|
).set_examples({LLAMA_EXAMPLE_TTS, LLAMA_EXAMPLE_SERVER}));
|
||||||
add_opt(common_arg(
|
add_opt(common_arg(
|
||||||
{"--tts-speaker-file"}, "FNAME",
|
{"--tts-speaker-file"}, "FNAME",
|
||||||
"speaker file path for audio generation",
|
"speaker file path for audio generation",
|
||||||
[](common_params & params, const std::string & value) {
|
[](common_params & params, const std::string & value) {
|
||||||
params.tts_speaker_file = value;
|
params.vocoder.speaker_file = value;
|
||||||
}
|
}
|
||||||
).set_examples({LLAMA_EXAMPLE_TTS}));
|
).set_examples({LLAMA_EXAMPLE_TTS}));
|
||||||
|
|
||||||
@@ -4579,6 +4336,16 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
|
|||||||
).set_examples({LLAMA_EXAMPLE_DEBUG}));
|
).set_examples({LLAMA_EXAMPLE_DEBUG}));
|
||||||
|
|
||||||
// presets
|
// presets
|
||||||
|
add_opt(common_arg(
|
||||||
|
{"--tts-oute-default"},
|
||||||
|
string_format("use default OuteTTS models (note: can download weights from the internet)"),
|
||||||
|
[](common_params & params) {
|
||||||
|
params.model.hf_repo = "OuteAI/OuteTTS-0.2-500M-GGUF";
|
||||||
|
params.model.hf_file = "OuteTTS-0.2-500M-Q8_0.gguf";
|
||||||
|
params.vocoder.model.hf_repo = "ggml-org/WavTokenizer";
|
||||||
|
params.vocoder.model.hf_file = "WavTokenizer-Large-75-F16.gguf";
|
||||||
|
}
|
||||||
|
).set_examples({LLAMA_EXAMPLE_TTS}));
|
||||||
|
|
||||||
add_opt(common_arg(
|
add_opt(common_arg(
|
||||||
{"--embd-gemma-default"},
|
{"--embd-gemma-default"},
|
||||||
@@ -4777,12 +4544,6 @@ void common_params_add_preset_options(std::vector<common_arg> & args) {
|
|||||||
[](common_params &, int) { /* unused */ }
|
[](common_params &, int) { /* unused */ }
|
||||||
).set_env(COMMON_ARG_PRESET_STOP_TIMEOUT).set_preset_only());
|
).set_env(COMMON_ARG_PRESET_STOP_TIMEOUT).set_preset_only());
|
||||||
|
|
||||||
args.push_back(common_arg(
|
|
||||||
{"dedup-cache-models"}, "0|1",
|
|
||||||
"in server router mode, hide a cached model from the model list when this preset resolves to the same model file",
|
|
||||||
[](common_params &, const std::string &) { /* unused */ }
|
|
||||||
).set_env(COMMON_ARG_PRESET_DEDUP_CACHE_MODELS).set_preset_only());
|
|
||||||
|
|
||||||
// args.push_back(common_arg(
|
// args.push_back(common_arg(
|
||||||
// {"pin"},
|
// {"pin"},
|
||||||
// "in server router mode, do not unload this model if models_max is exceeded",
|
// "in server router mode, do not unload this model if models_max is exceeded",
|
||||||
|
|||||||
+3
-6
@@ -11,9 +11,8 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
// pseudo-env variable to identify preset-only arguments
|
// pseudo-env variable to identify preset-only arguments
|
||||||
#define COMMON_ARG_PRESET_LOAD_ON_STARTUP "__PRESET_LOAD_ON_STARTUP"
|
#define COMMON_ARG_PRESET_LOAD_ON_STARTUP "__PRESET_LOAD_ON_STARTUP"
|
||||||
#define COMMON_ARG_PRESET_STOP_TIMEOUT "__PRESET_STOP_TIMEOUT"
|
#define COMMON_ARG_PRESET_STOP_TIMEOUT "__PRESET_STOP_TIMEOUT"
|
||||||
#define COMMON_ARG_PRESET_DEDUP_CACHE_MODELS "__PRESET_DEDUP_CACHE_MODELS"
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// CLI argument parsing
|
// CLI argument parsing
|
||||||
@@ -124,9 +123,6 @@ struct common_params_context {
|
|||||||
// if one argument has invalid value, it will automatically display usage of the specific argument (and not the full usage message)
|
// if one argument has invalid value, it will automatically display usage of the specific argument (and not the full usage message)
|
||||||
bool common_params_parse(int argc, char ** argv, common_params & params, llama_example ex, void(*print_usage)(int, char **) = nullptr);
|
bool common_params_parse(int argc, char ** argv, common_params & params, llama_example ex, void(*print_usage)(int, char **) = nullptr);
|
||||||
|
|
||||||
// load all backends and print the list of available (non-CPU) devices to stdout
|
|
||||||
void common_print_available_devices();
|
|
||||||
|
|
||||||
// parse input arguments from CLI into a map
|
// parse input arguments from CLI into a map
|
||||||
bool common_params_to_map(int argc, char ** argv, llama_example ex, std::map<common_arg, std::string> & out_map);
|
bool common_params_to_map(int argc, char ** argv, llama_example ex, std::map<common_arg, std::string> & out_map);
|
||||||
|
|
||||||
@@ -138,6 +134,7 @@ void common_params_add_preset_options(std::vector<common_arg> & args);
|
|||||||
struct common_models_handler {
|
struct common_models_handler {
|
||||||
common_download_hf_plan plan;
|
common_download_hf_plan plan;
|
||||||
common_download_hf_plan plan_spec;
|
common_download_hf_plan plan_spec;
|
||||||
|
common_download_hf_plan plan_voc;
|
||||||
common_download_opts opts;
|
common_download_opts opts;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ const char * llama_build_info(void) {
|
|||||||
return s.c_str();
|
return s.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
void llama_print_build_info(const char * llama_version, FILE * stream) {
|
void llama_print_build_info(void) {
|
||||||
fprintf(stream, "version: %s (build %d, commit %s)\n", llama_version, llama_build_number(), llama_commit());
|
fprintf(stderr, "%s: build = %d (%s)\n", __func__, llama_build_number(), llama_commit());
|
||||||
fprintf(stream, "built with %s for %s\n", llama_compiler(), llama_build_target());
|
fprintf(stderr, "%s: built with %s for %s\n", __func__, llama_compiler(), llama_build_target());
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-3
@@ -1,7 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
|
|
||||||
int llama_build_number(void);
|
int llama_build_number(void);
|
||||||
|
|
||||||
const char * llama_commit(void);
|
const char * llama_commit(void);
|
||||||
@@ -10,4 +8,4 @@ const char * llama_compiler(void);
|
|||||||
const char * llama_build_target(void);
|
const char * llama_build_target(void);
|
||||||
const char * llama_build_info(void);
|
const char * llama_build_info(void);
|
||||||
|
|
||||||
void llama_print_build_info(const char *, FILE * = stderr);
|
void llama_print_build_info(void);
|
||||||
|
|||||||
@@ -5,12 +5,13 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "json-schema-to-grammar.h"
|
#include "json-schema-to-grammar.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "nlohmann/json.hpp"
|
||||||
#include "peg-parser.h"
|
#include "peg-parser.h"
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
using json = common_json;
|
using json = nlohmann::ordered_json;
|
||||||
|
|
||||||
// Helper to iterate over tools/functions
|
// Helper to iterate over tools/functions
|
||||||
static void foreach_function(const json & tools, const std::function<void(const json &)> & fn) {
|
static void foreach_function(const json & tools, const std::function<void(const json &)> & fn) {
|
||||||
@@ -390,7 +391,7 @@ common_peg_parser analyze_tools::build_tool_parser_tag_tagged(parser_build_conte
|
|||||||
|
|
||||||
std::set<std::string> required;
|
std::set<std::string> required;
|
||||||
if (params.contains("required")) {
|
if (params.contains("required")) {
|
||||||
required = params.at("required").get<std::set<std::string>>();
|
params.at("required").get_to(required);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto schema_info = common_schema_info();
|
auto schema_info = common_schema_info();
|
||||||
|
|||||||
@@ -4,11 +4,14 @@
|
|||||||
#include "chat-peg-parser.h"
|
#include "chat-peg-parser.h"
|
||||||
#include "chat.h"
|
#include "chat.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "nlohmann/json.hpp"
|
||||||
#include "peg-parser.h"
|
#include "peg-parser.h"
|
||||||
|
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
|
||||||
|
using json = nlohmann::ordered_json;
|
||||||
|
|
||||||
std::string trim_whitespace(const std::string & str) {
|
std::string trim_whitespace(const std::string & str) {
|
||||||
size_t start = 0;
|
size_t start = 0;
|
||||||
while (start < str.length() && std::isspace(static_cast<unsigned char>(str[start]))) {
|
while (start < str.length() && std::isspace(static_cast<unsigned char>(str[start]))) {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "jinja/caps.h"
|
#include "jinja/caps.h"
|
||||||
#include "peg-parser.h"
|
#include "peg-parser.h"
|
||||||
#include "json.h"
|
#include "nlohmann/json.hpp"
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
using json = common_json;
|
using json = nlohmann::ordered_json;
|
||||||
|
|
||||||
class common_chat_peg_builder;
|
class common_chat_peg_builder;
|
||||||
|
|
||||||
|
|||||||
@@ -4,11 +4,11 @@
|
|||||||
#include "chat.h"
|
#include "chat.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "nlohmann/json.hpp"
|
||||||
#include "peg-parser.h"
|
#include "peg-parser.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <numeric>
|
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
#define ANSI_ORANGE "\033[1m\x1b[38;5;214m"
|
#define ANSI_ORANGE "\033[1m\x1b[38;5;214m"
|
||||||
#define ANSI_RED "\033[1m\x1b[38;5;196m"
|
#define ANSI_RED "\033[1m\x1b[38;5;196m"
|
||||||
|
|
||||||
using json = common_json;
|
using json = nlohmann::ordered_json;
|
||||||
|
|
||||||
namespace autoparser {
|
namespace autoparser {
|
||||||
|
|
||||||
@@ -193,14 +193,6 @@ static std::vector<std::function<void(const common_chat_template & tmpl, autopar
|
|||||||
LOG_DBG(ANSI_ORANGE "[Patch: Laguna]\n" ANSI_RESET);
|
LOG_DBG(ANSI_ORANGE "[Patch: Laguna]\n" ANSI_RESET);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// Bailing V3
|
|
||||||
[](const common_chat_template & tmpl, autoparser & analysis) -> void {
|
|
||||||
if (tmpl.src.find("Bailing V3 chat template") != std::string::npos) {
|
|
||||||
analysis.tools.arguments.value_suffix = trim_whitespace(analysis.tools.arguments.value_suffix);
|
|
||||||
analysis.tools.arguments.tolerate_intertag_whitespace = true;
|
|
||||||
LOG_DBG(ANSI_ORANGE "[Patch: Bailing V3]\n" ANSI_RESET);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -929,7 +921,7 @@ void analyze_tools::analyze_tool_call_format_json_native(const std::string & cle
|
|||||||
int json_end = clean_haystack.find_last_of('}');
|
int json_end = clean_haystack.find_last_of('}');
|
||||||
std::string cut = clean_haystack.substr(json_start, json_end - json_start + 1);
|
std::string cut = clean_haystack.substr(json_start, json_end - json_start + 1);
|
||||||
json call_struct = json::parse(cut);
|
json call_struct = json::parse(cut);
|
||||||
auto register_field = [&](const std::string & prefix, const common_json_entry & subel) {
|
auto register_field = [&](const std::string & prefix, const nlohmann::detail::iteration_proxy_value<json::iterator> & subel) {
|
||||||
if (subel.value().is_string() && std::string(subel.value()).find("call0000") != std::string::npos) {
|
if (subel.value().is_string() && std::string(subel.value()).find("call0000") != std::string::npos) {
|
||||||
format.id_field = !prefix.empty() ? prefix + "." + subel.key() : subel.key();
|
format.id_field = !prefix.empty() ? prefix + "." + subel.key() : subel.key();
|
||||||
} else if (subel.value().is_string() && std::string(subel.value()) == fun_name_needle) {
|
} else if (subel.value().is_string() && std::string(subel.value()) == fun_name_needle) {
|
||||||
|
|||||||
+5
-179
@@ -4,10 +4,9 @@
|
|||||||
#include "ggml.h"
|
#include "ggml.h"
|
||||||
#include "peg-parser.h"
|
#include "peg-parser.h"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <nlohmann/json.hpp>
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
using ordered_json = common_json;
|
using ordered_json = nlohmann::ordered_json;
|
||||||
|
|
||||||
static std::string_view trim_trailing_space(std::string_view sv, int max = -1) {
|
static std::string_view trim_trailing_space(std::string_view sv, int max = -1) {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
@@ -236,43 +235,6 @@ common_peg_parser common_chat_peg_builder::tag_with_safe_content(const std::stri
|
|||||||
return zero_or_more(choice({ p, content_chunk }));
|
return zero_or_more(choice({ p, content_chunk }));
|
||||||
}
|
}
|
||||||
|
|
||||||
common_peg_parser common_chat_peg_builder::permute(const std::string & rule_prefix,
|
|
||||||
const std::vector<common_peg_parser> & parsers) {
|
|
||||||
if (parsers.empty()) {
|
|
||||||
return eps();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parsers.size() == 1 || parsers.size() > COMMON_CHAT_MAX_PERMUTE) {
|
|
||||||
return sequence(parsers);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::map<uint32_t, common_peg_parser> rules;
|
|
||||||
std::function<common_peg_parser(uint32_t)> remaining_of;
|
|
||||||
|
|
||||||
remaining_of = [&](uint32_t remaining) -> common_peg_parser {
|
|
||||||
if (remaining == 0) {
|
|
||||||
return eps();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto cached = rules.find(remaining);
|
|
||||||
if (cached != rules.end()) {
|
|
||||||
return cached->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto alternatives = choice();
|
|
||||||
for (size_t i = 0; i < parsers.size(); i++) {
|
|
||||||
const uint32_t bit = 1u << i;
|
|
||||||
if (remaining & bit) {
|
|
||||||
alternatives |= parsers[i] + remaining_of(remaining & ~bit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rules.emplace(remaining, rule(rule_prefix + "-" + std::to_string(remaining), alternatives)).first->second;
|
|
||||||
};
|
|
||||||
|
|
||||||
return remaining_of((1u << parsers.size()) - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string & common_chat_peg_mapper::args_target() {
|
std::string & common_chat_peg_mapper::args_target() {
|
||||||
return (current_tool && !current_tool->name.empty()) ? current_tool->arguments : args_buffer;
|
return (current_tool && !current_tool->name.empty()) ? current_tool->arguments : args_buffer;
|
||||||
}
|
}
|
||||||
@@ -592,7 +554,9 @@ common_peg_parser common_chat_peg_builder::python_style_tool_calls(
|
|||||||
|
|
||||||
// Full argument: name="value" or name=value
|
// Full argument: name="value" or name=value
|
||||||
auto arg_rule = tool_arg(
|
auto arg_rule = tool_arg(
|
||||||
tool_arg_open(tool_arg_name(arg_name_parser) + literal("=")) +
|
tool_arg_open(eps()) +
|
||||||
|
tool_arg_name(arg_name_parser) +
|
||||||
|
literal("=") +
|
||||||
arg_value_parser +
|
arg_value_parser +
|
||||||
tool_arg_close(eps())
|
tool_arg_close(eps())
|
||||||
);
|
);
|
||||||
@@ -1092,141 +1056,3 @@ void common_chat_peg_gemma4_mapper::visit(const common_peg_ast_arena & arena, co
|
|||||||
visit(arena, child_id);
|
visit(arena, child_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void minimax_m3_collect(const common_peg_ast_arena & arena,
|
|
||||||
const common_peg_ast_node & node,
|
|
||||||
const std::string & tag,
|
|
||||||
std::vector<common_peg_ast_id> & out) {
|
|
||||||
for (auto child_id : node.children) {
|
|
||||||
const auto & child = arena.get(child_id);
|
|
||||||
if (child.tag == tag) {
|
|
||||||
out.push_back(child_id);
|
|
||||||
} else {
|
|
||||||
minimax_m3_collect(arena, child, tag, out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static common_peg_ast_id minimax_m3_value_of(const common_peg_ast_arena & arena, const common_peg_ast_node & node) {
|
|
||||||
for (auto child_id : node.children) {
|
|
||||||
const auto & tag = arena.get(child_id).tag;
|
|
||||||
if (tag == common_chat_peg_builder::TOOL_ARG_VALUE ||
|
|
||||||
tag == common_chat_peg_builder::TOOL_ARG_STRING_VALUE ||
|
|
||||||
tag == common_chat_peg_minimax_m3_mapper::TOOL_ARG_OBJECT ||
|
|
||||||
tag == common_chat_peg_minimax_m3_mapper::TOOL_ARG_ARRAY) {
|
|
||||||
return child_id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return COMMON_PEG_INVALID_AST_ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string minimax_m3_value_to_json(const common_peg_ast_arena & arena, common_peg_ast_id id, bool closed);
|
|
||||||
|
|
||||||
static std::string minimax_m3_member_to_json(const common_peg_ast_arena & arena, const common_peg_ast_node & node) {
|
|
||||||
auto name_id = arena.find_by_tag(node, common_chat_peg_builder::TOOL_ARG_NAME);
|
|
||||||
if (name_id == COMMON_PEG_INVALID_AST_ID) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
return ordered_json(arena.get(name_id).text).dump() + ":" +
|
|
||||||
minimax_m3_value_to_json(arena, minimax_m3_value_of(arena, node), !node.is_partial);
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string minimax_m3_container_to_json(const common_peg_ast_arena & arena,
|
|
||||||
const common_peg_ast_node & node,
|
|
||||||
bool is_object,
|
|
||||||
bool closed) {
|
|
||||||
const std::string tag = is_object ? common_chat_peg_builder::TOOL_ARG
|
|
||||||
: common_chat_peg_minimax_m3_mapper::TOOL_ARG_ITEM;
|
|
||||||
|
|
||||||
std::vector<common_peg_ast_id> entries;
|
|
||||||
minimax_m3_collect(arena, node, tag, entries);
|
|
||||||
|
|
||||||
std::string result = is_object ? "{" : "[";
|
|
||||||
|
|
||||||
bool add_comma = false;
|
|
||||||
for (auto entry_id : entries) {
|
|
||||||
const auto & entry = arena.get(entry_id);
|
|
||||||
|
|
||||||
std::string text;
|
|
||||||
if (is_object) {
|
|
||||||
text = minimax_m3_member_to_json(arena, entry);
|
|
||||||
} else {
|
|
||||||
text = minimax_m3_value_to_json(arena, minimax_m3_value_of(arena, entry), !entry.is_partial);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (text.empty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (add_comma) {
|
|
||||||
result += ",";
|
|
||||||
}
|
|
||||||
add_comma = true;
|
|
||||||
result += text;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (closed) {
|
|
||||||
result += is_object ? "}" : "]";
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string minimax_m3_value_to_json(const common_peg_ast_arena & arena, common_peg_ast_id id, bool closed) {
|
|
||||||
if (id == COMMON_PEG_INVALID_AST_ID) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto & node = arena.get(id);
|
|
||||||
|
|
||||||
if (node.tag == common_chat_peg_minimax_m3_mapper::TOOL_ARG_OBJECT) {
|
|
||||||
return minimax_m3_container_to_json(arena, node, /* is_object = */ true, closed);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node.tag == common_chat_peg_minimax_m3_mapper::TOOL_ARG_ARRAY) {
|
|
||||||
return minimax_m3_container_to_json(arena, node, /* is_object = */ false, closed);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node.tag == common_chat_peg_builder::TOOL_ARG_STRING_VALUE) {
|
|
||||||
return "\"" + escape_json_string_inner(std::string(node.text)) + (closed ? "\"" : "");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Numbers and booleans are written verbatim by the template
|
|
||||||
return std::string(node.text);
|
|
||||||
}
|
|
||||||
|
|
||||||
void common_chat_peg_minimax_m3_mapper::from_ast(const common_peg_ast_arena & arena,
|
|
||||||
const common_peg_parse_result & result) {
|
|
||||||
for (const auto & node : result.nodes) {
|
|
||||||
visit(arena, node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void common_chat_peg_minimax_m3_mapper::visit(const common_peg_ast_arena & arena, common_peg_ast_id id) {
|
|
||||||
const auto & node = arena.get(id);
|
|
||||||
|
|
||||||
if (node.tag == common_chat_peg_builder::REASONING) {
|
|
||||||
result.reasoning_content += std::string(node.text);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node.tag == common_chat_peg_builder::CONTENT) {
|
|
||||||
result.content += std::string(node.text);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node.tag == common_chat_peg_builder::TOOL) {
|
|
||||||
auto name_id = arena.find_by_tag(node, common_chat_peg_builder::TOOL_NAME);
|
|
||||||
if (name_id != COMMON_PEG_INVALID_AST_ID) {
|
|
||||||
common_chat_tool_call call;
|
|
||||||
call.name = std::string(arena.get(name_id).text);
|
|
||||||
call.arguments = minimax_m3_container_to_json(arena, node, /* is_object = */ true, !node.is_partial);
|
|
||||||
result.tool_calls.push_back(call);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto child_id : node.children) {
|
|
||||||
visit(arena, child_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -40,23 +40,9 @@ class common_chat_peg_gemma4_mapper : public common_chat_peg_mapper {
|
|||||||
void visit(const common_peg_ast_arena & arena, common_peg_ast_id id);
|
void visit(const common_peg_ast_arena & arena, common_peg_ast_id id);
|
||||||
};
|
};
|
||||||
|
|
||||||
class common_chat_peg_minimax_m3_mapper : public common_chat_peg_mapper {
|
|
||||||
public:
|
|
||||||
static constexpr const char * TOOL_ARG_OBJECT = "tool-arg-object";
|
|
||||||
static constexpr const char * TOOL_ARG_ARRAY = "tool-arg-array";
|
|
||||||
static constexpr const char * TOOL_ARG_ITEM = "tool-arg-item";
|
|
||||||
|
|
||||||
common_chat_peg_minimax_m3_mapper(common_chat_msg & msg) : common_chat_peg_mapper(msg) {}
|
|
||||||
virtual void from_ast(const common_peg_ast_arena & arena, const common_peg_parse_result & result);
|
|
||||||
private:
|
|
||||||
void visit(const common_peg_ast_arena & arena, common_peg_ast_id id);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct content_structure;
|
struct content_structure;
|
||||||
struct tool_call_structure;
|
struct tool_call_structure;
|
||||||
|
|
||||||
constexpr size_t COMMON_CHAT_MAX_PERMUTE = 6;
|
|
||||||
|
|
||||||
class common_chat_peg_builder : public common_peg_parser_builder {
|
class common_chat_peg_builder : public common_peg_parser_builder {
|
||||||
public:
|
public:
|
||||||
// Tag constants (from former common_chat_peg_base_builder)
|
// Tag constants (from former common_chat_peg_base_builder)
|
||||||
@@ -107,9 +93,6 @@ class common_chat_peg_builder : public common_peg_parser_builder {
|
|||||||
common_peg_parser tool_arg_json_value(const common_peg_parser & p) { return tag(TOOL_ARG_VALUE, p); }
|
common_peg_parser tool_arg_json_value(const common_peg_parser & p) { return tag(TOOL_ARG_VALUE, p); }
|
||||||
|
|
||||||
|
|
||||||
// Matches every parser exactly once, in any order.
|
|
||||||
common_peg_parser permute(const std::string & rule_prefix, const std::vector<common_peg_parser> & parsers);
|
|
||||||
|
|
||||||
// Return a parser that parses the prefix of a string, up to a given delimiter.
|
// Return a parser that parses the prefix of a string, up to a given delimiter.
|
||||||
common_peg_parser prefix(const std::string & s, const std::string & delimiter = {});
|
common_peg_parser prefix(const std::string & s, const std::string & delimiter = {});
|
||||||
|
|
||||||
@@ -128,7 +111,7 @@ class common_chat_peg_builder : public common_peg_parser_builder {
|
|||||||
// parameters_order: order in which JSON fields should be parsed
|
// parameters_order: order in which JSON fields should be parsed
|
||||||
common_peg_parser standard_json_tools(const std::string & section_start,
|
common_peg_parser standard_json_tools(const std::string & section_start,
|
||||||
const std::string & section_end,
|
const std::string & section_end,
|
||||||
const common_json & tools,
|
const nlohmann::ordered_json & tools,
|
||||||
bool parallel_tool_calls,
|
bool parallel_tool_calls,
|
||||||
bool force_tool_calls,
|
bool force_tool_calls,
|
||||||
const std::string & name_key = "",
|
const std::string & name_key = "",
|
||||||
@@ -143,13 +126,13 @@ class common_chat_peg_builder : public common_peg_parser_builder {
|
|||||||
// Legacy-compatible helper for building XML/tagged style tool calls
|
// Legacy-compatible helper for building XML/tagged style tool calls
|
||||||
// Used by tests and manual parsers
|
// Used by tests and manual parsers
|
||||||
common_peg_parser standard_constructed_tools(const std::map<std::string, std::string> & markers,
|
common_peg_parser standard_constructed_tools(const std::map<std::string, std::string> & markers,
|
||||||
const common_json & tools,
|
const nlohmann::ordered_json & tools,
|
||||||
bool parallel_tool_calls,
|
bool parallel_tool_calls,
|
||||||
bool force_tool_calls);
|
bool force_tool_calls);
|
||||||
|
|
||||||
// Helper for Python-style function call format: name(arg1="value1", arg2=123)
|
// Helper for Python-style function call format: name(arg1="value1", arg2=123)
|
||||||
// Used by LFM2 and similar templates
|
// Used by LFM2 and similar templates
|
||||||
common_peg_parser python_style_tool_calls(const common_json & tools,
|
common_peg_parser python_style_tool_calls(const nlohmann::ordered_json & tools,
|
||||||
bool parallel_tool_calls,
|
bool parallel_tool_calls,
|
||||||
bool allow_json_literals);
|
bool allow_json_literals);
|
||||||
|
|
||||||
@@ -158,19 +141,19 @@ class common_chat_peg_builder : public common_peg_parser_builder {
|
|||||||
common_peg_parser python_or_json_value();
|
common_peg_parser python_or_json_value();
|
||||||
|
|
||||||
// Implementation helpers for standard_json_tools — one per JSON tool call layout mode
|
// Implementation helpers for standard_json_tools — one per JSON tool call layout mode
|
||||||
common_peg_parser build_json_tools_function_is_key(const common_json & tools,
|
common_peg_parser build_json_tools_function_is_key(const nlohmann::ordered_json & tools,
|
||||||
const std::string & args_key,
|
const std::string & args_key,
|
||||||
const std::string & effective_args_key,
|
const std::string & effective_args_key,
|
||||||
const std::string & call_id_key,
|
const std::string & call_id_key,
|
||||||
const std::string & gen_call_id_key);
|
const std::string & gen_call_id_key);
|
||||||
|
|
||||||
common_peg_parser build_json_tools_nested_keys(const common_json & tools,
|
common_peg_parser build_json_tools_nested_keys(const nlohmann::ordered_json & tools,
|
||||||
const std::string & effective_name_key,
|
const std::string & effective_name_key,
|
||||||
const std::string & effective_args_key,
|
const std::string & effective_args_key,
|
||||||
const std::string & call_id_key,
|
const std::string & call_id_key,
|
||||||
const std::string & gen_call_id_key);
|
const std::string & gen_call_id_key);
|
||||||
|
|
||||||
common_peg_parser build_json_tools_flat_keys(const common_json & tools,
|
common_peg_parser build_json_tools_flat_keys(const nlohmann::ordered_json & tools,
|
||||||
const std::string & effective_name_key,
|
const std::string & effective_name_key,
|
||||||
const std::string & effective_args_key,
|
const std::string & effective_args_key,
|
||||||
const std::string & call_id_key,
|
const std::string & call_id_key,
|
||||||
|
|||||||
+1663
-129
File diff suppressed because it is too large
Load Diff
+10
-10
@@ -8,7 +8,7 @@
|
|||||||
#include "jinja/runtime.h"
|
#include "jinja/runtime.h"
|
||||||
#include "jinja/caps.h"
|
#include "jinja/caps.h"
|
||||||
|
|
||||||
#include "json.h"
|
#include "nlohmann/json_fwd.hpp"
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
using chat_template_caps = jinja::caps;
|
using chat_template_caps = jinja::caps;
|
||||||
|
using json = nlohmann::ordered_json;
|
||||||
|
|
||||||
struct common_chat_templates;
|
struct common_chat_templates;
|
||||||
|
|
||||||
@@ -86,7 +87,7 @@ struct common_chat_msg {
|
|||||||
std::string tool_name;
|
std::string tool_name;
|
||||||
std::string tool_call_id;
|
std::string tool_call_id;
|
||||||
|
|
||||||
common_json to_json_oaicompat(bool concat_typed_text = false) const;
|
nlohmann::ordered_json to_json_oaicompat(bool concat_typed_text = false) const;
|
||||||
|
|
||||||
std::string render_content(const std::string & delimiter = "\n\n") const;
|
std::string render_content(const std::string & delimiter = "\n\n") const;
|
||||||
|
|
||||||
@@ -210,7 +211,7 @@ struct common_chat_msg_delimiters {
|
|||||||
// split tokens into message spans. skips maps a start index to a length of a region to jump over without matching
|
// split tokens into message spans. skips maps a start index to a length of a region to jump over without matching
|
||||||
common_chat_msg_spans split(const llama_tokens & tokens, const std::map<size_t, size_t> & skips = {}) const;
|
common_chat_msg_spans split(const llama_tokens & tokens, const std::map<size_t, size_t> & skips = {}) const;
|
||||||
|
|
||||||
common_json to_json() const;
|
nlohmann::ordered_json to_json() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct common_chat_tool {
|
struct common_chat_tool {
|
||||||
@@ -232,7 +233,6 @@ enum common_chat_format {
|
|||||||
COMMON_CHAT_FORMAT_PEG_SIMPLE,
|
COMMON_CHAT_FORMAT_PEG_SIMPLE,
|
||||||
COMMON_CHAT_FORMAT_PEG_NATIVE,
|
COMMON_CHAT_FORMAT_PEG_NATIVE,
|
||||||
COMMON_CHAT_FORMAT_PEG_GEMMA4,
|
COMMON_CHAT_FORMAT_PEG_GEMMA4,
|
||||||
COMMON_CHAT_FORMAT_PEG_MINIMAX_M3,
|
|
||||||
|
|
||||||
COMMON_CHAT_FORMAT_COUNT, // Not a format, just the # formats
|
COMMON_CHAT_FORMAT_COUNT, // Not a format, just the # formats
|
||||||
};
|
};
|
||||||
@@ -349,16 +349,16 @@ common_chat_tool_choice common_chat_tool_choice_parse_oaicompat(const std::strin
|
|||||||
bool common_chat_templates_support_enable_thinking(const common_chat_templates * chat_templates);
|
bool common_chat_templates_support_enable_thinking(const common_chat_templates * chat_templates);
|
||||||
|
|
||||||
// Parses a JSON array of messages in OpenAI's chat completion API format.
|
// Parses a JSON array of messages in OpenAI's chat completion API format.
|
||||||
std::vector<common_chat_msg> common_chat_msgs_parse_oaicompat(const common_json & messages);
|
std::vector<common_chat_msg> common_chat_msgs_parse_oaicompat(const nlohmann::ordered_json & messages);
|
||||||
|
|
||||||
std::vector<common_chat_tool> common_chat_tools_parse_oaicompat(const common_json & tools);
|
std::vector<common_chat_tool> common_chat_tools_parse_oaicompat(const nlohmann::ordered_json & tools);
|
||||||
|
|
||||||
common_chat_continuation common_chat_continuation_parse(const common_json & value);
|
common_chat_continuation common_chat_continuation_parse(const nlohmann::ordered_json & value);
|
||||||
|
|
||||||
// DEPRECATED: only used in tests
|
// DEPRECATED: only used in tests
|
||||||
common_json common_chat_msgs_to_json_oaicompat(const std::vector<common_chat_msg> & msgs, bool concat_typed_text = false);
|
nlohmann::ordered_json common_chat_msgs_to_json_oaicompat(const std::vector<common_chat_msg> & msgs, bool concat_typed_text = false);
|
||||||
|
|
||||||
common_json common_chat_tools_to_json_oaicompat(const std::vector<common_chat_tool> & tools);
|
nlohmann::ordered_json common_chat_tools_to_json_oaicompat(const std::vector<common_chat_tool> & tools);
|
||||||
|
|
||||||
// get template caps, useful for reporting to server /props endpoint
|
// get template caps, useful for reporting to server /props endpoint
|
||||||
std::map<std::string, bool> common_chat_templates_get_caps(const common_chat_templates * chat_templates);
|
std::map<std::string, bool> common_chat_templates_get_caps(const common_chat_templates * chat_templates);
|
||||||
@@ -385,4 +385,4 @@ struct common_chat_prompt_preset {
|
|||||||
|
|
||||||
common_chat_prompt_preset common_chat_get_asr_prompt(const common_chat_templates * chat_templates);
|
common_chat_prompt_preset common_chat_get_asr_prompt(const common_chat_templates * chat_templates);
|
||||||
|
|
||||||
common_chat_msg_delimiters common_chat_msg_delimiters_parse(const common_json & delimiters);
|
common_chat_msg_delimiters common_chat_msg_delimiters_parse(const nlohmann::ordered_json & delimiters);
|
||||||
|
|||||||
+36
-225
@@ -402,11 +402,10 @@ void common_params_print_info(const common_params & params, bool print_devices)
|
|||||||
#endif
|
#endif
|
||||||
COM_TRC("%s: build %d (%s) with %s for %s%s\n", __func__, llama_build_number(), llama_commit(), llama_compiler(), llama_build_target(), build_type);
|
COM_TRC("%s: build %d (%s) with %s for %s%s\n", __func__, llama_build_number(), llama_commit(), llama_compiler(), llama_build_target(), build_type);
|
||||||
|
|
||||||
const int verbosity = common_log_get_verbosity_thold();
|
COM_INF("%s: verbosity = %d (adjust with the `-lv N` CLI arg)\n", __func__, common_log_get_verbosity_thold());
|
||||||
COM_INF("%s: verbosity = %d (adjust with the `-lv N` CLI arg)\n", __func__, verbosity);
|
|
||||||
|
|
||||||
// device enumeration creates a primary context on CUDA backends, skip it when the caller does not own any device
|
// device enumeration creates a primary context on CUDA backends, skip it when the caller does not own any device
|
||||||
if (print_devices && verbosity >= LOG_LEVEL_TRACE) {
|
if (print_devices) {
|
||||||
COM_TRC("%s", "device_info:\n");
|
COM_TRC("%s", "device_info:\n");
|
||||||
for (size_t i = 0; i < ggml_backend_dev_count(); ++i) {
|
for (size_t i = 0; i < ggml_backend_dev_count(); ++i) {
|
||||||
auto * dev = ggml_backend_dev_get(i);
|
auto * dev = ggml_backend_dev_get(i);
|
||||||
@@ -999,42 +998,24 @@ bool fs_is_directory(const std::string & path) {
|
|||||||
return std::filesystem::exists(dir) && std::filesystem::is_directory(dir);
|
return std::filesystem::exists(dir) && std::filesystem::is_directory(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string common_get_env(const std::string & name) {
|
|
||||||
const char * value = std::getenv(name.c_str());
|
|
||||||
return value == nullptr ? "" : value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void common_set_env(const std::string & name, const std::string & value) {
|
|
||||||
#if defined(_WIN32)
|
|
||||||
_putenv_s(name.c_str(), value.c_str());
|
|
||||||
#else
|
|
||||||
if (value.empty()) {
|
|
||||||
unsetenv(name.c_str());
|
|
||||||
} else {
|
|
||||||
setenv(name.c_str(), value.c_str(), 1);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string fs_get_cache_directory() {
|
std::string fs_get_cache_directory() {
|
||||||
std::string cache_directory = "";
|
std::string cache_directory = "";
|
||||||
auto ensure_trailing_slash = [](std::string p) {
|
auto ensure_trailing_slash = [](std::string p) {
|
||||||
// Make sure to add trailing slash
|
// Make sure to add trailing slash
|
||||||
if (p.empty() || p.back() != DIRECTORY_SEPARATOR) {
|
if (p.back() != DIRECTORY_SEPARATOR) {
|
||||||
p += DIRECTORY_SEPARATOR;
|
p += DIRECTORY_SEPARATOR;
|
||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
};
|
};
|
||||||
cache_directory = common_get_env("LLAMA_CACHE");
|
if (getenv("LLAMA_CACHE")) {
|
||||||
if (cache_directory.empty()) {
|
cache_directory = std::getenv("LLAMA_CACHE");
|
||||||
|
} else {
|
||||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(_AIX) || \
|
#if defined(__linux__) || defined(__FreeBSD__) || defined(_AIX) || \
|
||||||
defined(__OpenBSD__) || defined(__NetBSD__)
|
defined(__OpenBSD__) || defined(__NetBSD__)
|
||||||
const std::string xdg_cache_home = common_get_env("XDG_CACHE_HOME");
|
if (std::getenv("XDG_CACHE_HOME")) {
|
||||||
const std::string home = common_get_env("HOME");
|
cache_directory = std::getenv("XDG_CACHE_HOME");
|
||||||
if (!xdg_cache_home.empty()) {
|
} else if (std::getenv("HOME")) {
|
||||||
cache_directory = xdg_cache_home;
|
cache_directory = std::getenv("HOME") + std::string("/.cache/");
|
||||||
} else if (!home.empty()) {
|
|
||||||
cache_directory = home + "/.cache/";
|
|
||||||
} else {
|
} else {
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
/* no $HOME is defined, fallback to getpwuid */
|
/* no $HOME is defined, fallback to getpwuid */
|
||||||
@@ -1049,16 +1030,9 @@ std::string fs_get_cache_directory() {
|
|||||||
#endif /* defined(__linux__) */
|
#endif /* defined(__linux__) */
|
||||||
}
|
}
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
cache_directory = common_get_env("HOME");
|
cache_directory = std::getenv("HOME") + std::string("/Library/Caches/");
|
||||||
if (cache_directory.empty()) {
|
|
||||||
throw std::runtime_error("Failed to find $HOME directory");
|
|
||||||
}
|
|
||||||
cache_directory += "/Library/Caches/";
|
|
||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32)
|
||||||
cache_directory = common_get_env("LOCALAPPDATA");
|
cache_directory = std::getenv("LOCALAPPDATA");
|
||||||
if (cache_directory.empty()) {
|
|
||||||
throw std::runtime_error("Failed to find %LOCALAPPDATA% directory");
|
|
||||||
}
|
|
||||||
#elif defined(__EMSCRIPTEN__)
|
#elif defined(__EMSCRIPTEN__)
|
||||||
GGML_ABORT("not implemented on this platform");
|
GGML_ABORT("not implemented on this platform");
|
||||||
#else
|
#else
|
||||||
@@ -1070,51 +1044,6 @@ std::string fs_get_cache_directory() {
|
|||||||
return ensure_trailing_slash(cache_directory);
|
return ensure_trailing_slash(cache_directory);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string fs_get_config_directory() {
|
|
||||||
std::string config_directory = "";
|
|
||||||
auto ensure_trailing_slash = [](std::string p) {
|
|
||||||
if (p.empty() || p.back() != DIRECTORY_SEPARATOR) {
|
|
||||||
p += DIRECTORY_SEPARATOR;
|
|
||||||
}
|
|
||||||
return p;
|
|
||||||
};
|
|
||||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(_AIX) || \
|
|
||||||
defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
|
|
||||||
const std::string xdg_config_home = common_get_env("XDG_CONFIG_HOME");
|
|
||||||
const std::string home = common_get_env("HOME");
|
|
||||||
if (!xdg_config_home.empty()) {
|
|
||||||
config_directory = xdg_config_home;
|
|
||||||
} else if (!home.empty()) {
|
|
||||||
config_directory = home + "/.config/";
|
|
||||||
} else {
|
|
||||||
#if defined(__linux__)
|
|
||||||
/* no $HOME is defined, fallback to getpwuid */
|
|
||||||
struct passwd *pw = getpwuid(getuid());
|
|
||||||
if ((!pw) || (!pw->pw_dir)) {
|
|
||||||
throw std::runtime_error("Failed to find $HOME directory");
|
|
||||||
}
|
|
||||||
|
|
||||||
config_directory = std::string(pw->pw_dir) + std::string("/.config/");
|
|
||||||
#else
|
|
||||||
throw std::runtime_error("Failed to find $HOME directory");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#elif defined(_WIN32)
|
|
||||||
config_directory = common_get_env("APPDATA");
|
|
||||||
if (config_directory.empty()) {
|
|
||||||
throw std::runtime_error("Failed to find %APPDATA% directory");
|
|
||||||
}
|
|
||||||
#elif defined(__EMSCRIPTEN__)
|
|
||||||
// caller decides what to do when there is no config directory
|
|
||||||
throw std::runtime_error("not implemented on this platform");
|
|
||||||
#else
|
|
||||||
# error Unknown architecture
|
|
||||||
#endif
|
|
||||||
config_directory = ensure_trailing_slash(config_directory);
|
|
||||||
config_directory += "llama.cpp";
|
|
||||||
return ensure_trailing_slash(config_directory);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string fs_get_cache_file(const std::string & filename) {
|
std::string fs_get_cache_file(const std::string & filename) {
|
||||||
GGML_ASSERT(filename.find(DIRECTORY_SEPARATOR) == std::string::npos);
|
GGML_ASSERT(filename.find(DIRECTORY_SEPARATOR) == std::string::npos);
|
||||||
std::string cache_directory = fs_get_cache_directory();
|
std::string cache_directory = fs_get_cache_directory();
|
||||||
@@ -1276,8 +1205,6 @@ struct common_init_result::impl {
|
|||||||
|
|
||||||
// note: the order in which model, context, etc. are declared matters because their destructors will be called bottom-to-top
|
// note: the order in which model, context, etc. are declared matters because their destructors will be called bottom-to-top
|
||||||
|
|
||||||
common_threadpools threadpools;
|
|
||||||
|
|
||||||
llama_model_ptr model;
|
llama_model_ptr model;
|
||||||
llama_context_ptr context;
|
llama_context_ptr context;
|
||||||
|
|
||||||
@@ -1295,34 +1222,11 @@ common_init_result::common_init_result(common_params & params, bool model_only)
|
|||||||
if (params.fit_params) {
|
if (params.fit_params) {
|
||||||
COM_TRC("%s", "fitting params to device memory ...\n");
|
COM_TRC("%s", "fitting params to device memory ...\n");
|
||||||
COM_TRC("%s", "(for bugs during this step try to reproduce them with -fit off, or provide --verbose logs if the bug only occurs with -fit on)\n");
|
COM_TRC("%s", "(for bugs during this step try to reproduce them with -fit off, or provide --verbose logs if the bug only occurs with -fit on)\n");
|
||||||
|
|
||||||
// the draft context is created from the same base params and follows the main context, fit both together
|
|
||||||
const bool has_draft = params.speculative.has_dft();
|
|
||||||
const bool spec_mtp = std::find(params.speculative.types.begin(), params.speculative.types.end(),
|
|
||||||
COMMON_SPECULATIVE_TYPE_DRAFT_MTP) != params.speculative.types.end();
|
|
||||||
|
|
||||||
common_params params_dft = common_base_params_to_speculative(params);
|
|
||||||
|
|
||||||
auto mparams_dft = common_model_params_to_llama(params_dft);
|
|
||||||
auto cparams_dft = common_context_params_to_llama(params_dft);
|
|
||||||
if (spec_mtp) {
|
|
||||||
cparams_dft.ctx_type = LLAMA_CONTEXT_TYPE_MTP;
|
|
||||||
}
|
|
||||||
cparams_dft.n_rs_seq = 0;
|
|
||||||
|
|
||||||
const common_fit_extra_model extra = {
|
|
||||||
/*.path_model =*/ params_dft.model.path.c_str(),
|
|
||||||
/*.mparams =*/ &mparams_dft,
|
|
||||||
/*.cparams =*/ &cparams_dft,
|
|
||||||
/*.shares_model =*/ !has_draft, // an MTP context runs on the weights of the main model
|
|
||||||
};
|
|
||||||
|
|
||||||
common_fit_params(params.model.path.c_str(), &mparams, &cparams,
|
common_fit_params(params.model.path.c_str(), &mparams, &cparams,
|
||||||
params.tensor_split,
|
params.tensor_split,
|
||||||
params.tensor_buft_overrides.data(),
|
params.tensor_buft_overrides.data(),
|
||||||
params.fit_params_target.data(),
|
params.fit_params_target.data(),
|
||||||
params.fit_params_min_ctx,
|
params.fit_params_min_ctx,
|
||||||
has_draft || spec_mtp ? &extra : nullptr,
|
|
||||||
params.verbosity >= LOG_LEVEL_DEBUG ? GGML_LOG_LEVEL_DEBUG : GGML_LOG_LEVEL_ERROR);
|
params.verbosity >= LOG_LEVEL_DEBUG ? GGML_LOG_LEVEL_DEBUG : GGML_LOG_LEVEL_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1381,6 +1285,16 @@ common_init_result::common_init_result(common_params & params, bool model_only)
|
|||||||
params.sampling.logit_bias_eog.begin(), params.sampling.logit_bias_eog.end());
|
params.sampling.logit_bias_eog.begin(), params.sampling.logit_bias_eog.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//if (params.sampling.penalty_last_n == -1) {
|
||||||
|
// LOG_TRC("%s: setting penalty_last_n to ctx_size = %d\n", __func__, llama_n_ctx(lctx));
|
||||||
|
// params.sampling.penalty_last_n = llama_n_ctx(lctx);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//if (params.sampling.dry_penalty_last_n == -1) {
|
||||||
|
// LOG_TRC("%s: setting dry_penalty_last_n to ctx_size = %d\n", __func__, llama_n_ctx(lctx));
|
||||||
|
// params.sampling.dry_penalty_last_n = llama_n_ctx(lctx);
|
||||||
|
//}
|
||||||
|
|
||||||
// init the backend samplers as part of the context creation
|
// init the backend samplers as part of the context creation
|
||||||
pimpl->samplers.resize(cparams.n_seq_max);
|
pimpl->samplers.resize(cparams.n_seq_max);
|
||||||
pimpl->samplers_seq_config.resize(cparams.n_seq_max);
|
pimpl->samplers_seq_config.resize(cparams.n_seq_max);
|
||||||
@@ -1402,10 +1316,6 @@ common_init_result::common_init_result(common_params & params, bool model_only)
|
|||||||
}
|
}
|
||||||
|
|
||||||
pimpl->context.reset(lctx);
|
pimpl->context.reset(lctx);
|
||||||
|
|
||||||
set_process_priority(params.cpuparams.priority);
|
|
||||||
|
|
||||||
pimpl->threadpools.init(lctx, params);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
llama_model * common_init_result::model() {
|
llama_model * common_init_result::model() {
|
||||||
@@ -1552,32 +1462,18 @@ common_init_result_ptr common_init_from_params(common_params & params, bool mode
|
|||||||
common_init_result::~common_init_result() = default;
|
common_init_result::~common_init_result() = default;
|
||||||
|
|
||||||
std::string common_get_model_endpoint() {
|
std::string common_get_model_endpoint() {
|
||||||
std::string endpoint = common_get_env("MODEL_ENDPOINT");
|
const char * model_endpoint_env = getenv("MODEL_ENDPOINT");
|
||||||
if (endpoint.empty()) {
|
// We still respect the use of environment-variable "HF_ENDPOINT" for backward-compatibility.
|
||||||
// the HF_ENDPOINT variable is respected for backward compatibility
|
const char * hf_endpoint_env = getenv("HF_ENDPOINT");
|
||||||
endpoint = common_get_env("HF_ENDPOINT");
|
const char * endpoint_env = model_endpoint_env ? model_endpoint_env : hf_endpoint_env;
|
||||||
|
std::string model_endpoint = "https://huggingface.co/";
|
||||||
|
if (endpoint_env) {
|
||||||
|
model_endpoint = endpoint_env;
|
||||||
|
if (model_endpoint.back() != '/') {
|
||||||
|
model_endpoint += '/';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (endpoint.empty()) {
|
return model_endpoint;
|
||||||
return "https://huggingface.co/";
|
|
||||||
}
|
|
||||||
if (endpoint.back() != '/') {
|
|
||||||
endpoint += '/';
|
|
||||||
}
|
|
||||||
return endpoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
char * common_get_model_or_exit(int argc, char * argv[]) {
|
|
||||||
if (argc > 1) {
|
|
||||||
return argv[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
char * path = getenv("LLAMACPP_TEST_MODELFILE");
|
|
||||||
if (!path || strlen(path) == 0) {
|
|
||||||
fprintf(stderr, "\033[33mWARNING: No model file provided. Skipping this test. Set LLAMACPP_TEST_MODELFILE=<gguf_model_path> to silence this warning and run this test.\n\033[0m");
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
return path;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
common_context_seq_rm_type common_context_can_seq_rm(llama_context * ctx) {
|
common_context_seq_rm_type common_context_can_seq_rm(llama_context * ctx) {
|
||||||
@@ -1622,49 +1518,23 @@ done:
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void common_context_seq_rm(llama_context * ctx, llama_seq_id seq_id, llama_pos p0, llama_pos p1) {
|
void common_context_seq_rm(llama_context * ctx, llama_seq_id seq_id, llama_pos p0, llama_pos p1) {
|
||||||
auto * mem = llama_get_memory(ctx);
|
auto * mem = llama_get_memory(ctx);
|
||||||
if (!llama_memory_seq_rm(mem, seq_id, p0, p1)) {
|
if (!llama_memory_seq_rm(mem, seq_id, p0, p1)) {
|
||||||
GGML_ABORT("%s", string_format("failed to remove sequence %d with p0=%d, p1=%d\n", seq_id, p0, p1).c_str());
|
GGML_ABORT("%s", string_format("failed to remove sequence %d with p0=%d, p1=%d\n", seq_id, p0, p1).c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void common_context_seq_cp(llama_context * ctx, llama_seq_id seq_id_src, llama_seq_id seq_id_dst, llama_pos p0, llama_pos p1) {
|
void common_context_seq_cp(llama_context * ctx, llama_seq_id seq_id_src, llama_seq_id seq_id_dst, llama_pos p0, llama_pos p1) {
|
||||||
auto * mem = llama_get_memory(ctx);
|
auto * mem = llama_get_memory(ctx);
|
||||||
llama_memory_seq_cp(mem, seq_id_src, seq_id_dst, p0, p1);
|
llama_memory_seq_cp(mem, seq_id_src, seq_id_dst, p0, p1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void common_context_seq_add(llama_context * ctx, llama_seq_id seq_id, llama_pos p0, llama_pos p1, llama_pos delta) {
|
void common_context_seq_add(llama_context * ctx, llama_seq_id seq_id, llama_pos p0, llama_pos p1, llama_pos delta) {
|
||||||
auto * mem = llama_get_memory(ctx);
|
auto * mem = llama_get_memory(ctx);
|
||||||
llama_memory_seq_add(mem, seq_id, p0, p1, delta);
|
llama_memory_seq_add(mem, seq_id, p0, p1, delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
void common_memory::init(llama_context * ctx_tgt, llama_context * ctx_dft) {
|
|
||||||
this->ctx_tgt = ctx_tgt;
|
|
||||||
this->ctx_dft = ctx_dft;
|
|
||||||
}
|
|
||||||
|
|
||||||
void common_memory::seq_rm(llama_seq_id seq_id, llama_pos p0, llama_pos p1) const {
|
|
||||||
common_context_seq_rm(ctx_tgt, seq_id, p0, p1);
|
|
||||||
if (ctx_dft) {
|
|
||||||
common_context_seq_rm(ctx_dft, seq_id, p0, p1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void common_memory::seq_cp(llama_seq_id seq_id_src, llama_seq_id seq_id_dst, llama_pos p0, llama_pos p1) const {
|
|
||||||
common_context_seq_cp(ctx_tgt, seq_id_src, seq_id_dst, p0, p1);
|
|
||||||
if (ctx_dft) {
|
|
||||||
common_context_seq_cp(ctx_dft, seq_id_src, seq_id_dst, p0, p1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void common_memory::seq_add(llama_seq_id seq_id, llama_pos p0, llama_pos p1, llama_pos delta) const {
|
|
||||||
common_context_seq_add(ctx_tgt, seq_id, p0, p1, delta);
|
|
||||||
if (ctx_dft) {
|
|
||||||
common_context_seq_add(ctx_dft, seq_id, p0, p1, delta);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void common_set_adapter_lora(struct llama_context * ctx, std::vector<common_adapter_lora_info> & lora) {
|
void common_set_adapter_lora(struct llama_context * ctx, std::vector<common_adapter_lora_info> & lora) {
|
||||||
std::vector<llama_adapter_lora *> loras;
|
std::vector<llama_adapter_lora *> loras;
|
||||||
std::vector<float> scales;
|
std::vector<float> scales;
|
||||||
@@ -1688,7 +1558,6 @@ struct llama_model_params common_model_params_to_llama(common_params & params) {
|
|||||||
mparams.main_gpu = params.main_gpu;
|
mparams.main_gpu = params.main_gpu;
|
||||||
mparams.split_mode = params.split_mode;
|
mparams.split_mode = params.split_mode;
|
||||||
mparams.load_mode = params.load_mode;
|
mparams.load_mode = params.load_mode;
|
||||||
mparams.lazy_mode = params.lazy_mode;
|
|
||||||
mparams.tensor_split = params.tensor_split;
|
mparams.tensor_split = params.tensor_split;
|
||||||
mparams.check_tensors = params.check_tensors;
|
mparams.check_tensors = params.check_tensors;
|
||||||
mparams.use_extra_bufts = !params.no_extra_bufts;
|
mparams.use_extra_bufts = !params.no_extra_bufts;
|
||||||
@@ -1711,7 +1580,6 @@ struct llama_model_params common_model_params_to_llama(common_params & params) {
|
|||||||
mparams.progress_callback = params.load_progress_callback;
|
mparams.progress_callback = params.load_progress_callback;
|
||||||
mparams.progress_callback_user_data = params.load_progress_callback_user_data;
|
mparams.progress_callback_user_data = params.load_progress_callback_user_data;
|
||||||
mparams.no_alloc = params.no_alloc;
|
mparams.no_alloc = params.no_alloc;
|
||||||
mparams.load_mtp = std::find(params.speculative.types.begin(), params.speculative.types.end(), COMMON_SPECULATIVE_TYPE_DRAFT_MTP) != params.speculative.types.end();
|
|
||||||
|
|
||||||
return mparams;
|
return mparams;
|
||||||
}
|
}
|
||||||
@@ -1723,7 +1591,6 @@ struct llama_context_params common_context_params_to_llama(const common_params &
|
|||||||
cparams.n_seq_max = params.n_parallel;
|
cparams.n_seq_max = params.n_parallel;
|
||||||
cparams.n_rs_seq = params.speculative.need_n_rs_seq();
|
cparams.n_rs_seq = params.speculative.need_n_rs_seq();
|
||||||
cparams.n_outputs_max = std::max(params.n_outputs_max, 0);
|
cparams.n_outputs_max = std::max(params.n_outputs_max, 0);
|
||||||
cparams.n_outputs_max_per_seq = std::max(params.n_outputs_max_per_seq, 0);
|
|
||||||
cparams.n_batch = params.n_batch;
|
cparams.n_batch = params.n_batch;
|
||||||
cparams.n_ubatch = params.n_ubatch;
|
cparams.n_ubatch = params.n_ubatch;
|
||||||
cparams.n_threads = params.cpuparams.n_threads;
|
cparams.n_threads = params.cpuparams.n_threads;
|
||||||
@@ -1755,10 +1622,6 @@ struct llama_context_params common_context_params_to_llama(const common_params &
|
|||||||
return cparams;
|
return cparams;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Threadpool utils
|
|
||||||
//
|
|
||||||
|
|
||||||
struct ggml_threadpool_params ggml_threadpool_params_from_cpu_params(const common_cpu_params & params) {
|
struct ggml_threadpool_params ggml_threadpool_params_from_cpu_params(const common_cpu_params & params) {
|
||||||
struct ggml_threadpool_params tpp;
|
struct ggml_threadpool_params tpp;
|
||||||
|
|
||||||
@@ -1775,58 +1638,6 @@ struct ggml_threadpool_params ggml_threadpool_params_from_cpu_params(const commo
|
|||||||
return tpp;
|
return tpp;
|
||||||
}
|
}
|
||||||
|
|
||||||
common_threadpools::~common_threadpools() {
|
|
||||||
if (!free_fn) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
free_fn(threadpool);
|
|
||||||
free_fn(threadpool_batch);
|
|
||||||
}
|
|
||||||
|
|
||||||
void common_threadpools::init(llama_context * ctx, const common_params & params) {
|
|
||||||
GGML_ASSERT(!threadpool);
|
|
||||||
GGML_ASSERT(!threadpool_batch);
|
|
||||||
|
|
||||||
COM_INF("llama threadpool init, n_threads = %d\n", (int) params.cpuparams.n_threads);
|
|
||||||
|
|
||||||
auto * cpu_dev = ggml_backend_dev_by_type(GGML_BACKEND_DEVICE_TYPE_CPU);
|
|
||||||
if (!cpu_dev) {
|
|
||||||
COM_WRN("%s", "no CPU backend found\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto * reg = ggml_backend_dev_backend_reg(cpu_dev);
|
|
||||||
auto * ggml_threadpool_new_fn = (decltype(ggml_threadpool_new) *) ggml_backend_reg_get_proc_address(reg, "ggml_threadpool_new");
|
|
||||||
free_fn = (decltype(ggml_threadpool_free) *) ggml_backend_reg_get_proc_address(reg, "ggml_threadpool_free");
|
|
||||||
|
|
||||||
struct ggml_threadpool_params tpp_batch =
|
|
||||||
ggml_threadpool_params_from_cpu_params(params.cpuparams_batch);
|
|
||||||
struct ggml_threadpool_params tpp =
|
|
||||||
ggml_threadpool_params_from_cpu_params(params.cpuparams);
|
|
||||||
|
|
||||||
// each pool needs to match the respective n_threads exactly
|
|
||||||
// see: https://github.com/ggml-org/llama.cpp/pull/27138#issuecomment-5332307332
|
|
||||||
if (!ggml_threadpool_params_match(&tpp, &tpp_batch)) {
|
|
||||||
threadpool_batch = ggml_threadpool_new_fn(&tpp_batch);
|
|
||||||
if (!threadpool_batch) {
|
|
||||||
COM_WRN("batch threadpool create failed : n_threads %d\n", tpp_batch.n_threads);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// start the non-batch threadpool in the paused state
|
|
||||||
tpp.paused = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
threadpool = ggml_threadpool_new_fn(&tpp);
|
|
||||||
if (!threadpool) {
|
|
||||||
COM_WRN("threadpool create failed : n_threads %d\n", tpp.n_threads);
|
|
||||||
free_fn(threadpool_batch);
|
|
||||||
threadpool_batch = nullptr;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
llama_attach_threadpool(ctx, threadpool, threadpool_batch);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Batch utils
|
// Batch utils
|
||||||
//
|
//
|
||||||
|
|||||||
+50
-94
@@ -8,7 +8,6 @@
|
|||||||
#include "ggml.h"
|
#include "ggml.h"
|
||||||
#include "llama.h"
|
#include "llama.h"
|
||||||
|
|
||||||
#include <list>
|
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -174,7 +173,6 @@ enum common_speculative_type {
|
|||||||
COMMON_SPECULATIVE_TYPE_DRAFT_EAGLE3, // Eagle3 speculative decoding
|
COMMON_SPECULATIVE_TYPE_DRAFT_EAGLE3, // Eagle3 speculative decoding
|
||||||
COMMON_SPECULATIVE_TYPE_DRAFT_MTP, // Multi-token prediction
|
COMMON_SPECULATIVE_TYPE_DRAFT_MTP, // Multi-token prediction
|
||||||
COMMON_SPECULATIVE_TYPE_DRAFT_DFLASH, // DFlash speculative decoding
|
COMMON_SPECULATIVE_TYPE_DRAFT_DFLASH, // DFlash speculative decoding
|
||||||
COMMON_SPECULATIVE_TYPE_DRAFT_DSPARK, // DSpark speculative decoding (DFlash + Markov head)
|
|
||||||
COMMON_SPECULATIVE_TYPE_NGRAM_SIMPLE, // simple self-speculative decoding based on n-grams
|
COMMON_SPECULATIVE_TYPE_NGRAM_SIMPLE, // simple self-speculative decoding based on n-grams
|
||||||
COMMON_SPECULATIVE_TYPE_NGRAM_MAP_K, // self-speculative decoding with n-gram keys only
|
COMMON_SPECULATIVE_TYPE_NGRAM_MAP_K, // self-speculative decoding with n-gram keys only
|
||||||
COMMON_SPECULATIVE_TYPE_NGRAM_MAP_K4V, // self-speculative decoding with n-gram keys and 4 m-gram values
|
COMMON_SPECULATIVE_TYPE_NGRAM_MAP_K4V, // self-speculative decoding with n-gram keys and 4 m-gram values
|
||||||
@@ -236,14 +234,14 @@ struct common_params_sampling {
|
|||||||
float temp = 0.80f; // <= 0.0 to sample greedily, 0.0 to not output probabilities
|
float temp = 0.80f; // <= 0.0 to sample greedily, 0.0 to not output probabilities
|
||||||
float dynatemp_range = 0.00f; // 0.0 = disabled
|
float dynatemp_range = 0.00f; // 0.0 = disabled
|
||||||
float dynatemp_exponent = 1.00f; // controls how entropy maps to temperature in dynamic temperature sampler
|
float dynatemp_exponent = 1.00f; // controls how entropy maps to temperature in dynamic temperature sampler
|
||||||
int32_t penalty_last_n = 64; // last n tokens to penalize (0 = disable penalty)
|
int32_t penalty_last_n = 64; // last n tokens to penalize (0 = disable penalty, -1 = context size)
|
||||||
float penalty_repeat = 1.00f; // 1.0 = disabled
|
float penalty_repeat = 1.00f; // 1.0 = disabled
|
||||||
float penalty_freq = 0.00f; // 0.0 = disabled
|
float penalty_freq = 0.00f; // 0.0 = disabled
|
||||||
float penalty_present = 0.00f; // 0.0 = disabled
|
float penalty_present = 0.00f; // 0.0 = disabled
|
||||||
float dry_multiplier = 0.0f; // 0.0 = disabled; DRY repetition penalty for tokens extending repetition:
|
float dry_multiplier = 0.0f; // 0.0 = disabled; DRY repetition penalty for tokens extending repetition:
|
||||||
float dry_base = 1.75f; // 0.0 = disabled; multiplier * base ^ (length of sequence before token - allowed length)
|
float dry_base = 1.75f; // 0.0 = disabled; multiplier * base ^ (length of sequence before token - allowed length)
|
||||||
int32_t dry_allowed_length = 2; // tokens extending repetitions beyond this receive penalty
|
int32_t dry_allowed_length = 2; // tokens extending repetitions beyond this receive penalty
|
||||||
int32_t dry_penalty_last_n = 64; // how many tokens to scan for repetitions (0 = disable penalty)
|
int32_t dry_penalty_last_n = -1; // how many tokens to scan for repetitions (0 = disable penalty, -1 = context size)
|
||||||
float adaptive_target = -1.0f; // select tokens near this probability (valid range 0.0 to 1.0; negative = disabled)
|
float adaptive_target = -1.0f; // select tokens near this probability (valid range 0.0 to 1.0; negative = disabled)
|
||||||
float adaptive_decay = 0.90f; // EMA decay for adaptation; history ≈ 1/(1-decay) tokens (0.0 - 0.99)
|
float adaptive_decay = 0.90f; // EMA decay for adaptation; history ≈ 1/(1-decay) tokens (0.0 - 0.99)
|
||||||
int32_t mirostat = 0; // 0 = disabled, 1 = mirostat, 2 = mirostat 2.0
|
int32_t mirostat = 0; // 0 = disabled, 1 = mirostat, 2 = mirostat 2.0
|
||||||
@@ -270,7 +268,7 @@ struct common_params_sampling {
|
|||||||
COMMON_SAMPLER_TYPE_TEMPERATURE,
|
COMMON_SAMPLER_TYPE_TEMPERATURE,
|
||||||
};
|
};
|
||||||
|
|
||||||
common_grammar grammar; // optional grammar constraint (user / output-format / tool-calls)
|
common_grammar grammar; // optional grammar constraint (user / output-format / tool-calls)
|
||||||
bool grammar_lazy = false;
|
bool grammar_lazy = false;
|
||||||
std::vector<common_grammar_trigger> grammar_triggers; // optional triggers (for lazy grammars)
|
std::vector<common_grammar_trigger> grammar_triggers; // optional triggers (for lazy grammars)
|
||||||
std::set<llama_token> preserved_tokens;
|
std::set<llama_token> preserved_tokens;
|
||||||
@@ -295,6 +293,10 @@ struct common_params_sampling {
|
|||||||
|
|
||||||
bool backend_sampling = false;
|
bool backend_sampling = false;
|
||||||
|
|
||||||
|
bool has_logit_bias() const {
|
||||||
|
return !logit_bias.empty();
|
||||||
|
}
|
||||||
|
|
||||||
// print the parameters into a string
|
// print the parameters into a string
|
||||||
std::string print() const;
|
std::string print() const;
|
||||||
};
|
};
|
||||||
@@ -370,9 +372,6 @@ struct common_params_speculative_ngram_cache {
|
|||||||
struct common_params_speculative {
|
struct common_params_speculative {
|
||||||
std::vector<enum common_speculative_type> types = { COMMON_SPECULATIVE_TYPE_NONE };
|
std::vector<enum common_speculative_type> types = { COMMON_SPECULATIVE_TYPE_NONE };
|
||||||
|
|
||||||
double synth_len = -1.0;
|
|
||||||
std::vector<double> synth_rates;
|
|
||||||
|
|
||||||
// used by Simple, MTP, Eagle3, etc. - all methods that require some kind of draft model
|
// used by Simple, MTP, Eagle3, etc. - all methods that require some kind of draft model
|
||||||
common_params_speculative_draft draft;
|
common_params_speculative_draft draft;
|
||||||
|
|
||||||
@@ -387,19 +386,23 @@ struct common_params_speculative {
|
|||||||
return !draft.mparams.empty();
|
return !draft.mparams.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_synth() const {
|
|
||||||
return synth_len != -1.0 || !synth_rates.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t need_n_rs_seq() const {
|
uint32_t need_n_rs_seq() const {
|
||||||
bool needs_rs_seq = std::any_of(types.begin(), types.end(), [&](auto t) {
|
bool needs_rs_seq = std::any_of(types.begin(), types.end(), [&](auto t) {
|
||||||
return t == COMMON_SPECULATIVE_TYPE_DRAFT_MTP || t == COMMON_SPECULATIVE_TYPE_DRAFT_EAGLE3 || t == COMMON_SPECULATIVE_TYPE_DRAFT_DFLASH || t == COMMON_SPECULATIVE_TYPE_DRAFT_DSPARK;
|
return t == COMMON_SPECULATIVE_TYPE_DRAFT_MTP || t == COMMON_SPECULATIVE_TYPE_DRAFT_EAGLE3 || t == COMMON_SPECULATIVE_TYPE_DRAFT_DFLASH;
|
||||||
});
|
});
|
||||||
|
|
||||||
return needs_rs_seq ? draft.n_max : 0u;
|
return needs_rs_seq ? draft.n_max : 0u;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct common_params_vocoder {
|
||||||
|
struct common_params_model model;
|
||||||
|
|
||||||
|
std::string speaker_file; // speaker file path
|
||||||
|
|
||||||
|
bool use_guide_tokens = false; // enable guide tokens to improve TTS accuracy
|
||||||
|
};
|
||||||
|
|
||||||
struct common_params_diffusion {
|
struct common_params_diffusion {
|
||||||
int32_t steps = 128;
|
int32_t steps = 128;
|
||||||
bool visual_mode = false;
|
bool visual_mode = false;
|
||||||
@@ -455,7 +458,6 @@ struct common_params {
|
|||||||
int32_t n_parallel = 1; // number of parallel sequences to decode
|
int32_t n_parallel = 1; // number of parallel sequences to decode
|
||||||
int32_t n_sequences = 1; // number of sequences to decode
|
int32_t n_sequences = 1; // number of sequences to decode
|
||||||
int32_t n_outputs_max = 0; // max outputs in a batch (0 = n_batch)
|
int32_t n_outputs_max = 0; // max outputs in a batch (0 = n_batch)
|
||||||
int32_t n_outputs_max_per_seq = 1; // max outputs per sequence
|
|
||||||
int32_t grp_attn_n = 1; // group-attention factor
|
int32_t grp_attn_n = 1; // group-attention factor
|
||||||
int32_t grp_attn_w = 512; // group-attention width
|
int32_t grp_attn_w = 512; // group-attention width
|
||||||
int32_t n_print = -1; // print token count every n tokens (-1 = disabled)
|
int32_t n_print = -1; // print token count every n tokens (-1 = disabled)
|
||||||
@@ -481,9 +483,7 @@ struct common_params {
|
|||||||
std::vector<size_t> fit_params_target = std::vector<size_t>(llama_max_devices(), 1024 * 1024*1024);
|
std::vector<size_t> fit_params_target = std::vector<size_t>(llama_max_devices(), 1024 * 1024*1024);
|
||||||
|
|
||||||
enum llama_split_mode split_mode = LLAMA_SPLIT_MODE_LAYER; // how to split the model across GPUs
|
enum llama_split_mode split_mode = LLAMA_SPLIT_MODE_LAYER; // how to split the model across GPUs
|
||||||
enum llama_load_mode load_mode = LLAMA_LOAD_MODE_AUTO; // how to load the model
|
enum llama_load_mode load_mode = LLAMA_LOAD_MODE_MMAP; // how to load the model
|
||||||
|
|
||||||
enum llama_lazy_mode lazy_mode = LLAMA_LAZY_MODE_AUTO; // on-demand reading of tensors marked by the arch
|
|
||||||
|
|
||||||
common_cpu_params cpuparams;
|
common_cpu_params cpuparams;
|
||||||
common_cpu_params cpuparams_batch;
|
common_cpu_params cpuparams_batch;
|
||||||
@@ -500,6 +500,7 @@ struct common_params {
|
|||||||
|
|
||||||
struct common_params_sampling sampling;
|
struct common_params_sampling sampling;
|
||||||
struct common_params_speculative speculative;
|
struct common_params_speculative speculative;
|
||||||
|
struct common_params_vocoder vocoder;
|
||||||
struct common_params_diffusion diffusion;
|
struct common_params_diffusion diffusion;
|
||||||
|
|
||||||
struct common_params_model model;
|
struct common_params_model model;
|
||||||
@@ -591,19 +592,13 @@ struct common_params {
|
|||||||
|
|
||||||
// multimodal models (see tools/mtmd)
|
// multimodal models (see tools/mtmd)
|
||||||
struct common_params_model mmproj;
|
struct common_params_model mmproj;
|
||||||
bool mmproj_use_gpu = true; // use GPU for multimodal model
|
bool mmproj_use_gpu = true; // use GPU for multimodal model
|
||||||
ggml_backend_dev_t mmproj_device = nullptr; // GPU device to use for multimodal model
|
bool no_mmproj = false; // explicitly disable multimodal model
|
||||||
bool no_mmproj = false; // explicitly disable multimodal model
|
std::vector<std::string> image; // path to image file(s) ; TODO: change the name to "media"
|
||||||
std::vector<std::string> image; // path to image file(s) ; TODO: change the name to "media"
|
|
||||||
int image_min_tokens = -1;
|
int image_min_tokens = -1;
|
||||||
int image_max_tokens = -1;
|
int image_max_tokens = -1;
|
||||||
int mtmd_batch_max_tokens = 1024;
|
int mtmd_batch_max_tokens = 1024;
|
||||||
|
|
||||||
// for video input
|
|
||||||
float video_fps = 4.0f;
|
|
||||||
int64_t video_timestamp_interval_ms = 5000;
|
|
||||||
std::string video_ffmpeg_bin_dir = "";
|
|
||||||
|
|
||||||
// finetune
|
// finetune
|
||||||
struct lr_opt lr;
|
struct lr_opt lr;
|
||||||
enum ggml_opt_optimizer_type optimizer = GGML_OPT_OPTIMIZER_TYPE_ADAMW;
|
enum ggml_opt_optimizer_type optimizer = GGML_OPT_OPTIMIZER_TYPE_ADAMW;
|
||||||
@@ -627,7 +622,6 @@ struct common_params {
|
|||||||
bool cache_prompt = true; // whether to enable prompt caching
|
bool cache_prompt = true; // whether to enable prompt caching
|
||||||
bool cache_idle_slots = true; // save and clear idle slots upon starting a new task
|
bool cache_idle_slots = true; // save and clear idle slots upon starting a new task
|
||||||
int32_t n_ctx_checkpoints = 32; // max number of context checkpoints per slot
|
int32_t n_ctx_checkpoints = 32; // max number of context checkpoints per slot
|
||||||
int32_t kv_unified_per_slot = 0; // max context per parallel slot; 0 = unset
|
|
||||||
int32_t checkpoint_min_step = 8192; // minimum spacing between context checkpoints
|
int32_t checkpoint_min_step = 8192; // minimum spacing between context checkpoints
|
||||||
int32_t cache_ram_mib = 8192; // -1 = no limit, 0 - disable, 1 = 1 MiB, etc.
|
int32_t cache_ram_mib = 8192; // -1 = no limit, 0 - disable, 1 = 1 MiB, etc.
|
||||||
|
|
||||||
@@ -657,7 +651,6 @@ struct common_params {
|
|||||||
std::string ssl_file_cert = ""; // NOLINT
|
std::string ssl_file_cert = ""; // NOLINT
|
||||||
|
|
||||||
std::map<std::string, std::string> default_template_kwargs;
|
std::map<std::string, std::string> default_template_kwargs;
|
||||||
bool preserve_reasoning_specified = false;
|
|
||||||
|
|
||||||
// CLI params
|
// CLI params
|
||||||
std::string server_base; // if set, connect to this server instead of starting a new one
|
std::string server_base; // if set, connect to this server instead of starting a new one
|
||||||
@@ -674,7 +667,6 @@ struct common_params {
|
|||||||
|
|
||||||
// enable built-in tools
|
// enable built-in tools
|
||||||
std::vector<std::string> server_tools;
|
std::vector<std::string> server_tools;
|
||||||
std::string server_tools_runtime;
|
|
||||||
|
|
||||||
// MCP server configs (Cursor-compatible JSON)
|
// MCP server configs (Cursor-compatible JSON)
|
||||||
std::string mcp_servers_config; // path to JSON file with MCP server definitions
|
std::string mcp_servers_config; // path to JSON file with MCP server definitions
|
||||||
@@ -750,12 +742,6 @@ struct common_params {
|
|||||||
llama_progress_callback load_progress_callback = NULL;
|
llama_progress_callback load_progress_callback = NULL;
|
||||||
void * load_progress_callback_user_data = NULL;
|
void * load_progress_callback_user_data = NULL;
|
||||||
bool no_alloc = false; // Don't allocate model buffers
|
bool no_alloc = false; // Don't allocate model buffers
|
||||||
|
|
||||||
// TTS params
|
|
||||||
std::string tts_lang = "";
|
|
||||||
std::string tts_speaker_file = "";
|
|
||||||
|
|
||||||
bool is_gen_docs = false; // whether we are running inside llama-gen-docs
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// call once at the start of a program if it uses libcommon
|
// call once at the start of a program if it uses libcommon
|
||||||
@@ -880,15 +866,6 @@ std::string string_from(const struct llama_context * ctx, const struct llama_bat
|
|||||||
|
|
||||||
bool glob_match(const std::string & pattern, const std::string & str);
|
bool glob_match(const std::string & pattern, const std::string & str);
|
||||||
|
|
||||||
//
|
|
||||||
// Environment utils
|
|
||||||
//
|
|
||||||
|
|
||||||
// portable environment access, an unset variable reads as an empty string
|
|
||||||
// and setting an empty value unsets the variable
|
|
||||||
std::string common_get_env(const std::string & name);
|
|
||||||
void common_set_env(const std::string & name, const std::string & value);
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Filesystem utils
|
// Filesystem utils
|
||||||
//
|
//
|
||||||
@@ -899,7 +876,6 @@ bool fs_is_directory(const std::string & path);
|
|||||||
|
|
||||||
std::string fs_get_cache_directory();
|
std::string fs_get_cache_directory();
|
||||||
std::string fs_get_cache_file(const std::string & filename);
|
std::string fs_get_cache_file(const std::string & filename);
|
||||||
std::string fs_get_config_directory();
|
|
||||||
|
|
||||||
struct common_file_info {
|
struct common_file_info {
|
||||||
std::string path;
|
std::string path;
|
||||||
@@ -947,8 +923,9 @@ using common_init_result_ptr = std::unique_ptr<common_init_result>;
|
|||||||
|
|
||||||
common_init_result_ptr common_init_from_params(common_params & params, bool model_only = false);
|
common_init_result_ptr common_init_from_params(common_params & params, bool model_only = false);
|
||||||
|
|
||||||
struct llama_model_params common_model_params_to_llama ( common_params & params);
|
struct llama_model_params common_model_params_to_llama ( common_params & params);
|
||||||
struct llama_context_params common_context_params_to_llama(const common_params & params);
|
struct llama_context_params common_context_params_to_llama(const common_params & params);
|
||||||
|
struct ggml_threadpool_params ggml_threadpool_params_from_cpu_params(const common_cpu_params & params);
|
||||||
|
|
||||||
// clear LoRA adapters from context, then apply new list of adapters
|
// clear LoRA adapters from context, then apply new list of adapters
|
||||||
void common_set_adapter_lora(struct llama_context * ctx, std::vector<common_adapter_lora_info> & lora);
|
void common_set_adapter_lora(struct llama_context * ctx, std::vector<common_adapter_lora_info> & lora);
|
||||||
@@ -956,31 +933,6 @@ void common_set_adapter_lora(struct llama_context * ctx, std::vector<common_adap
|
|||||||
// model endpoint from env
|
// model endpoint from env
|
||||||
std::string common_get_model_endpoint();
|
std::string common_get_model_endpoint();
|
||||||
|
|
||||||
// for testing purposes
|
|
||||||
char * common_get_model_or_exit(int, char*[]);
|
|
||||||
|
|
||||||
//
|
|
||||||
// Threadpool utils
|
|
||||||
//
|
|
||||||
|
|
||||||
struct ggml_threadpool_params ggml_threadpool_params_from_cpu_params(const common_cpu_params & params);
|
|
||||||
|
|
||||||
struct common_threadpools {
|
|
||||||
common_threadpools() = default;
|
|
||||||
~common_threadpools();
|
|
||||||
|
|
||||||
common_threadpools(const common_threadpools &) = delete;
|
|
||||||
common_threadpools & operator=(const common_threadpools &) = delete;
|
|
||||||
|
|
||||||
void init(llama_context * ctx, const common_params & params);
|
|
||||||
|
|
||||||
private:
|
|
||||||
ggml_threadpool * threadpool = nullptr;
|
|
||||||
ggml_threadpool * threadpool_batch = nullptr;
|
|
||||||
|
|
||||||
decltype(ggml_threadpool_free) * free_fn = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Context utils
|
// Context utils
|
||||||
//
|
//
|
||||||
@@ -996,17 +948,10 @@ enum common_context_seq_rm_type {
|
|||||||
// note: clears the memory of the context
|
// note: clears the memory of the context
|
||||||
common_context_seq_rm_type common_context_can_seq_rm(llama_context * ctx);
|
common_context_seq_rm_type common_context_can_seq_rm(llama_context * ctx);
|
||||||
|
|
||||||
struct common_memory {
|
// aborts execution on failure
|
||||||
llama_context * ctx_tgt = nullptr;
|
void common_context_seq_rm (llama_context * ctx, llama_seq_id seq_id, llama_pos p0, llama_pos p1);
|
||||||
llama_context * ctx_dft = nullptr;
|
void common_context_seq_add(llama_context * ctx, llama_seq_id seq_id, llama_pos p0, llama_pos p1, llama_pos delta);
|
||||||
|
void common_context_seq_cp (llama_context * ctx, llama_seq_id seq_id_src, llama_seq_id seq_id_dst, llama_pos p0, llama_pos p1);
|
||||||
void init(llama_context * ctx_tgt, llama_context * ctx_dft = nullptr);
|
|
||||||
|
|
||||||
// aborts execution on failure
|
|
||||||
void seq_rm (llama_seq_id seq_id, llama_pos p0, llama_pos p1) const;
|
|
||||||
void seq_add(llama_seq_id seq_id, llama_pos p0, llama_pos p1, llama_pos delta) const;
|
|
||||||
void seq_cp (llama_seq_id seq_id_src, llama_seq_id seq_id_dst, llama_pos p0, llama_pos p1) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Batch utils
|
// Batch utils
|
||||||
@@ -1125,28 +1070,39 @@ const char * const LLM_KV_SPLIT_TENSORS_COUNT = "split.tensors.count";
|
|||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// FFN offload utils
|
// MoE utils
|
||||||
//
|
//
|
||||||
|
|
||||||
const char * const LLM_FFN_EXPS_REGEX = "\\.ffn_(up|down|gate|gate_up)_(ch|)exps";
|
const char * const LLM_FFN_EXPS_REGEX = "\\.ffn_(up|down|gate|gate_up)_(ch|)exps";
|
||||||
|
|
||||||
const char * const LLM_FFN_DENSE_REGEX = "\\.ffn_(up|down|gate)\\.";
|
inline std::string llm_ffn_exps_block_regex(int idx) {
|
||||||
|
return string_format("blk\\.%d%s", idx, LLM_FFN_EXPS_REGEX);
|
||||||
inline std::string llm_ffn_block_regex(int idx, const char * ffn_regex) {
|
|
||||||
return string_format("blk\\.%d%s", idx, ffn_regex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline llama_model_tensor_buft_override llm_ffn_exps_cpu_override() {
|
inline llama_model_tensor_buft_override llm_ffn_exps_cpu_override() {
|
||||||
return { LLM_FFN_EXPS_REGEX, ggml_backend_cpu_buffer_type() };
|
return { LLM_FFN_EXPS_REGEX, ggml_backend_cpu_buffer_type() };
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void llm_add_n_cpu_ffn_overrides(int n, const char * ffn_regex, std::vector<llama_model_tensor_buft_override> & overrides) {
|
// ATSInfer-style tensor-granularity static placement of MoE expert weights.
|
||||||
// keep strings alive and avoid leaking memory by storing them in a static list
|
// Offloads the expert weights of the first floor(n) layers to the CPU, plus a
|
||||||
static std::list<std::string> buft_override_strings;
|
// subset of the boundary layer's three expert tensors for the fractional part.
|
||||||
for (int i = 0; i < n; ++i) {
|
// Expert tensors are dropped from the GPU in ascending performance-density
|
||||||
buft_override_strings.push_back(llm_ffn_block_regex(i, ffn_regex));
|
// order (gate, then up), keeping the higher-value down_proj resident longest.
|
||||||
overrides.push_back({buft_override_strings.back().c_str(), ggml_backend_cpu_buffer_type()});
|
inline std::vector<std::string> llm_ffn_exps_cpu_block_regexes(double n_cpu_moe) {
|
||||||
|
std::vector<std::string> regexes;
|
||||||
|
const int n_full = n_cpu_moe > 0 ? (int) n_cpu_moe : 0;
|
||||||
|
for (int i = 0; i < n_full; ++i) {
|
||||||
|
regexes.push_back(llm_ffn_exps_block_regex(i));
|
||||||
}
|
}
|
||||||
|
const int k = (int) ((n_cpu_moe - n_full) * 3.0 + 0.5);
|
||||||
|
if (k >= 3) {
|
||||||
|
regexes.push_back(llm_ffn_exps_block_regex(n_full));
|
||||||
|
} else if (k == 2) {
|
||||||
|
regexes.push_back(string_format("blk\\.%d\\.ffn_(gate|up)_(ch|)exps", n_full));
|
||||||
|
} else if (k == 1) {
|
||||||
|
regexes.push_back(string_format("blk\\.%d\\.ffn_gate_(ch|)exps", n_full));
|
||||||
|
}
|
||||||
|
return regexes;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
+29
-91
@@ -5,7 +5,9 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "download.h"
|
#include "download.h"
|
||||||
#include "hf-cache.h"
|
#include "hf-cache.h"
|
||||||
#include "json.h"
|
|
||||||
|
#define JSON_ASSERT GGML_ASSERT
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
@@ -42,6 +44,8 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
using json = nlohmann::ordered_json;
|
||||||
|
|
||||||
//
|
//
|
||||||
// downloader
|
// downloader
|
||||||
//
|
//
|
||||||
@@ -564,30 +568,16 @@ static hf_cache::hf_files get_split_files(const hf_cache::hf_files & files,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// pick the best sibling GGUF whose filename contains `keyword` (e.g. "mmproj" / "mtp"),
|
// pick the best sibling GGUF whose filename contains `keyword` (e.g. "mmproj" / "mtp"),
|
||||||
// preferring deeper shared directory prefix with the model, then exact `tag` match,
|
// preferring deeper shared directory prefix with the model, then closest quantization
|
||||||
// then closest quantization to the tag when given, or to the model otherwise
|
|
||||||
static hf_cache::hf_file find_best_sibling(const hf_cache::hf_files & files,
|
static hf_cache::hf_file find_best_sibling(const hf_cache::hf_files & files,
|
||||||
const std::string & model,
|
const std::string & model,
|
||||||
const std::string & keyword,
|
const std::string & keyword) {
|
||||||
const std::string & tag = "") {
|
|
||||||
hf_cache::hf_file best;
|
hf_cache::hf_file best;
|
||||||
size_t best_depth = 0;
|
size_t best_depth = 0;
|
||||||
int best_diff = 0;
|
int best_diff = 0;
|
||||||
bool best_exact = false;
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
std::string tag_upper = tag;
|
auto model_bits = extract_quant_bits(model);
|
||||||
for (char & c : tag_upper) {
|
|
||||||
c = (char) std::toupper((unsigned char) c);
|
|
||||||
}
|
|
||||||
|
|
||||||
int model_bits = 0;
|
|
||||||
if (!tag_upper.empty()) {
|
|
||||||
auto pos = tag_upper.find_first_of("0123456789");
|
|
||||||
model_bits = pos == std::string::npos ? 0 : std::stoi(tag_upper.substr(pos));
|
|
||||||
} else {
|
|
||||||
model_bits = extract_quant_bits(model);
|
|
||||||
}
|
|
||||||
auto model_parts = string_split<std::string>(model, '/');
|
auto model_parts = string_split<std::string>(model, '/');
|
||||||
auto model_dir = model_parts.end() - 1;
|
auto model_dir = model_parts.end() - 1;
|
||||||
|
|
||||||
@@ -610,19 +600,10 @@ static hf_cache::hf_file find_best_sibling(const hf_cache::hf_files & files,
|
|||||||
auto bits = extract_quant_bits(f.path);
|
auto bits = extract_quant_bits(f.path);
|
||||||
auto diff = std::abs(bits - model_bits);
|
auto diff = std::abs(bits - model_bits);
|
||||||
|
|
||||||
std::string path_upper = f.path;
|
if (!found || depth > best_depth || (depth == best_depth && diff < best_diff)) {
|
||||||
for (char & c : path_upper) {
|
|
||||||
c = (char) std::toupper((unsigned char) c);
|
|
||||||
}
|
|
||||||
bool exact = !tag_upper.empty() && path_upper.find("-" + tag_upper + ".") != std::string::npos;
|
|
||||||
|
|
||||||
if (!found || depth > best_depth ||
|
|
||||||
(depth == best_depth && exact && !best_exact) ||
|
|
||||||
(depth == best_depth && exact == best_exact && diff < best_diff)) {
|
|
||||||
best = f;
|
best = f;
|
||||||
best_depth = depth;
|
best_depth = depth;
|
||||||
best_diff = diff;
|
best_diff = diff;
|
||||||
best_exact = exact;
|
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -635,27 +616,18 @@ static hf_cache::hf_file find_best_mmproj(const hf_cache::hf_files & files,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static hf_cache::hf_file find_best_mtp(const hf_cache::hf_files & files,
|
static hf_cache::hf_file find_best_mtp(const hf_cache::hf_files & files,
|
||||||
const std::string & model,
|
const std::string & model) {
|
||||||
const std::string & tag = "") {
|
return find_best_sibling(files, model, "mtp-");
|
||||||
return find_best_sibling(files, model, "mtp-", tag);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static hf_cache::hf_file find_best_eagle3(const hf_cache::hf_files & files,
|
static hf_cache::hf_file find_best_eagle3(const hf_cache::hf_files & files,
|
||||||
const std::string & model,
|
const std::string & model) {
|
||||||
const std::string & tag = "") {
|
return find_best_sibling(files, model, "eagle3-");
|
||||||
return find_best_sibling(files, model, "eagle3-", tag);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static hf_cache::hf_file find_best_dflash(const hf_cache::hf_files & files,
|
static hf_cache::hf_file find_best_dflash(const hf_cache::hf_files & files,
|
||||||
const std::string & model,
|
const std::string & model) {
|
||||||
const std::string & tag = "") {
|
return find_best_sibling(files, model, "dflash-");
|
||||||
return find_best_sibling(files, model, "dflash-", tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
static hf_cache::hf_file find_best_dspark(const hf_cache::hf_files & files,
|
|
||||||
const std::string & model,
|
|
||||||
const std::string & tag = "") {
|
|
||||||
return find_best_sibling(files, model, "dspark-", tag);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool gguf_filename_is_model(const std::string & filepath) {
|
static bool gguf_filename_is_model(const std::string & filepath) {
|
||||||
@@ -672,8 +644,7 @@ static bool gguf_filename_is_model(const std::string & filepath) {
|
|||||||
filename.find("imatrix") == std::string::npos &&
|
filename.find("imatrix") == std::string::npos &&
|
||||||
filename.find("mtp-") == std::string::npos &&
|
filename.find("mtp-") == std::string::npos &&
|
||||||
filename.find("eagle3-") == std::string::npos &&
|
filename.find("eagle3-") == std::string::npos &&
|
||||||
filename.find("dflash-") == std::string::npos &&
|
filename.find("dflash-") == std::string::npos;
|
||||||
filename.find("dspark-") == std::string::npos;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static hf_cache::hf_file find_best_model(const hf_cache::hf_files & files,
|
static hf_cache::hf_file find_best_model(const hf_cache::hf_files & files,
|
||||||
@@ -765,39 +736,27 @@ common_download_hf_plan common_download_get_hf_plan(const common_params_model &
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
primary = find_best_model(all, tag);
|
primary = find_best_model(all, tag);
|
||||||
// a requested sidecar can resolve on its own, without a full model of the same tag
|
if (primary.path.empty()) {
|
||||||
if (primary.path.empty() && !opts.download_mtp && !opts.download_dflash && !opts.download_eagle3 && !opts.download_dspark) {
|
|
||||||
LOG_ERR("%s: no GGUF files found in repository %s\n", __func__, repo.c_str());
|
LOG_ERR("%s: no GGUF files found in repository %s\n", __func__, repo.c_str());
|
||||||
list_available_gguf_files(all);
|
list_available_gguf_files(all);
|
||||||
return plan;
|
return plan;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!primary.path.empty()) {
|
plan.primary = primary;
|
||||||
plan.primary = primary;
|
plan.model_files = get_split_files(all, primary);
|
||||||
plan.model_files = get_split_files(all, primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts.download_mmproj && !primary.path.empty()) {
|
if (opts.download_mmproj) {
|
||||||
plan.mmproj = find_best_mmproj(all, primary.path);
|
plan.mmproj = find_best_mmproj(all, primary.path);
|
||||||
}
|
}
|
||||||
if (opts.download_mtp) {
|
if (opts.download_mtp) {
|
||||||
plan.mtp = find_best_mtp(all, primary.path, tag);
|
plan.mtp = find_best_mtp(all, primary.path);
|
||||||
}
|
}
|
||||||
if (opts.download_dflash) {
|
if (opts.download_dflash) {
|
||||||
plan.dflash = find_best_dflash(all, primary.path, tag);
|
plan.dflash = find_best_dflash(all, primary.path);
|
||||||
}
|
}
|
||||||
if (opts.download_eagle3) {
|
if (opts.download_eagle3) {
|
||||||
plan.eagle3 = find_best_eagle3(all, primary.path, tag);
|
plan.eagle3 = find_best_eagle3(all, primary.path);
|
||||||
}
|
|
||||||
if (opts.download_dspark) {
|
|
||||||
plan.dspark = find_best_dspark(all, primary.path, tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (primary.path.empty() &&
|
|
||||||
plan.mtp.local_path.empty() && plan.dflash.local_path.empty() && plan.eagle3.local_path.empty() && plan.dspark.local_path.empty()) {
|
|
||||||
LOG_ERR("%s: no GGUF files found in repository %s\n", __func__, repo.c_str());
|
|
||||||
list_available_gguf_files(all);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return plan;
|
return plan;
|
||||||
@@ -852,8 +811,8 @@ static std::string common_docker_get_token(const std::string & repo) {
|
|||||||
throw std::runtime_error("Failed to get Docker registry token, HTTP code: " + std::to_string(res.first));
|
throw std::runtime_error("Failed to get Docker registry token, HTTP code: " + std::to_string(res.first));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string response_str(res.second.begin(), res.second.end());
|
std::string response_str(res.second.begin(), res.second.end());
|
||||||
common_json response = common_json::parse(response_str);
|
nlohmann::ordered_json response = nlohmann::ordered_json::parse(response_str);
|
||||||
|
|
||||||
if (!response.contains("token")) {
|
if (!response.contains("token")) {
|
||||||
throw std::runtime_error("Docker registry token response missing 'token' field");
|
throw std::runtime_error("Docker registry token response missing 'token' field");
|
||||||
@@ -915,9 +874,9 @@ std::string common_docker_resolve_model(const std::string & docker) {
|
|||||||
throw std::runtime_error("Failed to get Docker manifest, HTTP code: " + std::to_string(manifest_res.first));
|
throw std::runtime_error("Failed to get Docker manifest, HTTP code: " + std::to_string(manifest_res.first));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string manifest_str(manifest_res.second.begin(), manifest_res.second.end());
|
std::string manifest_str(manifest_res.second.begin(), manifest_res.second.end());
|
||||||
common_json manifest = common_json::parse(manifest_str);
|
nlohmann::ordered_json manifest = nlohmann::ordered_json::parse(manifest_str);
|
||||||
std::string gguf_digest; // Find the GGUF layer
|
std::string gguf_digest; // Find the GGUF layer
|
||||||
if (manifest.contains("layers")) {
|
if (manifest.contains("layers")) {
|
||||||
for (const auto & layer : manifest["layers"]) {
|
for (const auto & layer : manifest["layers"]) {
|
||||||
if (layer.contains("mediaType")) {
|
if (layer.contains("mediaType")) {
|
||||||
@@ -973,8 +932,7 @@ std::vector<common_cached_model_info> common_list_cached_models() {
|
|||||||
split.prefix.find("mmproj") != std::string::npos ||
|
split.prefix.find("mmproj") != std::string::npos ||
|
||||||
split.prefix.find("mtp-") != std::string::npos ||
|
split.prefix.find("mtp-") != std::string::npos ||
|
||||||
split.prefix.find("eagle3-") != std::string::npos ||
|
split.prefix.find("eagle3-") != std::string::npos ||
|
||||||
split.prefix.find("dflash-") != std::string::npos ||
|
split.prefix.find("dflash-") != std::string::npos) {
|
||||||
split.prefix.find("dspark-") != std::string::npos) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (seen.insert(f.repo_id + ":" + split.tag).second) {
|
if (seen.insert(f.repo_id + ":" + split.tag).second) {
|
||||||
@@ -985,26 +943,6 @@ std::vector<common_cached_model_info> common_list_cached_models() {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string common_download_resolve_path(const std::string & hf_repo_with_tag, const std::string & hf_file) {
|
|
||||||
auto [repo, tag] = common_download_split_repo_tag(hf_repo_with_tag);
|
|
||||||
|
|
||||||
auto files = hf_cache::get_cached_files(repo);
|
|
||||||
if (files.empty()) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hf_file.empty()) {
|
|
||||||
for (const auto & f : files) {
|
|
||||||
if (f.path == hf_file) {
|
|
||||||
return f.local_path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
return find_best_model(files, tag).local_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool common_download_remove(const std::string & hf_repo_with_tag) {
|
bool common_download_remove(const std::string & hf_repo_with_tag) {
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,6 @@ struct common_download_opts {
|
|||||||
bool download_mtp = false;
|
bool download_mtp = false;
|
||||||
bool download_eagle3 = false;
|
bool download_eagle3 = false;
|
||||||
bool download_dflash = false;
|
bool download_dflash = false;
|
||||||
bool download_dspark = false;
|
|
||||||
common_download_callback * callback = nullptr;
|
common_download_callback * callback = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -85,10 +84,6 @@ std::vector<std::string> common_download_get_all_parts(const std::string & url);
|
|||||||
// returns list of cached models
|
// returns list of cached models
|
||||||
std::vector<common_cached_model_info> common_list_cached_models();
|
std::vector<common_cached_model_info> common_list_cached_models();
|
||||||
|
|
||||||
// resolve the local cached file path for a HF repo without network access (hf_file, if given, must match exactly)
|
|
||||||
// returns an empty string if the model is not present in the cache
|
|
||||||
std::string common_download_resolve_path(const std::string & hf_repo_with_tag, const std::string & hf_file = "");
|
|
||||||
|
|
||||||
// download single file from url to local path
|
// download single file from url to local path
|
||||||
// returns status code or -1 on error
|
// returns status code or -1 on error
|
||||||
// skip_etag: if true, don't read/write .etag files (for HF cache where filename is the hash)
|
// skip_etag: if true, don't read/write .etag files (for HF cache where filename is the hash)
|
||||||
@@ -115,7 +110,6 @@ struct common_download_hf_plan {
|
|||||||
hf_cache::hf_file mtp;
|
hf_cache::hf_file mtp;
|
||||||
hf_cache::hf_file eagle3;
|
hf_cache::hf_file eagle3;
|
||||||
hf_cache::hf_file dflash;
|
hf_cache::hf_file dflash;
|
||||||
hf_cache::hf_file dspark;
|
|
||||||
hf_cache::hf_file preset; // if set, only this file is downloaded
|
hf_cache::hf_file preset; // if set, only this file is downloaded
|
||||||
};
|
};
|
||||||
common_download_hf_plan common_download_get_hf_plan(const common_params_model & model, const common_download_opts & opts);
|
common_download_hf_plan common_download_get_hf_plan(const common_params_model & model, const common_download_opts & opts);
|
||||||
|
|||||||
+17
-108
@@ -137,9 +137,6 @@ static std::vector<llama_device_memory_data> common_get_device_memory_data_impl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
hp_ngl = llama_model_n_layer(model);
|
hp_ngl = llama_model_n_layer(model);
|
||||||
if (mparams->load_mtp) {
|
|
||||||
hp_ngl += llama_model_n_layer_nextn(model);
|
|
||||||
}
|
|
||||||
hp_n_ctx_train = llama_model_n_ctx_train(model);
|
hp_n_ctx_train = llama_model_n_ctx_train(model);
|
||||||
hp_n_expert = llama_model_n_expert(model);
|
hp_n_expert = llama_model_n_expert(model);
|
||||||
|
|
||||||
@@ -178,7 +175,7 @@ common_device_memory_data_vec common_get_device_memory_data(
|
|||||||
static void common_params_fit_impl(
|
static void common_params_fit_impl(
|
||||||
const char * path_model, struct llama_model_params * mparams, struct llama_context_params * cparams,
|
const char * path_model, struct llama_model_params * mparams, struct llama_context_params * cparams,
|
||||||
float * tensor_split, struct llama_model_tensor_buft_override * tensor_buft_overrides,
|
float * tensor_split, struct llama_model_tensor_buft_override * tensor_buft_overrides,
|
||||||
size_t * margins_s, uint32_t n_ctx_min, const common_fit_extra_model * extra, enum ggml_log_level log_level) {
|
size_t * margins_s, uint32_t n_ctx_min, enum ggml_log_level log_level) {
|
||||||
if (mparams->split_mode == LLAMA_SPLIT_MODE_TENSOR) {
|
if (mparams->split_mode == LLAMA_SPLIT_MODE_TENSOR) {
|
||||||
throw common_params_fit_exception("llama_params_fit is not implemented for SPLIT_MODE_TENSOR, abort");
|
throw common_params_fit_exception("llama_params_fit is not implemented for SPLIT_MODE_TENSOR, abort");
|
||||||
}
|
}
|
||||||
@@ -191,92 +188,10 @@ static void common_params_fit_impl(
|
|||||||
uint32_t hp_nct = 0; // hparams.n_ctx_train
|
uint32_t hp_nct = 0; // hparams.n_ctx_train
|
||||||
uint32_t hp_nex = 0; // hparams.n_expert
|
uint32_t hp_nex = 0; // hparams.n_expert
|
||||||
|
|
||||||
// with non-unified kv, we need to take into account n_streams
|
|
||||||
// for example, if memory can hold more than model's trained context size, we must extend the n_ctx to hold enough n_streams
|
|
||||||
const uint32_t n_streams = cparams->kv_unified ? 1 : std::max<uint32_t>(1, cparams->n_seq_max);
|
|
||||||
const bool n_ctx_auto = cparams->n_ctx == 0;
|
|
||||||
|
|
||||||
dmds_t dmds_extra; // memory of the extra model, laid out on the devices of the main model
|
|
||||||
uint32_t n_ctx_extra = 0; // context that memory was measured at
|
|
||||||
|
|
||||||
// the extra model competes for the same memory as the main model, add it to every measurement
|
|
||||||
// its memory is measured again whenever the context it follows changes
|
|
||||||
auto add_extra_memory = [&](dmds_t & dmds) {
|
|
||||||
if (extra == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dmds_extra.empty() || n_ctx_extra != cparams->n_ctx) {
|
|
||||||
std::vector<ggml_backend_dev_t> devs_extra;
|
|
||||||
uint32_t ngl_extra = 0;
|
|
||||||
uint32_t nct_extra = 0;
|
|
||||||
uint32_t nex_extra = 0;
|
|
||||||
|
|
||||||
extra->cparams->n_ctx = cparams->n_ctx;
|
|
||||||
|
|
||||||
LOG_TRC("%s: getting device memory data for the extra model at a context size of %" PRIu32 ":\n",
|
|
||||||
__func__, cparams->n_ctx);
|
|
||||||
|
|
||||||
dmds_t measured;
|
|
||||||
try {
|
|
||||||
measured = common_get_device_memory_data_impl(
|
|
||||||
extra->path_model, extra->mparams, extra->cparams, devs_extra, ngl_extra, nct_extra, nex_extra, log_level);
|
|
||||||
} catch (const std::runtime_error & e) {
|
|
||||||
// the extra model is optional, fit the main model alone rather than giving up
|
|
||||||
LOG_WRN("%s: failed to measure the memory of the extra model, fitting without it: %s\n", __func__, e.what());
|
|
||||||
dmds_extra = dmds_t(devs.size() + 1);
|
|
||||||
n_ctx_extra = cparams->n_ctx;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dmds_extra = dmds_t(devs.size() + 1);
|
|
||||||
dmds_extra.back().mb = measured.back().mb;
|
|
||||||
for (size_t je = 0; je < devs_extra.size(); je++) {
|
|
||||||
for (size_t id = 0; id < devs.size(); id++) {
|
|
||||||
if (devs_extra[je] == devs[id]) {
|
|
||||||
dmds_extra[id].mb.model += measured[je].mb.model;
|
|
||||||
dmds_extra[id].mb.context += measured[je].mb.context;
|
|
||||||
dmds_extra[id].mb.compute += measured[je].mb.compute;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (extra->shares_model) {
|
|
||||||
for (llama_device_memory_data & dmd : dmds_extra) {
|
|
||||||
dmd.mb.model = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
n_ctx_extra = cparams->n_ctx;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t id = 0; id < dmds.size(); id++) {
|
|
||||||
dmds[id].mb.model += dmds_extra[id].mb.model;
|
|
||||||
dmds[id].mb.context += dmds_extra[id].mb.context;
|
|
||||||
dmds[id].mb.compute += dmds_extra[id].mb.compute;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// step 1: get data for default parameters and check whether any changes are necessary in the first place
|
// step 1: get data for default parameters and check whether any changes are necessary in the first place
|
||||||
|
|
||||||
LOG_TRC("%s: getting device memory data for initial parameters:\n", __func__);
|
LOG_TRC("%s: getting device memory data for initial parameters:\n", __func__);
|
||||||
dmds_t dmds_full = common_get_device_memory_data_impl(path_model, mparams, cparams, devs, hp_ngl, hp_nct, hp_nex, log_level);
|
const dmds_t dmds_full = common_get_device_memory_data_impl(path_model, mparams, cparams, devs, hp_ngl, hp_nct, hp_nex, log_level);
|
||||||
|
|
||||||
// saturate instead of overflowing, this also preserves the UINT32_MAX sentinel of n_ctx_min:
|
|
||||||
const uint32_t n_ctx_max = (uint32_t) std::min<uint64_t>(uint64_t(hp_nct) * n_streams, UINT32_MAX);
|
|
||||||
const uint32_t n_ctx_min_total = (uint32_t) std::min<uint64_t>(uint64_t(n_ctx_min) * n_streams, UINT32_MAX);
|
|
||||||
|
|
||||||
// llama_context would use only hp_nct in total for n_ctx == 0, resolve the context before measuring anything else:
|
|
||||||
if (n_ctx_auto) {
|
|
||||||
cparams->n_ctx = n_ctx_max;
|
|
||||||
if (n_streams > 1) {
|
|
||||||
LOG_TRC("%s: context size unset and KV cache not unified -> using %" PRIu32 " for %" PRIu32 " sequences:\n",
|
|
||||||
__func__, n_ctx_max, n_streams);
|
|
||||||
dmds_full = common_get_device_memory_data_impl(path_model, mparams, cparams, devs, hp_ngl, hp_nct, hp_nex, log_level);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
add_extra_memory(dmds_full);
|
|
||||||
|
|
||||||
const size_t nd = devs.size(); // number of devices
|
const size_t nd = devs.size(); // number of devices
|
||||||
|
|
||||||
std::vector<int64_t> margins; // this function uses int64_t rather than size_t for memory sizes to more conveniently handle deficits
|
std::vector<int64_t> margins; // this function uses int64_t rather than size_t for memory sizes to more conveniently handle deficits
|
||||||
@@ -389,8 +304,8 @@ static void common_params_fit_impl(
|
|||||||
"%s: cannot meet free memory targets on all devices, need to use %" PRId64 " MiB less in total\n",
|
"%s: cannot meet free memory targets on all devices, need to use %" PRId64 " MiB less in total\n",
|
||||||
__func__, -global_surplus/MiB);
|
__func__, -global_surplus/MiB);
|
||||||
}
|
}
|
||||||
if (n_ctx_auto) {
|
if (cparams->n_ctx == 0) {
|
||||||
if (n_ctx_max > n_ctx_min_total) {
|
if (hp_nct > n_ctx_min) {
|
||||||
int64_t sum_used_target = sum_free;
|
int64_t sum_used_target = sum_free;
|
||||||
if (nd == 0) {
|
if (nd == 0) {
|
||||||
sum_used_target -= margins[0];
|
sum_used_target -= margins[0];
|
||||||
@@ -410,9 +325,8 @@ static void common_params_fit_impl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
int64_t sum_projected_used_min_ctx = 0;
|
int64_t sum_projected_used_min_ctx = 0;
|
||||||
cparams->n_ctx = n_ctx_min_total;
|
cparams->n_ctx = n_ctx_min;
|
||||||
dmds_t dmds_min_ctx = common_get_device_memory_data_impl(path_model, mparams, cparams, devs, hp_ngl, hp_nct, hp_nex, log_level);
|
const dmds_t dmds_min_ctx = common_get_device_memory_data_impl(path_model, mparams, cparams, devs, hp_ngl, hp_nct, hp_nex, log_level);
|
||||||
add_extra_memory(dmds_min_ctx);
|
|
||||||
if (nd == 0) {
|
if (nd == 0) {
|
||||||
sum_projected_used_min_ctx = dmds_min_ctx.back().mb.total();
|
sum_projected_used_min_ctx = dmds_min_ctx.back().mb.total();
|
||||||
} else {
|
} else {
|
||||||
@@ -422,16 +336,14 @@ static void common_params_fit_impl(
|
|||||||
}
|
}
|
||||||
if (sum_used_target > sum_projected_used_min_ctx) {
|
if (sum_used_target > sum_projected_used_min_ctx) {
|
||||||
// linear interpolation between minimum and maximum context size:
|
// linear interpolation between minimum and maximum context size:
|
||||||
cparams->n_ctx += (n_ctx_max - n_ctx_min_total) * (sum_used_target - sum_projected_used_min_ctx)
|
cparams->n_ctx += (hp_nct - n_ctx_min) * (sum_used_target - sum_projected_used_min_ctx)
|
||||||
/ (sum_projected_used - sum_projected_used_min_ctx);
|
/ (sum_projected_used - sum_projected_used_min_ctx);
|
||||||
// round down context for CUDA backend, keep it divisible by the number of streams:
|
cparams->n_ctx = std::max(cparams->n_ctx - cparams->n_ctx % 256, n_ctx_min); // round down context for CUDA backend
|
||||||
const uint32_t align = 256 * n_streams;
|
|
||||||
cparams->n_ctx = std::max(cparams->n_ctx - cparams->n_ctx % align, n_ctx_min_total);
|
|
||||||
|
|
||||||
const int64_t bytes_per_ctx = (sum_projected_used - sum_projected_used_min_ctx) / (n_ctx_max - n_ctx_min_total);
|
const int64_t bytes_per_ctx = (sum_projected_used - sum_projected_used_min_ctx) / (hp_nct - n_ctx_min);
|
||||||
const int64_t memory_reduction = (n_ctx_max - cparams->n_ctx) * bytes_per_ctx;
|
const int64_t memory_reduction = (hp_nct - cparams->n_ctx) * bytes_per_ctx;
|
||||||
LOG_TRC("%s: context size reduced from %" PRIu32 " to %" PRIu32 " -> need %" PRId64 " MiB less memory in total\n",
|
LOG_TRC("%s: context size reduced from %" PRIu32 " to %" PRIu32 " -> need %" PRId64 " MiB less memory in total\n",
|
||||||
__func__, n_ctx_max, cparams->n_ctx, memory_reduction/MiB);
|
__func__, hp_nct, cparams->n_ctx, memory_reduction/MiB);
|
||||||
if (nd <= 1) {
|
if (nd <= 1) {
|
||||||
LOG_TRC("%s: entire model can be fit by reducing context\n", __func__);
|
LOG_TRC("%s: entire model can be fit by reducing context\n", __func__);
|
||||||
return;
|
return;
|
||||||
@@ -440,14 +352,14 @@ static void common_params_fit_impl(
|
|||||||
} else {
|
} else {
|
||||||
const int64_t memory_reduction = sum_projected_used - sum_projected_used_min_ctx;
|
const int64_t memory_reduction = sum_projected_used - sum_projected_used_min_ctx;
|
||||||
LOG_TRC("%s: context size reduced from %" PRIu32 " to %" PRIu32 " -> need %" PRId64 " MiB less memory in total\n",
|
LOG_TRC("%s: context size reduced from %" PRIu32 " to %" PRIu32 " -> need %" PRId64 " MiB less memory in total\n",
|
||||||
__func__, n_ctx_max, cparams->n_ctx, memory_reduction/MiB);
|
__func__, hp_nct, cparams->n_ctx, memory_reduction/MiB);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (n_ctx_min == UINT32_MAX) {
|
if (n_ctx_min == UINT32_MAX) {
|
||||||
LOG_TRC("%s: user has requested full context size of %" PRIu32 " -> no change\n", __func__, n_ctx_max);
|
LOG_TRC("%s: user has requested full context size of %" PRIu32 " -> no change\n", __func__, hp_nct);
|
||||||
} else {
|
} else {
|
||||||
LOG_TRC("%s: default model context size is %" PRIu32 " which is <= the min. context size of %" PRIu32 " -> no change\n",
|
LOG_TRC("%s: default model context size is %" PRIu32 " which is <= the min. context size of %" PRIu32 " -> no change\n",
|
||||||
__func__, n_ctx_max, n_ctx_min_total);
|
__func__, hp_nct, n_ctx_min);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -592,9 +504,8 @@ static void common_params_fit_impl(
|
|||||||
llama_model_params mparams_copy = *mparams;
|
llama_model_params mparams_copy = *mparams;
|
||||||
set_ngl_tensor_split_tbo(ngl_per_device, overflow_bufts, mparams_copy);
|
set_ngl_tensor_split_tbo(ngl_per_device, overflow_bufts, mparams_copy);
|
||||||
|
|
||||||
dmds_t dmd_nl = common_get_device_memory_data_impl(
|
const dmds_t dmd_nl = common_get_device_memory_data_impl(
|
||||||
path_model, &mparams_copy, cparams, devs, hp_ngl, hp_nct, hp_nex, log_level);
|
path_model, &mparams_copy, cparams, devs, hp_ngl, hp_nct, hp_nex, log_level);
|
||||||
add_extra_memory(dmd_nl);
|
|
||||||
|
|
||||||
LOG_TRC("%s: memory for test allocation by device:\n", func_name);
|
LOG_TRC("%s: memory for test allocation by device:\n", func_name);
|
||||||
for (size_t id = 0; id < nd; id++) {
|
for (size_t id = 0; id < nd; id++) {
|
||||||
@@ -621,9 +532,8 @@ static void common_params_fit_impl(
|
|||||||
mparams->tensor_buft_overrides = tensor_buft_overrides;
|
mparams->tensor_buft_overrides = tensor_buft_overrides;
|
||||||
|
|
||||||
LOG_TRC("%s: getting device memory data with all MoE tensors moved to system memory:\n", __func__);
|
LOG_TRC("%s: getting device memory data with all MoE tensors moved to system memory:\n", __func__);
|
||||||
dmds_t dmds_cpu_moe = common_get_device_memory_data_impl(
|
const dmds_t dmds_cpu_moe = common_get_device_memory_data_impl(
|
||||||
path_model, mparams, cparams, devs, hp_ngl, hp_nct, hp_nex, log_level);
|
path_model, mparams, cparams, devs, hp_ngl, hp_nct, hp_nex, log_level);
|
||||||
add_extra_memory(dmds_cpu_moe);
|
|
||||||
|
|
||||||
for (size_t id = 0; id < nd; id++) {
|
for (size_t id = 0; id < nd; id++) {
|
||||||
global_surplus_cpu_moe += dmds_cpu_moe[id].free;
|
global_surplus_cpu_moe += dmds_cpu_moe[id].free;
|
||||||
@@ -883,12 +793,11 @@ enum common_params_fit_status common_fit_params(
|
|||||||
llama_model_tensor_buft_override * tensor_buft_overrides,
|
llama_model_tensor_buft_override * tensor_buft_overrides,
|
||||||
size_t * margins,
|
size_t * margins,
|
||||||
uint32_t n_ctx_min,
|
uint32_t n_ctx_min,
|
||||||
const common_fit_extra_model * extra,
|
|
||||||
ggml_log_level log_level) {
|
ggml_log_level log_level) {
|
||||||
const int64_t t0_us = llama_time_us();
|
const int64_t t0_us = llama_time_us();
|
||||||
common_params_fit_status status = COMMON_PARAMS_FIT_STATUS_SUCCESS;
|
common_params_fit_status status = COMMON_PARAMS_FIT_STATUS_SUCCESS;
|
||||||
try {
|
try {
|
||||||
common_params_fit_impl(path_model, mparams, cparams, tensor_split, tensor_buft_overrides, margins, n_ctx_min, extra, log_level);
|
common_params_fit_impl(path_model, mparams, cparams, tensor_split, tensor_buft_overrides, margins, n_ctx_min, log_level);
|
||||||
LOG_TRC("%s: successfully fit params to free device memory\n", __func__);
|
LOG_TRC("%s: successfully fit params to free device memory\n", __func__);
|
||||||
} catch (const common_params_fit_exception & e) {
|
} catch (const common_params_fit_exception & e) {
|
||||||
LOG_WRN("%s: failed to fit params to free device memory: %s\n", __func__, e.what());
|
LOG_WRN("%s: failed to fit params to free device memory: %s\n", __func__, e.what());
|
||||||
|
|||||||
@@ -11,16 +11,6 @@ enum common_params_fit_status {
|
|||||||
COMMON_PARAMS_FIT_STATUS_ERROR = 2, // a hard error occurred, e.g. because no model could be found at the specified path
|
COMMON_PARAMS_FIT_STATUS_ERROR = 2, // a hard error occurred, e.g. because no model could be found at the specified path
|
||||||
};
|
};
|
||||||
|
|
||||||
// a second model that shares the devices of the main model, e.g. a draft model
|
|
||||||
// - its context follows the context of the main model, so its memory is measured again whenever that context changes
|
|
||||||
// - shares_model tells the fit that the weights are already counted in the main model, as for an MTP context
|
|
||||||
struct common_fit_extra_model {
|
|
||||||
const char * path_model;
|
|
||||||
llama_model_params * mparams;
|
|
||||||
llama_context_params * cparams;
|
|
||||||
bool shares_model;
|
|
||||||
};
|
|
||||||
|
|
||||||
// fits mparams and cparams to free device memory (assumes system memory is unlimited)
|
// fits mparams and cparams to free device memory (assumes system memory is unlimited)
|
||||||
// - returns true if the parameters could be successfully modified to fit device memory
|
// - returns true if the parameters could be successfully modified to fit device memory
|
||||||
// - this function is NOT thread safe because it modifies the global llama logger state
|
// - this function is NOT thread safe because it modifies the global llama logger state
|
||||||
@@ -34,7 +24,6 @@ common_params_fit_status common_fit_params(
|
|||||||
llama_model_tensor_buft_override * tensor_buft_overrides, // writable buffer for overrides, needs at least llama_max_tensor_buft_overrides elements
|
llama_model_tensor_buft_override * tensor_buft_overrides, // writable buffer for overrides, needs at least llama_max_tensor_buft_overrides elements
|
||||||
size_t * margins, // margins of memory to leave per device in bytes
|
size_t * margins, // margins of memory to leave per device in bytes
|
||||||
uint32_t n_ctx_min, // minimum context size to set when trying to reduce memory use
|
uint32_t n_ctx_min, // minimum context size to set when trying to reduce memory use
|
||||||
const common_fit_extra_model * extra, // model to fit alongside the main one, nullptr if there is none
|
|
||||||
ggml_log_level log_level); // minimum log level to print during fitting, lower levels go to debug log
|
ggml_log_level log_level); // minimum log level to print during fitting, lower levels go to debug log
|
||||||
|
|
||||||
// print estimated memory to stdout
|
// print estimated memory to stdout
|
||||||
|
|||||||
+11
-7
@@ -4,7 +4,9 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "http.h"
|
#include "http.h"
|
||||||
#include "json.h"
|
|
||||||
|
#define JSON_ASSERT GGML_ASSERT
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@@ -13,6 +15,8 @@
|
|||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace nl = nlohmann;
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#ifndef NOMINMAX
|
#ifndef NOMINMAX
|
||||||
@@ -191,8 +195,8 @@ static void safe_write_file(const fs::path & path, const std::string & data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static common_json api_get(const std::string & url,
|
static nl::json api_get(const std::string & url,
|
||||||
const std::string & token) {
|
const std::string & token) {
|
||||||
auto [cli, parts] = common_http_client(url);
|
auto [cli, parts] = common_http_client(url);
|
||||||
|
|
||||||
httplib::Headers headers = {
|
httplib::Headers headers = {
|
||||||
@@ -210,10 +214,10 @@ static common_json api_get(const std::string & url,
|
|||||||
auto body = res->body;
|
auto body = res->body;
|
||||||
|
|
||||||
if (res->status == 200) {
|
if (res->status == 200) {
|
||||||
return common_json::parse(res->body);
|
return nl::json::parse(res->body);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
body = common_json::parse(res->body)["error"].get<std::string>();
|
body = nl::json::parse(res->body)["error"].get<std::string>();
|
||||||
} catch (...) { }
|
} catch (...) { }
|
||||||
|
|
||||||
throw std::runtime_error("GET failed (" + std::to_string(res->status) + "): " + body);
|
throw std::runtime_error("GET failed (" + std::to_string(res->status) + "): " + body);
|
||||||
@@ -276,7 +280,7 @@ static std::string get_repo_commit(const std::string & repo_id,
|
|||||||
safe_write_file(refs_path / name, commit);
|
safe_write_file(refs_path / name, commit);
|
||||||
return commit;
|
return commit;
|
||||||
|
|
||||||
} catch (const common_json_error & e) {
|
} catch (const nl::json::exception & e) {
|
||||||
LOG_ERR("%s: JSON error: %s\n", __func__, e.what());
|
LOG_ERR("%s: JSON error: %s\n", __func__, e.what());
|
||||||
} catch (const std::exception & e) {
|
} catch (const std::exception & e) {
|
||||||
LOG_ERR("%s: error: %s\n", __func__, e.what());
|
LOG_ERR("%s: error: %s\n", __func__, e.what());
|
||||||
@@ -354,7 +358,7 @@ hf_files get_repo_files(const std::string & repo_id,
|
|||||||
|
|
||||||
files.push_back(file);
|
files.push_back(file);
|
||||||
}
|
}
|
||||||
} catch (const common_json_error & e) {
|
} catch (const nl::json::exception & e) {
|
||||||
LOG_ERR("%s: JSON error: %s\n", __func__, e.what());
|
LOG_ERR("%s: JSON error: %s\n", __func__, e.what());
|
||||||
} catch (const std::exception & e) {
|
} catch (const std::exception & e) {
|
||||||
LOG_ERR("%s: error: %s\n", __func__, e.what());
|
LOG_ERR("%s: error: %s\n", __func__, e.what());
|
||||||
|
|||||||
@@ -102,8 +102,7 @@ bool common_imatrix_load(const std::string & fname, common_imatrix & imatrix) {
|
|||||||
const int64_t chunk_count_key = gguf_find_key(ctx_gguf, LLM_KV_IMATRIX_CHUNK_COUNT);
|
const int64_t chunk_count_key = gguf_find_key(ctx_gguf, LLM_KV_IMATRIX_CHUNK_COUNT);
|
||||||
const int64_t chunk_size_key = gguf_find_key(ctx_gguf, LLM_KV_IMATRIX_CHUNK_SIZE);
|
const int64_t chunk_size_key = gguf_find_key(ctx_gguf, LLM_KV_IMATRIX_CHUNK_SIZE);
|
||||||
|
|
||||||
if (datasets_key != -1 && gguf_get_kv_type(ctx_gguf, datasets_key) == GGUF_TYPE_ARRAY &&
|
if (datasets_key != -1 && gguf_get_arr_type(ctx_gguf, datasets_key) == GGUF_TYPE_STRING) {
|
||||||
gguf_get_arr_type(ctx_gguf, datasets_key) == GGUF_TYPE_STRING) {
|
|
||||||
const int64_t n = gguf_get_arr_n(ctx_gguf, datasets_key);
|
const int64_t n = gguf_get_arr_n(ctx_gguf, datasets_key);
|
||||||
imatrix.datasets.reserve(imatrix.datasets.size() + n);
|
imatrix.datasets.reserve(imatrix.datasets.size() + n);
|
||||||
for (int64_t i = 0; i < n; ++i) {
|
for (int64_t i = 0; i < n; ++i) {
|
||||||
@@ -144,13 +143,6 @@ bool common_imatrix_load(const std::string & fname, common_imatrix & imatrix) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in_sum2->type != GGML_TYPE_F32 || counts->type != GGML_TYPE_F32) {
|
|
||||||
LOG_ERR("%s: sums and counts for %s must be F32\n", __func__, name.c_str());
|
|
||||||
gguf_free(ctx_gguf);
|
|
||||||
ggml_free(ctx);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto & e = imatrix.entries[name];
|
auto & e = imatrix.entries[name];
|
||||||
|
|
||||||
const int64_t nval = ggml_nelements(in_sum2);
|
const int64_t nval = ggml_nelements(in_sum2);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ The implementation can be found in the `common/jinja` directory.
|
|||||||
## Key Features
|
## Key Features
|
||||||
|
|
||||||
- Input marking: security against special token injection
|
- Input marking: security against special token injection
|
||||||
- Decoupled from the JSON library: `common_json` is only used for JSON-to-internal type translation and is completely optional
|
- Decoupled from `nlohmann::json`: this dependency is only used for JSON-to-internal type translation and is completely optional
|
||||||
- Minimal primitive types: int, float, bool, string, array, object, none, undefined
|
- Minimal primitive types: int, float, bool, string, array, object, none, undefined
|
||||||
- Detailed logging: allow source tracing on error
|
- Detailed logging: allow source tracing on error
|
||||||
- Clean architecture: workarounds are applied to input data before entering the runtime (see `common/chat.cpp`)
|
- Clean architecture: workarounds are applied to input data before entering the runtime (see `common/chat.cpp`)
|
||||||
|
|||||||
+13
-85
@@ -4,32 +4,26 @@
|
|||||||
|
|
||||||
// note: the json dependency is only for defining input in a convenient way
|
// note: the json dependency is only for defining input in a convenient way
|
||||||
// we can remove it in the future when we figure out a better way to define inputs using jinja::value
|
// we can remove it in the future when we figure out a better way to define inputs using jinja::value
|
||||||
#include "json.h"
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#define FILENAME "jinja-caps"
|
#define FILENAME "jinja-caps"
|
||||||
|
|
||||||
using json = common_json;
|
using json = nlohmann::ordered_json;
|
||||||
|
|
||||||
namespace jinja {
|
namespace jinja {
|
||||||
|
|
||||||
using caps_json_fn = std::function<json()>;
|
using caps_json_fn = std::function<json()>;
|
||||||
using caps_ctx_fn = std::function<void(context &)>;
|
using caps_ctx_fn = std::function<void(context &)>;
|
||||||
using caps_analyze_fn = std::function<void(context &, bool, value &, value &, const std::string &)>;
|
using caps_analyze_fn = std::function<void(bool, value &, value &, const std::string &)>;
|
||||||
|
|
||||||
void caps_apply_preserve_reasoning(jinja::context & ctx, bool enabled) {
|
void caps_apply_preserve_reasoning(jinja::context & ctx, bool enabled) {
|
||||||
ctx.set_val("preserve_thinking", mk_val<value_bool>(enabled));
|
ctx.set_val("preserve_thinking", mk_val<value_bool>(enabled));
|
||||||
ctx.set_val("clear_thinking", mk_val<value_bool>(!enabled));
|
ctx.set_val("clear_thinking", mk_val<value_bool>(!enabled));
|
||||||
ctx.set_val("truncate_history_thinking", mk_val<value_bool>(!enabled));
|
ctx.set_val("truncate_history_thinking", mk_val<value_bool>(!enabled));
|
||||||
ctx.set_val("drop_thinking", mk_val<value_bool>(!enabled));
|
ctx.set_val("drop_thinking", mk_val<value_bool>(!enabled));
|
||||||
}
|
|
||||||
|
|
||||||
void caps_apply_reasoning_effort(jinja::context & ctx, const std::string & effort) {
|
|
||||||
value var = mk_val<value_string>(effort); // bind to the same value for stats
|
|
||||||
ctx.set_val("reasoning_effort", var);
|
|
||||||
ctx.set_val("reasoning_strength", var);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void caps_try_execute(jinja::program & prog,
|
static void caps_try_execute(jinja::program & prog,
|
||||||
@@ -68,7 +62,7 @@ static void caps_try_execute(jinja::program & prog,
|
|||||||
// ignore exceptions during capability analysis
|
// ignore exceptions during capability analysis
|
||||||
}
|
}
|
||||||
|
|
||||||
analyze_fn(ctx, success, messages, tools, result);
|
analyze_fn(success, messages, tools, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// for debugging only
|
// for debugging only
|
||||||
@@ -93,7 +87,6 @@ std::map<std::string, bool> caps::to_map() const {
|
|||||||
{"supports_parallel_tool_calls", supports_parallel_tool_calls},
|
{"supports_parallel_tool_calls", supports_parallel_tool_calls},
|
||||||
{"supports_system_role", supports_system_role},
|
{"supports_system_role", supports_system_role},
|
||||||
{"supports_preserve_reasoning", supports_preserve_reasoning},
|
{"supports_preserve_reasoning", supports_preserve_reasoning},
|
||||||
{"supports_reasoning_effort", supports_reasoning_effort},
|
|
||||||
{"supports_object_arguments", supports_object_arguments},
|
{"supports_object_arguments", supports_object_arguments},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -117,9 +110,6 @@ caps caps_get(jinja::program & prog) {
|
|||||||
|
|
||||||
JJ_DEBUG("%s\n", ">>> Running capability check: typed content");
|
JJ_DEBUG("%s\n", ">>> Running capability check: typed content");
|
||||||
|
|
||||||
bool checks_for_string = false;
|
|
||||||
static const std::string content_marker = "STRING_MARKER";
|
|
||||||
|
|
||||||
// case: typed content support
|
// case: typed content support
|
||||||
caps_try_execute(
|
caps_try_execute(
|
||||||
prog,
|
prog,
|
||||||
@@ -128,61 +118,26 @@ caps caps_get(jinja::program & prog) {
|
|||||||
return json::array({
|
return json::array({
|
||||||
{
|
{
|
||||||
{"role", "user"},
|
{"role", "user"},
|
||||||
{"content", content_marker}
|
{"content", "content"}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
nullptr, // ctx_fn
|
nullptr, // ctx_fn
|
||||||
nullptr, // tools_fn
|
nullptr, // tools_fn
|
||||||
[&](context &, bool success, value & messages, value &, const std::string & rendered) {
|
[&](bool success, value & messages, value &, const std::string &) {
|
||||||
auto & content = messages->at(0)->at("content");
|
auto & content = messages->at(0)->at("content");
|
||||||
caps_print_stats(content, "messages[0].content");
|
caps_print_stats(content, "messages[0].content");
|
||||||
if (has_op(content, "test_is_string")) {
|
if (has_op(content, "selectattr") || has_op(content, "array_access")) {
|
||||||
// checked if content is string
|
|
||||||
checks_for_string = true;
|
|
||||||
}
|
|
||||||
bool used_as_array = has_op(content, "selectattr") || has_op(content, "array_access");
|
|
||||||
if (used_as_array) {
|
|
||||||
// accessed as an array
|
// accessed as an array
|
||||||
result.supports_typed_content = true;
|
result.supports_typed_content = true;
|
||||||
}
|
}
|
||||||
if (!success) {
|
if (!success) {
|
||||||
// failed to execute with content as string
|
// failed to execute with content as string
|
||||||
result.supports_string_content = false;
|
result.supports_string_content = false;
|
||||||
} else if (used_as_array && rendered.find(content_marker) == std::string::npos) {
|
|
||||||
// edge case: string may be accessed for checking, but does not appear in the output
|
|
||||||
result.supports_string_content = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (checks_for_string) {
|
|
||||||
caps_try_execute(
|
|
||||||
prog,
|
|
||||||
[&]() {
|
|
||||||
// messages
|
|
||||||
return json::array({
|
|
||||||
{
|
|
||||||
{"role", "user"},
|
|
||||||
{"content", json::array({
|
|
||||||
})}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
nullptr, // ctx_fn
|
|
||||||
nullptr, // tools_fn
|
|
||||||
[&](context &, bool success, value & messages, value &, const std::string &) {
|
|
||||||
auto & content = messages->at(0)->at("content");
|
|
||||||
caps_print_stats(content, "messages[0].content");
|
|
||||||
bool used_as_array = has_op(content, "selectattr") || has_op(content, "array_access");
|
|
||||||
if (used_as_array && success) {
|
|
||||||
// accessed as an array
|
|
||||||
result.supports_typed_content = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
JJ_DEBUG("%s\n", ">>> Running capability check: system prompt");
|
JJ_DEBUG("%s\n", ">>> Running capability check: system prompt");
|
||||||
|
|
||||||
// case: system prompt support
|
// case: system prompt support
|
||||||
@@ -203,7 +158,7 @@ caps caps_get(jinja::program & prog) {
|
|||||||
},
|
},
|
||||||
nullptr, // ctx_fn
|
nullptr, // ctx_fn
|
||||||
nullptr, // tools_fn
|
nullptr, // tools_fn
|
||||||
[&](context &, bool, value & messages, value &, const std::string &) {
|
[&](bool, value & messages, value &, const std::string &) {
|
||||||
auto & content = messages->at(0)->at("content");
|
auto & content = messages->at(0)->at("content");
|
||||||
caps_print_stats(content, "messages[0].content");
|
caps_print_stats(content, "messages[0].content");
|
||||||
if (!content->stats.used) {
|
if (!content->stats.used) {
|
||||||
@@ -279,7 +234,7 @@ caps caps_get(jinja::program & prog) {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[&](context &, bool success, value & messages, value & tools, const std::string &) {
|
[&](bool success, value & messages, value & tools, const std::string &) {
|
||||||
if (!success) {
|
if (!success) {
|
||||||
return; // Nothing can be inferred
|
return; // Nothing can be inferred
|
||||||
}
|
}
|
||||||
@@ -372,7 +327,7 @@ caps caps_get(jinja::program & prog) {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[&](context &, bool success, value & messages, value & tools, const std::string &) {
|
[&](bool success, value & messages, value & tools, const std::string &) {
|
||||||
if (!success) {
|
if (!success) {
|
||||||
result.supports_tool_calls = false;
|
result.supports_tool_calls = false;
|
||||||
result.supports_tools = false;
|
result.supports_tools = false;
|
||||||
@@ -474,7 +429,7 @@ caps caps_get(jinja::program & prog) {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[&](context &, bool success, value & messages, value &, const std::string &) {
|
[&](bool success, value & messages, value &, const std::string &) {
|
||||||
if (!success) {
|
if (!success) {
|
||||||
result.supports_parallel_tool_calls = false;
|
result.supports_parallel_tool_calls = false;
|
||||||
return;
|
return;
|
||||||
@@ -527,11 +482,10 @@ caps caps_get(jinja::program & prog) {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
[&](context & ctx) {
|
[&](context & ctx) {
|
||||||
ctx.set_val("enable_thinking", mk_val<value_bool>(true));
|
|
||||||
caps_apply_preserve_reasoning(ctx, true);
|
caps_apply_preserve_reasoning(ctx, true);
|
||||||
},
|
},
|
||||||
nullptr, // tools_fn
|
nullptr, // tools_fn
|
||||||
[&](context &, bool, value &, value &, const std::string & output) {
|
[&](bool, value &, value &, const std::string & output) {
|
||||||
// note: we cannot use stats here because the reasoning_content may be used for "if" condition test, but not actually outputted in the final result
|
// note: we cannot use stats here because the reasoning_content may be used for "if" condition test, but not actually outputted in the final result
|
||||||
if (output.find(reasoning_placeholder) != std::string::npos) {
|
if (output.find(reasoning_placeholder) != std::string::npos) {
|
||||||
result.supports_preserve_reasoning = true;
|
result.supports_preserve_reasoning = true;
|
||||||
@@ -539,32 +493,6 @@ caps caps_get(jinja::program & prog) {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
JJ_DEBUG("%s\n", ">>> Running capability check: reasoning effort");
|
|
||||||
|
|
||||||
// case: reasoning effort level
|
|
||||||
caps_try_execute(
|
|
||||||
prog,
|
|
||||||
[&]() {
|
|
||||||
// messages
|
|
||||||
return json::array({
|
|
||||||
{
|
|
||||||
{"role", "user"},
|
|
||||||
{"content", "User message"}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
[&](context & ctx) {
|
|
||||||
ctx.set_val("enable_thinking", mk_val<value_bool>(true));
|
|
||||||
caps_apply_reasoning_effort(ctx, "low");
|
|
||||||
},
|
|
||||||
nullptr, // tools_fn
|
|
||||||
[&](context & ctx, bool, value &, value &, const std::string &) {
|
|
||||||
value effort = ctx.get_val("reasoning_effort");
|
|
||||||
caps_print_stats(effort, "reasoning_effort");
|
|
||||||
result.supports_reasoning_effort = effort->stats.used;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
JJ_DEBUG("%s\n", result.to_string().c_str());
|
JJ_DEBUG("%s\n", result.to_string().c_str());
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -16,9 +16,6 @@ struct caps {
|
|||||||
// supports preserve reasoning trace in the full history, not just the last assistant message
|
// supports preserve reasoning trace in the full history, not just the last assistant message
|
||||||
bool supports_preserve_reasoning = false;
|
bool supports_preserve_reasoning = false;
|
||||||
|
|
||||||
// supports reasoning effort levels
|
|
||||||
bool supports_reasoning_effort = false;
|
|
||||||
|
|
||||||
// one of the 2 content capabilities must be true
|
// one of the 2 content capabilities must be true
|
||||||
bool supports_string_content = true;
|
bool supports_string_content = true;
|
||||||
bool supports_typed_content = false;
|
bool supports_typed_content = false;
|
||||||
@@ -35,6 +32,5 @@ struct caps {
|
|||||||
caps caps_get(jinja::program & prog);
|
caps caps_get(jinja::program & prog);
|
||||||
|
|
||||||
void caps_apply_preserve_reasoning(jinja::context & ctx, bool enabled);
|
void caps_apply_preserve_reasoning(jinja::context & ctx, bool enabled);
|
||||||
void caps_apply_reasoning_effort(jinja::context & ctx, const std::string & effort);
|
|
||||||
|
|
||||||
} // namespace jinja
|
} // namespace jinja
|
||||||
|
|||||||
@@ -263,7 +263,7 @@ value binary_expression::execute_impl(context & ctx) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
for (int64_t i = 0; i < repeat; ++i) {
|
for (int64_t i = 0; i < repeat; ++i) {
|
||||||
res->val_str.append(str);
|
res->val_str = res->val_str.append(str);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@@ -412,18 +412,12 @@ value test_expression::execute_impl(context & ctx) {
|
|||||||
throw std::runtime_error("Invalid test expression");
|
throw std::runtime_error("Invalid test expression");
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string test_name = "test_is_" + test_id;
|
auto it = builtins.find("test_is_" + test_id);
|
||||||
auto it = builtins.find(test_name);
|
JJ_DEBUG("Test expression %s '%s' %s (using function 'test_is_%s')", operand->type().c_str(), test_id.c_str(), negate ? "(negate)" : "", test_id.c_str());
|
||||||
JJ_DEBUG("Test expression %s '%s' %s (using function '%s')", operand->type().c_str(), test_id.c_str(), negate ? "(negate)" : "", test_name.c_str());
|
|
||||||
if (it == builtins.end()) {
|
if (it == builtins.end()) {
|
||||||
throw std::runtime_error("Unknown test '" + test_id + "'");
|
throw std::runtime_error("Unknown test '" + test_id + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.is_get_stats) {
|
|
||||||
value_t::stats_t::mark_used(input);
|
|
||||||
input->stats.ops.insert(test_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto res = it->second(args);
|
auto res = it->second(args);
|
||||||
|
|
||||||
if (negate) {
|
if (negate) {
|
||||||
|
|||||||
+5
-13
@@ -763,22 +763,14 @@ struct runtime {
|
|||||||
gather_string_parts_recursive(val, parts);
|
gather_string_parts_recursive(val, parts);
|
||||||
// join consecutive parts with the same type
|
// join consecutive parts with the same type
|
||||||
auto & p = parts->val_str.parts;
|
auto & p = parts->val_str.parts;
|
||||||
if (p.empty()) {
|
for (size_t i = 1; i < p.size(); ) {
|
||||||
return parts;
|
if (p[i].is_input == p[i - 1].is_input) {
|
||||||
}
|
p[i - 1].val += p[i].val;
|
||||||
size_t w = 0;
|
p.erase(p.begin() + i);
|
||||||
for (size_t r = 1; r < p.size(); r++) {
|
|
||||||
if (p[w].is_input == p[r].is_input) {
|
|
||||||
p[w].val += p[r].val;
|
|
||||||
} else {
|
} else {
|
||||||
w++;
|
i++;
|
||||||
if (w != r) {
|
|
||||||
// the guard is needed, self-move leaves the string in an unspecified state
|
|
||||||
p[w] = std::move(p[r]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p.resize(w + 1);
|
|
||||||
return parts;
|
return parts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ void string::mark_input_based_on(const string & other) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string & string::append(const string & other) {
|
string string::append(const string & other) {
|
||||||
for (const auto & part : other.parts) {
|
for (const auto & part : other.parts) {
|
||||||
parts.push_back(part);
|
parts.push_back(part);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ struct string {
|
|||||||
// mark this string as input if other has ALL parts as input
|
// mark this string as input if other has ALL parts as input
|
||||||
void mark_input_based_on(const string & other);
|
void mark_input_based_on(const string & other);
|
||||||
|
|
||||||
string & append(const string & other);
|
string append(const string & other);
|
||||||
|
|
||||||
// in-place transformations
|
// in-place transformations
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
#include "value.h"
|
#include "value.h"
|
||||||
|
|
||||||
// for converting from JSON to jinja values
|
// for converting from JSON to jinja values
|
||||||
#include "json.h"
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -1355,7 +1355,7 @@ const func_builtins & value_undefined_t::get_builtins() const {
|
|||||||
//////////////////////////////////
|
//////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
static value from_json(const common_json & j, bool mark_input) {
|
static value from_json(const nlohmann::ordered_json & j, bool mark_input) {
|
||||||
if (j.is_null()) {
|
if (j.is_null()) {
|
||||||
return mk_val<value_none>();
|
return mk_val<value_none>();
|
||||||
} else if (j.is_boolean()) {
|
} else if (j.is_boolean()) {
|
||||||
@@ -1452,7 +1452,7 @@ bool value_compare(const value & a, const value & b, value_compare_op op) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void global_from_json(context & ctx, const common_json & json_obj, bool mark_input) {
|
void global_from_json(context & ctx, const nlohmann::ordered_json & json_obj, bool mark_input) {
|
||||||
// printf("global_from_json: %s\n" , json_obj.dump(2).c_str());
|
// printf("global_from_json: %s\n" , json_obj.dump(2).c_str());
|
||||||
if (json_obj.is_null() || !json_obj.is_object()) {
|
if (json_obj.is_null() || !json_obj.is_object()) {
|
||||||
throw std::runtime_error("global_from_json: input JSON value must be an object");
|
throw std::runtime_error("global_from_json: input JSON value must be an object");
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ struct context; // forward declaration
|
|||||||
// marking input can be useful for tracking data provenance
|
// marking input can be useful for tracking data provenance
|
||||||
// and preventing template injection attacks
|
// and preventing template injection attacks
|
||||||
//
|
//
|
||||||
// Note: T_JSON can be common_json
|
// Note: T_JSON can be nlohmann::ordered_json
|
||||||
template<typename T_JSON>
|
template<typename T_JSON>
|
||||||
void global_from_json(context & ctx, const T_JSON & json_obj, bool mark_input);
|
void global_from_json(context & ctx, const T_JSON & json_obj, bool mark_input);
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
#include "json-schema-to-grammar.h"
|
#include "json-schema-to-grammar.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <limits>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@@ -11,7 +12,7 @@
|
|||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
using json = common_json;
|
using json = nlohmann::ordered_json;
|
||||||
|
|
||||||
static std::string build_repetition(const std::string & item_rule, int min_items, int max_items, const std::string & separator_rule = "") {
|
static std::string build_repetition(const std::string & item_rule, int min_items, int max_items, const std::string & separator_rule = "") {
|
||||||
auto has_max = max_items != std::numeric_limits<int>::max();
|
auto has_max = max_items != std::numeric_limits<int>::max();
|
||||||
@@ -277,9 +278,7 @@ static std::unordered_map<char, std::string> GRAMMAR_LITERAL_ESCAPES = {
|
|||||||
{'\r', "\\r"}, {'\n', "\\n"}, {'"', "\\\""}, {'-', "\\-"}, {']', "\\]"}, {'\\', "\\\\"}
|
{'\r', "\\r"}, {'\n', "\\n"}, {'"', "\\\""}, {'-', "\\-"}, {']', "\\]"}, {'\\', "\\\\"}
|
||||||
};
|
};
|
||||||
|
|
||||||
static const int MAX_PATTERN_DEPTH = 100;
|
static std::unordered_set<char> NON_LITERAL_SET = {'|', '.', '(', ')', '[', ']', '{', '}', '*', '+', '?'};
|
||||||
|
|
||||||
static std::unordered_set<char> NON_LITERAL_SET = {'|', '.', '(', ')', '[', ']', '{', '}', '*', '+', '?', '^', '$'};
|
|
||||||
static std::unordered_set<char> ESCAPED_IN_REGEXPS_BUT_NOT_IN_LITERALS = {'^', '$', '.', '[', ']', '(', ')', '|', '{', '}', '*', '+', '?'};
|
static std::unordered_set<char> ESCAPED_IN_REGEXPS_BUT_NOT_IN_LITERALS = {'^', '$', '.', '[', ']', '(', ')', '|', '{', '}', '*', '+', '?'};
|
||||||
|
|
||||||
static std::string replacePattern(const std::string & input, const std::regex & regex, const std::function<std::string(const std::smatch &)> & replacement) {
|
static std::string replacePattern(const std::string & input, const std::regex & regex, const std::function<std::string(const std::smatch &)> & replacement) {
|
||||||
@@ -310,32 +309,6 @@ static std::string format_literal(const std::string & literal) {
|
|||||||
|
|
||||||
std::string gbnf_format_literal(const std::string & literal) { return format_literal(literal); }
|
std::string gbnf_format_literal(const std::string & literal) { return format_literal(literal); }
|
||||||
|
|
||||||
static size_t gbnf_escape_length(const std::string & pattern, size_t pos) {
|
|
||||||
if (pos + 1 >= pattern.length() || pattern[pos] != '\\') {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
size_t n_hex = 0;
|
|
||||||
switch (pattern[pos + 1]) {
|
|
||||||
case 'x': n_hex = 2; break;
|
|
||||||
case 'u': n_hex = 4; break;
|
|
||||||
case 'U': n_hex = 8; break;
|
|
||||||
case 't': case 'r': case 'n': case '\\': case '"': case '[': case ']':
|
|
||||||
return 2;
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (pos + 2 + n_hex > pattern.length()) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
for (size_t i = pos + 2; i < pos + 2 + n_hex; i++) {
|
|
||||||
char h = pattern[i];
|
|
||||||
if (!((h >= '0' && h <= '9') || (h >= 'a' && h <= 'f') || (h >= 'A' && h <= 'F'))) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 2 + n_hex;
|
|
||||||
}
|
|
||||||
|
|
||||||
class common_schema_converter {
|
class common_schema_converter {
|
||||||
private:
|
private:
|
||||||
friend class common_schema_info;
|
friend class common_schema_info;
|
||||||
@@ -372,42 +345,16 @@ private:
|
|||||||
return string_join(rules, " | ");
|
return string_join(rules, " | ");
|
||||||
}
|
}
|
||||||
|
|
||||||
// thrown when the pattern is a valid regex with no grammar equivalent
|
|
||||||
struct unsupported_pattern : public std::runtime_error {
|
|
||||||
using std::runtime_error::runtime_error;
|
|
||||||
};
|
|
||||||
|
|
||||||
// thrown when the pattern is not a valid regex
|
|
||||||
struct invalid_pattern : public std::runtime_error {
|
|
||||||
using std::runtime_error::runtime_error;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::string _visit_pattern(const std::string & pattern, const std::string & name) {
|
std::string _visit_pattern(const std::string & pattern, const std::string & name) {
|
||||||
auto rules_snapshot = _rules;
|
if (!(pattern.front() == '^' && pattern.back() == '$')) {
|
||||||
try {
|
_errors.push_back("Pattern must start with '^' and end with '$'");
|
||||||
return _pattern_to_rule(pattern, name);
|
|
||||||
} catch (const unsupported_pattern & err) {
|
|
||||||
// revert rules
|
|
||||||
_rules = std::move(rules_snapshot);
|
|
||||||
_warnings.push_back("pattern " + pattern + " is not supported (" + err.what() + "), accepting any string");
|
|
||||||
return _add_rule(name, _add_primitive("string", PRIMITIVE_RULES.at("string")));
|
|
||||||
} catch (const invalid_pattern & err) {
|
|
||||||
_rules = std::move(rules_snapshot);
|
|
||||||
_errors.push_back("Invalid pattern " + pattern + ": " + err.what());
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
std::string _pattern_to_rule(const std::string & pattern, const std::string & name) {
|
|
||||||
if (pattern.length() < 2 || pattern.front() != '^' || pattern.back() != '$') {
|
|
||||||
throw unsupported_pattern("not anchored with '^' and '$'");
|
|
||||||
}
|
|
||||||
std::string sub_pattern = pattern.substr(1, pattern.length() - 2);
|
std::string sub_pattern = pattern.substr(1, pattern.length() - 2);
|
||||||
std::unordered_map<std::string, std::string> sub_rule_ids;
|
std::unordered_map<std::string, std::string> sub_rule_ids;
|
||||||
|
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
size_t length = sub_pattern.length();
|
size_t length = sub_pattern.length();
|
||||||
int paren_depth = 0;
|
|
||||||
|
|
||||||
using literal_or_rule = std::pair<std::string, bool>;
|
using literal_or_rule = std::pair<std::string, bool>;
|
||||||
auto to_rule = [&](const literal_or_rule & ls) {
|
auto to_rule = [&](const literal_or_rule & ls) {
|
||||||
@@ -416,6 +363,7 @@ private:
|
|||||||
return is_literal ? "\"" + s + "\"" : s;
|
return is_literal ? "\"" + s + "\"" : s;
|
||||||
};
|
};
|
||||||
std::function<literal_or_rule()> transform = [&]() -> literal_or_rule {
|
std::function<literal_or_rule()> transform = [&]() -> literal_or_rule {
|
||||||
|
size_t start = i;
|
||||||
std::vector<literal_or_rule> seq;
|
std::vector<literal_or_rule> seq;
|
||||||
|
|
||||||
auto get_dot = [&]() {
|
auto get_dot = [&]() {
|
||||||
@@ -472,42 +420,43 @@ private:
|
|||||||
if (i + 1 < length && sub_pattern[i + 1] == ':') {
|
if (i + 1 < length && sub_pattern[i + 1] == ':') {
|
||||||
i += 2; // skip "?:" for non-capturing group, treat as regular group
|
i += 2; // skip "?:" for non-capturing group, treat as regular group
|
||||||
} else {
|
} else {
|
||||||
// lookaround, named group, inline flags, ...
|
// lookahead/lookbehind (?=, ?!, ?<=, ?<!) - not supported
|
||||||
throw unsupported_pattern("unsupported group syntax");
|
_warnings.push_back("Unsupported pattern syntax");
|
||||||
|
// skip to matching ')' to avoid UB on empty seq
|
||||||
|
int depth = 1;
|
||||||
|
while (i < length && depth > 0) {
|
||||||
|
if (sub_pattern[i] == '\\' && i + 1 < length) {
|
||||||
|
i += 2; // skip escaped character
|
||||||
|
} else {
|
||||||
|
if (sub_pattern[i] == '(') depth++;
|
||||||
|
else if (sub_pattern[i] == ')') depth--;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
paren_depth++;
|
|
||||||
if (paren_depth > MAX_PATTERN_DEPTH) {
|
|
||||||
throw unsupported_pattern("pattern nesting too deep");
|
|
||||||
}
|
|
||||||
seq.emplace_back("(" + to_rule(transform()) + ")", false);
|
seq.emplace_back("(" + to_rule(transform()) + ")", false);
|
||||||
} else if (c == ')') {
|
} else if (c == ')') {
|
||||||
i++;
|
i++;
|
||||||
if (paren_depth == 0) {
|
if (start > 0 && sub_pattern[start - 1] != '(' && (start < 2 || sub_pattern[start - 2] != '?' || sub_pattern[start - 1] != ':')) {
|
||||||
throw invalid_pattern("unbalanced parentheses");
|
_errors.push_back("Unbalanced parentheses");
|
||||||
}
|
}
|
||||||
paren_depth--;
|
|
||||||
return join_seq();
|
return join_seq();
|
||||||
} else if (c == '^' || c == '$') {
|
|
||||||
throw unsupported_pattern("anchor inside the pattern");
|
|
||||||
} else if (c == '[') {
|
} else if (c == '[') {
|
||||||
std::string square_brackets = std::string(1, c);
|
std::string square_brackets = std::string(1, c);
|
||||||
i++;
|
i++;
|
||||||
while (i < length && sub_pattern[i] != ']') {
|
while (i < length && sub_pattern[i] != ']') {
|
||||||
if (sub_pattern[i] == '\\') {
|
if (sub_pattern[i] == '\\') {
|
||||||
auto escape_length = gbnf_escape_length(sub_pattern, i);
|
square_brackets += sub_pattern.substr(i, 2);
|
||||||
if (escape_length == 0) {
|
i += 2;
|
||||||
throw unsupported_pattern("unsupported escape in character class: " + sub_pattern.substr(i, 2));
|
|
||||||
}
|
|
||||||
square_brackets += sub_pattern.substr(i, escape_length);
|
|
||||||
i += escape_length;
|
|
||||||
} else {
|
} else {
|
||||||
square_brackets += sub_pattern[i];
|
square_brackets += sub_pattern[i];
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i >= length) {
|
if (i >= length) {
|
||||||
throw invalid_pattern("unterminated character class");
|
_errors.push_back("Unbalanced square brackets");
|
||||||
}
|
}
|
||||||
square_brackets += ']';
|
square_brackets += ']';
|
||||||
i++;
|
i++;
|
||||||
@@ -516,9 +465,6 @@ private:
|
|||||||
seq.emplace_back("|", false);
|
seq.emplace_back("|", false);
|
||||||
i++;
|
i++;
|
||||||
} else if (c == '*' || c == '+' || c == '?') {
|
} else if (c == '*' || c == '+' || c == '?') {
|
||||||
if (seq.empty()) {
|
|
||||||
throw invalid_pattern("nothing to repeat");
|
|
||||||
}
|
|
||||||
seq.back() = std::make_pair(to_rule(seq.back()) + c, false);
|
seq.back() = std::make_pair(to_rule(seq.back()) + c, false);
|
||||||
i++;
|
i++;
|
||||||
} else if (c == '{') {
|
} else if (c == '{') {
|
||||||
@@ -529,19 +475,18 @@ private:
|
|||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
if (i >= length) {
|
if (i >= length) {
|
||||||
throw unsupported_pattern("unterminated curly brackets");
|
_errors.push_back("Unbalanced curly brackets");
|
||||||
}
|
}
|
||||||
curly_brackets += '}';
|
curly_brackets += '}';
|
||||||
i++;
|
i++;
|
||||||
auto nums = string_split(curly_brackets.substr(1, curly_brackets.length() - 2), ",");
|
auto nums = string_split(curly_brackets.substr(1, curly_brackets.length() - 2), ",");
|
||||||
int min_times = 0;
|
int min_times = 0;
|
||||||
int max_times = std::numeric_limits<int>::max();
|
int max_times = std::numeric_limits<int>::max();
|
||||||
if (nums.size() != 1 && nums.size() != 2) {
|
|
||||||
throw unsupported_pattern("wrong number of values in curly brackets");
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
if (nums.size() == 1) {
|
if (nums.size() == 1) {
|
||||||
min_times = max_times = std::stoi(nums[0]);
|
min_times = max_times = std::stoi(nums[0]);
|
||||||
|
} else if (nums.size() != 2) {
|
||||||
|
_errors.push_back("Wrong number of values in curly brackets");
|
||||||
} else {
|
} else {
|
||||||
if (!nums[0].empty()) {
|
if (!nums[0].empty()) {
|
||||||
min_times = std::stoi(nums[0]);
|
min_times = std::stoi(nums[0]);
|
||||||
@@ -550,11 +495,9 @@ private:
|
|||||||
max_times = std::stoi(nums[1]);
|
max_times = std::stoi(nums[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (const std::logic_error &) {
|
} catch (const std::invalid_argument & e) {
|
||||||
throw unsupported_pattern("invalid number in curly brackets");
|
_errors.push_back("Invalid number in curly brackets");
|
||||||
}
|
return std::make_pair("", false);
|
||||||
if (seq.empty()) {
|
|
||||||
throw invalid_pattern("nothing to repeat");
|
|
||||||
}
|
}
|
||||||
auto &last = seq.back();
|
auto &last = seq.back();
|
||||||
auto &sub = last.first;
|
auto &sub = last.first;
|
||||||
@@ -580,22 +523,15 @@ private:
|
|||||||
return NON_LITERAL_SET.find(c) != NON_LITERAL_SET.end();
|
return NON_LITERAL_SET.find(c) != NON_LITERAL_SET.end();
|
||||||
};
|
};
|
||||||
while (i < length) {
|
while (i < length) {
|
||||||
if (sub_pattern[i] == '\\') {
|
if (sub_pattern[i] == '\\' && i < length - 1) {
|
||||||
if (i == length - 1) {
|
|
||||||
throw invalid_pattern("trailing backslash");
|
|
||||||
}
|
|
||||||
char next = sub_pattern[i + 1];
|
char next = sub_pattern[i + 1];
|
||||||
if (ESCAPED_IN_REGEXPS_BUT_NOT_IN_LITERALS.find(next) != ESCAPED_IN_REGEXPS_BUT_NOT_IN_LITERALS.end()) {
|
if (ESCAPED_IN_REGEXPS_BUT_NOT_IN_LITERALS.find(next) != ESCAPED_IN_REGEXPS_BUT_NOT_IN_LITERALS.end()) {
|
||||||
i++;
|
i++;
|
||||||
literal += sub_pattern[i];
|
literal += sub_pattern[i];
|
||||||
i++;
|
i++;
|
||||||
} else {
|
} else {
|
||||||
auto escape_length = gbnf_escape_length(sub_pattern, i);
|
literal += sub_pattern.substr(i, 2);
|
||||||
if (escape_length == 0) {
|
i += 2;
|
||||||
throw unsupported_pattern("unsupported escape: " + sub_pattern.substr(i, 2));
|
|
||||||
}
|
|
||||||
literal += sub_pattern.substr(i, escape_length);
|
|
||||||
i += escape_length;
|
|
||||||
}
|
}
|
||||||
} else if (sub_pattern[i] == '"') {
|
} else if (sub_pattern[i] == '"') {
|
||||||
literal += "\\\"";
|
literal += "\\\"";
|
||||||
@@ -608,21 +544,14 @@ private:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (literal.empty()) { // nothing was consumed, ex. a stray ']' or '}'
|
if (!literal.empty()) {
|
||||||
throw unsupported_pattern(std::string("unsupported character: ") + c);
|
seq.emplace_back(literal, true);
|
||||||
}
|
}
|
||||||
seq.emplace_back(literal, true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return join_seq();
|
return join_seq();
|
||||||
};
|
};
|
||||||
|
return _add_rule(name, "\"\\\"\" (" + to_rule(transform()) + ") \"\\\"\"");
|
||||||
auto rule = to_rule(transform());
|
|
||||||
if (paren_depth != 0) {
|
|
||||||
throw invalid_pattern("unbalanced parentheses");
|
|
||||||
}
|
|
||||||
|
|
||||||
return _add_rule(name, "\"\\\"\" (" + rule + ") \"\\\"\"");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -748,10 +677,6 @@ private:
|
|||||||
optional_props.push_back("*");
|
optional_props.push_back("*");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (required_props.empty() && optional_props.empty()) {
|
|
||||||
return "\"{\" space \"}\"";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string rule = "\"{\" space ";
|
std::string rule = "\"{\" space ";
|
||||||
for (size_t i = 0; i < required_props.size(); i++) {
|
for (size_t i = 0; i < required_props.size(); i++) {
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
@@ -920,11 +845,7 @@ public:
|
|||||||
return _add_rule(rule_name, _resolve_ref(schema["$ref"]));
|
return _add_rule(rule_name, _resolve_ref(schema["$ref"]));
|
||||||
}
|
}
|
||||||
if (schema.contains("oneOf") || schema.contains("anyOf")) {
|
if (schema.contains("oneOf") || schema.contains("anyOf")) {
|
||||||
const json & alts = schema.contains("oneOf") ? schema.at("oneOf") : schema.at("anyOf");
|
std::vector<json> alt_schemas = schema.contains("oneOf") ? schema["oneOf"].get<std::vector<json>>() : schema["anyOf"].get<std::vector<json>>();
|
||||||
std::vector<json> alt_schemas;
|
|
||||||
for (const auto & alt : alts) {
|
|
||||||
alt_schemas.push_back(alt);
|
|
||||||
}
|
|
||||||
return _add_rule(rule_name, _generate_union_rule(name, alt_schemas));
|
return _add_rule(rule_name, _generate_union_rule(name, alt_schemas));
|
||||||
}
|
}
|
||||||
if (schema_type.is_array()) {
|
if (schema_type.is_array()) {
|
||||||
@@ -1118,7 +1039,7 @@ common_schema_info::~common_schema_info() = default;
|
|||||||
common_schema_info::common_schema_info(common_schema_info &&) noexcept = default;
|
common_schema_info::common_schema_info(common_schema_info &&) noexcept = default;
|
||||||
common_schema_info & common_schema_info::operator=(common_schema_info &&) noexcept = default;
|
common_schema_info & common_schema_info::operator=(common_schema_info &&) noexcept = default;
|
||||||
|
|
||||||
void common_schema_info::resolve_refs(common_json & schema) {
|
void common_schema_info::resolve_refs(nlohmann::ordered_json & schema) {
|
||||||
impl_->resolve_refs(schema, "");
|
impl_->resolve_refs(schema, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1126,7 +1047,7 @@ void common_schema_info::resolve_refs(common_json & schema) {
|
|||||||
// Some models emit raw string values rather than JSON-encoded strings for string parameters.
|
// Some models emit raw string values rather than JSON-encoded strings for string parameters.
|
||||||
// If any branch of the schema (via oneOf, anyOf, $ref, etc.) permits a string, this returns
|
// If any branch of the schema (via oneOf, anyOf, $ref, etc.) permits a string, this returns
|
||||||
// true, allowing callers to handle the value as a raw string for simplicity.
|
// true, allowing callers to handle the value as a raw string for simplicity.
|
||||||
bool common_schema_info::resolves_to_string(const common_json & schema) {
|
bool common_schema_info::resolves_to_string(const nlohmann::ordered_json & schema) {
|
||||||
std::unordered_set<std::string> visited_refs;
|
std::unordered_set<std::string> visited_refs;
|
||||||
|
|
||||||
std::function<bool(const json &)> check = [&](const json & s) -> bool {
|
std::function<bool(const json &)> check = [&](const json & s) -> bool {
|
||||||
@@ -1234,7 +1155,7 @@ bool common_schema_info::resolves_to_string(const common_json & schema) {
|
|||||||
return check(schema);
|
return check(schema);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string json_schema_to_grammar(const common_json & schema, bool force_gbnf) {
|
std::string json_schema_to_grammar(const json & schema, bool force_gbnf) {
|
||||||
#ifdef LLAMA_USE_LLGUIDANCE
|
#ifdef LLAMA_USE_LLGUIDANCE
|
||||||
if (!force_gbnf) {
|
if (!force_gbnf) {
|
||||||
return "%llguidance {}\nstart: %json " + schema.dump();
|
return "%llguidance {}\nstart: %json " + schema.dump();
|
||||||
@@ -1255,10 +1176,10 @@ std::string build_grammar(const std::function<void(const common_grammar_builder
|
|||||||
/* .add_rule = */ [&](const std::string & name, const std::string & rule) {
|
/* .add_rule = */ [&](const std::string & name, const std::string & rule) {
|
||||||
return converter._add_rule(name, rule);
|
return converter._add_rule(name, rule);
|
||||||
},
|
},
|
||||||
/* .add_schema = */ [&](const std::string & name, const common_json & schema) {
|
/* .add_schema = */ [&](const std::string & name, const nlohmann::ordered_json & schema) {
|
||||||
return converter.visit(schema, name == "root" ? "" : name);
|
return converter.visit(schema, name == "root" ? "" : name);
|
||||||
},
|
},
|
||||||
/* .resolve_refs = */ [&](common_json & schema) {
|
/* .resolve_refs = */ [&](nlohmann::ordered_json & schema) {
|
||||||
converter.resolve_refs(schema, "");
|
converter.resolve_refs(schema, "");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "json.h"
|
#include <nlohmann/json_fwd.hpp>
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
std::string json_schema_to_grammar(const common_json & schema,
|
std::string json_schema_to_grammar(const nlohmann::ordered_json & schema,
|
||||||
bool force_gbnf = false);
|
bool force_gbnf = false);
|
||||||
|
|
||||||
class common_schema_converter;
|
class common_schema_converter;
|
||||||
@@ -24,14 +24,14 @@ class common_schema_info {
|
|||||||
common_schema_info(common_schema_info &&) noexcept;
|
common_schema_info(common_schema_info &&) noexcept;
|
||||||
common_schema_info & operator=(common_schema_info &&) noexcept;
|
common_schema_info & operator=(common_schema_info &&) noexcept;
|
||||||
|
|
||||||
void resolve_refs(common_json & schema);
|
void resolve_refs(nlohmann::ordered_json & schema);
|
||||||
bool resolves_to_string(const common_json & schema);
|
bool resolves_to_string(const nlohmann::ordered_json & schema);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct common_grammar_builder {
|
struct common_grammar_builder {
|
||||||
std::function<std::string(const std::string &, const std::string &)> add_rule;
|
std::function<std::string(const std::string &, const std::string &)> add_rule;
|
||||||
std::function<std::string(const std::string &, const common_json &)> add_schema;
|
std::function<std::string(const std::string &, const nlohmann::ordered_json &)> add_schema;
|
||||||
std::function<void(common_json &)> resolve_refs;
|
std::function<void(nlohmann::ordered_json &)> resolve_refs;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct common_grammar_options {
|
struct common_grammar_options {
|
||||||
|
|||||||
-433
@@ -1,433 +0,0 @@
|
|||||||
#include "json.h"
|
|
||||||
|
|
||||||
#include "ggml.h"
|
|
||||||
|
|
||||||
#define JSON_ASSERT GGML_ASSERT
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
#include <iterator>
|
|
||||||
#include <new>
|
|
||||||
#include <set>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
using nlohmann::ordered_json;
|
|
||||||
|
|
||||||
// a common_json is the backing value, so any value of a tree can be used as a common_json
|
|
||||||
static_assert(sizeof(ordered_json) <= sizeof(common_json), "common_json storage is too small");
|
|
||||||
static_assert(alignof(ordered_json) <= alignof(common_json), "common_json alignment is too weak");
|
|
||||||
|
|
||||||
// runs fn and gives every error of the backing library as a common_json_error
|
|
||||||
template <typename F>
|
|
||||||
static decltype(auto) guard(F && fn) {
|
|
||||||
try {
|
|
||||||
return fn();
|
|
||||||
} catch (const ordered_json::exception & e) {
|
|
||||||
throw common_json_error(e.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static ordered_json & as_json(common_json * self) {
|
|
||||||
return *reinterpret_cast<ordered_json *>(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const ordered_json & as_json(const common_json * self) {
|
|
||||||
return *reinterpret_cast<const ordered_json *>(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
static common_json & as_common(ordered_json & json) {
|
|
||||||
return *reinterpret_cast<common_json *>(&json);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const common_json & as_common(const ordered_json & json) {
|
|
||||||
return *reinterpret_cast<const common_json *>(&json);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ordered_json to_json(const common_json_value & val) {
|
|
||||||
switch (val.type) {
|
|
||||||
case common_json_value::VAL_NULL: return nullptr;
|
|
||||||
case common_json_value::VAL_BOOL: return val.val_bool;
|
|
||||||
case common_json_value::VAL_INT: return val.val_int;
|
|
||||||
case common_json_value::VAL_UINT: return val.val_uint;
|
|
||||||
case common_json_value::VAL_DOUBLE: return val.val_double;
|
|
||||||
case common_json_value::VAL_STRING: return val.val_string;
|
|
||||||
case common_json_value::VAL_JSON:
|
|
||||||
// one owner means no one else can see this tree, so it is safe to move it out
|
|
||||||
// note: this makes a value single use, same as the json_ref of the backing library
|
|
||||||
if (val.val_json.use_count() == 1) {
|
|
||||||
return std::move(as_json(val.val_json.get()));
|
|
||||||
}
|
|
||||||
return as_json(val.val_json.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
common_json_value::common_json_value(const char * val) {
|
|
||||||
if (val) {
|
|
||||||
type = VAL_STRING;
|
|
||||||
val_string = val;
|
|
||||||
} else {
|
|
||||||
type = VAL_NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
common_json_value::common_json_value(const common_json & val) :
|
|
||||||
type(VAL_JSON), val_json(std::make_shared<common_json>(val)) {}
|
|
||||||
|
|
||||||
common_json_value::common_json_value(common_json && val) :
|
|
||||||
type(VAL_JSON), val_json(std::make_shared<common_json>(std::move(val))) {}
|
|
||||||
|
|
||||||
// the ctors and get<T>() below are explicit specializations, giving strong symbols
|
|
||||||
// an explicit instantiation is a weak symbol, dropped by some LTO builds (clang-cl)
|
|
||||||
template <typename T>
|
|
||||||
static std::shared_ptr<common_json> set_json(const std::set<T> & vals) {
|
|
||||||
common_json out = common_json::array();
|
|
||||||
|
|
||||||
for (const auto & val : vals) {
|
|
||||||
out.push_back(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::make_shared<common_json>(std::move(out));
|
|
||||||
}
|
|
||||||
|
|
||||||
// a set value is usable only for the types below
|
|
||||||
#define COMMON_JSON_SET(...) template <> common_json_value::common_json_value(const std::set<__VA_ARGS__> & vals) : type(VAL_JSON), val_json(set_json(vals)) {}
|
|
||||||
|
|
||||||
COMMON_JSON_SET(int)
|
|
||||||
COMMON_JSON_SET(std::string)
|
|
||||||
|
|
||||||
#undef COMMON_JSON_SET
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
static std::shared_ptr<common_json> map_json(const T & vals) {
|
|
||||||
common_json out = common_json::object();
|
|
||||||
|
|
||||||
for (const auto & val : vals) {
|
|
||||||
out.set({ val.first, val.second });
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::make_shared<common_json>(std::move(out));
|
|
||||||
}
|
|
||||||
|
|
||||||
// a map value is usable only for the types below
|
|
||||||
#define COMMON_JSON_MAP(...) template <> common_json_value::common_json_value(const std::map<std::string, __VA_ARGS__> & vals) : type(VAL_JSON), val_json(map_json(vals)) {}
|
|
||||||
|
|
||||||
COMMON_JSON_MAP(bool)
|
|
||||||
COMMON_JSON_MAP(std::string)
|
|
||||||
|
|
||||||
#undef COMMON_JSON_MAP
|
|
||||||
|
|
||||||
// an unordered map value is usable only for the types below
|
|
||||||
#define COMMON_JSON_UMAP(...) template <> common_json_value::common_json_value(const std::unordered_map<std::string, __VA_ARGS__> & vals) : type(VAL_JSON), val_json(map_json(vals)) {}
|
|
||||||
|
|
||||||
COMMON_JSON_UMAP(size_t)
|
|
||||||
|
|
||||||
#undef COMMON_JSON_UMAP
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
static std::shared_ptr<common_json> vec_json(const std::vector<T> & vals) {
|
|
||||||
common_json out = common_json::array();
|
|
||||||
|
|
||||||
for (const auto & val : vals) {
|
|
||||||
out.push_back(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::make_shared<common_json>(std::move(out));
|
|
||||||
}
|
|
||||||
|
|
||||||
// a vector value is usable only for the types below
|
|
||||||
// note: std::vector<bool> is not here, its proxy reference does not convert
|
|
||||||
#define COMMON_JSON_VEC(...) template <> common_json_value::common_json_value(const std::vector<__VA_ARGS__> & vals) : type(VAL_JSON), val_json(vec_json(vals)) {}
|
|
||||||
|
|
||||||
COMMON_JSON_VEC(int)
|
|
||||||
COMMON_JSON_VEC(unsigned char)
|
|
||||||
COMMON_JSON_VEC(unsigned int)
|
|
||||||
COMMON_JSON_VEC(long)
|
|
||||||
COMMON_JSON_VEC(unsigned long)
|
|
||||||
COMMON_JSON_VEC(long long)
|
|
||||||
COMMON_JSON_VEC(unsigned long long)
|
|
||||||
COMMON_JSON_VEC(float)
|
|
||||||
COMMON_JSON_VEC(double)
|
|
||||||
COMMON_JSON_VEC(std::string)
|
|
||||||
COMMON_JSON_VEC(std::vector<float>)
|
|
||||||
COMMON_JSON_VEC(common_json)
|
|
||||||
|
|
||||||
#undef COMMON_JSON_VEC
|
|
||||||
|
|
||||||
common_json_value::common_json_value(std::initializer_list<common_json_item> items) :
|
|
||||||
type(VAL_JSON), val_json(std::make_shared<common_json>(items)) {}
|
|
||||||
|
|
||||||
// null, same as the backing library
|
|
||||||
// operator[] turns it into an object, push_back() into an array
|
|
||||||
common_json::common_json() {
|
|
||||||
new (storage) ordered_json();
|
|
||||||
}
|
|
||||||
|
|
||||||
common_json::common_json(const common_json & other) {
|
|
||||||
new (storage) ordered_json(as_json(&other));
|
|
||||||
}
|
|
||||||
|
|
||||||
common_json::common_json(common_json && other) noexcept {
|
|
||||||
new (storage) ordered_json(std::move(as_json(&other)));
|
|
||||||
}
|
|
||||||
|
|
||||||
common_json::common_json(std::initializer_list<common_json_item> items) {
|
|
||||||
new (storage) ordered_json(ordered_json::object());
|
|
||||||
|
|
||||||
for (const auto & item : items) {
|
|
||||||
set(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
common_json::common_json(const common_json_value & val) {
|
|
||||||
new (storage) ordered_json(to_json(val));
|
|
||||||
}
|
|
||||||
|
|
||||||
common_json::common_json(std::nullptr_t) {
|
|
||||||
new (storage) ordered_json(nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
common_json & common_json::operator=(common_json other) noexcept {
|
|
||||||
as_json(this).swap(as_json(&other));
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
common_json::~common_json() {
|
|
||||||
as_json(this).~basic_json();
|
|
||||||
}
|
|
||||||
|
|
||||||
common_json common_json::parse(const std::string & text) {
|
|
||||||
try {
|
|
||||||
// the assignment moves the parsed tree in, it does not copy
|
|
||||||
common_json out;
|
|
||||||
as_json(&out) = ordered_json::parse(text);
|
|
||||||
return out;
|
|
||||||
} catch (const std::exception & e) {
|
|
||||||
throw common_json_error(e.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
common_json common_json::parse_no_throw(const std::string & text) {
|
|
||||||
common_json out;
|
|
||||||
as_json(&out) = ordered_json::parse(text, nullptr, false);
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool common_json::is_discarded() const {
|
|
||||||
return as_json(this).is_discarded();
|
|
||||||
}
|
|
||||||
|
|
||||||
common_json common_json::array() {
|
|
||||||
common_json out;
|
|
||||||
as_json(&out) = ordered_json::array();
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
common_json common_json::array(std::initializer_list<common_json_value> vals) {
|
|
||||||
common_json out;
|
|
||||||
ordered_json & arr = as_json(&out);
|
|
||||||
arr = ordered_json::array();
|
|
||||||
|
|
||||||
for (const auto & val : vals) {
|
|
||||||
arr.push_back(to_json(val));
|
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
common_json common_json::object() {
|
|
||||||
common_json out;
|
|
||||||
as_json(&out) = ordered_json::object();
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
common_json common_json::object(std::initializer_list<common_json_item> items) {
|
|
||||||
return common_json(items);
|
|
||||||
}
|
|
||||||
|
|
||||||
common_json common_json::make(const common_json_value & val) {
|
|
||||||
return common_json(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool common_json::is_null() const { return as_json(this).is_null(); }
|
|
||||||
bool common_json::is_object() const { return as_json(this).is_object(); }
|
|
||||||
bool common_json::is_array() const { return as_json(this).is_array(); }
|
|
||||||
bool common_json::is_string() const { return as_json(this).is_string(); }
|
|
||||||
bool common_json::is_boolean() const { return as_json(this).is_boolean(); }
|
|
||||||
bool common_json::is_number() const { return as_json(this).is_number(); }
|
|
||||||
bool common_json::is_number_integer() const { return as_json(this).is_number_integer(); }
|
|
||||||
bool common_json::is_number_float() const { return as_json(this).is_number_float(); }
|
|
||||||
|
|
||||||
bool common_json::empty() const { return as_json(this).empty(); }
|
|
||||||
size_t common_json::size() const { return as_json(this).size(); }
|
|
||||||
|
|
||||||
bool common_json::contains(const std::string & key) const {
|
|
||||||
return as_json(this).contains(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool common_json::operator==(const common_json_value & val) const {
|
|
||||||
// compare a tree in place, to_json() would copy it
|
|
||||||
if (val.type == common_json_value::VAL_JSON) {
|
|
||||||
return as_json(this) == as_json(val.val_json.get());
|
|
||||||
}
|
|
||||||
return as_json(this) == to_json(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool common_json::operator!=(const common_json_value & val) const {
|
|
||||||
return !(*this == val);
|
|
||||||
}
|
|
||||||
|
|
||||||
common_json & common_json::at(const std::string & key) { return guard([&]() -> common_json & { return as_common(as_json(this).at(key)); }); }
|
|
||||||
const common_json & common_json::at(const std::string & key) const { return guard([&]() -> const common_json & { return as_common(as_json(this).at(key)); }); }
|
|
||||||
common_json & common_json::at(size_t idx) { return guard([&]() -> common_json & { return as_common(as_json(this).at(idx)); }); }
|
|
||||||
const common_json & common_json::at(size_t idx) const { return guard([&]() -> const common_json & { return as_common(as_json(this).at(idx)); }); }
|
|
||||||
|
|
||||||
common_json & common_json::operator[](const std::string & key) { return guard([&]() -> common_json & { return as_common(as_json(this)[key]); }); }
|
|
||||||
const common_json & common_json::operator[](const std::string & key) const { return guard([&]() -> const common_json & { return as_common(as_json(this).at(key)); }); }
|
|
||||||
common_json & common_json::operator[](size_t idx) { return guard([&]() -> common_json & { return as_common(as_json(this)[idx]); }); }
|
|
||||||
const common_json & common_json::operator[](size_t idx) const { return guard([&]() -> const common_json & { return as_common(as_json(this).at(idx)); }); }
|
|
||||||
|
|
||||||
common_json & common_json::front() { return as_common(as_json(this).front()); }
|
|
||||||
const common_json & common_json::front() const { return as_common(as_json(this).front()); }
|
|
||||||
common_json & common_json::back() { return as_common(as_json(this).back()); }
|
|
||||||
const common_json & common_json::back() const { return as_common(as_json(this).back()); }
|
|
||||||
|
|
||||||
void common_json::clear() {
|
|
||||||
as_json(this).clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void common_json::erase(const std::string & key) {
|
|
||||||
guard([&] { as_json(this).erase(key); });
|
|
||||||
}
|
|
||||||
|
|
||||||
void common_json::erase(size_t idx) {
|
|
||||||
guard([&] { as_json(this).erase(idx); });
|
|
||||||
}
|
|
||||||
|
|
||||||
void common_json::assign(const common_json_value & val) {
|
|
||||||
as_json(this) = to_json(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
void common_json::set(const common_json_item & item) {
|
|
||||||
guard([&] { as_json(this)[item.key] = to_json(item.val); });
|
|
||||||
}
|
|
||||||
|
|
||||||
void common_json::push_back(const common_json_value & val) {
|
|
||||||
guard([&] { as_json(this).push_back(to_json(val)); });
|
|
||||||
}
|
|
||||||
|
|
||||||
void common_json::push_back(std::initializer_list<common_json_item> items) {
|
|
||||||
common_json val(items);
|
|
||||||
|
|
||||||
guard([&] { as_json(this).push_back(std::move(as_json(&val))); });
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t common_json::count(const std::string & key) const {
|
|
||||||
return as_json(this).count(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
void common_json::insert(const common_json & vals) {
|
|
||||||
guard([&] {
|
|
||||||
ordered_json & self = as_json(this);
|
|
||||||
|
|
||||||
self.insert(self.end(), as_json(&vals).begin(), as_json(&vals).end());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string common_json::dump(int indent) const {
|
|
||||||
return guard([&] { return as_json(this).dump(indent); });
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string common_json::dump_safe(int indent) const {
|
|
||||||
return as_json(this).dump(indent, ' ', false, ordered_json::error_handler_t::replace);
|
|
||||||
}
|
|
||||||
|
|
||||||
// an array is indexed directly, an object needs a walk from the start
|
|
||||||
common_json & common_json::iterator::operator*() const {
|
|
||||||
return guard([&]() -> common_json & {
|
|
||||||
ordered_json & j = as_json(node);
|
|
||||||
|
|
||||||
if (j.is_object()) {
|
|
||||||
return as_common(std::next(j.begin(), idx).value());
|
|
||||||
}
|
|
||||||
if (j.is_array()) {
|
|
||||||
return as_common(j[idx]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// a plain value gives itself once, same as the backing library
|
|
||||||
return *node;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string common_json::iterator::key() const {
|
|
||||||
return guard([&] { return std::next(as_json(node).begin(), idx).key(); });
|
|
||||||
}
|
|
||||||
|
|
||||||
common_json::iterator common_json::begin() const {
|
|
||||||
return iterator(const_cast<common_json *>(this), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
common_json::iterator common_json::end() const {
|
|
||||||
return iterator(const_cast<common_json *>(this), size());
|
|
||||||
}
|
|
||||||
|
|
||||||
// the keys follow the backing library: the index for an array, "" for a plain value
|
|
||||||
common_json::items_view::entry common_json::items_view::iterator::operator*() const {
|
|
||||||
return guard([&]() -> entry {
|
|
||||||
ordered_json & j = as_json(node);
|
|
||||||
|
|
||||||
if (j.is_object()) {
|
|
||||||
auto it = std::next(j.begin(), idx);
|
|
||||||
|
|
||||||
return { it.key(), as_common(it.value()) };
|
|
||||||
}
|
|
||||||
if (j.is_array()) {
|
|
||||||
return { std::to_string(idx), as_common(j[idx]) };
|
|
||||||
}
|
|
||||||
|
|
||||||
return { std::string(), *node };
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
common_json::items_view common_json::items() const {
|
|
||||||
return items_view(const_cast<common_json *>(this), size());
|
|
||||||
}
|
|
||||||
|
|
||||||
// the backing library cannot build a common_json, so this one is just a copy
|
|
||||||
template <> common_json common_json::get<common_json>() const {
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get<T>() is usable only for the types below
|
|
||||||
|
|
||||||
#define COMMON_JSON_GET(...) template <> __VA_ARGS__ common_json::get<__VA_ARGS__>() const { return guard([&] { return as_json(this).get<__VA_ARGS__>(); }); }
|
|
||||||
|
|
||||||
COMMON_JSON_GET(bool)
|
|
||||||
COMMON_JSON_GET(int)
|
|
||||||
COMMON_JSON_GET(unsigned int)
|
|
||||||
COMMON_JSON_GET(long)
|
|
||||||
COMMON_JSON_GET(unsigned long)
|
|
||||||
COMMON_JSON_GET(long long)
|
|
||||||
COMMON_JSON_GET(unsigned long long)
|
|
||||||
COMMON_JSON_GET(float)
|
|
||||||
COMMON_JSON_GET(double)
|
|
||||||
COMMON_JSON_GET(std::string)
|
|
||||||
COMMON_JSON_GET(std::vector<float>)
|
|
||||||
COMMON_JSON_GET(std::vector<std::string>)
|
|
||||||
COMMON_JSON_GET(std::set<std::string>)
|
|
||||||
COMMON_JSON_GET(std::vector<int>)
|
|
||||||
COMMON_JSON_GET(std::vector<size_t>)
|
|
||||||
COMMON_JSON_GET(std::unordered_map<std::string, size_t>)
|
|
||||||
|
|
||||||
#undef COMMON_JSON_GET
|
|
||||||
|
|
||||||
// must stay below the get<std::string> specialization
|
|
||||||
common_json::operator std::string() const {
|
|
||||||
return get<std::string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string common_json::value(const std::string & key, const char * def) const {
|
|
||||||
return contains(key) ? at(key).get<std::string>() : std::string(def);
|
|
||||||
}
|
|
||||||
-352
@@ -1,352 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <initializer_list>
|
|
||||||
#include <iterator>
|
|
||||||
#include <map>
|
|
||||||
#include <memory>
|
|
||||||
#include <set>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <string>
|
|
||||||
#include <string_view>
|
|
||||||
#include <type_traits>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
// common_json, a thin wrapper around vendor json library
|
|
||||||
// the underlay library is pimpl, we are using nlohmann::json for now
|
|
||||||
//
|
|
||||||
// many features of the library are deliberately left out, to keep this interface small and generic and to keep compile time down
|
|
||||||
//
|
|
||||||
// some main differences compared to nlohmann::json :
|
|
||||||
// - object keys keep the order in which they are added
|
|
||||||
// - errors are always throw as common_json_error
|
|
||||||
// - obj.push_back({key, val}) is intentionally unsupported to avoid confusion with push_back on a vector; write it as obj[key] = val for clarity
|
|
||||||
// - a braced pair in value position does not build, e.g. {"key", {"a", "b"}}; write array({"a", "b"}) where nlohmann made an array
|
|
||||||
//
|
|
||||||
// in doubt, search the code base for an existing usage example; do not add anything to this header unless absolutely necessary
|
|
||||||
|
|
||||||
class common_json;
|
|
||||||
|
|
||||||
// common_json_value holds a list of these, and each of them holds a value, so one must come first
|
|
||||||
struct common_json_item;
|
|
||||||
|
|
||||||
struct common_json_error : std::runtime_error {
|
|
||||||
using std::runtime_error::runtime_error;
|
|
||||||
};
|
|
||||||
|
|
||||||
// one value, tagged so that this header stays free of the backing library
|
|
||||||
// note: a value that holds a tree is single use, the second use gives null
|
|
||||||
struct common_json_value {
|
|
||||||
enum value_type {
|
|
||||||
VAL_NULL,
|
|
||||||
VAL_BOOL,
|
|
||||||
VAL_INT,
|
|
||||||
VAL_UINT,
|
|
||||||
VAL_DOUBLE,
|
|
||||||
VAL_STRING,
|
|
||||||
VAL_JSON,
|
|
||||||
};
|
|
||||||
|
|
||||||
value_type type = VAL_NULL;
|
|
||||||
|
|
||||||
union {
|
|
||||||
bool val_bool;
|
|
||||||
int64_t val_int;
|
|
||||||
uint64_t val_uint = 0;
|
|
||||||
double val_double;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::string val_string;
|
|
||||||
std::shared_ptr<common_json> val_json;
|
|
||||||
|
|
||||||
common_json_value(std::nullptr_t = nullptr) : type(VAL_NULL) {}
|
|
||||||
common_json_value(bool val) : type(VAL_BOOL), val_bool(val) {}
|
|
||||||
common_json_value(std::string val) : type(VAL_STRING), val_string(std::move(val)) {}
|
|
||||||
// without this a string_view lands on the common_json ctor below and recurses
|
|
||||||
common_json_value(std::string_view val) : type(VAL_STRING), val_string(val) {}
|
|
||||||
common_json_value(const char * val);
|
|
||||||
common_json_value(const common_json & val);
|
|
||||||
common_json_value(common_json && val);
|
|
||||||
// only for the types instantiated in json.cpp, the rest fails at link time
|
|
||||||
template <typename T> common_json_value(const std::vector<T> & vals);
|
|
||||||
// a set becomes an array, in the set's own order
|
|
||||||
template <typename T> common_json_value(const std::set<T> & vals);
|
|
||||||
// a map becomes an object, keyed in the map's own order
|
|
||||||
template <typename T> common_json_value(const std::map<std::string, T> & vals);
|
|
||||||
template <typename T> common_json_value(const std::unordered_map<std::string, T> & vals);
|
|
||||||
|
|
||||||
// nested object, e.g. {"fn", {{"name", "x"}}}
|
|
||||||
// note: a nested pair {"a", "b"} does not build, use common_json::array({"a", "b"}) for an array
|
|
||||||
common_json_value(std::initializer_list<common_json_item> items);
|
|
||||||
|
|
||||||
template <typename T, typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, bool>::value, int>::type = 0>
|
|
||||||
common_json_value(T val) : type(std::is_signed<T>::value ? VAL_INT : VAL_UINT) {
|
|
||||||
if (std::is_signed<T>::value) {
|
|
||||||
val_int = (int64_t) val;
|
|
||||||
} else {
|
|
||||||
val_uint = (uint64_t) val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename std::enable_if<std::is_floating_point<T>::value, int>::type = 0>
|
|
||||||
common_json_value(T val) : type(VAL_DOUBLE), val_double((double) val) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct common_json_item {
|
|
||||||
std::string key;
|
|
||||||
common_json_value val;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
common_json_item(std::string key, T && val) :
|
|
||||||
key(std::move(key)), val(std::forward<T>(val)) {}
|
|
||||||
|
|
||||||
// a braced list cannot deduce T, so it needs its own overload
|
|
||||||
common_json_item(std::string key, std::initializer_list<common_json_item> items) :
|
|
||||||
key(std::move(key)), val(items) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
// the types common_json_value holds on its own
|
|
||||||
// anything else reaches its common_json ctor and recurses forever
|
|
||||||
template <typename T> struct common_json_is_value : std::integral_constant<bool,
|
|
||||||
std::is_arithmetic<T>::value ||
|
|
||||||
std::is_same<T, std::nullptr_t>::value ||
|
|
||||||
std::is_same<T, std::string>::value ||
|
|
||||||
std::is_same<T, std::string_view>::value ||
|
|
||||||
std::is_same<T, char *>::value ||
|
|
||||||
std::is_same<T, const char *>::value ||
|
|
||||||
std::is_same<T, common_json>::value> {};
|
|
||||||
|
|
||||||
template <typename T, typename A>
|
|
||||||
struct common_json_is_value<std::vector<T, A>> : std::true_type {};
|
|
||||||
|
|
||||||
template <typename T, typename C, typename A>
|
|
||||||
struct common_json_is_value<std::set<T, C, A>> : std::true_type {};
|
|
||||||
|
|
||||||
template <typename V, typename C, typename A>
|
|
||||||
struct common_json_is_value<std::map<std::string, V, C, A>> : std::true_type {};
|
|
||||||
|
|
||||||
template <typename V, typename H, typename E, typename A>
|
|
||||||
struct common_json_is_value<std::unordered_map<std::string, V, H, E, A>> : std::true_type {};
|
|
||||||
|
|
||||||
class common_json {
|
|
||||||
public:
|
|
||||||
common_json();
|
|
||||||
common_json(const common_json & other);
|
|
||||||
common_json(common_json && other) noexcept;
|
|
||||||
common_json(std::initializer_list<common_json_item> items);
|
|
||||||
common_json(const common_json_value & val);
|
|
||||||
|
|
||||||
// direct, a value would need two conversions in a row
|
|
||||||
common_json(std::nullptr_t);
|
|
||||||
|
|
||||||
// one step, so that "abc" or a vector can go straight into a common_json
|
|
||||||
template <typename T, typename std::enable_if<!std::is_same<typename std::decay<T>::type, common_json>::value &&
|
|
||||||
!std::is_same<typename std::decay<T>::type, common_json_value>::value, int>::type = 0>
|
|
||||||
common_json(T && val) : common_json(common_json_value(std::forward<T>(val))) {
|
|
||||||
static_assert(common_json_is_value<typename std::decay<T>::type>::value,
|
|
||||||
"no common_json_value ctor holds this type, add one instead of letting it recurse");
|
|
||||||
}
|
|
||||||
|
|
||||||
// by value, same as the backing library
|
|
||||||
// the right side is copied before the left side can invalidate it, e.g. msg["a"] = msg.at("b")
|
|
||||||
common_json & operator=(common_json other) noexcept;
|
|
||||||
|
|
||||||
~common_json();
|
|
||||||
|
|
||||||
// throws common_json_error if the text is not valid JSON
|
|
||||||
static common_json parse(const std::string & text);
|
|
||||||
|
|
||||||
// gives a discarded value instead of throwing, check it with is_discarded()
|
|
||||||
static common_json parse_no_throw(const std::string & text);
|
|
||||||
|
|
||||||
bool is_discarded() const;
|
|
||||||
|
|
||||||
static common_json array();
|
|
||||||
static common_json array(std::initializer_list<common_json_value> vals);
|
|
||||||
static common_json object();
|
|
||||||
static common_json object(std::initializer_list<common_json_item> items);
|
|
||||||
|
|
||||||
// holds a single value, e.g. make("abc").dump() gives "\"abc\""
|
|
||||||
static common_json make(const common_json_value & val);
|
|
||||||
|
|
||||||
bool is_null() const;
|
|
||||||
bool is_object() const;
|
|
||||||
bool is_array() const;
|
|
||||||
bool is_string() const;
|
|
||||||
bool is_boolean() const;
|
|
||||||
bool is_number() const;
|
|
||||||
bool is_number_integer() const;
|
|
||||||
bool is_number_float() const;
|
|
||||||
|
|
||||||
bool empty() const;
|
|
||||||
size_t size() const;
|
|
||||||
|
|
||||||
bool contains(const std::string & key) const;
|
|
||||||
|
|
||||||
bool operator==(const common_json_value & val) const;
|
|
||||||
bool operator!=(const common_json_value & val) const;
|
|
||||||
|
|
||||||
// at() throws common_json_error if the key is missing, operator[] adds a null value instead
|
|
||||||
// note: a const operator[] cannot add, it throws like at()
|
|
||||||
common_json & at(const std::string & key);
|
|
||||||
const common_json & at(const std::string & key) const;
|
|
||||||
common_json & at(size_t idx);
|
|
||||||
const common_json & at(size_t idx) const;
|
|
||||||
|
|
||||||
common_json & operator[](const std::string & key);
|
|
||||||
const common_json & operator[](const std::string & key) const;
|
|
||||||
common_json & operator[](const char * key) { return (*this)[std::string(key)]; }
|
|
||||||
const common_json & operator[](const char * key) const { return (*this)[std::string(key)]; }
|
|
||||||
common_json & operator[](int idx) { return (*this)[to_idx(idx)]; }
|
|
||||||
const common_json & operator[](int idx) const { return (*this)[to_idx(idx)]; }
|
|
||||||
common_json & operator[](size_t idx);
|
|
||||||
const common_json & operator[](size_t idx) const;
|
|
||||||
|
|
||||||
common_json & front();
|
|
||||||
const common_json & front() const;
|
|
||||||
common_json & back();
|
|
||||||
const common_json & back() const;
|
|
||||||
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
void erase(const std::string & key);
|
|
||||||
void erase(size_t idx);
|
|
||||||
|
|
||||||
// only for the types instantiated in json.cpp, the rest fails at link time
|
|
||||||
template <typename T> T get() const;
|
|
||||||
|
|
||||||
// implicit get<T>() for plain values, so they can be assigned to their C++ type directly
|
|
||||||
// note: kept to this short list on purpose, a wider one makes j["key"] ambiguous
|
|
||||||
// note: a numeric one would make "str = json;" ambiguous, a number converts to char too
|
|
||||||
operator std::string() const;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
T value(const std::string & key, T def) const {
|
|
||||||
return contains(key) ? at(key).get<T>() : def;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string value(const std::string & key, const char * def) const;
|
|
||||||
|
|
||||||
// a JSON default needs no get<T>(), it is already the right type
|
|
||||||
common_json value(const std::string & key, const common_json & def) const {
|
|
||||||
return contains(key) ? at(key) : def;
|
|
||||||
}
|
|
||||||
|
|
||||||
void assign(const common_json_value & val);
|
|
||||||
void set(const common_json_item & item);
|
|
||||||
void push_back(const common_json_value & val);
|
|
||||||
|
|
||||||
// appends one object, e.g. push_back({{"a", 1}})
|
|
||||||
void push_back(std::initializer_list<common_json_item> items);
|
|
||||||
|
|
||||||
// 1 if the key is there, 0 if not
|
|
||||||
size_t count(const std::string & key) const;
|
|
||||||
|
|
||||||
// appends every value of another array; inserting an array into itself throws
|
|
||||||
void insert(const common_json & vals);
|
|
||||||
|
|
||||||
// a common_json goes through the copy assignment above, everything else becomes a value
|
|
||||||
template <typename T, typename std::enable_if<!std::is_same<typename std::decay<T>::type, common_json>::value, int>::type = 0>
|
|
||||||
common_json & operator=(T && val) {
|
|
||||||
assign(common_json_value(std::forward<T>(val)));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string dump(int indent = -1) const;
|
|
||||||
|
|
||||||
// same as dump(), but bad UTF-8 gets replaced instead of throwing
|
|
||||||
std::string dump_safe(int indent = -1) const;
|
|
||||||
|
|
||||||
// walks an array by index, or an object in insertion order
|
|
||||||
// a plain value gives itself once, same as the backing library
|
|
||||||
class iterator {
|
|
||||||
public:
|
|
||||||
using iterator_category = std::forward_iterator_tag;
|
|
||||||
using value_type = common_json;
|
|
||||||
using difference_type = std::ptrdiff_t;
|
|
||||||
using pointer = common_json *;
|
|
||||||
using reference = common_json &;
|
|
||||||
|
|
||||||
iterator(common_json * node, size_t idx) : node(node), idx(idx) {}
|
|
||||||
|
|
||||||
common_json & operator*() const;
|
|
||||||
common_json & value() const { return **this; }
|
|
||||||
std::string key() const;
|
|
||||||
|
|
||||||
iterator & operator++() {
|
|
||||||
idx++;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator!=(const iterator & other) const { return idx != other.idx; }
|
|
||||||
bool operator==(const iterator & other) const { return idx == other.idx; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
common_json * node;
|
|
||||||
size_t idx;
|
|
||||||
};
|
|
||||||
|
|
||||||
iterator begin() const;
|
|
||||||
iterator end() const;
|
|
||||||
|
|
||||||
// allows: for (const auto & [key, val] : obj.items())
|
|
||||||
class items_view {
|
|
||||||
public:
|
|
||||||
// the members are public, so an entry also works with structured bindings
|
|
||||||
struct entry {
|
|
||||||
std::string k;
|
|
||||||
common_json & v;
|
|
||||||
|
|
||||||
const std::string & key() const { return k; }
|
|
||||||
common_json & value() const { return v; }
|
|
||||||
};
|
|
||||||
|
|
||||||
items_view(common_json * node, size_t n) : node(node), n(n) {}
|
|
||||||
|
|
||||||
class iterator {
|
|
||||||
public:
|
|
||||||
iterator(common_json * node, size_t idx) : node(node), idx(idx) {}
|
|
||||||
|
|
||||||
entry operator*() const;
|
|
||||||
|
|
||||||
iterator & operator++() {
|
|
||||||
idx++;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator!=(const iterator & other) const { return idx != other.idx; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
common_json * node;
|
|
||||||
size_t idx;
|
|
||||||
};
|
|
||||||
|
|
||||||
iterator begin() const { return iterator(node, 0); }
|
|
||||||
iterator end() const { return iterator(node, n); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
common_json * node;
|
|
||||||
size_t n;
|
|
||||||
};
|
|
||||||
|
|
||||||
items_view items() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
// a negative index must not turn into a huge size_t
|
|
||||||
static size_t to_idx(int idx) {
|
|
||||||
if (idx < 0) {
|
|
||||||
throw common_json_error("negative array index");
|
|
||||||
}
|
|
||||||
return (size_t) idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
// the backing value is built here, json.cpp checks that it fits
|
|
||||||
// it cannot be a pointer: a value inside a tree would then not be a common_json
|
|
||||||
// at() could then only give back a copy instead of a real reference
|
|
||||||
alignas(8) unsigned char storage[32];
|
|
||||||
};
|
|
||||||
|
|
||||||
using common_json_entry = common_json::items_view::entry;
|
|
||||||
@@ -116,8 +116,6 @@ static llama_sampler_i llama_sampler_llg_i = {
|
|||||||
/* .backend_accept = */ NULL,
|
/* .backend_accept = */ NULL,
|
||||||
/* .backend_apply = */ NULL,
|
/* .backend_apply = */ NULL,
|
||||||
/* .backend_set_input = */ NULL,
|
/* .backend_set_input = */ NULL,
|
||||||
/* .backend_reset = */ NULL,
|
|
||||||
/* .copy_state = */ NULL,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static size_t llama_sampler_llg_tokenize_fn(const void * user_data, const uint8_t * bytes, size_t bytes_len,
|
static size_t llama_sampler_llg_tokenize_fn(const void * user_data, const uint8_t * bytes, size_t bytes_len,
|
||||||
|
|||||||
+3
-41
@@ -1,6 +1,5 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "json.h"
|
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
@@ -67,17 +66,6 @@ static const char* g_col[] = {
|
|||||||
"",
|
"",
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char * level_str(enum ggml_log_level level) {
|
|
||||||
switch (level) {
|
|
||||||
case GGML_LOG_LEVEL_DEBUG: return "debug";
|
|
||||||
case GGML_LOG_LEVEL_INFO: return "info";
|
|
||||||
case GGML_LOG_LEVEL_WARN: return "warn";
|
|
||||||
case GGML_LOG_LEVEL_ERROR: return "error";
|
|
||||||
case GGML_LOG_LEVEL_CONT: return "cont";
|
|
||||||
default: return "none";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct common_log_entry {
|
struct common_log_entry {
|
||||||
enum ggml_log_level level {GGML_LOG_LEVEL_INFO};
|
enum ggml_log_level level {GGML_LOG_LEVEL_INFO};
|
||||||
|
|
||||||
@@ -86,7 +74,6 @@ struct common_log_entry {
|
|||||||
int64_t timestamp { 0 };
|
int64_t timestamp { 0 };
|
||||||
bool is_end { false }; // signals the worker thread to stop
|
bool is_end { false }; // signals the worker thread to stop
|
||||||
bool prefix { false };
|
bool prefix { false };
|
||||||
bool jsonl { false };
|
|
||||||
|
|
||||||
common_log_entry(size_t size = 256) : msg(size) { }
|
common_log_entry(size_t size = 256) : msg(size) { }
|
||||||
|
|
||||||
@@ -101,23 +88,11 @@ struct common_log_entry {
|
|||||||
|
|
||||||
fcur = stdout;
|
fcur = stdout;
|
||||||
|
|
||||||
if (level != GGML_LOG_LEVEL_NONE && !jsonl) {
|
if (level != GGML_LOG_LEVEL_NONE) {
|
||||||
fcur = stderr;
|
fcur = stderr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (jsonl) {
|
|
||||||
common_json obj = {
|
|
||||||
{"type", "log"},
|
|
||||||
{"time", timestamp},
|
|
||||||
{"level", level_str(level)},
|
|
||||||
{"msg", msg.data()},
|
|
||||||
};
|
|
||||||
fprintf(fcur, "%s\n", obj.dump_safe().c_str());
|
|
||||||
fflush(fcur);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (level != GGML_LOG_LEVEL_NONE && level != GGML_LOG_LEVEL_CONT && prefix) {
|
if (level != GGML_LOG_LEVEL_NONE && level != GGML_LOG_LEVEL_CONT && prefix) {
|
||||||
if (timestamp) {
|
if (timestamp) {
|
||||||
// [M.s.ms.us]
|
// [M.s.ms.us]
|
||||||
@@ -156,7 +131,6 @@ struct common_log {
|
|||||||
file = nullptr;
|
file = nullptr;
|
||||||
prefix = false;
|
prefix = false;
|
||||||
timestamps = false;
|
timestamps = false;
|
||||||
jsonl = false;
|
|
||||||
running = false;
|
running = false;
|
||||||
t_start = t_us();
|
t_start = t_us();
|
||||||
|
|
||||||
@@ -184,7 +158,6 @@ private:
|
|||||||
|
|
||||||
bool prefix;
|
bool prefix;
|
||||||
bool timestamps;
|
bool timestamps;
|
||||||
bool jsonl;
|
|
||||||
bool running;
|
bool running;
|
||||||
|
|
||||||
int64_t t_start;
|
int64_t t_start;
|
||||||
@@ -273,7 +246,6 @@ public:
|
|||||||
entry.is_end = false;
|
entry.is_end = false;
|
||||||
entry.level = level;
|
entry.level = level;
|
||||||
entry.prefix = prefix;
|
entry.prefix = prefix;
|
||||||
entry.jsonl = jsonl;
|
|
||||||
entry.timestamp = 0;
|
entry.timestamp = 0;
|
||||||
if (timestamps) {
|
if (timestamps) {
|
||||||
entry.timestamp = t_us() - t_start;
|
entry.timestamp = t_us() - t_start;
|
||||||
@@ -388,12 +360,6 @@ public:
|
|||||||
|
|
||||||
this->timestamps = timestamps;
|
this->timestamps = timestamps;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_jsonl(bool jsonl) {
|
|
||||||
std::lock_guard<std::mutex> lock(mtx);
|
|
||||||
|
|
||||||
this->jsonl = jsonl;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -467,16 +433,12 @@ void common_log_set_timestamps(struct common_log * log, bool timestamps) {
|
|||||||
log->set_timestamps(timestamps);
|
log->set_timestamps(timestamps);
|
||||||
}
|
}
|
||||||
|
|
||||||
void common_log_set_jsonl(struct common_log * log, bool jsonl) {
|
|
||||||
log->set_jsonl(jsonl);
|
|
||||||
}
|
|
||||||
|
|
||||||
void common_log_flush(struct common_log * log) {
|
void common_log_flush(struct common_log * log) {
|
||||||
log->pause();
|
log->pause();
|
||||||
log->resume();
|
log->resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
int common_log_get_verbosity(enum ggml_log_level level) {
|
static int common_get_verbosity(enum ggml_log_level level) {
|
||||||
switch (level) {
|
switch (level) {
|
||||||
case GGML_LOG_LEVEL_DEBUG: return LOG_LEVEL_DEBUG;
|
case GGML_LOG_LEVEL_DEBUG: return LOG_LEVEL_DEBUG;
|
||||||
case GGML_LOG_LEVEL_INFO: return LOG_LEVEL_TRACE;
|
case GGML_LOG_LEVEL_INFO: return LOG_LEVEL_TRACE;
|
||||||
@@ -490,7 +452,7 @@ int common_log_get_verbosity(enum ggml_log_level level) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void common_log_default_callback(enum ggml_log_level level, const char * text, void * /*user_data*/) {
|
void common_log_default_callback(enum ggml_log_level level, const char * text, void * /*user_data*/) {
|
||||||
auto verbosity = common_log_get_verbosity(level);
|
auto verbosity = common_get_verbosity(level);
|
||||||
if (verbosity <= common_log_verbosity_thold) {
|
if (verbosity <= common_log_verbosity_thold) {
|
||||||
common_log_add(common_log_main(), level, "%s", text);
|
common_log_add(common_log_main(), level, "%s", text);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,8 +43,6 @@ int common_log_get_verbosity_thold(void);
|
|||||||
|
|
||||||
void common_log_set_verbosity_thold(int verbosity); // not thread-safe
|
void common_log_set_verbosity_thold(int verbosity); // not thread-safe
|
||||||
|
|
||||||
int common_log_get_verbosity(enum ggml_log_level level);
|
|
||||||
|
|
||||||
void common_log_default_callback(enum ggml_log_level level, const char * text, void * user_data);
|
void common_log_default_callback(enum ggml_log_level level, const char * text, void * user_data);
|
||||||
|
|
||||||
// the common_log uses an internal worker thread to print/write log messages
|
// the common_log uses an internal worker thread to print/write log messages
|
||||||
@@ -91,7 +89,6 @@ void common_log_set_file (struct common_log * log, const char * file); // n
|
|||||||
void common_log_set_colors (struct common_log * log, log_colors colors); // not thread-safe
|
void common_log_set_colors (struct common_log * log, log_colors colors); // not thread-safe
|
||||||
void common_log_set_prefix (struct common_log * log, bool prefix); // whether to output prefix to each log
|
void common_log_set_prefix (struct common_log * log, bool prefix); // whether to output prefix to each log
|
||||||
void common_log_set_timestamps(struct common_log * log, bool timestamps); // whether to output timestamps in the prefix
|
void common_log_set_timestamps(struct common_log * log, bool timestamps); // whether to output timestamps in the prefix
|
||||||
void common_log_set_jsonl (struct common_log * log, bool jsonl); // print each log as a JSON object on one line, not thread-safe
|
|
||||||
void common_log_flush (struct common_log * log); // flush all pending log messages
|
void common_log_flush (struct common_log * log); // flush all pending log messages
|
||||||
|
|
||||||
// helper macros for logging
|
// helper macros for logging
|
||||||
|
|||||||
@@ -1,150 +0,0 @@
|
|||||||
#include "parsers.h"
|
|
||||||
|
|
||||||
// Cohere2 MoE (a.k.a. "North Code") parser.
|
|
||||||
//
|
|
||||||
// The assistant turn is fully marker-wrapped:
|
|
||||||
// <|START_OF_TURN_TOKEN|><|CHATBOT_TOKEN|>
|
|
||||||
// <|START_THINKING|>{reasoning}<|END_THINKING|>
|
|
||||||
// then EITHER content: <|START_TEXT|>{content}<|END_TEXT|>
|
|
||||||
// OR tool calls: <|START_ACTION|>[
|
|
||||||
// {"tool_call_id": "0", "tool_name": "f", "parameters": {...}}, ...
|
|
||||||
// ]<|END_ACTION|>
|
|
||||||
// <|END_OF_TURN_TOKEN|>
|
|
||||||
//
|
|
||||||
// The generation prompt forces a leading <|START_THINKING|> (when reasoning is enabled, which is
|
|
||||||
// the template default), so the model's output continues from *inside* the thinking block. The
|
|
||||||
// parser literal therefore only covers the stable <|START_OF_TURN_TOKEN|><|CHATBOT_TOKEN|> prefix
|
|
||||||
// and the reasoning rule consumes the <|START_THINKING|> ... <|END_THINKING|> markers itself,
|
|
||||||
// regardless of whether they came from the generation prompt or the generated text.
|
|
||||||
common_chat_params common_chat_params_init_cohere2moe(const common_chat_template & tmpl,
|
|
||||||
const autoparser::generation_params & inputs) {
|
|
||||||
common_chat_params data;
|
|
||||||
|
|
||||||
const std::string TURN_START = "<|START_OF_TURN_TOKEN|>";
|
|
||||||
const std::string TURN_END = "<|END_OF_TURN_TOKEN|>";
|
|
||||||
const std::string CHATBOT = "<|CHATBOT_TOKEN|>";
|
|
||||||
const std::string USER = "<|USER_TOKEN|>";
|
|
||||||
const std::string SYSTEM = "<|SYSTEM_TOKEN|>";
|
|
||||||
const std::string THINK_START = "<|START_THINKING|>";
|
|
||||||
const std::string THINK_END = "<|END_THINKING|>";
|
|
||||||
const std::string TEXT_START = "<|START_TEXT|>";
|
|
||||||
const std::string TEXT_END = "<|END_TEXT|>";
|
|
||||||
const std::string ACTION_START = "<|START_ACTION|>";
|
|
||||||
const std::string ACTION_END = "<|END_ACTION|>";
|
|
||||||
const std::string RESULT_START = "<|START_TOOL_RESULT|>";
|
|
||||||
const std::string RESULT_END = "<|END_TOOL_RESULT|>";
|
|
||||||
|
|
||||||
// Stable prefix of the generation prompt that precedes the (forced) <|START_THINKING|> marker.
|
|
||||||
const std::string GEN_PREFIX = TURN_START + CHATBOT;
|
|
||||||
|
|
||||||
data.prompt = common_chat_template_direct_apply_impl(tmpl, inputs);
|
|
||||||
data.generation_prompt = common_chat_template_generation_prompt_impl(tmpl, inputs);
|
|
||||||
data.format = COMMON_CHAT_FORMAT_PEG_NATIVE;
|
|
||||||
data.supports_thinking = true;
|
|
||||||
data.thinking_start_tag = THINK_START;
|
|
||||||
data.thinking_end_tags = {THINK_END};
|
|
||||||
data.preserved_tokens = {
|
|
||||||
TURN_START, TURN_END, CHATBOT, USER, SYSTEM,
|
|
||||||
THINK_START, THINK_END,
|
|
||||||
TEXT_START, TEXT_END,
|
|
||||||
ACTION_START, ACTION_END,
|
|
||||||
RESULT_START, RESULT_END,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Declare per-role message delimiters. Tool results are rendered with the
|
|
||||||
// system token followed by <|START_TOOL_RESULT|>, so the "tool" delimiter must be listed before
|
|
||||||
// the plain "system" one (it is a strict superset, and the role split tries delimiters in order).
|
|
||||||
data.message_delimiters = {
|
|
||||||
{ COMMON_CHAT_ROLE_ASSISTANT, GEN_PREFIX },
|
|
||||||
{ COMMON_CHAT_ROLE_USER, TURN_START + USER },
|
|
||||||
{ COMMON_CHAT_ROLE_TOOL, TURN_START + SYSTEM + RESULT_START },
|
|
||||||
{ COMMON_CHAT_ROLE_SYSTEM, TURN_START + SYSTEM },
|
|
||||||
};
|
|
||||||
|
|
||||||
auto has_tools = inputs.tools.is_array() && !inputs.tools.empty();
|
|
||||||
auto has_response_format = inputs.json_schema.is_object() && !inputs.json_schema.empty();
|
|
||||||
auto extract_reasoning = inputs.reasoning_format != COMMON_REASONING_FORMAT_NONE;
|
|
||||||
auto include_grammar = has_response_format || (has_tools && inputs.tool_choice != COMMON_CHAT_TOOL_CHOICE_NONE);
|
|
||||||
|
|
||||||
if (inputs.has_continuation()) {
|
|
||||||
const auto & msg = inputs.continue_msg;
|
|
||||||
|
|
||||||
data.generation_prompt = GEN_PREFIX + THINK_START + msg.reasoning_content;
|
|
||||||
if (inputs.continue_final_message == COMMON_CHAT_CONTINUATION_CONTENT) {
|
|
||||||
data.generation_prompt += THINK_END + TEXT_START + msg.render_content();
|
|
||||||
}
|
|
||||||
|
|
||||||
data.prompt += data.generation_prompt;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto parser = build_chat_peg_parser([&](common_chat_peg_builder & p) {
|
|
||||||
auto generation_prompt = p.literal(GEN_PREFIX);
|
|
||||||
auto end = p.end();
|
|
||||||
|
|
||||||
// The thinking block is always present (the generation prompt forces <|START_THINKING|>).
|
|
||||||
// When extracting reasoning, capture its body; otherwise keep the whole block (markers
|
|
||||||
// included) inline as content, matching reasoning_format=NONE conventions.
|
|
||||||
common_peg_parser reasoning = p.eps();
|
|
||||||
if (extract_reasoning) {
|
|
||||||
reasoning = p.optional(p.literal(THINK_START) +
|
|
||||||
p.reasoning(p.until_one_of({ THINK_END, TEXT_START, ACTION_START })) +
|
|
||||||
p.optional(p.literal(THINK_END)));
|
|
||||||
} else {
|
|
||||||
reasoning = p.optional(p.content(p.literal(THINK_START) +
|
|
||||||
p.until_one_of({ THINK_END, TEXT_START, ACTION_START }) +
|
|
||||||
p.optional(p.literal(THINK_END))));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto text_content = has_response_format
|
|
||||||
? p.literal(TEXT_START) +
|
|
||||||
p.content(p.schema(p.json(), "response-format-schema", inputs.json_schema)) +
|
|
||||||
p.optional(p.literal(TEXT_END))
|
|
||||||
: p.literal(TEXT_START) + p.content(p.until(TEXT_END)) + p.optional(p.literal(TEXT_END));
|
|
||||||
|
|
||||||
if (!has_tools || inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_NONE) {
|
|
||||||
return generation_prompt + reasoning + text_content + p.optional(p.literal(TURN_END)) + end;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto require_tools = inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_REQUIRED;
|
|
||||||
|
|
||||||
// <|START_ACTION|>[ {"tool_call_id": "0", "tool_name": "f", "parameters": {...}}, ... ]<|END_ACTION|>
|
|
||||||
auto tool_calls = p.standard_json_tools(ACTION_START, ACTION_END, inputs.tools, inputs.parallel_tool_calls,
|
|
||||||
/* force_tool_calls = */ true,
|
|
||||||
/* name_key = */ "tool_name",
|
|
||||||
/* args_key = */ "parameters",
|
|
||||||
/* array_wrapped = */ true,
|
|
||||||
/* function_is_key = */ false,
|
|
||||||
/* call_id_key = */ "",
|
|
||||||
/* gen_call_id_key = */ "tool_call_id",
|
|
||||||
/* parameters_order = */ { "tool_call_id", "tool_name", "parameters" });
|
|
||||||
|
|
||||||
// Content and tool calls are mutually exclusive in this format.
|
|
||||||
common_peg_parser body = require_tools ? tool_calls : p.choice({ tool_calls, text_content });
|
|
||||||
|
|
||||||
return generation_prompt + reasoning + body + p.optional(p.literal(TURN_END)) + end;
|
|
||||||
});
|
|
||||||
|
|
||||||
data.parser = parser.save();
|
|
||||||
|
|
||||||
if (include_grammar) {
|
|
||||||
data.grammar_lazy = !has_response_format && inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_AUTO;
|
|
||||||
data.grammar = build_grammar([&](const common_grammar_builder & builder) {
|
|
||||||
foreach_function(inputs.tools, [&](const json & tool) {
|
|
||||||
const auto & function = tool.at("function");
|
|
||||||
auto schema = function.at("parameters");
|
|
||||||
builder.resolve_refs(schema);
|
|
||||||
});
|
|
||||||
if (has_response_format) {
|
|
||||||
auto schema = inputs.json_schema;
|
|
||||||
builder.resolve_refs(schema);
|
|
||||||
}
|
|
||||||
parser.build_grammar(builder, data.grammar_lazy);
|
|
||||||
});
|
|
||||||
|
|
||||||
data.grammar_triggers = {
|
|
||||||
{ COMMON_GRAMMAR_TRIGGER_TYPE_WORD, ACTION_START }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
@@ -1,287 +0,0 @@
|
|||||||
#include "parsers.h"
|
|
||||||
|
|
||||||
// The DeepSeek V4 reference implementation renders consecutive tool results into a single
|
|
||||||
// user block, ordered by the tool call order of the preceding assistant message (matched
|
|
||||||
// by tool call id) rather than by the order they appear in the conversation.
|
|
||||||
static json deepseek_v4_sort_tool_results(const json & messages) {
|
|
||||||
json adjusted = messages;
|
|
||||||
std::map<std::string, size_t> call_order;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < adjusted.size();) {
|
|
||||||
const auto & msg = adjusted[i];
|
|
||||||
const auto role = msg.value("role", "");
|
|
||||||
|
|
||||||
if (role == "assistant" && msg.contains("tool_calls") &&
|
|
||||||
msg.at("tool_calls").is_array() && !msg.at("tool_calls").empty()) {
|
|
||||||
call_order.clear();
|
|
||||||
const auto & tool_calls = msg.at("tool_calls");
|
|
||||||
for (size_t idx = 0; idx < tool_calls.size(); idx++) {
|
|
||||||
auto id = tool_calls[idx].value("id", "");
|
|
||||||
if (!id.empty()) {
|
|
||||||
call_order[id] = idx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (role != "user" && role != "tool") {
|
|
||||||
i++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// collect a maximal run of user/tool messages - they render into one user block
|
|
||||||
std::vector<size_t> tool_positions;
|
|
||||||
size_t run_end = i;
|
|
||||||
for (; run_end < adjusted.size(); run_end++) {
|
|
||||||
const auto r = adjusted[run_end].value("role", "");
|
|
||||||
if (r == "tool") {
|
|
||||||
tool_positions.push_back(run_end);
|
|
||||||
} else if (r != "user") {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tool_positions.size() > 1 && !call_order.empty()) {
|
|
||||||
std::vector<json> results;
|
|
||||||
results.reserve(tool_positions.size());
|
|
||||||
for (auto pos : tool_positions) {
|
|
||||||
results.push_back(adjusted[pos]);
|
|
||||||
}
|
|
||||||
std::stable_sort(results.begin(), results.end(), [&](const json & a, const json & b) {
|
|
||||||
const auto order = [&](const json & m) {
|
|
||||||
auto it = call_order.find(m.value("tool_call_id", ""));
|
|
||||||
return it == call_order.end() ? (size_t) 0 : it->second;
|
|
||||||
};
|
|
||||||
return order(a) < order(b);
|
|
||||||
});
|
|
||||||
for (size_t k = 0; k < tool_positions.size(); k++) {
|
|
||||||
adjusted[tool_positions[k]] = std::move(results[k]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
i = run_end;
|
|
||||||
}
|
|
||||||
|
|
||||||
return adjusted;
|
|
||||||
}
|
|
||||||
|
|
||||||
common_chat_params common_chat_params_init_deepseek_v3_2(const common_chat_template & tmpl,
|
|
||||||
const autoparser::generation_params & inputs) {
|
|
||||||
common_chat_params data;
|
|
||||||
|
|
||||||
// V4 uses the same DSML markup as V3.2, but names the tool call block "tool_calls"
|
|
||||||
// instead of "function_calls", renders tool results in tool call order and its
|
|
||||||
// non-thinking generation prompt ends with a bare </think> instead of an empty
|
|
||||||
// <think></think> pair.
|
|
||||||
const bool is_v4 = tmpl.source().find("function_calls") == std::string::npos;
|
|
||||||
|
|
||||||
std::optional<json> adjusted_messages;
|
|
||||||
if (is_v4) {
|
|
||||||
adjusted_messages = deepseek_v4_sort_tool_results(inputs.messages);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto has_tools = inputs.tools.is_array() && !inputs.tools.empty();
|
|
||||||
auto has_response_format = !inputs.json_schema.is_null() && inputs.json_schema.is_object();
|
|
||||||
auto extract_reasoning = inputs.reasoning_format != COMMON_REASONING_FORMAT_NONE;
|
|
||||||
auto include_grammar = has_response_format || (has_tools && inputs.tool_choice != COMMON_CHAT_TOOL_CHOICE_NONE);
|
|
||||||
|
|
||||||
std::optional<json> additional_context;
|
|
||||||
if (is_v4 && has_response_format) {
|
|
||||||
additional_context = json{ { "response_format", inputs.json_schema } };
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string DSML = "|DSML|";
|
|
||||||
const std::string THINK_START = "<think>";
|
|
||||||
const std::string THINK_END = "</think>";
|
|
||||||
const std::string TC_BLOCK = is_v4 ? "tool_calls" : "function_calls";
|
|
||||||
const std::string FC_START = "<" + DSML + TC_BLOCK + ">";
|
|
||||||
const std::string FC_END = "</" + DSML + TC_BLOCK + ">";
|
|
||||||
const std::string INVOKE_START = "<" + DSML + "invoke";
|
|
||||||
const std::string INVOKE_END = "</" + DSML + "invoke>";
|
|
||||||
const std::string PARAM_START = "<" + DSML + "parameter";
|
|
||||||
const std::string PARAM_END = "</" + DSML + "parameter>";
|
|
||||||
const std::string GEN_PROMPT = "<|Assistant|>";
|
|
||||||
const std::string TC_SEPARATOR = "\n\n";
|
|
||||||
|
|
||||||
data.prompt = common_chat_template_direct_apply_impl(
|
|
||||||
tmpl, inputs, adjusted_messages, std::nullopt, additional_context);
|
|
||||||
data.generation_prompt = common_chat_template_generation_prompt_impl(
|
|
||||||
tmpl, inputs, adjusted_messages, std::nullopt, additional_context);
|
|
||||||
data.format = COMMON_CHAT_FORMAT_PEG_NATIVE;
|
|
||||||
data.supports_thinking = true;
|
|
||||||
data.thinking_start_tag = THINK_START;
|
|
||||||
data.thinking_end_tags = {THINK_END, FC_START};
|
|
||||||
data.preserved_tokens = {
|
|
||||||
DSML,
|
|
||||||
THINK_START,
|
|
||||||
THINK_END,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (inputs.has_continuation()) {
|
|
||||||
const auto & msg = inputs.continue_msg;
|
|
||||||
|
|
||||||
if (is_v4 && msg.reasoning_content.empty()) {
|
|
||||||
data.generation_prompt = GEN_PROMPT + THINK_END;
|
|
||||||
if (inputs.continue_final_message == COMMON_CHAT_CONTINUATION_CONTENT) {
|
|
||||||
data.generation_prompt += msg.render_content();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
data.generation_prompt = GEN_PROMPT + THINK_START + msg.reasoning_content;
|
|
||||||
if (inputs.continue_final_message == COMMON_CHAT_CONTINUATION_CONTENT) {
|
|
||||||
data.generation_prompt += THINK_END + msg.render_content();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data.prompt += data.generation_prompt;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool require_tools = inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_REQUIRED;
|
|
||||||
bool has_tool_calls = has_tools && inputs.tool_choice != COMMON_CHAT_TOOL_CHOICE_NONE;
|
|
||||||
|
|
||||||
auto parser = build_chat_peg_parser([&](common_chat_peg_builder & p) {
|
|
||||||
auto generation_prompt = p.literal(GEN_PROMPT);
|
|
||||||
auto end = p.end();
|
|
||||||
|
|
||||||
// build tool call section first since we might need it in reasoning
|
|
||||||
auto tool_choice = p.choice();
|
|
||||||
if (has_tool_calls) {
|
|
||||||
foreach_function(inputs.tools, [&](const json & tool) {
|
|
||||||
const auto & function = tool.at("function");
|
|
||||||
std::string name = function.at("name");
|
|
||||||
auto params = function.contains("parameters") ? function.at("parameters") : json::object();
|
|
||||||
const auto & props = params.contains("properties") ? params.at("properties") : json::object();
|
|
||||||
|
|
||||||
std::set<std::string> required;
|
|
||||||
if (params.contains("required")) {
|
|
||||||
required = params.at("required").get<std::set<std::string>>();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto schema_info = common_schema_info();
|
|
||||||
schema_info.resolve_refs(params);
|
|
||||||
|
|
||||||
std::vector<common_peg_parser> required_parsers;
|
|
||||||
std::vector<common_peg_parser> optional_parsers;
|
|
||||||
for (const auto & [param_name, param_schema] : props.items()) {
|
|
||||||
bool is_required = required.find(param_name) != required.end();
|
|
||||||
bool is_string = schema_info.resolves_to_string(param_schema);
|
|
||||||
|
|
||||||
auto arg = p.tool_arg(
|
|
||||||
p.tool_arg_open(p.literal(PARAM_START + " name=\"") + p.tool_arg_name(p.literal(param_name)) +
|
|
||||||
p.literal("\" string=\"" + std::string(is_string ? "true" : "false") + "\">")) +
|
|
||||||
(is_string ?
|
|
||||||
p.tool_arg_string_value(p.until(PARAM_END)) :
|
|
||||||
p.tool_arg_json_value(p.schema(p.json(), "tool-" + name + "-arg-" + param_name + "-schema",
|
|
||||||
param_schema, false))) +
|
|
||||||
p.tool_arg_close(p.literal(PARAM_END)));
|
|
||||||
|
|
||||||
auto named_arg = p.rule("tool-" + name + "-arg-" + param_name, arg);
|
|
||||||
if (is_required) {
|
|
||||||
required_parsers.push_back(named_arg);
|
|
||||||
} else {
|
|
||||||
optional_parsers.push_back(named_arg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
common_peg_parser args_seq = p.eps();
|
|
||||||
for (size_t i = 0; i < required_parsers.size(); i++) {
|
|
||||||
if (i > 0) {
|
|
||||||
args_seq = args_seq + p.space();
|
|
||||||
}
|
|
||||||
args_seq = args_seq + required_parsers[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!optional_parsers.empty()) {
|
|
||||||
common_peg_parser any_opt = p.choice();
|
|
||||||
for (const auto & opt : optional_parsers) {
|
|
||||||
any_opt |= opt;
|
|
||||||
}
|
|
||||||
args_seq = args_seq + p.repeat(p.space() + any_opt, 0, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
common_peg_parser invoke_body = args_seq;
|
|
||||||
auto func_parser = p.tool(p.tool_open(p.literal(INVOKE_START + " name=\"") +
|
|
||||||
p.tool_name(p.literal(name)) + p.literal("\">\n")) +
|
|
||||||
invoke_body + p.space() + p.tool_close(p.literal(INVOKE_END)));
|
|
||||||
|
|
||||||
tool_choice |= p.rule("tool-" + name, func_parser);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
common_peg_parser tool_calls = p.eps();
|
|
||||||
if (inputs.parallel_tool_calls) {
|
|
||||||
tool_calls = p.trigger_rule("tool-call",
|
|
||||||
p.literal(FC_START) + p.space() + tool_choice +
|
|
||||||
p.zero_or_more(p.space() + tool_choice) + p.space() + p.literal(FC_END));
|
|
||||||
} else {
|
|
||||||
tool_calls = p.trigger_rule("tool-call",
|
|
||||||
p.literal(FC_START) + p.space() + tool_choice + p.space() + p.literal(FC_END));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto reasoning = p.eps();
|
|
||||||
auto reasoning_with_tc = p.eps();
|
|
||||||
auto obligatory_tool_calls = tool_calls;
|
|
||||||
bool allow_reasoning_with_tc = false;
|
|
||||||
|
|
||||||
if (!require_tools) {
|
|
||||||
tool_calls = p.optional(tool_calls);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (extract_reasoning && inputs.enable_thinking) {
|
|
||||||
reasoning = p.optional(THINK_START + p.reasoning(p.until(THINK_END)) + THINK_END);
|
|
||||||
reasoning_with_tc = THINK_START +
|
|
||||||
p.reasoning(p.until_one_of({ TC_SEPARATOR + FC_START, FC_START, THINK_END })) +
|
|
||||||
p.space() + obligatory_tool_calls;
|
|
||||||
allow_reasoning_with_tc = true;
|
|
||||||
} else if (extract_reasoning) {
|
|
||||||
// Thinking disabled but reasoning extraction requested: the generation prompt
|
|
||||||
// contains an empty <think></think> pair (V3.2) or a bare </think> (V4) that
|
|
||||||
// must still be consumed.
|
|
||||||
reasoning = is_v4
|
|
||||||
? p.optional(p.literal(THINK_END))
|
|
||||||
: p.optional(p.literal(THINK_START) + p.until(THINK_END) + p.literal(THINK_END));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (has_response_format) {
|
|
||||||
auto response_format = p.rule("response-format",
|
|
||||||
p.literal("```json") + p.space() +
|
|
||||||
p.content(p.schema(p.json(), "response-format-schema", inputs.json_schema)) +
|
|
||||||
p.space() + p.literal("```"));
|
|
||||||
return generation_prompt + reasoning + response_format + end;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!has_tool_calls) {
|
|
||||||
return generation_prompt + reasoning + p.content(p.rest()) + end;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto content_before_tools = p.negate(p.literal(THINK_START)) +
|
|
||||||
p.content(p.until_one_of({ TC_SEPARATOR + FC_START, FC_START })) +
|
|
||||||
p.space();
|
|
||||||
return allow_reasoning_with_tc ? generation_prompt + (reasoning_with_tc | (reasoning + content_before_tools + tool_calls)) + end :
|
|
||||||
generation_prompt + reasoning + content_before_tools + tool_calls + end;
|
|
||||||
});
|
|
||||||
|
|
||||||
data.parser = parser.save();
|
|
||||||
|
|
||||||
if (include_grammar) {
|
|
||||||
data.grammar_lazy = has_tools && !require_tools;
|
|
||||||
data.grammar = build_grammar([&](const common_grammar_builder & builder) {
|
|
||||||
foreach_function(inputs.tools, [&](const json & tool) {
|
|
||||||
const auto & function = tool.at("function");
|
|
||||||
auto schema = function.contains("parameters") ? function.at("parameters") : json::object();
|
|
||||||
builder.resolve_refs(schema);
|
|
||||||
});
|
|
||||||
if (has_response_format) {
|
|
||||||
auto schema = inputs.json_schema;
|
|
||||||
builder.resolve_refs(schema);
|
|
||||||
}
|
|
||||||
parser.build_grammar(builder, data.grammar_lazy);
|
|
||||||
});
|
|
||||||
|
|
||||||
data.grammar_triggers = {
|
|
||||||
{ COMMON_GRAMMAR_TRIGGER_TYPE_WORD, FC_START },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
#include "parsers.h"
|
|
||||||
|
|
||||||
// Functionary v3.2 - uses recipient-based format: >>>recipient\n{content}
|
|
||||||
common_chat_params common_chat_params_init_functionary_v3_2(const common_chat_template & tmpl,
|
|
||||||
const autoparser::generation_params & inputs) {
|
|
||||||
common_chat_params data;
|
|
||||||
|
|
||||||
data.prompt = common_chat_template_direct_apply_impl(tmpl, inputs);
|
|
||||||
data.generation_prompt = common_chat_template_generation_prompt_impl(tmpl, inputs);
|
|
||||||
data.format = COMMON_CHAT_FORMAT_PEG_NATIVE;
|
|
||||||
data.preserved_tokens = {
|
|
||||||
">>>all",
|
|
||||||
};
|
|
||||||
|
|
||||||
auto has_tools = inputs.tools.is_array() && !inputs.tools.empty();
|
|
||||||
auto include_grammar = has_tools && inputs.tool_choice != COMMON_CHAT_TOOL_CHOICE_NONE;
|
|
||||||
|
|
||||||
if (inputs.has_continuation()) {
|
|
||||||
const auto & msg = inputs.continue_msg;
|
|
||||||
data.generation_prompt = "<|start_header_id|>assistant<|end_header_id|>\n\n>>>all\n" + msg.render_content();
|
|
||||||
data.prompt += data.generation_prompt;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto parser = build_chat_peg_parser([&](common_chat_peg_builder & p) {
|
|
||||||
// Functionary v3.2 format:
|
|
||||||
// - Normal content: >>>all\n{content}
|
|
||||||
// - Tool calls: >>>function_name\n{json_args}
|
|
||||||
// Generation prompt ends with ">>>" so model outputs recipient immediately
|
|
||||||
|
|
||||||
// Build content parser for >>>all\n{content}
|
|
||||||
// When tools are present, content stops before the next ">>>" (tool call)
|
|
||||||
// When no tools, content goes until end
|
|
||||||
auto content_until_tool = p.literal("all\n") + p.content(p.until(">>>"));
|
|
||||||
auto content_until_end = p.literal("all\n") + p.content(p.rest());
|
|
||||||
auto generation_prompt = p.literal("<|start_header_id|>assistant<|end_header_id|>\n\n>>>");
|
|
||||||
|
|
||||||
// If no tools or tool_choice is NONE, just parse content
|
|
||||||
if (!has_tools || inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_NONE) {
|
|
||||||
// When no tools, just match the prefix and capture everything after
|
|
||||||
return generation_prompt + content_until_end + p.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build tool call parsers for each available function
|
|
||||||
auto tool_choice = p.choice();
|
|
||||||
foreach_function(inputs.tools, [&](const json & tool) {
|
|
||||||
const auto & function = tool.at("function");
|
|
||||||
std::string name = function.at("name");
|
|
||||||
const auto & schema = function.at("parameters");
|
|
||||||
|
|
||||||
// Tool format: >>>function_name\n{json_args}
|
|
||||||
auto tool_parser = p.tool(
|
|
||||||
p.tool_open(p.tool_name(p.literal(name)) + p.literal("\n")) +
|
|
||||||
p.tool_args(p.schema(p.json(), "tool-" + name + "-schema", schema))
|
|
||||||
);
|
|
||||||
|
|
||||||
tool_choice |= p.rule("tool-" + name, tool_parser);
|
|
||||||
});
|
|
||||||
|
|
||||||
auto content_only = content_until_end;
|
|
||||||
auto tools_only = p.trigger_rule("tools", p.one_or_more(tool_choice));
|
|
||||||
auto content_and_tools = content_until_tool + tools_only;
|
|
||||||
|
|
||||||
auto ret = p.eps();
|
|
||||||
if (inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_REQUIRED) {
|
|
||||||
if (inputs.parallel_tool_calls) {
|
|
||||||
ret = p.choice({ content_and_tools, tools_only }) + p.end();
|
|
||||||
} else {
|
|
||||||
ret = p.choice({ content_until_tool + tool_choice, tools_only }) + p.end();
|
|
||||||
}
|
|
||||||
} else if (inputs.parallel_tool_calls) {
|
|
||||||
ret = p.choice({ content_and_tools, content_only, tools_only }) + p.end();
|
|
||||||
} else {
|
|
||||||
auto content_and_tool = content_until_tool + tool_choice;
|
|
||||||
ret = p.choice({ content_and_tool, content_only, tool_choice }) + p.end();
|
|
||||||
}
|
|
||||||
return generation_prompt + ret;
|
|
||||||
});
|
|
||||||
|
|
||||||
data.parser = parser.save();
|
|
||||||
|
|
||||||
if (include_grammar) {
|
|
||||||
data.grammar_lazy = inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_AUTO;
|
|
||||||
|
|
||||||
data.grammar = build_grammar([&](const common_grammar_builder & builder) {
|
|
||||||
foreach_function(inputs.tools, [&](const json & tool) {
|
|
||||||
const auto & function = tool.at("function");
|
|
||||||
auto schema = function.at("parameters");
|
|
||||||
builder.resolve_refs(schema);
|
|
||||||
});
|
|
||||||
parser.build_grammar(builder, data.grammar_lazy);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Grammar trigger for when the model starts outputting a tool call
|
|
||||||
// (after the initial ">>>" in the generation prompt but recipient other than "all")
|
|
||||||
data.grammar_triggers = {
|
|
||||||
{ COMMON_GRAMMAR_TRIGGER_TYPE_PATTERN, ">>>(?!all)" }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
@@ -1,312 +0,0 @@
|
|||||||
#include "parsers.h"
|
|
||||||
|
|
||||||
namespace workaround {
|
|
||||||
|
|
||||||
// Gemma4 uses a custom tool_responses field instead of role:tool messages.
|
|
||||||
//
|
|
||||||
// This will transform a sequence of messages:
|
|
||||||
// assistant(tool_call+) -> tool+ -> assistant(content)
|
|
||||||
//
|
|
||||||
// Into a single assistant message containing a tool_responses field:
|
|
||||||
// assistant(content + tool_call + tool_responses)
|
|
||||||
//
|
|
||||||
// This is necessary for the Gemma4 chat template to properly format the prompt.
|
|
||||||
// See https://ai.google.dev/gemma/docs/core/prompt-formatting-gemma4
|
|
||||||
struct gemma4_model_turn_builder {
|
|
||||||
json & messages;
|
|
||||||
size_t pos;
|
|
||||||
json tool_calls = json::array();
|
|
||||||
json tool_responses = json::array();
|
|
||||||
json content;
|
|
||||||
json reasoning_content;
|
|
||||||
|
|
||||||
gemma4_model_turn_builder(json & msgs, size_t pos) : messages(msgs), pos(pos) {}
|
|
||||||
|
|
||||||
void collect() {
|
|
||||||
// Collect the first assistant message
|
|
||||||
auto & msg = messages[pos];
|
|
||||||
if (msg.contains("reasoning_content") && msg.at("reasoning_content").is_string()) {
|
|
||||||
// According to the prompt formatting guide, we need to preserve reasoning_content
|
|
||||||
// between function calls. The current chat templates do not support this, but we will do it anyway.
|
|
||||||
reasoning_content = msg.at("reasoning_content");
|
|
||||||
}
|
|
||||||
for (auto & tc : msg.at("tool_calls")) {
|
|
||||||
tool_calls.push_back(tc);
|
|
||||||
}
|
|
||||||
pos++;
|
|
||||||
|
|
||||||
// Collect tool call results
|
|
||||||
while (pos < messages.size() && messages[pos].value("role", "") == "tool") {
|
|
||||||
collect_result(messages[pos]);
|
|
||||||
pos++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the next assistant message is the final message
|
|
||||||
if (pos < messages.size() && messages[pos].value("role", "") == "assistant") {
|
|
||||||
auto & next = messages[pos];
|
|
||||||
if (!has_tool_calls(next) && has_content(next)) {
|
|
||||||
content = next.at("content");
|
|
||||||
pos++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void collect_result(const json & curr) {
|
|
||||||
json response;
|
|
||||||
if (curr.contains("content")) {
|
|
||||||
const auto & content = curr.at("content");
|
|
||||||
if (content.is_string()) {
|
|
||||||
// Try to parse the content as JSON; fall back to raw string
|
|
||||||
try {
|
|
||||||
response = json::parse(content.get<std::string>());
|
|
||||||
} catch (...) {
|
|
||||||
response = content;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
response = content;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string name;
|
|
||||||
|
|
||||||
// Match name with corresponding tool call
|
|
||||||
size_t idx = tool_responses.size();
|
|
||||||
if (idx < tool_calls.size()) {
|
|
||||||
auto & tc = tool_calls[idx];
|
|
||||||
if (tc.contains("function")) {
|
|
||||||
name = tc.at("function").value("name", "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback to the tool call id
|
|
||||||
if (name.empty()) {
|
|
||||||
name = curr.value("tool_call_id", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
tool_responses.push_back({{"name", name}, {"response", response}});
|
|
||||||
}
|
|
||||||
|
|
||||||
json build() {
|
|
||||||
collect();
|
|
||||||
|
|
||||||
json msg = {
|
|
||||||
{"role", "assistant"},
|
|
||||||
{"tool_calls", tool_calls},
|
|
||||||
};
|
|
||||||
if (!tool_responses.empty()) {
|
|
||||||
msg["tool_responses"] = tool_responses;
|
|
||||||
}
|
|
||||||
if (!content.is_null()) {
|
|
||||||
msg["content"] = content;
|
|
||||||
}
|
|
||||||
if (!reasoning_content.is_null()) {
|
|
||||||
msg["reasoning_content"] = reasoning_content;
|
|
||||||
}
|
|
||||||
return msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool has_content(const json & msg) {
|
|
||||||
if (!msg.contains("content") || msg.at("content").is_null()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const auto & content = msg.at("content");
|
|
||||||
if (content.is_string() && !content.get<std::string>().empty()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (content.is_array() && !content.empty()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool has_tool_calls(const json & msg) {
|
|
||||||
return msg.contains("tool_calls") && msg.at("tool_calls").is_array() && !msg.at("tool_calls").empty();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void convert_tool_responses_gemma4(json & messages) {
|
|
||||||
json result = json::array();
|
|
||||||
size_t i = 0;
|
|
||||||
|
|
||||||
while (i < messages.size()) {
|
|
||||||
auto & msg = messages[i];
|
|
||||||
|
|
||||||
if (msg.value("role", "") != "assistant" || !msg.contains("tool_calls") ||
|
|
||||||
!msg.at("tool_calls").is_array() || msg.at("tool_calls").empty()) {
|
|
||||||
result.push_back(msg);
|
|
||||||
i++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
gemma4_model_turn_builder builder(messages, i);
|
|
||||||
result.push_back(builder.build());
|
|
||||||
i = builder.pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
messages = result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
common_chat_params common_chat_params_init_gemma4(const common_chat_template & tmpl,
|
|
||||||
const autoparser::generation_params & inputs) {
|
|
||||||
common_chat_params data;
|
|
||||||
|
|
||||||
data.prompt = common_chat_template_direct_apply_impl(tmpl, inputs);
|
|
||||||
data.generation_prompt = common_chat_template_generation_prompt_impl(tmpl, inputs);
|
|
||||||
|
|
||||||
if (inputs.add_generation_prompt && string_ends_with(data.prompt, "<turn|>\n")) {
|
|
||||||
// This may happen if the model generates content + tool_call, the
|
|
||||||
// template does not add the model's next turn and confuses the model
|
|
||||||
// from emitting its proper reasoning token sequence.
|
|
||||||
data.generation_prompt = "<|turn>model\n";
|
|
||||||
data.prompt += data.generation_prompt;
|
|
||||||
}
|
|
||||||
|
|
||||||
data.message_delimiters = {
|
|
||||||
{ COMMON_CHAT_ROLE_USER, "<|turn>user" },
|
|
||||||
{ COMMON_CHAT_ROLE_ASSISTANT, "<|turn>model" },
|
|
||||||
};
|
|
||||||
|
|
||||||
data.format = COMMON_CHAT_FORMAT_PEG_GEMMA4;
|
|
||||||
data.supports_thinking = true;
|
|
||||||
data.thinking_start_tag = "<|channel>thought";
|
|
||||||
data.thinking_end_tags = {"<channel|>"};
|
|
||||||
|
|
||||||
data.preserved_tokens = {
|
|
||||||
"<|channel>",
|
|
||||||
"<channel|>",
|
|
||||||
"<|tool_call>",
|
|
||||||
"<tool_call|>",
|
|
||||||
"<|turn>",
|
|
||||||
};
|
|
||||||
|
|
||||||
if (inputs.has_continuation()) {
|
|
||||||
const auto & msg = inputs.continue_msg;
|
|
||||||
|
|
||||||
data.generation_prompt = string_ends_with(data.prompt, "<turn|>\n") ? "<|turn>model\n" : "";
|
|
||||||
data.generation_prompt += "<|channel>thought\n" + msg.reasoning_content;
|
|
||||||
if (inputs.continue_final_message == COMMON_CHAT_CONTINUATION_CONTENT) {
|
|
||||||
data.generation_prompt += "<channel|>" + msg.render_content();
|
|
||||||
}
|
|
||||||
|
|
||||||
data.prompt += data.generation_prompt;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto has_tools = inputs.tools.is_array() && !inputs.tools.empty();
|
|
||||||
auto has_response_format = !inputs.json_schema.is_null() && inputs.json_schema.is_object();
|
|
||||||
auto include_grammar = has_response_format || (has_tools && inputs.tool_choice != COMMON_CHAT_TOOL_CHOICE_NONE);
|
|
||||||
auto extract_reasoning = inputs.reasoning_format != COMMON_REASONING_FORMAT_NONE;
|
|
||||||
|
|
||||||
auto parser = build_chat_peg_parser([&](common_chat_peg_builder & p) {
|
|
||||||
auto start = p.rule("start", p.optional(p.literal("<|turn>model\n")));
|
|
||||||
|
|
||||||
if (extract_reasoning) {
|
|
||||||
p.rule("thought", p.literal("<|channel>thought") + p.space() + p.reasoning(p.until("<channel|>")) + p.literal("<channel|>"));
|
|
||||||
} else {
|
|
||||||
p.rule("thought", p.content(p.literal("<|channel>thought") + p.space() + p.until("<channel|>") + p.literal("<channel|>")));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto consume_empty_channels = p.gbnf(p.zero_or_more(p.literal("<|channel>") + p.negate(p.literal("thought"))), "");
|
|
||||||
auto thought = (p.peek(p.literal("<|channel>")) + consume_empty_channels + p.ref("thought")) | p.negate(p.literal("<|channel>"));
|
|
||||||
|
|
||||||
if (has_response_format) {
|
|
||||||
auto response_format = p.literal("```json") <<
|
|
||||||
p.content(p.schema(p.json(), "response-format-schema", inputs.json_schema)) <<
|
|
||||||
p.literal("```");
|
|
||||||
return start + p.optional(thought) + response_format;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (has_tools && inputs.tool_choice != COMMON_CHAT_TOOL_CHOICE_NONE) {
|
|
||||||
// Gemma4 tool calling syntax
|
|
||||||
// Rules should match traversal logic in gemma4_to_json()
|
|
||||||
p.rule("gemma4-string-content", p.until("<|\"|>"));
|
|
||||||
p.rule("gemma4-string", p.literal("<|\"|>") + p.ref("gemma4-string-content") + p.literal("<|\"|>"));
|
|
||||||
p.rule("gemma4-bool", p.json_bool());
|
|
||||||
p.rule("gemma4-null", p.json_null());
|
|
||||||
p.rule("gemma4-number", p.json_number());
|
|
||||||
p.rule("gemma4-dict-key", p.rule("gemma4-dict-key-name", p.chars("[^:}]", 1, -1)) + p.literal(":"));
|
|
||||||
p.rule("gemma4-dict-kv", p.ref("gemma4-dict-key") + p.space() + p.ref("gemma4-value"));
|
|
||||||
p.rule("gemma4-dict", [&]() {
|
|
||||||
auto ws = p.space();
|
|
||||||
auto member = p.ref("gemma4-dict-kv");
|
|
||||||
auto members = p.sequence({member, p.zero_or_more(p.sequence({p.literal(","), ws, member}))});
|
|
||||||
return p.sequence({
|
|
||||||
p.literal("{"), ws,
|
|
||||||
p.choice({p.literal("}"), p.sequence({members, ws, p.literal("}")})})
|
|
||||||
});
|
|
||||||
});
|
|
||||||
p.rule("gemma4-array", [&]() {
|
|
||||||
auto ws = p.space();
|
|
||||||
auto value = p.ref("gemma4-value");
|
|
||||||
auto elements = p.sequence({value, p.zero_or_more(p.sequence({p.literal(","), ws, value}))});
|
|
||||||
return p.sequence({
|
|
||||||
p.literal("["), ws,
|
|
||||||
p.choice({p.literal("]"), p.sequence({elements, ws, p.literal("]")})})
|
|
||||||
});
|
|
||||||
});
|
|
||||||
p.rule("gemma4-value", [&]() {
|
|
||||||
return p.choice({
|
|
||||||
p.ref("gemma4-string"), p.ref("gemma4-dict"), p.ref("gemma4-array"),
|
|
||||||
p.ref("gemma4-number"), p.ref("gemma4-bool"), p.ref("gemma4-null")
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
auto tool_choice = p.choice();
|
|
||||||
|
|
||||||
foreach_function(inputs.tools, [&](const json & tool) {
|
|
||||||
const auto & function = tool.at("function");
|
|
||||||
std::string name = function.at("name");
|
|
||||||
// TODO @aldehir : need to extend json-schema-to-grammar to produce more than JSON rules
|
|
||||||
// const auto & params = function.at("parameters");
|
|
||||||
|
|
||||||
tool_choice |= p.rule("tool-" + name, p.tool(p.sequence({
|
|
||||||
p.tool_open(p.tool_name(p.literal(name)) + p.peek(p.literal("{"))),
|
|
||||||
p.tool_args(p.ref("gemma4-dict")),
|
|
||||||
})));
|
|
||||||
});
|
|
||||||
|
|
||||||
auto tool_call = p.trigger_rule("tool-call", p.repeat(
|
|
||||||
"<|tool_call>call:" + tool_choice + "<tool_call|>",
|
|
||||||
/* min = */ inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_REQUIRED ? 1 : 0,
|
|
||||||
/* max = */ inputs.parallel_tool_calls ? -1 : 1
|
|
||||||
));
|
|
||||||
|
|
||||||
auto scan_to_toolcall = p.rule("scan-to-toolcall", p.until("<|tool_call>"));
|
|
||||||
auto content = p.rule("content", p.content(p.until_one_of({"<|channel>", "<channel|>", "<|tool_call>"})));
|
|
||||||
auto message = p.rule("message", thought + content);
|
|
||||||
return start + p.zero_or_more(message) + scan_to_toolcall + tool_call;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gemma 4 may emit an extra <|channel>thought\n<channel|> at the end of the content. It may
|
|
||||||
// also emit a single trailing <channel|> token. Consume all complete reasoning blocks and
|
|
||||||
// then stop at the first unmatched <channel|> token.
|
|
||||||
auto content = p.rule("content", p.content(p.until_one_of({"<|channel>", "<channel|>"})));
|
|
||||||
auto message = p.rule("message", thought + content);
|
|
||||||
return start + p.one_or_more(message);
|
|
||||||
});
|
|
||||||
|
|
||||||
data.parser = parser.save();
|
|
||||||
|
|
||||||
if (include_grammar) {
|
|
||||||
data.grammar_lazy = !(has_response_format || (has_tools && inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_REQUIRED));
|
|
||||||
data.grammar = build_grammar([&](const common_grammar_builder & builder) {
|
|
||||||
foreach_function(inputs.tools, [&](const json & tool) {
|
|
||||||
const auto & function = tool.at("function");
|
|
||||||
auto schema = function.at("parameters");
|
|
||||||
builder.resolve_refs(schema);
|
|
||||||
});
|
|
||||||
if (has_response_format) {
|
|
||||||
auto schema = inputs.json_schema;
|
|
||||||
builder.resolve_refs(schema);
|
|
||||||
}
|
|
||||||
parser.build_grammar(builder, data.grammar_lazy);
|
|
||||||
});
|
|
||||||
|
|
||||||
data.grammar_triggers = {
|
|
||||||
{ COMMON_GRAMMAR_TRIGGER_TYPE_WORD, "<|tool_call>" },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
#include "parsers.h"
|
|
||||||
|
|
||||||
common_chat_params common_chat_params_init_gigachat_v3(
|
|
||||||
const common_chat_template & tmpl,
|
|
||||||
const autoparser::generation_params & inputs) {
|
|
||||||
|
|
||||||
common_chat_params data;
|
|
||||||
|
|
||||||
data.prompt = common_chat_template_direct_apply_impl(tmpl, inputs);
|
|
||||||
data.generation_prompt = common_chat_template_generation_prompt_impl(tmpl, inputs);
|
|
||||||
data.format = COMMON_CHAT_FORMAT_PEG_NATIVE;
|
|
||||||
data.supports_thinking = false;
|
|
||||||
data.preserved_tokens = {
|
|
||||||
"<|message_sep|>\n\n",
|
|
||||||
"<|role_sep|>\n",
|
|
||||||
};
|
|
||||||
|
|
||||||
if (inputs.has_continuation()) {
|
|
||||||
const auto & msg = inputs.continue_msg;
|
|
||||||
data.generation_prompt = "assistant<|role_sep|>\n" + msg.render_content();
|
|
||||||
data.prompt += data.generation_prompt;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto has_tools = inputs.tools.is_array() && !inputs.tools.empty();
|
|
||||||
auto include_grammar = has_tools && inputs.tool_choice != COMMON_CHAT_TOOL_CHOICE_NONE;
|
|
||||||
const auto *tool_call_start_prefix = "<|message_sep|>\n\nfunction call<|role_sep|>\n";
|
|
||||||
|
|
||||||
auto parser = build_chat_peg_parser([&](common_chat_peg_builder & p) {
|
|
||||||
auto ret = p.eps();
|
|
||||||
if (has_tools && inputs.tool_choice != COMMON_CHAT_TOOL_CHOICE_NONE) {
|
|
||||||
// Build a choice of all available tools
|
|
||||||
auto tool_choice = p.choice();
|
|
||||||
for (const auto & tool : inputs.tools) {
|
|
||||||
const auto & function = tool.at("function");
|
|
||||||
std::string name = function.at("name");
|
|
||||||
const auto & schema = function.at("parameters");
|
|
||||||
|
|
||||||
auto tool_name = p.json_member("name", "\"" + p.tool_name(p.literal(name)) + "\"");
|
|
||||||
auto tool_args = p.json_member("arguments", p.tool_args(p.schema(p.json(), "tool-" + name + "-schema", schema)));
|
|
||||||
|
|
||||||
auto tool_open = p.tool_open(p.literal("{") << tool_name);
|
|
||||||
|
|
||||||
tool_choice |= p.rule("tool-" + name, tool_open << "," << tool_args << "}");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Define the tool call structure
|
|
||||||
auto min_calls = inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_REQUIRED ? 1 : 0;
|
|
||||||
auto max_calls = 1; // parallel toolcalls are not supported
|
|
||||||
auto tool_call = p.rule("tool-call", p.literal(tool_call_start_prefix) + tool_choice);
|
|
||||||
auto tool_calls = p.trigger_rule("tool-call-root", p.repeat(tool_call, /* min = */ min_calls, /* max = */ max_calls));
|
|
||||||
|
|
||||||
ret = p.content(p.until("<|message_sep|>\n\n")) << tool_calls;
|
|
||||||
} else {
|
|
||||||
// Content only parser
|
|
||||||
include_grammar = false;
|
|
||||||
ret = p.content(p.rest());
|
|
||||||
}
|
|
||||||
|
|
||||||
return p.literal("assistant<|role_sep|>\n") + ret;
|
|
||||||
});
|
|
||||||
|
|
||||||
data.parser = parser.save();
|
|
||||||
|
|
||||||
if (include_grammar) {
|
|
||||||
data.grammar_lazy = has_tools && inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_AUTO;
|
|
||||||
|
|
||||||
data.grammar = build_grammar([&](const common_grammar_builder & builder) {
|
|
||||||
foreach_function(inputs.tools, [&](const json & tool) {
|
|
||||||
const auto & function = tool.at("function");
|
|
||||||
auto schema = function.at("parameters");
|
|
||||||
builder.resolve_refs(schema);
|
|
||||||
});
|
|
||||||
parser.build_grammar(builder, data.grammar_lazy);
|
|
||||||
});
|
|
||||||
|
|
||||||
data.grammar_triggers = {
|
|
||||||
{COMMON_GRAMMAR_TRIGGER_TYPE_WORD, tool_call_start_prefix}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user