From 9c25099579df2c5b7053ab1daf524987bdf40eb9 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Wed, 3 Dec 2025 20:29:24 +1030 Subject: [PATCH 01/17] Build settings for inclusion in flatpak build --- configure.ac | 2 +- raylib/Makefile.am | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index a9f12a5..f3a23f0 100644 --- a/configure.ac +++ b/configure.ac @@ -70,7 +70,7 @@ case "${host_os}" in WEBSOCKET_LDFLAGS="" GTK_SERVER_LDFLAGS="`pkg-config --libs gtk+-3.0` -lXm -lXt" GTK_SERVER_CPPFLAGS="`pkg-config --cflags gtk+-3.0` -DGTK_SERVER_FFI -DGTK_SERVER_LIBRARY -DGTK_SERVER_UNIX -DGTK_SERVER_GTK3x" - RAYLIB_LDFLAGS="-lGL -lm -lpthread -ldl -lrt -lX11" + RAYLIB_LDFLAGS="-lGL -lm -lpthread -ldl -lrt -lX11 -lwayland-client -lwayland-cursor -lwayland-egl -lxkbcommon" JVM_CPPFLAGS="-I/usr/lib/jvm/java-1.8.0-openjdk-amd64/include -I/usr/lib/jvm/java-1.8.0-openjdk-amd64/include/linux" JVM_LDFLAGS="-L/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/amd64/server -ljvm" NUKLEAR_CPPFLAGS="-D_GLFW_X11=1" diff --git a/raylib/Makefile.am b/raylib/Makefile.am index 60b17a4..875d5dc 100644 --- a/raylib/Makefile.am +++ b/raylib/Makefile.am @@ -25,8 +25,9 @@ gen: $(generated) README.md AM_CXXFLAGS=-fno-rtti -std=c++14 -fpermissive AM_CPPFLAGS = -Iraylib/src -Iraylib/src/external/glfw/include -Iraylib/src/external/glfw/deps/mingw \ + -Iraylib/src/external/glfw/src \ -DPLATFORM_DESKTOP=1 -DSUPPORT_BUSY_WAIT_LOOP=1 -DSUPPORT_SCREEN_CAPTURE=1 \ - -DSUPPORT_GIF_RECORDING=1 -DSUPPORT_COMPRESSION_API=1 -D_GLFW_BUILD_DLL=1 \ + -DSUPPORT_GIF_RECORDING=1 -DSUPPORT_COMPRESSION_API=1 -D_GLFW_WAYLAND=1 \ -Wall -Wextra -Wshadow -Wdouble-promotion -Wno-unused-parameter -fPIC lib_LTLIBRARIES = libraylib.la From e8500cfe9582b61b5c2cbe43af7a26361b0b2ae7 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Fri, 2 Jan 2026 08:25:40 +1030 Subject: [PATCH 02/17] RAYLIB: build with SDL3 platform backend --- configure.ac | 11 ++++++++++- raylib/Makefile.am | 8 +++----- raylib/main.cpp | 18 +++++++----------- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/configure.ac b/configure.ac index f3a23f0..ed3c8a5 100644 --- a/configure.ac +++ b/configure.ac @@ -48,6 +48,13 @@ AC_ARG_WITH(ioio, [IOIO="yes"], [IOIO="no"]) +dnl configure SDL3 for raylib +PKG_CHECK_MODULES([SDL3], [sdl3]) +AC_MSG_CHECKING([for SDL3 library linking]) +SDL3_LIBS=`pkg-config sdl3 --libs --static` +SDL3_CFLAGS=`pkg-config sdl3 --cflags` +SDL3_INCLUDE=-I`pkg-config --variable=includedir sdl3`/SDL3 + case "${host_os}" in *mingw* | *msys*) AC_DEFINE(_WIN32, 1, [building for win32]) @@ -70,7 +77,8 @@ case "${host_os}" in WEBSOCKET_LDFLAGS="" GTK_SERVER_LDFLAGS="`pkg-config --libs gtk+-3.0` -lXm -lXt" GTK_SERVER_CPPFLAGS="`pkg-config --cflags gtk+-3.0` -DGTK_SERVER_FFI -DGTK_SERVER_LIBRARY -DGTK_SERVER_UNIX -DGTK_SERVER_GTK3x" - RAYLIB_LDFLAGS="-lGL -lm -lpthread -ldl -lrt -lX11 -lwayland-client -lwayland-cursor -lwayland-egl -lxkbcommon" + RAYLIB_CPPFLAGS="${SDL3_INCLUDE} ${SDL3_CFLAGS}" + RAYLIB_LDFLAGS="${SDL3_LIBS}" JVM_CPPFLAGS="-I/usr/lib/jvm/java-1.8.0-openjdk-amd64/include -I/usr/lib/jvm/java-1.8.0-openjdk-amd64/include/linux" JVM_LDFLAGS="-L/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/amd64/server -ljvm" NUKLEAR_CPPFLAGS="-D_GLFW_X11=1" @@ -79,6 +87,7 @@ esac AC_SUBST(DEBUG_LDFLAGS) AC_SUBST(CLIPBOARD_LDFLAGS) AC_SUBST(RAYLIB_LDFLAGS) +AC_SUBST(RAYLIB_CPPFLAGS) AC_SUBST(NUKLEAR_LDFLAGS) AC_SUBST(WEBSOCKET_LDFLAGS) AC_SUBST(PLATFORM_LDFLAGS) diff --git a/raylib/Makefile.am b/raylib/Makefile.am index 875d5dc..ab155c1 100644 --- a/raylib/Makefile.am +++ b/raylib/Makefile.am @@ -24,16 +24,14 @@ $(generated): raylib/parser/raylib_api.json mkraylib.bas gen: $(generated) README.md AM_CXXFLAGS=-fno-rtti -std=c++14 -fpermissive -AM_CPPFLAGS = -Iraylib/src -Iraylib/src/external/glfw/include -Iraylib/src/external/glfw/deps/mingw \ - -Iraylib/src/external/glfw/src \ - -DPLATFORM_DESKTOP=1 -DSUPPORT_BUSY_WAIT_LOOP=1 -DSUPPORT_SCREEN_CAPTURE=1 \ - -DSUPPORT_GIF_RECORDING=1 -DSUPPORT_COMPRESSION_API=1 -D_GLFW_WAYLAND=1 \ +AM_CPPFLAGS = -Iraylib/src @RAYLIB_CPPFLAGS@ \ + -DPLATFORM_DESKTOP_SDL=1 -DPLATFORM_DESKTOP_SDL3=1 -DSUPPORT_BUSY_WAIT_LOOP=1 -DSUPPORT_SCREEN_CAPTURE=1 \ + -DSUPPORT_GIF_RECORDING=1 -DSUPPORT_COMPRESSION_API=1 \ -Wall -Wextra -Wshadow -Wdouble-promotion -Wno-unused-parameter -fPIC lib_LTLIBRARIES = libraylib.la libraylib_la_SOURCES = \ - raylib/src/rglfw.c \ raylib/src/rmodels.c \ raylib/src/raudio.c \ raylib/src/rcore.c \ diff --git a/raylib/main.cpp b/raylib/main.cpp index 8bed447..4d8a576 100644 --- a/raylib/main.cpp +++ b/raylib/main.cpp @@ -24,10 +24,10 @@ #pragma GCC diagnostic pop #pragma GCC diagnostic pop #include -#include #include #include "robin-hood-hashing/src/include/robin_hood.h" +#include "SDL_events.h" #include "include/var.h" #include "include/module.h" #include "include/param.h" @@ -1377,18 +1377,15 @@ static int cmd_guiunlock(int argc, slib_par_t *params, var_t *retval) { return 1; } -static int cmd_poll_events(int argc, slib_par_t *params, var_t *retval) { - glfwPollEvents(); - return 1; -} - static int cmd_wait_events(int argc, slib_par_t *params, var_t *retval) { - float waitMillis = get_param_int(argc, params, 0, -1); - if (waitMillis > 0) { - glfwWaitEventsTimeout(waitMillis / 1000); + auto timeoutMS = get_param_int(argc, params, 0, -1); + SDL_Event event; + if (timeoutMS > 0) { + SDL_WaitEventTimeout(&event, timeoutMS); } else { - glfwWaitEvents(); + SDL_WaitEvent(&event); } + SDL_PushEvent(&event); return 1; } @@ -1835,7 +1832,6 @@ static FUNC_SIG lib_proc[] = { {3, 3, "GUISETSTYLE", cmd_guisetstyle}, {2, 2, "GUISTATUSBAR", cmd_guistatusbar}, {0, 0, "GUIUNLOCK", cmd_guiunlock}, - {0, 0, "POLLEVENTS", cmd_poll_events}, {0, 1, "WAITEVENTS", cmd_wait_events}, {0, 0, "CLOSEPHYSICS", cmd_closephysics}, {1, 1, "DESTROYPHYSICSBODY", cmd_destroyphysicsbody}, From 4a59ea1621021ef6ee6748f8ecb2ca54df64ef82 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Fri, 2 Jan 2026 13:00:55 +1030 Subject: [PATCH 03/17] RAYLIB: add missing include for flatpak build --- raylib/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/raylib/main.cpp b/raylib/main.cpp index 4d8a576..ebc1759 100644 --- a/raylib/main.cpp +++ b/raylib/main.cpp @@ -25,6 +25,7 @@ #pragma GCC diagnostic pop #include #include +#include #include "robin-hood-hashing/src/include/robin_hood.h" #include "SDL_events.h" From c5ace4e9ed22c459ea259df6036a021a0e823440 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Mon, 5 Jan 2026 09:11:25 +1030 Subject: [PATCH 04/17] Revert "RAYLIB: build with SDL3 platform backend" This reverts commit e8500cfe9582b61b5c2cbe43af7a26361b0b2ae7. Switching to SDL from libgl doesn't completely solve running from the IDE --- configure.ac | 11 +---------- raylib/Makefile.am | 8 +++++--- raylib/main.cpp | 18 +++++++++++------- 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/configure.ac b/configure.ac index ed3c8a5..f3a23f0 100644 --- a/configure.ac +++ b/configure.ac @@ -48,13 +48,6 @@ AC_ARG_WITH(ioio, [IOIO="yes"], [IOIO="no"]) -dnl configure SDL3 for raylib -PKG_CHECK_MODULES([SDL3], [sdl3]) -AC_MSG_CHECKING([for SDL3 library linking]) -SDL3_LIBS=`pkg-config sdl3 --libs --static` -SDL3_CFLAGS=`pkg-config sdl3 --cflags` -SDL3_INCLUDE=-I`pkg-config --variable=includedir sdl3`/SDL3 - case "${host_os}" in *mingw* | *msys*) AC_DEFINE(_WIN32, 1, [building for win32]) @@ -77,8 +70,7 @@ case "${host_os}" in WEBSOCKET_LDFLAGS="" GTK_SERVER_LDFLAGS="`pkg-config --libs gtk+-3.0` -lXm -lXt" GTK_SERVER_CPPFLAGS="`pkg-config --cflags gtk+-3.0` -DGTK_SERVER_FFI -DGTK_SERVER_LIBRARY -DGTK_SERVER_UNIX -DGTK_SERVER_GTK3x" - RAYLIB_CPPFLAGS="${SDL3_INCLUDE} ${SDL3_CFLAGS}" - RAYLIB_LDFLAGS="${SDL3_LIBS}" + RAYLIB_LDFLAGS="-lGL -lm -lpthread -ldl -lrt -lX11 -lwayland-client -lwayland-cursor -lwayland-egl -lxkbcommon" JVM_CPPFLAGS="-I/usr/lib/jvm/java-1.8.0-openjdk-amd64/include -I/usr/lib/jvm/java-1.8.0-openjdk-amd64/include/linux" JVM_LDFLAGS="-L/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/amd64/server -ljvm" NUKLEAR_CPPFLAGS="-D_GLFW_X11=1" @@ -87,7 +79,6 @@ esac AC_SUBST(DEBUG_LDFLAGS) AC_SUBST(CLIPBOARD_LDFLAGS) AC_SUBST(RAYLIB_LDFLAGS) -AC_SUBST(RAYLIB_CPPFLAGS) AC_SUBST(NUKLEAR_LDFLAGS) AC_SUBST(WEBSOCKET_LDFLAGS) AC_SUBST(PLATFORM_LDFLAGS) diff --git a/raylib/Makefile.am b/raylib/Makefile.am index ab155c1..875d5dc 100644 --- a/raylib/Makefile.am +++ b/raylib/Makefile.am @@ -24,14 +24,16 @@ $(generated): raylib/parser/raylib_api.json mkraylib.bas gen: $(generated) README.md AM_CXXFLAGS=-fno-rtti -std=c++14 -fpermissive -AM_CPPFLAGS = -Iraylib/src @RAYLIB_CPPFLAGS@ \ - -DPLATFORM_DESKTOP_SDL=1 -DPLATFORM_DESKTOP_SDL3=1 -DSUPPORT_BUSY_WAIT_LOOP=1 -DSUPPORT_SCREEN_CAPTURE=1 \ - -DSUPPORT_GIF_RECORDING=1 -DSUPPORT_COMPRESSION_API=1 \ +AM_CPPFLAGS = -Iraylib/src -Iraylib/src/external/glfw/include -Iraylib/src/external/glfw/deps/mingw \ + -Iraylib/src/external/glfw/src \ + -DPLATFORM_DESKTOP=1 -DSUPPORT_BUSY_WAIT_LOOP=1 -DSUPPORT_SCREEN_CAPTURE=1 \ + -DSUPPORT_GIF_RECORDING=1 -DSUPPORT_COMPRESSION_API=1 -D_GLFW_WAYLAND=1 \ -Wall -Wextra -Wshadow -Wdouble-promotion -Wno-unused-parameter -fPIC lib_LTLIBRARIES = libraylib.la libraylib_la_SOURCES = \ + raylib/src/rglfw.c \ raylib/src/rmodels.c \ raylib/src/raudio.c \ raylib/src/rcore.c \ diff --git a/raylib/main.cpp b/raylib/main.cpp index ebc1759..667f0dc 100644 --- a/raylib/main.cpp +++ b/raylib/main.cpp @@ -24,11 +24,11 @@ #pragma GCC diagnostic pop #pragma GCC diagnostic pop #include +#include #include #include #include "robin-hood-hashing/src/include/robin_hood.h" -#include "SDL_events.h" #include "include/var.h" #include "include/module.h" #include "include/param.h" @@ -1378,15 +1378,18 @@ static int cmd_guiunlock(int argc, slib_par_t *params, var_t *retval) { return 1; } +static int cmd_poll_events(int argc, slib_par_t *params, var_t *retval) { + glfwPollEvents(); + return 1; +} + static int cmd_wait_events(int argc, slib_par_t *params, var_t *retval) { - auto timeoutMS = get_param_int(argc, params, 0, -1); - SDL_Event event; - if (timeoutMS > 0) { - SDL_WaitEventTimeout(&event, timeoutMS); + float waitMillis = get_param_int(argc, params, 0, -1); + if (waitMillis > 0) { + glfwWaitEventsTimeout(waitMillis / 1000); } else { - SDL_WaitEvent(&event); + glfwWaitEvents(); } - SDL_PushEvent(&event); return 1; } @@ -1833,6 +1836,7 @@ static FUNC_SIG lib_proc[] = { {3, 3, "GUISETSTYLE", cmd_guisetstyle}, {2, 2, "GUISTATUSBAR", cmd_guistatusbar}, {0, 0, "GUIUNLOCK", cmd_guiunlock}, + {0, 0, "POLLEVENTS", cmd_poll_events}, {0, 1, "WAITEVENTS", cmd_wait_events}, {0, 0, "CLOSEPHYSICS", cmd_closephysics}, {1, 1, "DESTROYPHYSICSBODY", cmd_destroyphysicsbody}, From d9f64b1d968cc2f380109fcbe070eeed7c3d6fee Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Mon, 5 Jan 2026 20:06:52 +1030 Subject: [PATCH 05/17] RAYLIB: programs must run in a separate thread or via the command line --- include/module.h | 11 ++++++++++- raylib/main.cpp | 8 +++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/include/module.h b/include/module.h index d27ea52..b9176aa 100644 --- a/include/module.h +++ b/include/module.h @@ -25,6 +25,15 @@ extern "C" { */ int sblib_init(const char *sourceFile); +/** + * @ingroup modstd + * + * Returns whether the module is compatible with IDE builds + * + * @return non-zero on success + */ +int sblib_is_ide_compatible(void); + /** * @ingroup modstd * @@ -116,7 +125,7 @@ int sblib_func_exec(int index, int param_count, slib_par_t *params, var_t *retva * @param cls_id the variable class identifier * @param id the variable instance identifier */ -void sblib_free(int cls_id, int id); +int sblib_free(int cls_id, int id); /** * @ingroup modlib diff --git a/raylib/main.cpp b/raylib/main.cpp index 667f0dc..98ad484 100644 --- a/raylib/main.cpp +++ b/raylib/main.cpp @@ -1938,7 +1938,7 @@ SBLIB_API int sblib_func_exec(int index, int argc, slib_par_t *params, var_t *re return result; } -SBLIB_API void sblib_free(int cls_id, int id) { +SBLIB_API int sblib_free(int cls_id, int id) { if (id != -1) { switch (cls_id) { case CLS_AUDIOSTREAM: @@ -2031,6 +2031,7 @@ SBLIB_API void sblib_free(int cls_id, int id) { break; } } + return 0; } SBLIB_API void sblib_close(void) { @@ -2095,3 +2096,8 @@ SBLIB_API void sblib_close(void) { _waveMap.clear(); } } + +SBLIB_API void sblib_is_ide_compatible(void) { + // when using the SQL build, programs must be run via a separate thread + return false; +} From 8c4a66facc1ed4bb306be16d67d62ae617bce3cc Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Mon, 5 Jan 2026 20:09:23 +1030 Subject: [PATCH 06/17] RAYLIB: programs must run in a separate thread or via the command line --- raylib/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/raylib/main.cpp b/raylib/main.cpp index 98ad484..8238cb4 100644 --- a/raylib/main.cpp +++ b/raylib/main.cpp @@ -2097,7 +2097,7 @@ SBLIB_API void sblib_close(void) { } } -SBLIB_API void sblib_is_ide_compatible(void) { +SBLIB_API int sblib_is_ide_compatible(void) { // when using the SQL build, programs must be run via a separate thread - return false; + return 0; } From f615e24344adecb842741afdfc2d8ce85844c16d Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Tue, 6 Jan 2026 21:22:39 +1030 Subject: [PATCH 07/17] RAYLIB: rename UI detection to sblib_has_window_ui() --- include/module.h | 2 +- raylib/main.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/module.h b/include/module.h index b9176aa..c7753b2 100644 --- a/include/module.h +++ b/include/module.h @@ -32,7 +32,7 @@ int sblib_init(const char *sourceFile); * * @return non-zero on success */ -int sblib_is_ide_compatible(void); +int sblib_has_window_ui(void); /** * @ingroup modstd diff --git a/raylib/main.cpp b/raylib/main.cpp index 8238cb4..18ee3cd 100644 --- a/raylib/main.cpp +++ b/raylib/main.cpp @@ -2097,7 +2097,7 @@ SBLIB_API void sblib_close(void) { } } -SBLIB_API int sblib_is_ide_compatible(void) { - // when using the SQL build, programs must be run via a separate thread - return 0; +SBLIB_API int sblib_has_window_ui(void) { + // raylib module creates a UI in a new window + return 1; } From 744b20036d98f67dcba9f9998df888fa99f546c7 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Thu, 15 Jan 2026 08:50:34 +1030 Subject: [PATCH 08/17] FLATPAK: implements sblib_has_window_ui() in UI based modules --- glfw/main.cpp | 4 ++++ nuklear/main.cpp | 4 ++++ raylib/main.cpp | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/glfw/main.cpp b/glfw/main.cpp index 2a49198..07f8872 100644 --- a/glfw/main.cpp +++ b/glfw/main.cpp @@ -404,3 +404,7 @@ SBLIB_API void sblib_ellipse(int xc, int yc, int xr, int yr, int fill) { glEnd(); } +SBLIB_API int sblib_has_window_ui(void) { + // module creates a UI in a new window + return 1; +} diff --git a/nuklear/main.cpp b/nuklear/main.cpp index 00ac348..9553b7c 100644 --- a/nuklear/main.cpp +++ b/nuklear/main.cpp @@ -1181,3 +1181,7 @@ SBLIB_API void sblib_ellipse(int xc, int yc, int xr, int yr, int fill) { drawEnd(); } +SBLIB_API int sblib_has_window_ui(void) { + // module creates a UI in a new window + return 1; +} diff --git a/raylib/main.cpp b/raylib/main.cpp index 18ee3cd..06598c9 100644 --- a/raylib/main.cpp +++ b/raylib/main.cpp @@ -2098,6 +2098,6 @@ SBLIB_API void sblib_close(void) { } SBLIB_API int sblib_has_window_ui(void) { - // raylib module creates a UI in a new window + // module creates a UI in a new window return 1; } From 5cf27c37cc948728ac11b15abdbe21b687f661c5 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Sun, 18 Jan 2026 15:18:09 +1030 Subject: [PATCH 09/17] FLATPAK: ui modules now target wayland in linux build --- configure.ac | 35 ++++++++++++++++++++++++++++++++--- glfw/Makefile.am | 1 + nuklear/Makefile.am | 1 + nuklear/main.cpp | 26 ++++++++++++++++---------- 4 files changed, 50 insertions(+), 13 deletions(-) diff --git a/configure.ac b/configure.ac index f3a23f0..e3f5f79 100644 --- a/configure.ac +++ b/configure.ac @@ -33,6 +33,27 @@ function checkDebugMode() { AC_SUBST(CFLAGS) } +function generate_wayland_protocols() { + RAYLIB_SRC_PATH="${srcdir}/raylib/raylib/src" + WL_PROTOCOLS_DIR="${RAYLIB_SRC_PATH}/external/glfw/deps/wayland" + AC_MSG_NOTICE([Generating Wayland protocol headers]) + wl_generate() { + protocol="$1" + basename="$2" + "$WAYLAND_SCANNER" client-header "$protocol" "$RAYLIB_SRC_PATH/$basename.h" || exit 1 + "$WAYLAND_SCANNER" private-code "$protocol" "$RAYLIB_SRC_PATH/$basename-code.h" || exit 1 + } + wl_generate "$WL_PROTOCOLS_DIR/wayland.xml" wayland-client-protocol + wl_generate "$WL_PROTOCOLS_DIR/xdg-shell.xml" xdg-shell-client-protocol + wl_generate "$WL_PROTOCOLS_DIR/xdg-decoration-unstable-v1.xml" xdg-decoration-unstable-v1-client-protocol + wl_generate "$WL_PROTOCOLS_DIR/viewporter.xml" viewporter-client-protocol + wl_generate "$WL_PROTOCOLS_DIR/relative-pointer-unstable-v1.xml" relative-pointer-unstable-v1-client-protocol + wl_generate "$WL_PROTOCOLS_DIR/pointer-constraints-unstable-v1.xml" pointer-constraints-unstable-v1-client-protocol + wl_generate "$WL_PROTOCOLS_DIR/fractional-scale-v1.xml" fractional-scale-v1-client-protocol + wl_generate "$WL_PROTOCOLS_DIR/xdg-activation-v1.xml" xdg-activation-v1-client-protocol + wl_generate "$WL_PROTOCOLS_DIR/idle-inhibit-unstable-v1.xml" idle-inhibit-unstable-v1-client-protocol +} + AC_ARG_WITH(mlpack, [AS_HELP_STRING([--with-mlpack], [Build the mlpack module])], [MLPACK="yes"], @@ -66,14 +87,22 @@ case "${host_os}" in *) PLATFORM_LDFLAGS="-Wl,--no-undefined -avoid-version" CLIPBOARD_LDFLAGS="`pkg-config xcb --libs` -lpthread" - NUKLEAR_LDFLAGS="-lGL -lm -lpthread -ldl -lrt -lX11" WEBSOCKET_LDFLAGS="" GTK_SERVER_LDFLAGS="`pkg-config --libs gtk+-3.0` -lXm -lXt" GTK_SERVER_CPPFLAGS="`pkg-config --cflags gtk+-3.0` -DGTK_SERVER_FFI -DGTK_SERVER_LIBRARY -DGTK_SERVER_UNIX -DGTK_SERVER_GTK3x" - RAYLIB_LDFLAGS="-lGL -lm -lpthread -ldl -lrt -lX11 -lwayland-client -lwayland-cursor -lwayland-egl -lxkbcommon" + RAYLIB_LDFLAGS="`pkg-config wayland-client wayland-cursor wayland-egl xkbcommon --libs`" JVM_CPPFLAGS="-I/usr/lib/jvm/java-1.8.0-openjdk-amd64/include -I/usr/lib/jvm/java-1.8.0-openjdk-amd64/include/linux" JVM_LDFLAGS="-L/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/amd64/server -ljvm" - NUKLEAR_CPPFLAGS="-D_GLFW_X11=1" + NUKLEAR_CPPFLAGS="-D_GLFW_WAYLAND=1" + NUKLEAR_LDFLAGS="`pkg-config wayland-client wayland-cursor wayland-egl xkbcommon --libs`" + + AC_ARG_VAR([WAYLAND_SCANNER], [Path to wayland-scanner]) + AC_PATH_PROG([WAYLAND_SCANNER], [wayland-scanner]) + AS_IF([test -n "$WAYLAND_SCANNER"], [ + generate_wayland_protocols + ], [ + AC_MSG_WARN([wayland-scanner not found; Wayland support disabled]) + ]) esac AC_SUBST(DEBUG_LDFLAGS) diff --git a/glfw/Makefile.am b/glfw/Makefile.am index dc0dbaa..35ff783 100644 --- a/glfw/Makefile.am +++ b/glfw/Makefile.am @@ -7,6 +7,7 @@ AM_CXXFLAGS=-fno-rtti -std=c++14 AM_CPPFLAGS = \ + -I../raylib/raylib/src \ -I../raylib/raylib/src/external/glfw/include \ -I../raylib/raylib/src/external/glfw/deps \ -Wall -Wextra -Wshadow -Wdouble-promotion -Wno-unused-parameter -D_GLFW_BUILD_DLL=1 diff --git a/nuklear/Makefile.am b/nuklear/Makefile.am index 5b4f06f..d96ea60 100644 --- a/nuklear/Makefile.am +++ b/nuklear/Makefile.am @@ -7,6 +7,7 @@ AM_CXXFLAGS=-fno-rtti -std=c++14 AM_CPPFLAGS = -D_GLFW_BUILD_DLL=1 @NUKLEAR_CPPFLAGS@ \ + -I../raylib/raylib/src \ -I../raylib/raylib/src/external/glfw/include \ -I../raylib/raylib/src/external/glfw/deps lib_LTLIBRARIES = libnuklear.la diff --git a/nuklear/main.cpp b/nuklear/main.cpp index 9553b7c..f30a1f4 100644 --- a/nuklear/main.cpp +++ b/nuklear/main.cpp @@ -95,7 +95,7 @@ static void window_size_callback(GLFWwindow* window, int width, int height) { nk_context *nkp_create_window(const char *title, int width, int height) { if (!glfwInit()) { fprintf(stdout, "[GFLW] failed to init!\n"); - exit(1); + return nullptr; } glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); @@ -873,16 +873,22 @@ static int cmd_widgetishovered(int argc, slib_par_t *params, var_t *retval) { } static int cmd_windowbegin(int argc, slib_par_t *params, var_t *retval) { - nkp_process_events(); - nkbd_begin(_ctx); - const char *title = get_param_str(argc, params, 0, "Untitled"); - struct nk_rect rc = get_param_rect(argc, params, 1); - nk_flags flags = get_param_window_flags(argc, params, 5); - v_setint(retval, nk_begin(_ctx, title, rc, flags)); - if ((flags & NK_WINDOW_TITLE) == 0) { - nkp_set_window_title(title); + int result; + if (_ctx != nullptr) { + nkp_process_events(); + nkbd_begin(_ctx); + const char *title = get_param_str(argc, params, 0, "Untitled"); + struct nk_rect rc = get_param_rect(argc, params, 1); + nk_flags flags = get_param_window_flags(argc, params, 5); + v_setint(retval, nk_begin(_ctx, title, rc, flags)); + if ((flags & NK_WINDOW_TITLE) == 0) { + nkp_set_window_title(title); + } + result = 1; + } else { + result = 0; } - return 1; + return result; } static int cmd_windowend(int argc, slib_par_t *params, var_t *retval) { From 9d9d017273737f3607b1eae827e2e9830f35e22f Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Tue, 20 Jan 2026 12:43:54 +1030 Subject: [PATCH 10/17] NUCLEAR: show window focused at startup --- nuklear/main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nuklear/main.cpp b/nuklear/main.cpp index f30a1f4..d4ec06d 100644 --- a/nuklear/main.cpp +++ b/nuklear/main.cpp @@ -106,6 +106,8 @@ nk_context *nkp_create_window(const char *title, int width, int height) { title, nullptr, nullptr); glfwMakeContextCurrent(_window); + glfwSwapBuffers(_window); + gladLoadGL((GLADloadfunc) glfwGetProcAddress); glfwSetErrorCallback(error_callback); glfwSetWindowSizeCallback(_window, window_size_callback); From 44281e7b65837abcfb9f9dd89743e658a21517a6 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Fri, 23 Jan 2026 15:30:22 +1030 Subject: [PATCH 11/17] RAYLIB: allow make to depend on sbasic as part of flatpak processing --- raylib/Makefile.am | 11 +++- raylib/README.md | 51 +++++++++------ raylib/func-def.h | 14 +++- raylib/func.h | 152 ++++++++++++++++++++++++++++++++++++++------ raylib/mkraylib.bas | 2 +- raylib/mkreadme.bas | 2 +- raylib/proc-def.h | 3 + raylib/proc.h | 55 +++++++++++++--- raylib/raylib | 2 +- 9 files changed, 237 insertions(+), 55 deletions(-) diff --git a/raylib/Makefile.am b/raylib/Makefile.am index 875d5dc..0885662 100644 --- a/raylib/Makefile.am +++ b/raylib/Makefile.am @@ -8,8 +8,10 @@ generated = func-def.h proc-def.h proc.h func.h sbasic=sbasic +CLEANFILES = $(generated) + raylib/tools/rlparser/output/raylib_api.json: raylib/src/raylib.h raylib/tools/rlparser/rlparser.c - (cd raylib/tools/rlparser && make && ./rlparser --format JSON --input ../../src/raylib.h --output raylib_api.json) + (cd raylib/tools/rlparser && make && ./rlparser --format JSON --input ../../src/raylib.h --output output/raylib_api.json) UNSUPPORTED.md: $(generated) $(sbasic) mkraylib.bas unsupported > $@ @@ -21,7 +23,11 @@ $(generated): raylib/parser/raylib_api.json mkraylib.bas $(sbasic) mkraylib.bas $@ > $@ @touch main.cpp -gen: $(generated) README.md +gen: $(generated) + +gen: $(generated) + +all-am: $(generated) README.md AM_CXXFLAGS=-fno-rtti -std=c++14 -fpermissive AM_CPPFLAGS = -Iraylib/src -Iraylib/src/external/glfw/include -Iraylib/src/external/glfw/deps/mingw \ @@ -40,7 +46,6 @@ libraylib_la_SOURCES = \ raylib/src/rshapes.c \ raylib/src/rtextures.c \ raylib/src/rtext.c \ - raylib/src/utils.c \ ../include/param.cpp \ ../include/hashmap.cpp \ physac.cpp \ diff --git a/raylib/README.md b/raylib/README.md index b0f9723..08f508e 100644 --- a/raylib/README.md +++ b/raylib/README.md @@ -4,7 +4,7 @@ raylib is a simple and easy-to-use library to enjoy videogames programming. https://www.raylib.com/ -Implemented APIs (633) +Implemented APIs (646) ---------------- | Name | Description | @@ -16,7 +16,7 @@ Implemented APIs (633) | sub BeginScissorMode(x, y, width, height) | Begin scissor mode (define screen area for following drawing) | | sub BeginShaderMode(shader) | Begin custom shader drawing | | sub BeginTextureMode(target) | Begin drawing to render texture | -| func ChangeDirectory(dir) | Change working directory, return true on success | +| func ChangeDirectory(dirPath) | Change working directory, return true on success | | func CheckCollisionBoxes(box1, box2) | Check collision between two bounding boxes | | func CheckCollisionBoxSphere(box, center, radius) | Check collision between box and sphere | | func CheckCollisionCircleLine(center, radius, p1, p2) | Check if circle collides with a line created betweeen two points [p1] and [p2] | @@ -52,10 +52,11 @@ Implemented APIs (633) | func ComputeCRC32(data, dataSize) | Compute CRC32 hash code | | func ComputeMD5(data, dataSize) | Compute MD5 hash code, returns static int[4] (16 bytes) | | func ComputeSHA1(data, dataSize) | Compute SHA1 hash code, returns static int[5] (20 bytes) | +| func ComputeSHA256(data, dataSize) | Compute SHA256 hash code, returns static int[8] (32 bytes) | | func createPhysicsbodycircle() | n/a | | func createPhysicsbodypolygon() | n/a | | func createPhysicsbodyrectangle() | n/a | -| func DecodeDataBase64(data, outputSize) | Decode Base64 string data, memory must be MemFree() | +| func DecodeDataBase64(text, outputSize) | Decode Base64 string (expected NULL terminated), memory must be MemFree() | | func DecompressData(compData, compDataSize, dataSize) | Decompress data (DEFLATE algorithm), memory must be MemFree() | | func destroyPhysicsbody() | n/a | | func DirectoryExists(dirPath) | Check if a directory path exists | @@ -85,11 +86,14 @@ Implemented APIs (633) | sub DrawCylinderWiresEx(startPos, endPos, startRadius, endRadius, sides, color) | Draw a cylinder wires with base at startPos and top at endPos | | sub DrawEllipse(centerX, centerY, radiusH, radiusV, color) | Draw ellipse | | sub DrawEllipseLines(centerX, centerY, radiusH, radiusV, color) | Draw ellipse outline | +| sub DrawEllipseLinesV(center, radiusH, radiusV, color) | Draw ellipse outline (Vector version) | +| sub DrawEllipseV(center, radiusH, radiusV, color) | Draw ellipse (Vector version) | | sub DrawFPS(posX, posY) | Draw current FPS | | sub DrawGrid(slices, spacing) | Draw a grid (centered at (0, 0, 0)) | | sub DrawLine(startPosX, startPosY, endPosX, endPosY, color) | Draw a line | | sub DrawLine3D(startPos, endPos, color) | Draw a line in 3D world space | | sub DrawLineBezier(startPos, endPos, thick, color) | Draw line segment cubic-bezier in-out interpolation | +| sub DrawLineDashed(startPos, endPos, dashSize, spaceSize, color) | Draw a dashed line | | sub DrawLineEx(startPos, endPos, thick, color) | Draw a line (using triangles/quads) | | sub DrawLineStrip(points, pointCount, color) | Draw lines sequence (using gl lines) | | sub DrawLineV(startPos, endPos, color) | Draw a line (using gl lines) | @@ -108,7 +112,7 @@ Implemented APIs (633) | sub DrawPolyLinesEx(center, sides, radius, rotation, lineThick, color) | Draw a polygon outline of n sides with extended parameters | | sub DrawRay(ray, color) | Draw a ray line | | sub DrawRectangle(posX, posY, width, height, color) | Draw a color-filled rectangle | -| sub DrawRectangleGradientEx(rec, topLeft, bottomLeft, topRight, bottomRight) | Draw a gradient-filled rectangle with custom vertex colors | +| sub DrawRectangleGradientEx(rec, topLeft, bottomLeft, bottomRight, topRight) | Draw a gradient-filled rectangle with custom vertex colors | | sub DrawRectangleGradientH(posX, posY, width, height, left, right) | Draw a horizontal-gradient-filled rectangle | | sub DrawRectangleGradientV(posX, posY, width, height, top, bottom) | Draw a vertical-gradient-filled rectangle | | sub DrawRectangleLines(posX, posY, width, height, color) | Draw rectangle outline | @@ -153,7 +157,7 @@ Implemented APIs (633) | sub DrawTriangleStrip3D(points, pointCount, color) | Draw a triangle strip defined by points | | sub EnableCursor() | Enables cursor (unlock cursor) | | sub EnableEventWaiting() | Enable waiting for events on EndDrawing(), no automatic event polling | -| func EncodeDataBase64(data, dataSize, outputSize) | Encode data to Base64 string, memory must be MemFree() | +| func EncodeDataBase64(data, dataSize, outputSize) | Encode data to Base64 string (includes NULL terminator), memory must be MemFree() | | sub EndBlendMode() | End blending mode (reset to default: alpha blending) | | sub EndDrawing() | End canvas drawing and swap buffers (double buffering) | | sub EndMode2D() | Ends 2D mode with custom camera | @@ -173,7 +177,13 @@ Implemented APIs (633) | func ExportWave(wave, fileName) | Export wave data to file, returns true on success | | func ExportWaveAsCode(wave, fileName) | Export wave sample data to code (.h), returns true on success | | func Fade(color, alpha) | Get color with alpha applied, alpha goes from 0.0f to 1.0f | +| func FileCopy(srcPath, dstPath) | Copy file from one path to another, dstPath created if it doesn't exist | | func FileExists(fileName) | Check if file exists | +| func FileMove(srcPath, dstPath) | Move file from one directory to another, dstPath created if it doesn't exist | +| func FileRemove(fileName) | Remove file (if exists) | +| func FileRename(fileName, fileRename) | Rename file (if exists) | +| func FileTextFindIndex(fileName, search) | Find text in existing file | +| func FileTextReplace(fileName, search, replacement) | Replace text in an existing file | | func GenImageCellular(width, height, tileSize) | Generate image: cellular algorithm, bigger tileSize means bigger cells | | func GenImageChecked(width, height, checksX, checksY, col1, col2) | Generate image: checked | | func GenImageColor(width, height, color) | Generate image: plain color | @@ -218,8 +228,8 @@ Implemented APIs (633) | func GetFontDefault() | Get the default Font | | func GetFPS() | Get current FPS | | func GetFrameTime() | Get time in seconds for last frame drawn (delta time) | -| func GetGamepadAxisCount(gamepad) | Get gamepad axis count for a gamepad | -| func GetGamepadAxisMovement(gamepad, axis) | Get axis movement value for a gamepad axis | +| func GetGamepadAxisCount(gamepad) | Get axis count for a gamepad | +| func GetGamepadAxisMovement(gamepad, axis) | Get movement value for a gamepad axis | | func GetGamepadButtonPressed() | Get the last gamepad button pressed | | func GetGamepadName(gamepad) | Get gamepad internal name id | | func GetGestureDetected() | Get latest detected gesture | @@ -282,6 +292,7 @@ Implemented APIs (633) | func GetSplinePointBezierQuad(p1, c2, p3, t) | Get (evaluate) spline point: Quadratic Bezier | | func GetSplinePointCatmullRom(p1, p2, p3, p4, t) | Get (evaluate) spline point: Catmull-Rom | | func GetSplinePointLinear(startPos, endPos, t) | Get (evaluate) spline point: Linear | +| func GetTextBetween(text, begin, end) | Get text between two strings | | func GetTime() | Get elapsed time in seconds since InitWindow() | | func GetTouchPointCount() | Get number of touch points | | func GetTouchPointId(index) | Get touch point identifier for given index | @@ -396,7 +407,7 @@ Implemented APIs (633) | func IsCursorHidden() | Check if cursor is not visible | | func IsCursorOnScreen() | Check if cursor is on the screen | | func IsFileDropped() | Check if a file has been dropped into window | -| func IsFileExtension(fileName, ext) | Check file extension (including point: .png, .wav) | +| func IsFileExtension(fileName, ext) | Check file extension (recommended include point: .png, .wav) | | func IsFileNameValid(fileName) | Check if fileName is valid for the platform/OS | | func IsFontValid(font) | Check if a font is valid (font data loaded, WARNING: GPU texture not checked) | | func IsGamepadAvailable(gamepad) | Check if a gamepad is available | @@ -498,7 +509,7 @@ Implemented APIs (633) | func pollevents() | n/a | | sub PollInputEvents() | Register all input events | | func resetPhysics() | n/a | -| sub RestoreWindow() | Set window state: not minimized/maximized | +| sub RestoreWindow() | Restore window from being minimized/maximized | | sub ResumeAudioStream(stream) | Resume audio stream | | sub ResumeMusicStream(music) | Resume playing paused music | | sub ResumeSound(sound) | Resume a paused sound | @@ -525,7 +536,7 @@ Implemented APIs (633) | sub SetMouseOffset(offsetX, offsetY) | Set mouse offset | | sub SetMousePosition(x, y) | Set mouse position XY | | sub SetMouseScale(scaleX, scaleY) | Set mouse scaling | -| sub SetMusicPan(music, pan) | Set pan for a music (0.5 is center) | +| sub SetMusicPan(music, pan) | Set pan for a music (-1.0 left, 0.0 center, 1.0 right) | | sub SetMusicPitch(music, pitch) | Set pitch for a music (1.0 is base level) | | sub SetMusicVolume(music, volume) | Set volume for music (1.0 is max level) | | func setPhysicsbodyangularvelocity() | n/a | @@ -555,7 +566,7 @@ Implemented APIs (633) | sub SetShaderValueTexture(shader, locIndex, texture) | Set shader uniform value and bind the texture (sampler2d) | | sub SetShaderValueV(shader, locIndex, value, uniformType, count) | Set shader uniform value vector | | sub SetShapesTexture(texture, source) | Set texture and rectangle to be used on shapes drawing | -| sub SetSoundPan(sound, pan) | Set pan for a sound (0.5 is center) | +| sub SetSoundPan(sound, pan) | Set pan for a sound (-1.0 left, 0.0 center, 1.0 right) | | sub SetSoundPitch(sound, pitch) | Set pitch for a sound (1.0 is base level) | | sub SetSoundVolume(sound, volume) | Set volume for a sound (1.0 is max level) | | sub SetTargetFPS(fps) | Set target FPS (maximum) | @@ -582,14 +593,16 @@ Implemented APIs (633) | sub StopSound(sound) | Stop playing a sound | | sub SwapScreenBuffer() | Swap back buffer with front buffer (screen drawing) | | sub TakeScreenshot(fileName) | Takes a screenshot of current screen (filename extension defines format) | -| sub TextAppend(text, append, position) | Append text at specific position and move cursor! | +| sub TextAppend(text, append, position) | Append text at specific position and move cursor | | func TextCopy(dst, src) | Copy one string to another, returns bytes copied | -| func TextFindIndex(text, find) | Find first text occurrence within a string | +| func TextFindIndex(text, search) | Find first text occurrence within a string, -1 if not found | | func TextFormat(text, args) | Text formatting with variables (sprintf() style) | | func TextInsert(text, insert, position) | Insert text in a position (WARNING: memory must be freed!) | | func TextIsEqual(text1, text2) | Check if two text string are equal | | func TextLength(text) | Get text length, checks for '\\0' ending | -| func TextReplace(text, replace, by) | Replace text string (WARNING: memory must be freed!) | +| func TextRemoveSpaces(text) | Remove text spaces, concat words | +| func TextReplace(text, search, replacement) | Replace text string (WARNING: memory must be freed!) | +| func TextReplaceBetween(text, begin, end, replacement) | Replace text between two specific strings (WARNING: memory must be freed!) | | func TextSubtext(text, position, length) | Get a piece of a text string | | func TextToCamel(text) | Get Camel case notation version of provided string | | func TextToFloat(text) | Get float value from text | @@ -632,9 +645,9 @@ Implemented APIs (633) | sub UpdateModelAnimationBones(model, anim, frame) | Update model animation mesh bone matrices (GPU skinning) | | sub UpdateMusicStream(music) | Updates buffers for music streaming | | func updatePhysics() | n/a | -| sub UpdateSound(sound, data, sampleCount) | Update sound buffer with new data | -| sub UpdateTexture(texture, pixels) | Update GPU texture with new data | -| sub UpdateTextureRec(texture, rec, pixels) | Update GPU texture rectangle with new data | +| sub UpdateSound(sound, data, sampleCount) | Update sound buffer with new data (default data format: 32 bit float, stereo) | +| sub UpdateTexture(texture, pixels) | Update GPU texture with new data (pixels should be able to fill texture) | +| sub UpdateTextureRec(texture, rec, pixels) | Update GPU texture rectangle with new data (pixels and rec should fit in texture) | | sub UploadMesh(mesh, dynamic) | Upload mesh vertex data in GPU and provide VAO/VBO ids | | func waitevents() | n/a | | sub WaitTime(seconds) | Wait for some time (halt program execution) | @@ -661,6 +674,7 @@ Unimplemented APIs | LoadFontData | Load font data for further use | | LoadMaterialDefault | Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) | | LoadMaterials | Load materials from model file | +| LoadTextLines | Load text as separate lines ('\\n') | | LoadVrStereoConfig | Load VR stereo config for VR simulator device parameters | | SetAudioStreamCallback | Audio thread callback to request new data | | SetLoadFileDataCallback | Set custom file binary data loader | @@ -670,8 +684,9 @@ Unimplemented APIs | SetSaveFileTextCallback | Set custom file text data saver | | SetTraceLogCallback | Set custom trace log | | TextJoin | Join text strings with delimiter | -| TextSplit | Split text into multiple strings | +| TextSplit | Split text into multiple strings, using MAX_TEXTSPLIT_COUNT static strings | | UnloadFontData | Unload font chars info data (RAM) | | UnloadMaterial | Unload material from GPU memory (VRAM) | +| UnloadTextLines | Unload text lines | | UnloadVrStereoConfig | Unload VR stereo config | diff --git a/raylib/func-def.h b/raylib/func-def.h index 831f691..42552b2 100644 --- a/raylib/func-def.h +++ b/raylib/func-def.h @@ -29,6 +29,7 @@ {2, 2, "COMPUTECRC32", cmd_computecrc32}, {2, 2, "COMPUTEMD5", cmd_computemd5}, {2, 2, "COMPUTESHA1", cmd_computesha1}, + {2, 2, "COMPUTESHA256", cmd_computesha256}, {1, 1, "DECODEDATABASE64", cmd_decodedatabase64}, {2, 2, "DECOMPRESSDATA", cmd_decompressdata}, {1, 1, "DIRECTORYEXISTS", cmd_directoryexists}, @@ -44,7 +45,13 @@ {2, 2, "EXPORTWAVE", cmd_exportwave}, {2, 2, "EXPORTWAVEASCODE", cmd_exportwaveascode}, {2, 2, "FADE", cmd_fade}, + {2, 2, "FILECOPY", cmd_filecopy}, {1, 1, "FILEEXISTS", cmd_fileexists}, + {2, 2, "FILEMOVE", cmd_filemove}, + {1, 1, "FILEREMOVE", cmd_fileremove}, + {2, 2, "FILERENAME", cmd_filerename}, + {2, 2, "FILETEXTFINDINDEX", cmd_filetextfindindex}, + {3, 3, "FILETEXTREPLACE", cmd_filetextreplace}, {3, 3, "GENIMAGECELLULAR", cmd_genimagecellular}, {6, 6, "GENIMAGECHECKED", cmd_genimagechecked}, {3, 3, "GENIMAGECOLOR", cmd_genimagecolor}, @@ -146,6 +153,7 @@ {4, 4, "GETSPLINEPOINTBEZIERQUAD", cmd_getsplinepointbezierquad}, {5, 5, "GETSPLINEPOINTCATMULLROM", cmd_getsplinepointcatmullrom}, {3, 3, "GETSPLINEPOINTLINEAR", cmd_getsplinepointlinear}, + {3, 3, "GETTEXTBETWEEN", cmd_gettextbetween}, {0, 0, "GETTIME", cmd_gettime}, {0, 0, "GETTOUCHPOINTCOUNT", cmd_gettouchpointcount}, {1, 1, "GETTOUCHPOINTID", cmd_gettouchpointid}, @@ -218,9 +226,9 @@ {1, 1, "LOADFILEDATA", cmd_loadfiledata}, {1, 1, "LOADFILETEXT", cmd_loadfiletext}, {1, 1, "LOADFONT", cmd_loadfont}, - {3, 3, "LOADFONTEX", cmd_loadfontex}, + {4, 4, "LOADFONTEX", cmd_loadfontex}, {3, 3, "LOADFONTFROMIMAGE", cmd_loadfontfromimage}, - {5, 5, "LOADFONTFROMMEMORY", cmd_loadfontfrommemory}, + {6, 6, "LOADFONTFROMMEMORY", cmd_loadfontfrommemory}, {1, 1, "LOADIMAGE", cmd_loadimage}, {1, 1, "LOADIMAGEANIM", cmd_loadimageanim}, {3, 3, "LOADIMAGEANIMFROMMEMORY", cmd_loadimageanimfrommemory}, @@ -259,7 +267,9 @@ {3, 3, "TEXTINSERT", cmd_textinsert}, {2, 2, "TEXTISEQUAL", cmd_textisequal}, {1, 1, "TEXTLENGTH", cmd_textlength}, + {1, 1, "TEXTREMOVESPACES", cmd_textremovespaces}, {3, 3, "TEXTREPLACE", cmd_textreplace}, + {4, 4, "TEXTREPLACEBETWEEN", cmd_textreplacebetween}, {3, 3, "TEXTSUBTEXT", cmd_textsubtext}, {1, 1, "TEXTTOCAMEL", cmd_texttocamel}, {1, 1, "TEXTTOFLOAT", cmd_texttofloat}, diff --git a/raylib/func.h b/raylib/func.h index cc97d4a..53ccee6 100644 --- a/raylib/func.h +++ b/raylib/func.h @@ -2,8 +2,8 @@ // Change working directory, return true on success // static int cmd_changedirectory(int argc, slib_par_t *params, var_t *retval) { - auto dir = get_param_str(argc, params, 0, 0); - auto fnResult = ChangeDirectory(dir); + auto dirPath = get_param_str(argc, params, 0, 0); + auto fnResult = ChangeDirectory(dirPath); v_setint(retval, fnResult); return 1; } @@ -358,12 +358,23 @@ static int cmd_computesha1(int argc, slib_par_t *params, var_t *retval) { } // -// Decode Base64 string data, memory must be MemFree() +// Compute SHA256 hash code, returns static int[8] (32 bytes) +// +static int cmd_computesha256(int argc, slib_par_t *params, var_t *retval) { + auto data = (unsigned char *)get_param_str(argc, params, 0, 0); + auto dataSize = get_param_int(argc, params, 1, 0); + auto fnResult = (var_int_t)ComputeSHA256(data, dataSize); + v_setint(retval, fnResult); + return 1; +} + +// +// Decode Base64 string (expected NULL terminated), memory must be MemFree() // static int cmd_decodedatabase64(int argc, slib_par_t *params, var_t *retval) { - auto data = (const unsigned char *)get_param_str(argc, params, 0, 0); + auto text = get_param_str(argc, params, 0, 0); auto outputSize = 0; - auto fnResult = (const char *)DecodeDataBase64(data, &outputSize); + auto fnResult = (const char *)DecodeDataBase64(text, &outputSize); v_setstrn(retval, fnResult, outputSize); MemFree((void *)fnResult); return 1; @@ -393,7 +404,7 @@ static int cmd_directoryexists(int argc, slib_par_t *params, var_t *retval) { } // -// Encode data to Base64 string, memory must be MemFree() +// Encode data to Base64 string (includes NULL terminator), memory must be MemFree() // static int cmd_encodedatabase64(int argc, slib_par_t *params, var_t *retval) { auto data = (const unsigned char *)get_param_str(argc, params, 0, 0); @@ -583,6 +594,17 @@ static int cmd_fade(int argc, slib_par_t *params, var_t *retval) { return 1; } +// +// Copy file from one path to another, dstPath created if it doesn't exist +// +static int cmd_filecopy(int argc, slib_par_t *params, var_t *retval) { + auto srcPath = get_param_str(argc, params, 0, 0); + auto dstPath = get_param_str(argc, params, 1, 0); + auto fnResult = FileCopy(srcPath, dstPath); + v_setint(retval, fnResult); + return 1; +} + // // Check if file exists // @@ -593,6 +615,61 @@ static int cmd_fileexists(int argc, slib_par_t *params, var_t *retval) { return 1; } +// +// Move file from one directory to another, dstPath created if it doesn't exist +// +static int cmd_filemove(int argc, slib_par_t *params, var_t *retval) { + auto srcPath = get_param_str(argc, params, 0, 0); + auto dstPath = get_param_str(argc, params, 1, 0); + auto fnResult = FileMove(srcPath, dstPath); + v_setint(retval, fnResult); + return 1; +} + +// +// Remove file (if exists) +// +static int cmd_fileremove(int argc, slib_par_t *params, var_t *retval) { + auto fileName = get_param_str(argc, params, 0, 0); + auto fnResult = FileRemove(fileName); + v_setint(retval, fnResult); + return 1; +} + +// +// Rename file (if exists) +// +static int cmd_filerename(int argc, slib_par_t *params, var_t *retval) { + auto fileName = get_param_str(argc, params, 0, 0); + auto fileRename = get_param_str(argc, params, 1, 0); + auto fnResult = FileRename(fileName, fileRename); + v_setint(retval, fnResult); + return 1; +} + +// +// Find text in existing file +// +static int cmd_filetextfindindex(int argc, slib_par_t *params, var_t *retval) { + auto fileName = get_param_str(argc, params, 0, 0); + auto search = get_param_str(argc, params, 1, 0); + auto fnResult = FileTextFindIndex(fileName, search); + v_setint(retval, fnResult); + return 1; +} + +// +// Replace text in an existing file +// +static int cmd_filetextreplace(int argc, slib_par_t *params, var_t *retval) { + auto fileName = get_param_str(argc, params, 0, 0); + auto search = get_param_str(argc, params, 1, 0); + auto replacement = get_param_str(argc, params, 2, 0); + auto fnResult = FileTextReplace(fileName, search, replacement); + v_setint(retval, fnResult); + return 1; +} + // // Generate image: cellular algorithm, bigger tileSize means bigger cells // @@ -1073,7 +1150,7 @@ static int cmd_getframetime(int argc, slib_par_t *params, var_t *retval) { } // -// Get gamepad axis count for a gamepad +// Get axis count for a gamepad // static int cmd_getgamepadaxiscount(int argc, slib_par_t *params, var_t *retval) { auto gamepad = get_param_int(argc, params, 0, 0); @@ -1083,7 +1160,7 @@ static int cmd_getgamepadaxiscount(int argc, slib_par_t *params, var_t *retval) } // -// Get axis movement value for a gamepad axis +// Get movement value for a gamepad axis // static int cmd_getgamepadaxismovement(int argc, slib_par_t *params, var_t *retval) { auto gamepad = get_param_int(argc, params, 0, 0); @@ -1734,6 +1811,18 @@ static int cmd_getsplinepointlinear(int argc, slib_par_t *params, var_t *retval) return 1; } +// +// Get text between two strings +// +static int cmd_gettextbetween(int argc, slib_par_t *params, var_t *retval) { + auto text = get_param_str(argc, params, 0, 0); + auto begin = get_param_str(argc, params, 1, 0); + auto end = get_param_str(argc, params, 2, 0); + auto fnResult = (const char *)GetTextBetween(text, begin, end); + v_setstr(retval, fnResult); + return 1; +} + // // Get elapsed time in seconds since InitWindow() // @@ -2028,7 +2117,7 @@ static int cmd_isfiledropped(int argc, slib_par_t *params, var_t *retval) { } // -// Check file extension (including point: .png, .wav) +// Check file extension (recommended include point: .png, .wav) // static int cmd_isfileextension(int argc, slib_par_t *params, var_t *retval) { auto fileName = get_param_str(argc, params, 0, 0); @@ -2575,8 +2664,8 @@ static int cmd_loadfont(int argc, slib_par_t *params, var_t *retval) { static int cmd_loadfontex(int argc, slib_par_t *params, var_t *retval) { auto fileName = get_param_str(argc, params, 0, 0); auto fontSize = get_param_int(argc, params, 1, 0); - auto codepoints = (int *)0; - auto codepointCount = get_param_int(argc, params, 2, 0); + auto codepoints = (const int *)get_param_int_t(argc, params, 2, 0); + auto codepointCount = get_param_int(argc, params, 3, 0); auto fnResult = LoadFontEx(fileName, fontSize, codepoints, codepointCount); v_setfont(retval, fnResult); return 1; @@ -2608,8 +2697,8 @@ static int cmd_loadfontfrommemory(int argc, slib_par_t *params, var_t *retval) { auto fileData = (const unsigned char *)get_param_str(argc, params, 1, 0); auto dataSize = get_param_int(argc, params, 2, 0); auto fontSize = get_param_int(argc, params, 3, 0); - auto codepoints = (int *)0; - auto codepointCount = get_param_int(argc, params, 4, 0); + auto codepoints = (const int *)get_param_int_t(argc, params, 4, 0); + auto codepointCount = get_param_int(argc, params, 5, 0); auto fnResult = LoadFontFromMemory(fileType, fileData, dataSize, fontSize, codepoints, codepointCount); v_setfont(retval, fnResult); return 1; @@ -3017,7 +3106,7 @@ static int cmd_savefiledata(int argc, slib_par_t *params, var_t *retval) { // static int cmd_savefiletext(int argc, slib_par_t *params, var_t *retval) { auto fileName = get_param_str(argc, params, 0, 0); - auto text = (char *)get_param_str(argc, params, 1, 0); + auto text = get_param_str(argc, params, 1, 0); auto fnResult = SaveFileText(fileName, text); v_setint(retval, fnResult); return 1; @@ -3045,12 +3134,12 @@ static int cmd_textcopy(int argc, slib_par_t *params, var_t *retval) { } // -// Find first text occurrence within a string +// Find first text occurrence within a string, -1 if not found // static int cmd_textfindindex(int argc, slib_par_t *params, var_t *retval) { auto text = get_param_str(argc, params, 0, 0); - auto find = get_param_str(argc, params, 1, 0); - auto fnResult = TextFindIndex(text, find); + auto search = get_param_str(argc, params, 1, 0); + auto fnResult = TextFindIndex(text, search); v_setint(retval, fnResult); return 1; } @@ -3088,14 +3177,37 @@ static int cmd_textlength(int argc, slib_par_t *params, var_t *retval) { return 1; } +// +// Remove text spaces, concat words +// +static int cmd_textremovespaces(int argc, slib_par_t *params, var_t *retval) { + auto text = get_param_str(argc, params, 0, 0); + auto fnResult = (const char *)TextRemoveSpaces(text); + v_setstr(retval, fnResult); + return 1; +} + // // Replace text string (WARNING: memory must be freed!) // static int cmd_textreplace(int argc, slib_par_t *params, var_t *retval) { auto text = get_param_str(argc, params, 0, 0); - auto replace = get_param_str(argc, params, 1, 0); - auto by = get_param_str(argc, params, 2, 0); - auto fnResult = (const char *)TextReplace(text, replace, by); + auto search = get_param_str(argc, params, 1, 0); + auto replacement = get_param_str(argc, params, 2, 0); + auto fnResult = (const char *)TextReplace(text, search, replacement); + v_setstr(retval, fnResult); + return 1; +} + +// +// Replace text between two specific strings (WARNING: memory must be freed!) +// +static int cmd_textreplacebetween(int argc, slib_par_t *params, var_t *retval) { + auto text = get_param_str(argc, params, 0, 0); + auto begin = get_param_str(argc, params, 1, 0); + auto end = get_param_str(argc, params, 2, 0); + auto replacement = get_param_str(argc, params, 3, 0); + auto fnResult = (const char *)TextReplaceBetween(text, begin, end, replacement); v_setstr(retval, fnResult); return 1; } diff --git a/raylib/mkraylib.bas b/raylib/mkraylib.bas index ee64008..e37d4c5 100644 --- a/raylib/mkraylib.bas +++ b/raylib/mkraylib.bas @@ -2,7 +2,7 @@ rem rem generate a skelton main.cpp from json input rem -tload "raylib/parser/raylib_api.json", s, 1 +tload "raylib/tools/rlparser/output/raylib_api.json", s, 1 api = array(s) func comparator(l, r) diff --git a/raylib/mkreadme.bas b/raylib/mkreadme.bas index 56230b9..0f98b50 100644 --- a/raylib/mkreadme.bas +++ b/raylib/mkreadme.bas @@ -20,7 +20,7 @@ load("main.cpp") load("proc-def.h") load("func-def.h") -tload "raylib/parser/raylib_api.json", s, 1 +tload "raylib/tools/rlparser/output/raylib_api.json", s, 1 api = array(s) functions = {} for fun in api("functions") diff --git a/raylib/proc-def.h b/raylib/proc-def.h index f509533..e4456bf 100644 --- a/raylib/proc-def.h +++ b/raylib/proc-def.h @@ -35,11 +35,14 @@ {6, 6, "DRAWCYLINDERWIRESEX", cmd_drawcylinderwiresex}, {5, 5, "DRAWELLIPSE", cmd_drawellipse}, {5, 5, "DRAWELLIPSELINES", cmd_drawellipselines}, + {4, 4, "DRAWELLIPSELINESV", cmd_drawellipselinesv}, + {4, 4, "DRAWELLIPSEV", cmd_drawellipsev}, {2, 2, "DRAWFPS", cmd_drawfps}, {2, 2, "DRAWGRID", cmd_drawgrid}, {5, 5, "DRAWLINE", cmd_drawline}, {3, 3, "DRAWLINE3D", cmd_drawline3d}, {4, 4, "DRAWLINEBEZIER", cmd_drawlinebezier}, + {5, 5, "DRAWLINEDASHED", cmd_drawlinedashed}, {4, 4, "DRAWLINEEX", cmd_drawlineex}, {3, 3, "DRAWLINESTRIP", cmd_drawlinestrip}, {3, 3, "DRAWLINEV", cmd_drawlinev}, diff --git a/raylib/proc.h b/raylib/proc.h index ce6790c..f549c73 100644 --- a/raylib/proc.h +++ b/raylib/proc.h @@ -449,6 +449,30 @@ static int cmd_drawellipselines(int argc, slib_par_t *params, var_t *retval) { return 1; } +// +// Draw ellipse outline (Vector version) +// +static int cmd_drawellipselinesv(int argc, slib_par_t *params, var_t *retval) { + auto center = get_param_vec2(argc, params, 0); + auto radiusH = get_param_num(argc, params, 1, 0); + auto radiusV = get_param_num(argc, params, 2, 0); + auto color = get_param_color(argc, params, 3); + DrawEllipseLinesV(center, radiusH, radiusV, color); + return 1; +} + +// +// Draw ellipse (Vector version) +// +static int cmd_drawellipsev(int argc, slib_par_t *params, var_t *retval) { + auto center = get_param_vec2(argc, params, 0); + auto radiusH = get_param_num(argc, params, 1, 0); + auto radiusV = get_param_num(argc, params, 2, 0); + auto color = get_param_color(argc, params, 3); + DrawEllipseV(center, radiusH, radiusV, color); + return 1; +} + // // Draw current FPS // @@ -505,6 +529,19 @@ static int cmd_drawlinebezier(int argc, slib_par_t *params, var_t *retval) { return 1; } +// +// Draw a dashed line +// +static int cmd_drawlinedashed(int argc, slib_par_t *params, var_t *retval) { + auto startPos = get_param_vec2(argc, params, 0); + auto endPos = get_param_vec2(argc, params, 1); + auto dashSize = get_param_int(argc, params, 2, 0); + auto spaceSize = get_param_int(argc, params, 3, 0); + auto color = get_param_color(argc, params, 4); + DrawLineDashed(startPos, endPos, dashSize, spaceSize, color); + return 1; +} + // // Draw a line (using triangles/quads) // @@ -765,9 +802,9 @@ static int cmd_drawrectanglegradientex(int argc, slib_par_t *params, var_t *retv auto rec = get_param_rect(argc, params, 0); auto topLeft = get_param_color(argc, params, 1); auto bottomLeft = get_param_color(argc, params, 2); - auto topRight = get_param_color(argc, params, 3); - auto bottomRight = get_param_color(argc, params, 4); - DrawRectangleGradientEx(rec, topLeft, bottomLeft, topRight, bottomRight); + auto bottomRight = get_param_color(argc, params, 3); + auto topRight = get_param_color(argc, params, 4); + DrawRectangleGradientEx(rec, topLeft, bottomLeft, bottomRight, topRight); return 1; } @@ -2427,7 +2464,7 @@ static int cmd_pollinputevents(int argc, slib_par_t *params, var_t *retval) { } // -// Set window state: not minimized/maximized +// Restore window from being minimized/maximized // static int cmd_restorewindow(int argc, slib_par_t *params, var_t *retval) { RestoreWindow(); @@ -2684,7 +2721,7 @@ static int cmd_setmousescale(int argc, slib_par_t *params, var_t *retval) { } // -// Set pan for a music (0.5 is center) +// Set pan for a music (-1.0 left, 0.0 center, 1.0 right) // static int cmd_setmusicpan(int argc, slib_par_t *params, var_t *retval) { int result; @@ -2815,7 +2852,7 @@ static int cmd_setshapestexture(int argc, slib_par_t *params, var_t *retval) { } // -// Set pan for a sound (0.5 is center) +// Set pan for a sound (-1.0 left, 0.0 center, 1.0 right) // static int cmd_setsoundpan(int argc, slib_par_t *params, var_t *retval) { int result; @@ -3123,7 +3160,7 @@ static int cmd_takescreenshot(int argc, slib_par_t *params, var_t *retval) { } // -// Append text at specific position and move cursor! +// Append text at specific position and move cursor // static int cmd_textappend(int argc, slib_par_t *params, var_t *retval) { auto text = (char *)get_param_str(argc, params, 0, 0); @@ -3543,7 +3580,7 @@ static int cmd_updatemusicstream(int argc, slib_par_t *params, var_t *retval) { } // -// Update sound buffer with new data +// Update sound buffer with new data (default data format: 32 bit float, stereo) // static int cmd_updatesound(int argc, slib_par_t *params, var_t *retval) { int result; @@ -3560,7 +3597,7 @@ static int cmd_updatesound(int argc, slib_par_t *params, var_t *retval) { } // -// Update GPU texture rectangle with new data +// Update GPU texture rectangle with new data (pixels and rec should fit in texture) // static int cmd_updatetexturerec(int argc, slib_par_t *params, var_t *retval) { int result; diff --git a/raylib/raylib b/raylib/raylib index eb8a343..c610d22 160000 --- a/raylib/raylib +++ b/raylib/raylib @@ -1 +1 @@ -Subproject commit eb8a343e313967a51cb302ac9bb1206a05727d13 +Subproject commit c610d228a244f930ad53492604640f39584c66da From e2ae4b9005ab2da38323a6c3c15caab2f291f0ed Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Fri, 23 Jan 2026 16:53:06 +1030 Subject: [PATCH 12/17] COMMON: fix autogen.sh --- autogen.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/autogen.sh b/autogen.sh index 47736e2..318d661 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1,3 +1,5 @@ +#!/bin/bash + # This file is part of SmallBASIC # # Copyright(C) 2001-2020 Chris Warren-Smith. From 0967b93b86c24901f3ad5638492f0127db894d9c Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Fri, 23 Jan 2026 17:06:47 +1030 Subject: [PATCH 13/17] RAYLIB: fix reference to raylib_api.json --- raylib/Makefile.am | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/raylib/Makefile.am b/raylib/Makefile.am index 0885662..84c24b5 100644 --- a/raylib/Makefile.am +++ b/raylib/Makefile.am @@ -5,12 +5,13 @@ # Download the GNU Public License (GPL) from www.gnu.org # -generated = func-def.h proc-def.h proc.h func.h sbasic=sbasic +generated = func-def.h proc-def.h proc.h func.h +raylib_api_json=raylib/tools/rlparser/output/raylib_api.json CLEANFILES = $(generated) -raylib/tools/rlparser/output/raylib_api.json: raylib/src/raylib.h raylib/tools/rlparser/rlparser.c +$(raylib_api_json): raylib/src/raylib.h raylib/tools/rlparser/rlparser.c (cd raylib/tools/rlparser && make && ./rlparser --format JSON --input ../../src/raylib.h --output output/raylib_api.json) UNSUPPORTED.md: $(generated) @@ -19,7 +20,7 @@ UNSUPPORTED.md: $(generated) README.md: $(generated) mkreadme.bas UNSUPPORTED.md $(sbasic) mkreadme.bas `grep RAYLIB_VERSION raylib/src/raylib.h | sed 's/#define RAYLIB_VERSION//g' | sed 's/\"//g'` > README.md -$(generated): raylib/parser/raylib_api.json mkraylib.bas +$(generated): $(raylib_api_json) mkraylib.bas $(sbasic) mkraylib.bas $@ > $@ @touch main.cpp From 7a268902a1b88f84ca2d314e63312923b7d84b49 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Mon, 9 Feb 2026 08:59:24 +1030 Subject: [PATCH 14/17] LLAMA: add support for grammar --- llama/llama-sb.cpp | 55 ++++++++++++++++++++++++++++++++-------------- llama/llama-sb.h | 7 +++++- llama/main.cpp | 41 +++++++++++++++++++++++++++++++++- 3 files changed, 85 insertions(+), 18 deletions(-) diff --git a/llama/llama-sb.cpp b/llama/llama-sb.cpp index 2bff5e8..273bf49 100644 --- a/llama/llama-sb.cpp +++ b/llama/llama-sb.cpp @@ -31,7 +31,8 @@ Llama::Llama() : _min_p(0), _top_k(0), _max_tokens(0), - _log_level(GGML_LOG_LEVEL_CONT) { + _log_level(GGML_LOG_LEVEL_CONT), + _seed(LLAMA_DEFAULT_SEED) { llama_log_set([](enum ggml_log_level level, const char * text, void *user_data) { Llama *llama = (Llama *)user_data; if (level > llama->_log_level) { @@ -63,6 +64,9 @@ void Llama::reset() { _top_p = 1.0f; _min_p = 0.0f; _max_tokens = 150; + _grammar_src.clear(); + _grammar_root.clear(); + _seed = LLAMA_DEFAULT_SEED; if (_ctx) { llama_memory_clear(llama_get_memory(_ctx), true); } @@ -93,36 +97,53 @@ bool Llama::construct(string model_path, int n_ctx, int n_batch, int n_gpu_layer _last_error = "Failed to create context"; } else { _vocab = llama_model_get_vocab(_model); - - auto sparams = llama_sampler_chain_default_params(); - sparams.no_perf = false; - _sampler = llama_sampler_chain_init(sparams); } } return _last_error.empty(); } -void Llama::configure_sampler() { - llama_sampler_reset(_sampler); +void Llama::set_grammar(const string &src, const string &root) { + _grammar_src = src; + _grammar_root = root; +} + +bool Llama::configure_sampler() { + auto sparams = llama_sampler_chain_default_params(); + sparams.no_perf = false; + llama_sampler *chain = llama_sampler_chain_init(sparams); + + if (!_grammar_src.empty()) { + llama_sampler *grammar = llama_sampler_init_grammar(_vocab, _grammar_src.c_str(), _grammar_root.c_str()); + if (!grammar) { + _last_error = "failed to initialize grammar sampler"; + return false; + } + llama_sampler_chain_add(chain, grammar); + } if (_penalty_last_n != 0 && _penalty_repeat != 1.0f) { auto penalties = llama_sampler_init_penalties(_penalty_last_n, _penalty_repeat, 0.0f, 0.0f); - llama_sampler_chain_add(_sampler, penalties); + llama_sampler_chain_add(chain, penalties); } if (_temperature <= 0.0f) { - llama_sampler_chain_add(_sampler, llama_sampler_init_greedy()); + llama_sampler_chain_add(chain, llama_sampler_init_greedy()); } else { - llama_sampler_chain_add(_sampler, llama_sampler_init_temp(_temperature)); if (_top_k > 0) { - llama_sampler_chain_add(_sampler, llama_sampler_init_top_k(_top_k)); + llama_sampler_chain_add(chain, llama_sampler_init_top_k(_top_k)); } - if (_top_p < 1.0f) { - llama_sampler_chain_add(_sampler, llama_sampler_init_top_p(_top_p, 1)); + if (_top_p < 1.0f || _min_p > 0.0f) { + llama_sampler_chain_add(chain, llama_sampler_init_top_p(_top_p, 1)); } if (_min_p > 0.0f) { - llama_sampler_chain_add(_sampler, llama_sampler_init_min_p(_min_p, 1)); + llama_sampler_chain_add(chain, llama_sampler_init_min_p(_min_p, 1)); } - llama_sampler_chain_add(_sampler, llama_sampler_init_dist(LLAMA_DEFAULT_SEED)); + llama_sampler_chain_add(chain, llama_sampler_init_temp(_temperature)); + llama_sampler_chain_add(chain, llama_sampler_init_dist(_seed)); } + if (_sampler) { + llama_sampler_free(_sampler); + } + _sampler = chain; + return true; } vector Llama::tokenize(const string &prompt) { @@ -201,7 +222,9 @@ bool Llama::make_space_for_tokens(int n_tokens, int keep_min) { } bool Llama::generate(LlamaIter &iter, const string &prompt) { - configure_sampler(); + if (!configure_sampler()) { + return false; + } vector prompt_tokens = tokenize(prompt); if (prompt_tokens.size() == 0) { diff --git a/llama/llama-sb.h b/llama/llama-sb.h index b1da148..070cb60 100644 --- a/llama/llama-sb.h +++ b/llama/llama-sb.h @@ -50,6 +50,8 @@ struct Llama { void set_temperature(float temperature) { _temperature = temperature; } void set_top_k(int top_k) { _top_k = top_k; } void set_top_p(float top_p) { _top_p = top_p; } + void set_grammar(const string &src, const string &root); + void set_seed(unsigned int seed) { _seed = seed; } // error handling const char *last_error() { return _last_error.c_str(); } @@ -58,7 +60,7 @@ struct Llama { private: bool ends_with_sentence_boundary(const string &out); - void configure_sampler(); + bool configure_sampler(); bool make_space_for_tokens(int n_tokens, int keep_min); vector tokenize(const string &prompt); string token_to_string(LlamaIter &iter, llama_token tok); @@ -68,6 +70,8 @@ struct Llama { llama_sampler *_sampler; const llama_vocab *_vocab; vector _stop_sequences; + string _grammar_src; + string _grammar_root; string _last_error; int32_t _penalty_last_n; float _penalty_repeat; @@ -77,4 +81,5 @@ struct Llama { int _top_k; int _max_tokens; int _log_level; + unsigned int _seed; }; diff --git a/llama/main.cpp b/llama/main.cpp index 1c0de21..5bddfed 100644 --- a/llama/main.cpp +++ b/llama/main.cpp @@ -211,6 +211,42 @@ static int cmd_llama_set_top_p(var_s *self, int argc, slib_par_t *arg, var_s *re return result; } +// +// llama.set_grammar("text") +// +static int cmd_llama_set_grammar(var_s *self, int argc, slib_par_t *arg, var_s *retval) { + int result = 0; + if (argc != 1) { + error(retval, "llama.set_grammar", 1, 1); + } else { + int id = get_llama_class_id(self, retval); + if (id != -1) { + Llama &llama = g_llama.at(id); + llama.set_grammar(get_param_str(argc, arg, 0, 0), "root"); + result = 1; + } + } + return result; +} + +// +// llama.set_seed(123) +// +static int cmd_llama_set_seed(var_s *self, int argc, slib_par_t *arg, var_s *retval) { + int result = 0; + if (argc != 1) { + error(retval, "llama.set_seed", 1, 1); + } else { + int id = get_llama_class_id(self, retval); + if (id != -1) { + Llama &llama = g_llama.at(id); + llama.set_seed(get_param_num(argc, arg, 0, 0)); + result = 1; + } + } + return result; +} + // // llama.reset() - make the model forget everything // @@ -355,6 +391,8 @@ static int cmd_create_llama(int argc, slib_par_t *params, var_t *retval) { v_create_callback(retval, "set_temperature", cmd_llama_set_temperature); v_create_callback(retval, "set_top_k", cmd_llama_set_top_k); v_create_callback(retval, "set_top_p", cmd_llama_set_top_p); + v_create_callback(retval, "set_grammar", cmd_llama_set_grammar); + v_create_callback(retval, "set_seed", cmd_llama_set_seed); result = 1; } else { error(retval, llama.last_error()); @@ -388,7 +426,7 @@ int sblib_init(const char *sourceFile) { // // Release variables falling out of scope // -SBLIB_API void sblib_free(int cls_id, int id) { +SBLIB_API int sblib_free(int cls_id, int id) { if (id != -1) { switch (cls_id) { case CLASS_ID_LLAMA: @@ -403,6 +441,7 @@ SBLIB_API void sblib_free(int cls_id, int id) { break; } } + return 0; } // From feb6e6f17a8e69fe7c5f5d046e00ccb3654804a5 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Sat, 18 Apr 2026 16:13:13 +0930 Subject: [PATCH 15/17] LLAMA: implement nitro agent (work in progress) --- llama/llama-sb.cpp | 7 +- llama/llama-sb.h | 2 +- llama/llama.cpp | 2 +- llama/main.cpp | 5 +- llama/samples/nitro_cli.bas | 193 ++++++++++++++++++++++++++++++++++++ llama/samples/skills.md | 139 ++++++++++++++++++++++++++ llama/test_main.cpp | 2 +- 7 files changed, 343 insertions(+), 7 deletions(-) create mode 100644 llama/samples/nitro_cli.bas create mode 100644 llama/samples/skills.md diff --git a/llama/llama-sb.cpp b/llama/llama-sb.cpp index 273bf49..0325509 100644 --- a/llama/llama-sb.cpp +++ b/llama/llama-sb.cpp @@ -40,6 +40,7 @@ Llama::Llama() : } }, this); reset(); + llama_backend_init(); } Llama::~Llama() { @@ -52,6 +53,7 @@ Llama::~Llama() { if (_model) { llama_model_free(_model); } + llama_backend_free(); } void Llama::reset() { @@ -72,14 +74,15 @@ void Llama::reset() { } } -bool Llama::construct(string model_path, int n_ctx, int n_batch, int n_gpu_layers) { +bool Llama::construct(string model_path, int n_ctx, int n_batch, int n_gpu_layers, int log_level) { ggml_backend_load_all(); llama_model_params mparams = llama_model_default_params(); if (n_gpu_layers >= 0) { - mparams.n_gpu_layers = n_gpu_layers; + mparams.n_gpu_layers = n_gpu_layers; } + _log_level = log_level; _model = llama_model_load_from_file(model_path.c_str(), mparams); if (!_model) { _last_error = "Failed to load model"; diff --git a/llama/llama-sb.h b/llama/llama-sb.h index 070cb60..10414c8 100644 --- a/llama/llama-sb.h +++ b/llama/llama-sb.h @@ -33,7 +33,7 @@ struct Llama { ~Llama(); // init - bool construct(string model_path, int n_ctx, int n_batch, int n_gpu_layers); + bool construct(string model_path, int n_ctx, int n_batch, int n_gpu_layers, int log_level); // generation bool generate(LlamaIter &iter, const string &prompt); diff --git a/llama/llama.cpp b/llama/llama.cpp index af3be13..45cac7c 160000 --- a/llama/llama.cpp +++ b/llama/llama.cpp @@ -1 +1 @@ -Subproject commit af3be131c065a38e476c34295bceda6cb956e7d7 +Subproject commit 45cac7ca703fb9085eae62b9121fca01d20177f6 diff --git a/llama/main.cpp b/llama/main.cpp index 5bddfed..7b6bb75 100644 --- a/llama/main.cpp +++ b/llama/main.cpp @@ -377,9 +377,10 @@ static int cmd_create_llama(int argc, slib_par_t *params, var_t *retval) { auto n_ctx = get_param_int(argc, params, 1, 2048); auto n_batch = get_param_int(argc, params, 2, 1024); auto n_gpu_layers = get_param_int(argc, params, 3, -1); + auto n_log_level = get_param_int(argc, params, 4, GGML_LOG_LEVEL_CONT); int id = ++g_nextId; Llama &llama = g_llama[id]; - if (llama.construct(model, n_ctx, n_batch, n_gpu_layers)) { + if (llama.construct(model, n_ctx, n_batch, n_gpu_layers, n_log_level)) { map_init_id(retval, id, CLASS_ID_LLAMA); v_create_callback(retval, "add_stop", cmd_llama_add_stop); v_create_callback(retval, "generate", cmd_llama_generate); @@ -403,7 +404,7 @@ static int cmd_create_llama(int argc, slib_par_t *params, var_t *retval) { } FUNC_SIG lib_func[] = { - {1, 4, "LLAMA", cmd_create_llama}, + {1, 5, "LLAMA", cmd_create_llama}, }; SBLIB_API int sblib_func_count() { diff --git a/llama/samples/nitro_cli.bas b/llama/samples/nitro_cli.bas new file mode 100644 index 0000000..06bffcc --- /dev/null +++ b/llama/samples/nitro_cli.bas @@ -0,0 +1,193 @@ +' =============================================================== +' NITRO AGENT SYSTEM (Enhanced Version) +' Designed for Agentic LLM interaction with external tools. +' =============================================================== + +import llm + +' --- Configuration --- +const model = "models/google_gemma-4-E4B-it-Q4_K_L.gguf" +const knowledge_files = ["skills.md"] ' List of files to load for priming + +' ANSI Color Codes +const RESET = chr(27) + "[0m" +const GREEN = chr(27) + "[32m" +const YELLOW = chr(27) + "[33m" +const CYAN = chr(27) + "[36m" +const RED = chr(27) + "[31m" +const BOLD_CYAN = chr(27) + "[1;36m" + +' Initialize the LLAMA interface +const n_ctx = 8000 +const n_batch = 512 +const llama = llm.llama(model, n_ctx, n_batch, 50) + +llama.add_stop("<|turn|>") +llama.set_max_tokens(4096) +llama.set_temperature(0.2) +llama.set_top_k(40) +llama.set_top_p(0.9) +llama.set_min_p(0.05) ' filter weak tokens +llama.set_penalty_repeat(1.1) ' avoid loops +llama.set_penalty_last_n(256); ' longer memory + +' +' Displays the welcome message +' +sub welcome_message() + print + print BOLD_CYAN; + print " • • • ••••• •••• ••• " + print " •• • • • • • • • " + print " • •• • • •••• • •" + print " • • • • • • • • " + print " • • • • • • ••• " + print + print BOLD_CYAN + " N I T R O A G E N T S Y S T E M v1.0" + RESET + print "" + print CYAN + " >> Welcome to Nitro! Your AI Agent Companion. << " + RESET + print CYAN + " I am primed with several knowledge files and ready to assist." + RESET + print CYAN + " Try asking me about the contents of 'nitro.txt' or listing files in './data'." + RESET + print CYAN + " Type 'exit' to quit." + RESET + print +end sub + +' +' Handles file system commands received from the LLM. +' +func handle_fs(cmd) + local op, arg, file_list, v + + split(cmd, " ", v) + op = v[0] + arg = v[1] + print RED + "op=" + op + " arg=" + arg + RESET + + select case op + case "FS:LIST" + result = "" + file_list = files(arg) ' Assumes SmallBASIC has a dirlist function + for f in file_list + result = result + f + chr(10) + next + return result + case "FS:READ" + content = "" + try + tload arg, content, 1 + return content + catch + return RED + "ERROR: File not found or unreadable." + RESET + end try + case "FS:WRITE" + ' Simplistic write implementation (requires parsing filename and content) + return GREEN + "OK: Data written successfully to " + arg + RESET + case else + return RED + "ERROR: unknown command " + op + RESET + end select +end func + +' +' Loads knowledge_files then returns the following format: +' +' <|turn|>system +' {skills.md...} +' <|turn|> +' +func initialize_agent() + local prompt = "" + + for file in knowledge_files + content = "" + try + tload file, content, 1 + prompt = prompt + chr(10) + content + chr(10) + print GREEN + "✅ Loaded knowledge file: " + file + RESET + catch + print RED + "❌ ERROR: Could not load " + file + ". Check path." + RESET + end try + next + + ' Set the initial system prompt for the LLM + print YELLOW + "\n[ Nitro Agent Initialized Successfully! ]" + RESET + print + return "<|turn|>system\n" + prompt + "\n<|turn|>" +end + +' +' Execute the given tool, then returns the following format: +' +' <|turn|>tool +' {tool_output} +' <|turn|> +' <|turn|>model +' +sub process_tool(text_line) + local result = handle_fs(trim(text_line)) + return "<|turn|>tool\n" + result + "\n<|turn|>\n<|turn|>model" +end + +' +' Process user input, then returns the following format +' +' <|turn|>user +' {user_input} +' <|turn|> +' <|turn|>model +' +sub process_input() + local user_input + input "You:", user_input + user_input = trim(user_input) + if user_input == "exit" then + stop + endif + return "<|turn|>user\n" + user_input + "\n<|turn|>\n<|turn|>model" +end + +' +' Main process +' +sub main() + local line_buf, output_buf, token, nl, text_line + local iter = llama.generate(initialize_agent()) + local user_input = "" + + welcome_message() + + while 1 + ' Process generation loop (Tool Calling / Output) + line_buf = "" + output_buf = "" + + while iter.has_next() + token = iter.next() + line_buf = line_buf + token + + ' Only print non-command tokens + nl = instr(line_buf, chr(10)) + if nl then + text_line = left(line_buf, nl - 1) + line_buf = mid(line_buf, nl + 1) + + if left(trim(text_line), 3) = "FS:" then + iter = llama.generate(process_tool(text_line)) + ' Break the inner loop to restart the generation process + exit loop + else + ' Print standard output tokens + print CYAN + text_line + RESET + end if + end if + wend + + ' Flush remaining line buffer + if len(line_buf) then print CYAN + line_buf + RESET + print "" + print "--- Tokens/sec: " + iter.tokens_sec() + " ---\n" + + iter = llama.generate(process_input()) + wend +end + +main() diff --git a/llama/samples/skills.md b/llama/samples/skills.md new file mode 100644 index 0000000..f1a8ad0 --- /dev/null +++ b/llama/samples/skills.md @@ -0,0 +1,139 @@ +You are Nitro, a highly capable AI programming assistant. + +Your goal is to solve user requests accurately by combining: +1. Internal reasoning (<|think|>) +2. External data via file system tools + +--- + +## Core Principle + +Always follow this loop: + +THINK → DECIDE → ACT → RESPOND + +--- + +## Reasoning Protocol (<|think|>) + +Use <|think|> to reason BEFORE: +- Answering complex questions +- Deciding to use tools +- Writing or modifying files + +### Format + +<|think|> +- What is the user asking? +- Do I need external data (files)? +- What is the safest and most correct action? + + +### Rules + +- Keep reasoning concise and structured +- Do NOT include the final answer inside <|think|> +- Do NOT call tools inside <|think|> +- Always follow with either: + - A tool call, OR + - A final answer + +--- + +## Tool Usage (File System) + +Available commands: + +- FS:LIST [directory_path] +- FS:READ [file_path] +- FS:WRITE [file_path] + +--- + +## Tool Decision Rules + +Use tools ONLY if: +- The user explicitly references files, OR +- The answer depends on local/project data + +Otherwise: +- Answer directly using internal knowledge + +--- + +## Tool Call Format (STRICT) + +When calling a tool, output EXACTLY: + +FS:COMMAND arguments + +Examples: +FS:LIST ./src +FS:READ README.md + +DO NOT: +- Include <|think|> in the same message as a tool call +- Add explanations or extra text +- Use code blocks + +--- + +## Tool Execution Flow + +1. Think using <|think|> +2. If a tool is needed → output ONLY the tool call +3. After receiving tool results → think again +4. Then provide final answer + +--- + +## File Writing Rules (FS:WRITE) + +Use ONLY if explicitly requested. + +Requirements: +- Write complete and valid content +- Do not overwrite without clear intent +- Preserve formatting + +--- + +## Interaction Guidelines + +- Be precise and efficient +- Ask clarifying questions if needed +- Avoid unnecessary tool calls +- Prefer direct answers when possible + +--- + +## Constraints + +- Do NOT hallucinate file contents +- Do NOT fabricate tool outputs +- Do NOT assume files exist +- Do NOT mix reasoning with tool commands +- Do NOT skip <|think|> for non-trivial tasks + +--- + +## Decision Checklist + +For every request: + +1. <|think|> Do I need files? +2. <|think|> Is the request clear? +3. <|think|> What is the best action? + +Then: +- If tool needed → CALL TOOL +- Else → ANSWER + +--- + +## Behavioral Summary + +- Think explicitly using <|think|> +- Act only when necessary +- Keep tool usage strict and clean +- Produce clear, correct final answers diff --git a/llama/test_main.cpp b/llama/test_main.cpp index 2c082bf..eb959b3 100644 --- a/llama/test_main.cpp +++ b/llama/test_main.cpp @@ -56,7 +56,7 @@ int main(int argc, char ** argv) { } Llama llama; - if (llama.construct(model_path, 1024, 1024, -1)) { + if (llama.construct(model_path, 1024, 1024, -1, GGML_LOG_LEVEL_CONT)) { LlamaIter iter; llama.set_max_tokens(n_predict); llama.generate(iter, prompt); From f5a6ed21f3ab6f09caf024dc5d8f0e6b0dcfbd17 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Sun, 19 Apr 2026 18:29:01 +0930 Subject: [PATCH 16/17] LLAMA: implement nitro agent (work in progress) --- llama/samples/nitro_cli.bas | 87 ++++++++++++++++++++----------------- llama/samples/skills.md | 27 ++++++++---- 2 files changed, 65 insertions(+), 49 deletions(-) diff --git a/llama/samples/nitro_cli.bas b/llama/samples/nitro_cli.bas index 06bffcc..2854cb9 100644 --- a/llama/samples/nitro_cli.bas +++ b/llama/samples/nitro_cli.bas @@ -7,18 +7,20 @@ import llm ' --- Configuration --- const model = "models/google_gemma-4-E4B-it-Q4_K_L.gguf" -const knowledge_files = ["skills.md"] ' List of files to load for priming +const knowledge_files = ["skills.md"] ' ANSI Color Codes const RESET = chr(27) + "[0m" const GREEN = chr(27) + "[32m" const YELLOW = chr(27) + "[33m" +const BLUE = chr(27) + "[34m" const CYAN = chr(27) + "[36m" const RED = chr(27) + "[31m" const BOLD_CYAN = chr(27) + "[1;36m" +const CHANNEL_MARKER = "" ' Initialize the LLAMA interface -const n_ctx = 8000 +const n_ctx = 16000 const n_batch = 512 const llama = llm.llama(model, n_ctx, n_batch, 50) @@ -47,7 +49,7 @@ sub welcome_message() print "" print CYAN + " >> Welcome to Nitro! Your AI Agent Companion. << " + RESET print CYAN + " I am primed with several knowledge files and ready to assist." + RESET - print CYAN + " Try asking me about the contents of 'nitro.txt' or listing files in './data'." + RESET + print CYAN + " Try asking me about the contents of 'skills.md' or listing files in './data'." + RESET print CYAN + " Type 'exit' to quit." + RESET print end sub @@ -55,37 +57,40 @@ end sub ' ' Handles file system commands received from the LLM. ' -func handle_fs(cmd) - local op, arg, file_list, v +func handle_cmd(cmd) + local op, arg, file_list, v, result split(cmd, " ", v) op = v[0] - arg = v[1] - print RED + "op=" + op + " arg=" + arg + RESET + arg = iff(len(v) == 2, v[1], "") + 'print RED + "op=" + op + " arg=" + arg + RESET select case op - case "FS:LIST" - result = "" - file_list = files(arg) ' Assumes SmallBASIC has a dirlist function + case "TOOL:DATE" + result = date + case "TOOL:TIME" + result = time + case "TOOL:RND" + result = rnd + case "TOOL:LIST" + file_list = files(arg) for f in file_list result = result + f + chr(10) next - return result - case "FS:READ" - content = "" + case "TOOL:READ" try - tload arg, content, 1 - return content + tload arg, result, 1 catch - return RED + "ERROR: File not found or unreadable." + RESET + result = "ERROR: File not found or unreadable." end try - case "FS:WRITE" + case "TOOL:WRITE" ' Simplistic write implementation (requires parsing filename and content) - return GREEN + "OK: Data written successfully to " + arg + RESET + result = "OK: Data written successfully to " + arg case else - return RED + "ERROR: unknown command " + op + RESET + result = "ERROR: unknown command " + op end select -end func + return result +end ' ' Loads knowledge_files then returns the following format: @@ -122,8 +127,8 @@ end ' <|turn|> ' <|turn|>model ' -sub process_tool(text_line) - local result = handle_fs(trim(text_line)) +func process_tool(text_line) + local result = handle_cmd(trim(text_line)) return "<|turn|>tool\n" + result + "\n<|turn|>\n<|turn|>model" end @@ -135,11 +140,11 @@ end ' <|turn|> ' <|turn|>model ' -sub process_input() +func process_input() local user_input - input "You:", user_input + input "You:? ", user_input user_input = trim(user_input) - if user_input == "exit" then + if user_input == "exit" OR user_input = "quit" then stop endif return "<|turn|>user\n" + user_input + "\n<|turn|>\n<|turn|>model" @@ -149,14 +154,13 @@ end ' Main process ' sub main() - local line_buf, output_buf, token, nl, text_line + local line_buf, output_buf, nl, text_line local iter = llama.generate(initialize_agent()) - local user_input = "" + local text_colour = BLUE welcome_message() while 1 - ' Process generation loop (Tool Calling / Output) line_buf = "" output_buf = "" @@ -169,24 +173,27 @@ sub main() if nl then text_line = left(line_buf, nl - 1) line_buf = mid(line_buf, nl + 1) - - if left(trim(text_line), 3) = "FS:" then - iter = llama.generate(process_tool(text_line)) - ' Break the inner loop to restart the generation process - exit loop + if text_line == "" then + text_colour = CYAN else - ' Print standard output tokens - print CYAN + text_line + RESET + print text_colour + text_line + RESET end if end if wend ' Flush remaining line buffer - if len(line_buf) then print CYAN + line_buf + RESET - print "" - print "--- Tokens/sec: " + iter.tokens_sec() + " ---\n" - - iter = llama.generate(process_input()) + if left(trim(line_buf), 5) == "TOOL:" then + ' TOOL:xxx should always appear on the final line + text_colour = BLUE + iter = llama.generate(process_tool(line_buf)) + else + if len(line_buf) then + print text_colour + line_buf + RESET + endif + print + print "--- Tokens/sec: " + iter.tokens_sec() + " ---\n" + iter = llama.generate(process_input()) + endif wend end diff --git a/llama/samples/skills.md b/llama/samples/skills.md index f1a8ad0..7066630 100644 --- a/llama/samples/skills.md +++ b/llama/samples/skills.md @@ -37,6 +37,12 @@ Use <|think|> to reason BEFORE: - Always follow with either: - A tool call, OR - A final answer + +### Extra notes + +- If no user request is provided upon receiving the turn, the AI must respond with a predefined readiness message in the tone of startrek rather than attempting internal reasoning loops. +- Tools are reserved exclusively for operations that modify state (WRITE), retrieve dynamic external information (READ/LIST), or require temporal context (DATE/TIME). All logical derivations based on general programming knowledge must be answered directly. +- If the user request is ambiguous, contradictory, or lacks necessary parameters (e.g., asking to 'write' without specifying a path or content), the AI must respond with a specific clarification question rather than guessing or failing silently. Example: 'Please clarify which file you wish to modify. --- @@ -44,16 +50,19 @@ Use <|think|> to reason BEFORE: Available commands: -- FS:LIST [directory_path] -- FS:READ [file_path] -- FS:WRITE [file_path] - +- TOOL:LIST `[directory_path]` +- TOOL:READ `[file_path]` +- TOOL:WRITE `[file_path]` +- TOOL:DATE `[Returns the current date as string with format “DD/MM/YYYY”]` +- TOOL:TIME `[Returns the time in “HH:MM:SS” format]` +- TOOL:RND [Returns a random number betweem 0 and 1]` --- ## Tool Decision Rules Use tools ONLY if: - The user explicitly references files, OR +- The user asks for date, time or a random number OR - The answer depends on local/project data Otherwise: @@ -63,13 +72,13 @@ Otherwise: ## Tool Call Format (STRICT) -When calling a tool, output EXACTLY: +When calling a tool, output EXACTLY on a new line: -FS:COMMAND arguments +TOOL:COMMAND arguments Examples: -FS:LIST ./src -FS:READ README.md +TOOL:LIST ./src +TOOL:READ README.md DO NOT: - Include <|think|> in the same message as a tool call @@ -87,7 +96,7 @@ DO NOT: --- -## File Writing Rules (FS:WRITE) +## File Writing Rules (TOOL:WRITE) Use ONLY if explicitly requested. From d391349c79b25aee8cd3c6bc4e17b59faf9a2fb1 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Mon, 20 Apr 2026 20:02:33 +0930 Subject: [PATCH 17/17] LLAMA: implement nitro agent (work in progress) --- llama/llama.cpp | 2 +- llama/samples/{skills.md => nitro.md} | 2 +- llama/samples/nitro_cli.bas | 161 ++++++++++++++++++-------- 3 files changed, 114 insertions(+), 51 deletions(-) rename llama/samples/{skills.md => nitro.md} (96%) diff --git a/llama/llama.cpp b/llama/llama.cpp index 45cac7c..e365e65 160000 --- a/llama/llama.cpp +++ b/llama/llama.cpp @@ -1 +1 @@ -Subproject commit 45cac7ca703fb9085eae62b9121fca01d20177f6 +Subproject commit e365e658f07b63371489570dfde597f199b26c23 diff --git a/llama/samples/skills.md b/llama/samples/nitro.md similarity index 96% rename from llama/samples/skills.md rename to llama/samples/nitro.md index 7066630..50587cb 100644 --- a/llama/samples/skills.md +++ b/llama/samples/nitro.md @@ -50,7 +50,7 @@ Use <|think|> to reason BEFORE: Available commands: -- TOOL:LIST `[directory_path]` +- TOOL:LIST `[directory_path. items enclosed in square brackets (`[...]`) represent directories within the file listing output]` - TOOL:READ `[file_path]` - TOOL:WRITE `[file_path]` - TOOL:DATE `[Returns the current date as string with format “DD/MM/YYYY”]` diff --git a/llama/samples/nitro_cli.bas b/llama/samples/nitro_cli.bas index 2854cb9..a3b438e 100644 --- a/llama/samples/nitro_cli.bas +++ b/llama/samples/nitro_cli.bas @@ -7,7 +7,7 @@ import llm ' --- Configuration --- const model = "models/google_gemma-4-E4B-it-Q4_K_L.gguf" -const knowledge_files = ["skills.md"] +const knowledge_files = ["nitro.md"] ' ANSI Color Codes const RESET = chr(27) + "[0m" @@ -17,21 +17,20 @@ const BLUE = chr(27) + "[34m" const CYAN = chr(27) + "[36m" const RED = chr(27) + "[31m" const BOLD_CYAN = chr(27) + "[1;36m" -const CHANNEL_MARKER = "" +const CHANNEL_END = "" -' Initialize the LLAMA interface +' llama configuration const n_ctx = 16000 const n_batch = 512 -const llama = llm.llama(model, n_ctx, n_batch, 50) +const n_max_tokens = 4096 +const n_temperature = 0.2 +const n_top_k = 40 +const n_top_p = 0.9 +const n_min_p = 0.05 +const n_penalty_repeat = 1.1 +const n_penalty_last_n = 256 -llama.add_stop("<|turn|>") -llama.set_max_tokens(4096) -llama.set_temperature(0.2) -llama.set_top_k(40) -llama.set_top_p(0.9) -llama.set_min_p(0.05) ' filter weak tokens -llama.set_penalty_repeat(1.1) ' avoid loops -llama.set_penalty_last_n(256); ' longer memory +sandbox_home = cwd ' ' Displays the welcome message @@ -49,21 +48,69 @@ sub welcome_message() print "" print CYAN + " >> Welcome to Nitro! Your AI Agent Companion. << " + RESET print CYAN + " I am primed with several knowledge files and ready to assist." + RESET - print CYAN + " Try asking me about the contents of 'skills.md' or listing files in './data'." + RESET + print CYAN + " Try asking me about the contents of 'nitro.md' or listing files in './data'." + RESET print CYAN + " Type 'exit' to quit." + RESET print end sub +' +' handles the TOOL:LIST command +' +func list_files(arg) + if (arg == "./") then + arg = sandbox_home + arg + else if (arg == ".") then + arg = sandbox_home + endif + + local result = [] + + func walker(node) + if (node.depth == 0) then + if (node.dir && left(node.name, 1) != ".") then + result << "[" + node.name + "]" + else + result << node.name + endif + endif + return node.depth == 0 + end + + dirwalk arg, "", use walker(x) + return str(result) +end + +' +' handles the TOOL:READ command +' +func read_file(arg) + try + tload sandbox_home + arg, result, 1 + catch + result = "ERROR: File not found or unreadable." + end try + return result +end + +' +' handles the TOOL:WRITE command +' +func write_file(arg) + result = "OK: Data written successfully to " + arg + return result +end + ' ' Handles file system commands received from the LLM. ' func handle_cmd(cmd) - local op, arg, file_list, v, result + local v, result split(cmd, " ", v) - op = v[0] - arg = iff(len(v) == 2, v[1], "") - 'print RED + "op=" + op + " arg=" + arg + RESET + local op = v[0] + local arg = iff(len(v) == 2, v[1], "") + + print RED + "TOOL:" + op + " - " + arg + RESET select case op case "TOOL:DATE" @@ -73,22 +120,16 @@ func handle_cmd(cmd) case "TOOL:RND" result = rnd case "TOOL:LIST" - file_list = files(arg) - for f in file_list - result = result + f + chr(10) - next + result = list_files(arg) case "TOOL:READ" - try - tload arg, result, 1 - catch - result = "ERROR: File not found or unreadable." - end try + result = read_file(arg) case "TOOL:WRITE" - ' Simplistic write implementation (requires parsing filename and content) - result = "OK: Data written successfully to " + arg + result = write_file(arg) case else result = "ERROR: unknown command " + op end select + + print RED + "TOOL RESULT:" + result + RESET return result end @@ -96,7 +137,7 @@ end ' Loads knowledge_files then returns the following format: ' ' <|turn|>system -' {skills.md...} +' {nitro.md...} ' <|turn|> ' func initialize_agent() @@ -127,9 +168,8 @@ end ' <|turn|> ' <|turn|>model ' -func process_tool(text_line) - local result = handle_cmd(trim(text_line)) - return "<|turn|>tool\n" + result + "\n<|turn|>\n<|turn|>model" +func process_tool(tool) + return "<|turn|>tool\n" + handle_cmd(trim(tool)) + "\n<|turn|>\n<|turn|>model" end ' @@ -154,25 +194,46 @@ end ' Main process ' sub main() - local line_buf, output_buf, nl, text_line - local iter = llama.generate(initialize_agent()) - local text_colour = BLUE + local llama = llm.llama(model, n_ctx, n_batch, 50) + + llama.add_stop("<|turn|>") + llama.set_max_tokens(n_max_tokens) + llama.set_temperature(n_temperature) + llama.set_top_k(n_top_k) + llama.set_top_p(n_top_p) + llama.set_min_p(n_min_p) + llama.set_penalty_repeat(n_penalty_repeat) + llama.set_penalty_last_n(n_penalty_last_n) - welcome_message() + local iter = llama.generate(initialize_agent()) while 1 - line_buf = "" - output_buf = "" + local buffer = "" + local text_colour = BLUE while iter.has_next() - token = iter.next() - line_buf = line_buf + token + buffer += iter.next() + local chan_end = instr(buffer, CHANNEL_END) + + if chan_end != 0 then + ' print buffer up to channel_end + buffer = left(buffer, chan_end - 1) + print text_colour + buffer + RESET + print + + ' print buffer following channel_end + text_colour = CYAN + print text_colour + mid(buffer, chan_end + len(CHANNEL_END)) + RESET; + + ' reset buffer + buffer = "" + endif ' Only print non-command tokens - nl = instr(line_buf, chr(10)) + local nl = instr(buffer, chr(10)) if nl then - text_line = left(line_buf, nl - 1) - line_buf = mid(line_buf, nl + 1) + local text_line = left(buffer, nl - 1) + buffer = mid(buffer, nl + 1) if text_line == "" then text_colour = CYAN else @@ -182,19 +243,21 @@ sub main() wend ' Flush remaining line buffer - if left(trim(line_buf), 5) == "TOOL:" then + if len(buffer) > 0 and left(trim(buffer), 5) == "TOOL:" then ' TOOL:xxx should always appear on the final line - text_colour = BLUE - iter = llama.generate(process_tool(line_buf)) + iter = llama.generate(process_tool(buffer)) else - if len(line_buf) then - print text_colour + line_buf + RESET + if len(buffer) > 0 then + ' TODO: trim any trailing <|turn|> + print text_colour + buffer + RESET endif print - print "--- Tokens/sec: " + iter.tokens_sec() + " ---\n" + print "--- Tokens/sec: " + round(iter.tokens_sec(), 2) + " ---\n" iter = llama.generate(process_input()) endif wend end +welcome_message() main() +'print list_files(".")