diff --git a/.github/workflows/bump-lemonade.yml b/.github/workflows/bump-lemonade.yml new file mode 100644 index 00000000..3f2e9a48 --- /dev/null +++ b/.github/workflows/bump-lemonade.yml @@ -0,0 +1,97 @@ +# Copyright 2026 bong-water-water-bong +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Keep third_party/lemonade on our fork's main (docs/lemonade.md): 1bit-MONSTER/lemonade +# follows upstream lemonade-sdk/lemonade daily (sync-lemonade-fork.yml); when the fork +# moves, open a PR here moving the submodule. Before merging, on Strix Halo: build with +# scripts/build-lemonade.sh and run Lemonade's LLM suite through the onebit recipe. +# +# Uses the secret HRX_BUMP_TOKEN (Contents and Pull requests read/write on +# 1bit-MONSTER/engine): a PR opened with the default GITHUB_TOKEN would not +# start CI. +name: bump-lemonade + +on: + schedule: + - cron: "23 7 * * *" + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: bump-lemonade + cancel-in-progress: false + +jobs: + bump: + runs-on: ubuntu-latest + steps: + - name: Require the token + env: + HRX_BUMP_TOKEN: ${{ secrets.HRX_BUMP_TOKEN }} + run: | + if [ -z "$HRX_BUMP_TOKEN" ]; then + echo "::error::secret HRX_BUMP_TOKEN is not set (see the header of this workflow)" + exit 1 + fi + + - uses: actions/checkout@v4 + with: + token: ${{ secrets.HRX_BUMP_TOKEN }} + + - name: Compare with upstream + id: pins + env: + GH_TOKEN: ${{ secrets.HRX_BUMP_TOKEN }} + run: | + set -euo pipefail + upstream=$(gh api repos/1bit-MONSTER/lemonade/commits/main --jq .sha) + ours=$(git ls-tree HEAD third_party/lemonade | awk '{print $3}') + echo "upstream $upstream, ours $ours" + { + echo "upstream=$upstream"; echo "ours=$ours" + if [ "$upstream" = "$ours" ]; then echo "changed=false"; else echo "changed=true"; fi + } >> "$GITHUB_OUTPUT" + + - name: Open the bump PR + if: steps.pins.outputs.changed == 'true' + env: + GH_TOKEN: ${{ secrets.HRX_BUMP_TOKEN }} + UPSTREAM: ${{ steps.pins.outputs.upstream }} + OURS: ${{ steps.pins.outputs.ours }} + run: | + set -euo pipefail + branch="bump-lemonade/${UPSTREAM:0:12}" + if git ls-remote --exit-code origin "refs/heads/$branch" > /dev/null; then + echo "$branch already exists"; exit 0 + fi + log=$(gh api "repos/1bit-MONSTER/lemonade/compare/${OURS}...${UPSTREAM}" \ + --jq '.commits[-30:][] | "- \(.sha[0:9]) \(.commit.message | split("\n")[0])"' || true) + git config user.name "lemonade-bump" + git config user.email "lemonade-bump@users.noreply.github.com" + git switch -c "$branch" + git update-index --cacheinfo "160000,$UPSTREAM,third_party/lemonade" + git commit -q -m "Bump Lemonade: 1bit-MONSTER/lemonade ${UPSTREAM:0:12}" + git push -q origin "$branch" + gh pr create --base main --head "$branch" \ + --title "Bump Lemonade: 1bit-MONSTER/lemonade ${UPSTREAM:0:12}" \ + --body "Moves third_party/lemonade from \`${OURS:0:12}\` to the fork's main \`${UPSTREAM:0:12}\`. + + Fork commits (last 30): + ${log} + + CI here has no GPU. Before merging, on Strix Halo: + \`scripts/build-lemonade.sh ~/.cache/lemonade-pin\`, then Lemonade's LLM suite through the onebit recipe (docs/lemonade.md)." diff --git a/.gitmodules b/.gitmodules index b3625f46..e9792528 100644 --- a/.gitmodules +++ b/.gitmodules @@ -74,3 +74,12 @@ path = third_party/comfyui.cpp url = https://github.com/1bit-MONSTER/comfyui.cpp.git branch = master +# Lemonade (docs/lemonade.md): the host the engine runs inside. Our fork, upstream +# lemonade-sdk/lemonade plus the onebit recipe; pinned so the engine is tested against a +# known Lemonade. Never linked; scripts/build-lemonade.sh builds lemond from it, and +# .github/workflows/bump-lemonade.yml keeps it on the fork's main. +[submodule "third_party/lemonade"] + path = third_party/lemonade + url = https://github.com/1bit-MONSTER/lemonade.git + branch = main + shallow = true diff --git a/NOTICE b/NOTICE index 736f55a4..2d2e3fbc 100644 --- a/NOTICE +++ b/NOTICE @@ -68,6 +68,14 @@ ZINC (third_party/zinc) Copyright (c) 2025 ZINC Contributors License: MIT +Lemonade (third_party/lemonade) + https://github.com/1bit-MONSTER/lemonade + (a fork of https://github.com/lemonade-sdk/lemonade, with the onebit recipe) + Copyright (C) 2024-2026 Advanced Micro Devices, Inc. + License: Apache-2.0. Pinned so the engine is tested against a known Lemonade; + built as its own program (scripts/build-lemonade.sh) that runs `1bit serve` + as a backend. None of its code is linked into this product. + ComfyUI.cpp (third_party/comfyui.cpp) https://github.com/1bit-MONSTER/comfyui.cpp A C++ port of ComfyUI (https://github.com/Comfy-Org/ComfyUI, Copyright (C) diff --git a/docs/lemonade.md b/docs/lemonade.md index bab47e47..3f50794c 100644 --- a/docs/lemonade.md +++ b/docs/lemonade.md @@ -52,18 +52,24 @@ through unchanged. The recipe lives in our Lemonade fork, [1bit-MONSTER/lemonade](https://github.com/1bit-MONSTER/lemonade): upstream Lemonade plus the `onebit` backend (fork PR #1). Build `lemond` from the fork and -put `1bit` on PATH (or set `$LEMONADE_ONEBIT_BIN`): +put `1bit` on PATH (or set `$LEMONADE_ONEBIT_BIN`). + +The engine pins the Lemonade it is tested with: `third_party/lemonade` is the fork at a +fixed commit. It is never linked into the engine. `scripts/build-lemonade.sh` builds +`lemond` and the `lemonade` CLI from it: ```sh -git clone https://github.com/1bit-MONSTER/lemonade && cd lemonade -cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_WEB_APP=OFF -cmake --build build --target lemond lemonade -LEMONADE_ONEBIT_BIN=/path/to/1bit build/lemond +scripts/build-lemonade.sh ~/.cache/lemonade-pin +LEMONADE_ONEBIT_BIN=$PWD/build/1bit ~/.cache/lemonade-pin/bin/lemond ``` +`.github/workflows/bump-lemonade.yml` opens a PR here when the fork's `main` moves (after +the daily upstream sync below). Before merging, rebuild and rerun the LLM suite on Strix Halo. + On Strix Halo the recipe passes Lemonade's own LLM test suite (`test/server_llm.py --wrapped-server onebit`) on Vulkan and HRX: 31 tests, 9 run, -22 skipped as unsupported. It is not proposed upstream. The fork follows upstream daily: +22 skipped as unsupported. It is not proposed upstream yet: the plan is to embed the engine fully +in the fork first, then propose it upstream. The fork follows upstream daily: `.github/workflows/sync-lemonade-fork.yml` merges upstream `main` into it. It pushes only a clean merge that still registers `onebit`; otherwise it opens a PR in the fork that lists the conflicts. It also keeps the fork's own copies of diff --git a/scripts/build-lemonade.sh b/scripts/build-lemonade.sh new file mode 100755 index 00000000..3f6d60fb --- /dev/null +++ b/scripts/build-lemonade.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +# Copyright 2026 bong-water-water-bong +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# build-lemonade.sh +# +# Builds lemond and the lemonade CLI from third_party/lemonade (our fork of +# lemonade-sdk/lemonade, with the onebit recipe; docs/lemonade.md) into +# /bin. Needs cmake, ninja and a C++ compiler; the web app is left out. +# Run it with the engine on PATH, or point the recipe at it: +# LEMONADE_ONEBIT_BIN=/path/to/1bit /bin/lemond +set -euo pipefail +prefix=${1:?usage: build-lemonade.sh } +root=$(cd "$(dirname "$0")/.." && pwd) +src=$root/third_party/lemonade +if [ ! -f "$src/CMakeLists.txt" ] && git -C "$root" rev-parse --git-dir > /dev/null 2>&1; then + echo "fetching third_party/lemonade" + git -C "$root" submodule update --init third_party/lemonade +fi +[ -f "$src/CMakeLists.txt" ] || { echo "third_party/lemonade is empty and could not be fetched: git submodule update --init third_party/lemonade"; exit 1; } +mkdir -p "$prefix/bin" +prefix=$(cd "$prefix" && pwd) +cmake -S "$src" -B "$prefix/build" -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_WEB_APP=OFF +cmake --build "$prefix/build" --target lemond lemonade +cp "$prefix/build/lemond" "$prefix/build/lemonade" "$prefix/bin/" +echo "built $prefix/bin/lemond (lemonade $(git -C "$src" rev-parse --short=12 HEAD 2>/dev/null || echo unknown))" diff --git a/third_party/lemonade b/third_party/lemonade new file mode 160000 index 00000000..7650b4fc --- /dev/null +++ b/third_party/lemonade @@ -0,0 +1 @@ +Subproject commit 7650b4fcfdff288ed0c6353ede697e52857a706c