Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .github/workflows/syncNext.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: Sync next

# Carries every change that lands on the base branch onto the paired `next`
# iteration branch, so `next` never drifts behind what has already shipped.
# `next` is created on the first run if the repo does not have one yet.
on:
push:
branches: ['master']
workflow_dispatch:

jobs:
sync:
uses: Start9Labs/start-technologies/.github/workflows/syncNext.yml@master
permissions:
contents: write
pull-requests: write
11 changes: 5 additions & 6 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@ Develop it inside a StartOS packaging workspace created by `start-cli s9pk init-
which provides the packaging guide and agent context one level up. If you're reading this in a
bare clone with no workspace, the full guide is at <https://docs.start9.com/packaging>.

Work this package's `TODO.md` from top to bottom. Keep `README.md` (architecture, for developers and LLMs) and `instructions.md` (end-user docs) in sync with your changes.
Work this package's `TODO.md` from top to bottom. Keep `README.md` (technical reference for an AI support or administering agent) and `instructions.md` (end-user docs) in sync with your changes.

## This repo

- **Package id is `llama-cpp`.** Ships four image variants — `generic` (CPU), `nvidia` (CUDA), `rocm` (AMD), and `vulkan` — selected at build time via `VARIANT=…`; the `Makefile` overrides `ARCHES`/`TARGETS` before the `s9pk.mk` include and fans out to per-variant targets. `rocm` is x86-only. Exposes one `ui` interface (`api`, port 8080): the OpenAI-compatible API plus built-in chat UI, gated by OS reverse-proxy basic auth (username `admin`, password set via the **Set UI Password** critical action). No dependencies.

## Inspecting a running install

To run a command inside the service's container (read its generated config, grep app logs), use `start-cli package attach llama-cpp -n llama-cpp-sub -- <cmd>`. Select the subcontainer by **name** with `-n` (the name passed to `SubContainer.of` in `main.ts` — here `llama-cpp-sub`) or by image with `-i`. Note: `-s/--subcontainer` matches the internal **Guid**, not the name, so passing a name to `-s` fails with "no matching subcontainers".
- **One repo, four builds.** `VARIANT` (see the `Makefile` targets) selects the image, architectures, and `hardwareRequirements` for `generic`, `nvidia`, `rocm`, and `vulkan`. Bump `upstreamBuild` once in `startos/manifest/index.ts` and every variant follows.
- **The AMD matcher is a positive allowlist of discrete product names, not an iGPU exclusion.** StartOS's regex engine has no lookahead, and ROCm is unreliable on integrated Radeon — so a broad `amdgpu` match would route Ryzen APUs onto a build that does not work for them.
- **The one-hour grace period on the health check is the model download.** Don't shorten it to something that looks more like a health check.
- **Preset sizing reads VRAM where it can and system memory otherwise** (`startos/hardware.ts`), and the result is cached per process. `minMemoryGB` in `actions/presets.ts` is weights plus roughly 25% for the KV cache — keep that convention when adding a preset.
299 changes: 141 additions & 158 deletions README.md

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions UPDATING.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ This package wraps [`ggml-org/llama.cpp`](https://github.com/ggml-org/llama.cpp)

llama.cpp releases use monotonic build numbers of the form `bNNNN` (no semver), one per merged commit. Each release publishes four server image variants on `ghcr.io`:

| Variant | Image tag | Arches |
| --------- | ----------------------------------------- | ------------ |
| `generic` | `ghcr.io/ggml-org/llama.cpp:server-bNNNN` | amd64, arm64 |
| `nvidia` | `ghcr.io/ggml-org/llama.cpp:server-cuda-bNNNN` | amd64, arm64 |
| `rocm` | `ghcr.io/ggml-org/llama.cpp:server-rocm-bNNNN` | amd64 |
| Variant | Image tag | Arches |
| --------- | ------------------------------------------------ | ------------ |
| `generic` | `ghcr.io/ggml-org/llama.cpp:server-bNNNN` | amd64, arm64 |
| `nvidia` | `ghcr.io/ggml-org/llama.cpp:server-cuda-bNNNN` | amd64, arm64 |
| `rocm` | `ghcr.io/ggml-org/llama.cpp:server-rocm-bNNNN` | amd64 |
| `vulkan` | `ghcr.io/ggml-org/llama.cpp:server-vulkan-bNNNN` | amd64, arm64 |

All four variants are cut from the same upstream commit and bump together.
Expand Down
Empty file added assets/.gitkeep
Empty file.
1 change: 0 additions & 1 deletion assets/README.md

This file was deleted.

2 changes: 1 addition & 1 deletion instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ curl -s -u admin:<your-ui-password> <your-interface-url>/v1/chat/completions \

### Actions

- **Set Model** — switch to a different preset or custom GGUF. The service restarts with the new weights; uncached models download on this restart.
- **Set Model** — switch to a different preset or custom GGUF. The form opens with your current selection already filled in, so you can change one setting without re-entering the rest. The service restarts with the new weights; uncached models download on this restart.
- **Set UI Password** — generate a new web UI password (username stays `admin`). Use it for first-time setup or to rotate the password later.
- **Delete Model Cache** — remove a specific filename from the cache (e.g. `Qwen2.5-7B-Instruct-Q4_K_M.gguf`) to reclaim disk space. A deleted model will be re-downloaded if you select it again.

Expand Down
33 changes: 31 additions & 2 deletions startos/actions/setModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,29 @@ export const setModel = sdk.Action.withInput(

inputSpec,

async ({ effects }) => ({}),
async ({ effects }) => {
const saved = await storeJson.read((s) => s?.modelSelection).const(effects)
if (!saved || !(saved.selection in allVariants)) return {}
return {
config: { selection: saved.selection, value: saved.custom ?? {} },
}
},

async ({ effects, input }) => {
const config = input.config
let serveArgs: string[]
let modelSelection: {
selection: string
custom:
| {
hfRepo: string
hfFile?: string
ctx: number
ngl: number
extraArgs?: string
}
| undefined
}
if (config.selection === 'custom') {
const v = config.value
serveArgs = ['-hf', v.hfRepo]
Expand All @@ -129,6 +147,16 @@ export const setModel = sdk.Action.withInput(
if (v.extraArgs && v.extraArgs.trim().length > 0) {
serveArgs.push(...v.extraArgs.split(/\s+/).filter(Boolean))
}
modelSelection = {
selection: 'custom',
custom: {
hfRepo: v.hfRepo,
hfFile: v.hfFile?.trim() || undefined,
ctx: v.ctx,
ngl: v.ngl,
extraArgs: v.extraArgs?.trim() || undefined,
},
}
} else {
const preset = models.find((m) => m.id === config.selection)
if (!preset) {
Expand All @@ -138,7 +166,8 @@ export const setModel = sdk.Action.withInput(
if (preset.hfFile) serveArgs.push('-hff', preset.hfFile)
serveArgs.push('-c', String(preset.defaultCtx))
if (isGpuVariant) serveArgs.push('-ngl', '999')
modelSelection = { selection: config.selection, custom: undefined }
}
await storeJson.merge(effects, { serveArgs })
await storeJson.merge(effects, { serveArgs, modelSelection })
},
)
Empty file added startos/fileModels/.gitkeep
Empty file.
15 changes: 15 additions & 0 deletions startos/fileModels/store.json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,21 @@ import { sdk } from '../sdk'
const shape = z.object({
serveArgs: z.array(z.string()).optional().catch(undefined),
uiPassword: z.string().optional().catch(undefined),
modelSelection: z
.object({
selection: z.string(),
custom: z
.object({
hfRepo: z.string(),
hfFile: z.string().optional(),
ctx: z.number(),
ngl: z.number(),
extraArgs: z.string().optional(),
})
.optional(),
})
.optional()
.catch(undefined),
})

export const storeJson = FileHelper.json(
Expand Down
30 changes: 10 additions & 20 deletions startos/i18n/dictionaries/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,19 @@ const dict = {

// actions/setModel.ts
'Set Model': 7,
'Pick a curated GGUF preset sized for your hardware, or supply a custom HuggingFace model. The model will be downloaded on first startup if not already cached.':
8,
'Changing the model will restart the service and may require downloading a new model.':
9,
'Pick a curated GGUF preset sized for your hardware, or supply a custom HuggingFace model. The model will be downloaded on first startup if not already cached.': 8,
'Changing the model will restart the service and may require downloading a new model.': 9,
Configuration: 10,
'HuggingFace repo': 11,
'A HuggingFace GGUF repo, optionally with a quant tag (e.g. `unsloth/Qwen2.5-7B-Instruct-GGUF:Q4_K_M`).':
12,
'A HuggingFace GGUF repo, optionally with a quant tag (e.g. `unsloth/Qwen2.5-7B-Instruct-GGUF:Q4_K_M`).': 12,
'HuggingFace file (optional)': 13,
'Specific GGUF filename inside the repo. Leave empty to let llama-server pick.':
14,
'Specific GGUF filename inside the repo. Leave empty to let llama-server pick.': 14,
'Context size': 15,
'Maximum context length in tokens. 0 uses the model default.': 16,
'GPU layers': 17,
'Number of model layers to offload to GPU. Use a large value (e.g. 999) to offload everything; ignored on the generic CPU variant.':
18,
'Number of model layers to offload to GPU. Use a large value (e.g. 999) to offload everything; ignored on the generic CPU variant.': 18,
'Extra arguments': 19,
'Additional `llama-server` flags, space-separated. Advanced — split on whitespace, so quoted values will not survive.':
20,
'Additional `llama-server` flags, space-separated. Advanced — split on whitespace, so quoted values will not survive.': 20,
Custom: 21,

// model preset labels
Expand All @@ -50,17 +44,13 @@ const dict = {
'Delete Model Cache': 31,
'Remove a downloaded GGUF model from the cache to free up disk space': 32,
'Cached file': 33,
'Filename inside `/data/models` to delete (e.g. `Qwen2.5-7B-Instruct-Q4_K_M.gguf`).':
34,
'This will permanently delete the cached file. The model will be re-downloaded if selected again.':
35,
'Filename inside `/data/models` to delete (e.g. `Qwen2.5-7B-Instruct-Q4_K_M.gguf`).': 34,
'This will permanently delete the cached file. The model will be re-downloaded if selected again.': 35,

// actions/setUiPassword.ts
'Set UI Password': 36,
'Generate a new password for logging in to the llama.cpp web UI. The username is always "admin".':
37,
'This replaces any existing password. Update saved logins after running it.':
38,
'Generate a new password for logging in to the llama.cpp web UI. The username is always "admin".': 37,
'This replaces any existing password. Update saved logins after running it.': 38,

// init/initializeService.ts
'Generate a password to log in to the llama.cpp web UI': 39,
Expand Down
2 changes: 1 addition & 1 deletion startos/manifest/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ export const long = {
pl_PL:
'llama.cpp to wydajne środowisko uruchomieniowe C/C++ dla dużych modeli językowych w formacie GGUF. Ten pakiet otacza oficjalny plik binarny `llama-server`, udostępniając API HTTP zgodne z OpenAI i wbudowany interfejs czatu webowego. Wybierz wyselekcjonowany preset dopasowany do Twojego sprzętu lub podaj własny GGUF z HuggingFace — serwer pobierze wagi przy pierwszym uruchomieniu i będzie je obsługiwał lokalnie, bez żadnych połączeń z usługami zewnętrznymi.',
fr_FR:
"llama.cpp est un runtime C/C++ haute performance pour les grands modèles de langage au format GGUF. Ce paquet enveloppe le binaire officiel `llama-server`, exposant une API HTTP compatible OpenAI et une interface de chat web intégrée. Choisissez un préréglage de modèle dimensionné pour votre matériel, ou fournissez un GGUF HuggingFace personnalisé — le serveur télécharge les poids au premier démarrage et les sert localement, sans appels à des tiers.",
'llama.cpp est un runtime C/C++ haute performance pour les grands modèles de langage au format GGUF. Ce paquet enveloppe le binaire officiel `llama-server`, exposant une API HTTP compatible OpenAI et une interface de chat web intégrée. Choisissez un préréglage de modèle dimensionné pour votre matériel, ou fournissez un GGUF HuggingFace personnalisé — le serveur télécharge les poids au premier démarrage et les sert localement, sans appels à des tiers.',
}
2 changes: 1 addition & 1 deletion startos/manifest/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const variant = process.env.VARIANT || 'generic'
type Mutable<T> = { -readonly [K in keyof T]: Mutable<T[K]> }
const mutable = <T>(value: T): Mutable<T> => value as Mutable<T>

const upstreamBuild = 'b10438'
const upstreamBuild = 'b10450'

const imageConfigs = {
generic: {
Expand Down
Loading