offload-kqv: false keeps the KV cache on the CPU. op-offload: false keeps host tensor operations on the CPU. These options can reduce discrete-GPU VRAM pressure at a performance cost. They do not reduce total memory requirements.
+
llama.cpp also supports the process-wide GGML_OP_OFFLOAD_MIN_BATCH environment variable. Set it before Kronk starts; GPU backends read it once during kronk.Init, so it cannot be configured independently per model.
For multimodal models, proj-on-cpu: true keeps the media projector on the CPU without changing placement of the language model itself. To place the projector on a specific accelerator, set proj-device to a name reported by kronk devices (for example, CUDA1 or MTL0). Omit both settings for automatic placement. proj-device cannot be combined with proj-on-cpu: true.
Supported response_format.type values are text, json_object, and json_schema. Kronk also accepts a schema directly in the top-level json_schema field and accepts a custom GBNF string in grammar. Use one structured-output mechanism per request.
+
Supported response_format.type values are text, json_object, and json_schema. Kronk also accepts a schema directly in the top-level json_schema field and accepts a custom GBNF string in grammar. Use one structured-output mechanism per request. JSON Schema pattern is not supported; Kronk rejects schemas containing it rather than interpreting its regular expression as GBNF.
When a constraint is present and enable_thinking is omitted, Kronk disables thinking automatically so free-form reasoning does not precede the structured answer. Explicitly enabling thinking overrides that default, but is generally counterproductive for constrained output.
A grammar restricts which tokens can be emitted; it does not guarantee a complete result. A response cut short by max_tokens, context limits, or cancellation can still contain an incomplete JSON value.
10.7 Token Log Probabilities
@@ -3223,6 +3224,7 @@ EOF`}
The selected model and projector must support the detected modality.
Image resolution, media count, and audio duration affect latency and memory.
Model quality and practical media limits vary by model and projector.
+
Kronk does not impose fixed media payload, image-dimension, or media-count limits. Image decoding allocates memory in proportion to decoded dimensions, and a request can retain multiple decoded media items at once. Applications that accept media from untrusted sources must validate those resources before passing them to Kronk.
restrict KRONK_WEB_CORS_ALLOWED_ORIGINS instead of retaining *;
issue separate, short-lived, least-privilege tokens for each application;
set quotas based on the workload and monitor authentication failures;
+
when an application forwards untrusted media, validate request size, media count, payload size, and decoded image dimensions before forwarding it;
protect and back up master.pem and master.jwt; and
rotate non-master signing keys deliberately, accounting for all tokens that a deletion will revoke.
diff --git a/cmd/server/api/frontends/bui/src/components/DocsSDKBuckyModel.tsx b/cmd/server/api/frontends/bui/src/components/DocsSDKBuckyModel.tsx
index d4a13a26b..ef74261cb 100644
--- a/cmd/server/api/frontends/bui/src/components/DocsSDKBuckyModel.tsx
+++ b/cmd/server/api/frontends/bui/src/components/DocsSDKBuckyModel.tsx
@@ -681,7 +681,7 @@ export default function DocsSDKBuckyModel() {
func (s *Stream) Close() error
-
Close performs one final flush over remaining audio, emits the resulting Final event, closes Events, and returns the whisper.State to the pool. It is idempotent and blocks until the worker has exited.
+
Close performs one final flush over remaining audio, emits the resulting Final event when the Events buffer has room, closes Events, and returns the whisper.State to the pool. If the consumer has abandoned a full Events buffer, cleanup takes priority and the closing event is dropped. Close is idempotent and blocks until the worker has exited.
@@ -721,6 +721,18 @@ export default function DocsSDKBuckyModel() {
Behavior is tunable via ResetOption. Reset blocks until any in-flight decode finishes and the worker has applied the reset.
ErrStreamStopped indicates that a stream's worker exited after a terminal processing error or close.
+
+
diff --git a/cmd/server/api/frontends/bui/src/components/DocsSDKKronk.tsx b/cmd/server/api/frontends/bui/src/components/DocsSDKKronk.tsx
index 66a98faef..b1d5dba13 100644
--- a/cmd/server/api/frontends/bui/src/components/DocsSDKKronk.tsx
+++ b/cmd/server/api/frontends/bui/src/components/DocsSDKKronk.tsx
@@ -49,6 +49,14 @@ export default function DocsSDKKronk() {
AutoTuneConfig seeds unset settings from a hardware-aware analysis of the model and returns the resulting Config. It uses the same shared models.AutoTune logic as the model pool so the SDK and pool seed defaults identically; the only SDK-specific part is preserving all settings outside AutoTune's ownership. On any failure the original cfg is returned unchanged so auto-tune never blocks a load.
AutoTuneConfigWithBudget seeds unset settings using a stable memory budget. Pool callers use this so custom loads honor the same resource-manager limits as catalog-driven loads.
+
+
Init
@@ -560,6 +568,7 @@ export default function DocsSDKKronk() {
Functions
NewModel loads a model from the GGUF files specified in cfg and returns a *Model ready to serve requests. It validates the configuration, builds llama.cpp model parameters, applies NUMA settings, performs the actual GGUF load (serialized via a process-wide mutex to guard the GGML_OP_OFFLOAD_MIN_BATCH env var), computes VRAM/KV diagnostics, retrieves the chat template, and initializes the per-model runtime — either the sequence-batch runtime or context-pool fallback for embed/rerank models, or a batch engine plus parser plugin and optional draft model for generation models.
+
NewModel loads a model from the GGUF files specified in cfg and returns a *Model ready to serve requests. It validates the configuration, builds llama.cpp model parameters, applies NUMA settings, performs the actual GGUF load, computes VRAM/KV diagnostics, retrieves the chat template, and initializes the per-model runtime — either the sequence-batch runtime or context-pool fallback for embed/rerank models, or a batch engine plus parser plugin and optional draft model for generation models.
The returned *Model owns the underlying llama.Model, llama.Context, KV memory, batch engine, and (when configured) draft model; release them via Model.Unload when finished.
IncrementalCache enables Incremental Message Caching (IMC) for agentic workflows. It caches all messages except the last one (which triggers generation) and extends the cache incrementally on each turn. This is ideal for agents like Cline or OpenCode where conversations grow monotonically. The cache is rebuilt from scratch when the message prefix changes (new thread).
InsecureLogging enables logging of potentially sensitive data such as message content. This should only be enabled for debugging purposes in non-production environments.
JinjaFile is the path to the jinja file. This is not required and can be used if you want to override the templated provided by the model metadata.
+
JinjaScript is an in-memory jinja template override. It takes precedence over JinjaFile and is intended for request-scoped model configurations.
LoadMode controls how model weights are loaded. The default is LoadModeAuto, which uses mmap when every selected device supports it and otherwise uses ordinary loading. LoadModeNone disables mmap, which can improve tensor placement on multi-socket NUMA systems running MoE models with CPU experts. LoadModeMLock requests resident pages without forcing mmap, LoadModeMMapMLock combines mmap and mlock, and LoadModeDirectIO bypasses the page cache where the platform and filesystem support it.
Log is the logger to use for model operations.
MainGPU is the index of the GPU to use as the primary device when SplitMode is SplitModeNone. When nil, the default GPU (usually index 0) is used.
@@ -447,7 +448,6 @@ export default function DocsSDKModel() {
NUMA controls the NUMA (Non-Uniform Memory Access) strategy. This matters most when expert tensors are on CPU and the system has multiple NUMA nodes. Valid values: "" (disabled), "distribute", "isolate", "numactl", "mirror". "distribute" is recommended for multi-socket MoE setups; without it, cross-socket memory access can cause significant bandwidth collapse.
OffloadKQV controls whether the KV cache is offloaded to the GPU. When nil or true, the KV cache is stored on the GPU (default behavior). Set to false to keep the KV cache on the CPU, which reduces VRAM usage but may slow inference.
OpOffload controls whether host tensor operations are offloaded to the device (GPU). When nil or true, operations are offloaded (default behavior). Set to false to keep operations on the CPU.
-
OpOffloadMinBatch sets the minimum batch size at which host tensor operations are offloaded to the device. When unset or 0, llama.cpp's default is used.
ProjFile is the path to the projection files. This is mandatory for media based models like vision and audio.
MTPDrafterFile is the path to a separate-file MTP drafter GGUF that ships alongside the main model. Supported files are Gemma assistant heads that share target KV and Qwen35 heads that own their draft KV. It is not the main model or a vocab-matched classic draft model. The catalog wires this field when it downloads a compatible companion from the model repository.
ProjOnCPU forces the multimodal projector (mmproj) to run on the CPU. When nil or false, the projector runs on whichever device llama.cpp picks by default (GPU when available). Set to true to keep the projector on the CPU — equivalent to llama-mtmd-cli's --no-mmproj-offload. The LLM itself is unaffected and still runs on whatever device WithNGpuLayers selects.
@@ -1201,6 +1201,7 @@ export default function DocsSDKModel() {
}`}
StateMachine is the per-request, per-slot streaming state machine. One instance is created per slot via Parser.NewStateMachine and reused across requests on that slot via Reset.
+
Implementations may consume protocol framing. Once content has been recognized as answer, reasoning, or tool payload, unexpected non-whitespace continuations must be returned on an appropriate channel so final parsing can reject malformed output atomically.
Behavior is undefined if Classify is called after a previous call returned eog=true. Callers must invoke Reset before reusing the state machine.
@@ -1459,13 +1460,6 @@ export default function DocsSDKModel() {
-
-
Config.OpOffloadMinBatch
-
- func (cfg Config) OpOffloadMinBatch() int
-
-
-
Config.PrefillBatchSize
@@ -2528,7 +2522,6 @@ export default function DocsSDKModel() {
Display implements loader.Loader.Display for the llama backend.
-
It returns the KV cache and total VRAM values to surface in BUI/observability output for a loaded model. Both this path and the SDK-internal calculateVRAMDiag route through vram.FromFiles, so the two computations are byte-identical for any well-formed local model. The dedicated lookup is retained so a hypothetical resman-side failure (e.g. an index miss) cleanly falls back to the values the SDK stored at load time rather than zeroing out the BUI display.
+
It returns the KV cache and total VRAM values to surface in BUI/observability output for a loaded model. The SDK calculated and stored these values while loading the model, so status queries do not need to read and parse the GGUF header again.
@@ -215,6 +215,14 @@ export default function DocsSDKPool() {
Prepare resolves the model configuration once for both planning and loading.
InvalidateSync invalidates a cache entry and waits for the eviction callback to release the underlying resource manager reservation.
+
InvalidateSync invalidates a cache entry and waits for the eviction callback to release the underlying resource manager reservation. If unloading fails, the model and reservation remain in the pool and the error is returned.
@@ -314,6 +322,14 @@ export default function DocsSDKPool() {
Cache keys use provider/modelID or provider/modelID/profile. The catalog resolver recovers the physical model metadata without discarding a profile.
diff --git a/cmd/server/api/frontends/bui/src/components/ModelList.tsx b/cmd/server/api/frontends/bui/src/components/ModelList.tsx
index 02b6b7d66..b1107ac58 100644
--- a/cmd/server/api/frontends/bui/src/components/ModelList.tsx
+++ b/cmd/server/api/frontends/bui/src/components/ModelList.tsx
@@ -470,7 +470,6 @@ export default function ModelList() {
{ key: 'numa', label: labelWithTip('numa', 'numa'), value: mc.numa || '—' },
{ key: 'offload-kqv', label: labelWithTip('offload-kqv', 'offloadKQV'), value: fmtVal(mc['offload-kqv']) },
{ key: 'op-offload', label: labelWithTip('op-offload', 'opOffload'), value: fmtVal(mc['op-offload']) },
- { key: 'op-offload-min-batch', label: labelWithTip('op-offload-min-batch', 'opOffloadMinBatch'), value: fmtVal(mc['op-offload-min-batch']) },
{ key: 'proj-on-cpu', label: labelWithTip('proj-on-cpu', 'projOnCpu'), value: fmtVal(mc['proj-on-cpu']) },
{ key: 'proj-device', label: labelWithTip('proj-device', 'projDevice'), value: mc['proj-device'] || 'automatic' },
{ key: 'rope-freq-base', label: labelWithTip('rope-freq-base', 'ropeFreqBase'), value: fmtVal(mc['rope-freq-base']) },
diff --git a/cmd/server/api/frontends/bui/src/components/ParamTooltips.tsx b/cmd/server/api/frontends/bui/src/components/ParamTooltips.tsx
index 276ad7bd5..8491f2222 100644
--- a/cmd/server/api/frontends/bui/src/components/ParamTooltips.tsx
+++ b/cmd/server/api/frontends/bui/src/components/ParamTooltips.tsx
@@ -47,10 +47,9 @@ export const PARAM_TOOLTIPS = {
moeTipComputeBuffer: 'A larger Prefill Batch Size increases compute buffer VRAM usage. Monitor with the VRAM calculator when tuning it.',
availableVRAM: 'Total GPU VRAM available (in GB). When set, config candidates estimated to exceed this are auto-skipped before the sweep runs. Set to 0 or leave empty to disable VRAM filtering.',
- // NUMA / model loading / Op-offload (Phase F2/F3)
+ // NUMA / model loading (Phase F2/F3)
loadMode: 'Controls how model weights are loaded. auto uses mmap when every selected device supports it and otherwise uses ordinary loading; mmap forces memory mapping; none disables it; mlock requests resident pages without forcing mmap; mmap+mlock combines both behaviors; direct-io bypasses the OS page cache where supported.',
numa: 'NUMA (Non-Uniform Memory Access) strategy for multi-socket systems. "distribute" spreads memory across NUMA nodes (recommended for MoE CPU-expert setups). "isolate" pins to one node. "numactl" defers to system numactl. "mirror" mirrors across nodes. Leave empty to disable.',
- opOffloadMinBatch: 'Minimum batch size before enabling GPU offload for certain host-side operations during prompt processing. 0 = use server default. For large MoE models with many CPU weights, values of 200–500+ may improve prompt ingestion speed.',
// ── Shared VRAM / Config tooltips ──────────────────────────────────────────
// These are used by both the VRAM Calculator and the Model Playground /
diff --git a/cmd/server/api/frontends/bui/src/services/autoTestRunner.ts b/cmd/server/api/frontends/bui/src/services/autoTestRunner.ts
index 0e93fdc34..832781902 100644
--- a/cmd/server/api/frontends/bui/src/services/autoTestRunner.ts
+++ b/cmd/server/api/frontends/bui/src/services/autoTestRunner.ts
@@ -2424,7 +2424,6 @@ export const defaultMoESweepDef: ConfigSweepDefinition = {
cacheMode: { enabled: true, values: ['none', 'imc'] },
moeMode: { enabled: true, values: ['experts_cpu', 'keep_top_n'] },
moeKeepExpertsTopN: { enabled: true, values: [0, 4, 8] },
- opOffloadMinBatch: { enabled: true, values: [0, 128, 256, 512] },
}
/** Generates config candidates as a full cross-product of all enabled parameter values. */
@@ -2468,8 +2467,6 @@ export function generateConfigCandidates(
const moeModeEnabled = def.moeMode?.enabled && def.moeMode.values.length > 0
const moeKeepTopNValues = (def.moeKeepExpertsTopN?.enabled && def.moeKeepExpertsTopN.values.length > 0)
? def.moeKeepExpertsTopN.values : []
- const opOffloadValues = (def.opOffloadMinBatch?.enabled && def.opOffloadMinBatch.values.length > 0)
- ? def.opOffloadMinBatch.values : []
if (allAxes.length === 0 && !moeModeEnabled) {
return [{ ...baseline }]
@@ -2501,13 +2498,6 @@ export function generateConfigCandidates(
if (moeKeepTopNValues.length > 0) {
modeAxes.push({ configKey: 'moe_keep_experts_top_n', values: moeKeepTopNValues })
}
- if (opOffloadValues.length > 0) {
- modeAxes.push({ configKey: 'op_offload_min_batch', values: opOffloadValues })
- }
- } else if (mode === 'experts_cpu') {
- if (opOffloadValues.length > 0) {
- modeAxes.push({ configKey: 'op_offload_min_batch', values: opOffloadValues })
- }
}
// experts_gpu: no additional MoE-specific axes
@@ -2531,7 +2521,7 @@ export function generateConfigCandidates(
const candidates: ConfigCandidate[] = []
const keyOf = (c: ConfigCandidate) =>
- `cw=${c['context_window']}|pbs=${c['prefill_batch_size']}|ns=${c['nseq_max']}|fa=${c['flash_attention']}|ct=${c['cache_type']}|cm=${c['cache_mode']}|mm=${c['moe_mode']}|mk=${c['moe_keep_experts_top_n'] ?? ''}|oomb=${c['op_offload_min_batch']}`
+ `cw=${c['context_window']}|pbs=${c['prefill_batch_size']}|ns=${c['nseq_max']}|fa=${c['flash_attention']}|ct=${c['cache_type']}|cm=${c['cache_mode']}|mm=${c['moe_mode']}|mk=${c['moe_keep_experts_top_n'] ?? ''}`
for (const c of combos) {
const k = keyOf(c)
diff --git a/cmd/server/api/frontends/bui/src/types/index.ts b/cmd/server/api/frontends/bui/src/types/index.ts
index bb6bcda8d..f9c379981 100644
--- a/cmd/server/api/frontends/bui/src/types/index.ts
+++ b/cmd/server/api/frontends/bui/src/types/index.ts
@@ -192,7 +192,6 @@ export interface ModelConfig {
'imc-session-capacity': number;
'offload-kqv': boolean | null;
'op-offload': boolean | null;
- 'op-offload-min-batch'?: number;
'proj-on-cpu': boolean | null;
'proj-device'?: string;
'ngpu-layers': number | null;
@@ -797,7 +796,6 @@ export interface PlaygroundModelConfig {
'moe_mode'?: string;
'moe_keep_experts_top_n'?: number | null;
'tensor_buft_overrides'?: string[];
- 'op_offload_min_batch'?: number | null;
'draft_model_id'?: string;
'draft_ndraft'?: number;
}
@@ -979,7 +977,6 @@ export interface ConfigSweepDefinition {
cacheMode: SweepStringValues;
moeMode?: SweepStringValues;
moeKeepExpertsTopN?: SweepParamValues;
- opOffloadMinBatch?: SweepParamValues;
}
export interface SamplingSweepDefinition {
@@ -1028,7 +1025,6 @@ export interface ConfigCandidate {
'cache_mode'?: string;
'moe_mode'?: string;
'moe_keep_experts_top_n'?: number;
- 'op_offload_min_batch'?: number;
}
export interface ModelCaps {
diff --git a/cmd/server/api/services/kronk/build/all.go b/cmd/server/api/services/kronk/build/all.go
index dbe89aea2..8ca75de4b 100644
--- a/cmd/server/api/services/kronk/build/all.go
+++ b/cmd/server/api/services/kronk/build/all.go
@@ -79,6 +79,7 @@ func (all) Add(app *web.App, cfg mux.Config) {
AuthClient: cfg.AuthClient,
Pool: cfg.Pool,
AuthorizationMode: cfg.AuthorizationMode,
+ InferenceTimeout: cfg.InferenceTimeout,
})
imageapp.Routes(app, imageapp.Config{
diff --git a/cmd/server/api/services/kronk/main.go b/cmd/server/api/services/kronk/main.go
index c6b5ba57e..47fc2d153 100644
--- a/cmd/server/api/services/kronk/main.go
+++ b/cmd/server/api/services/kronk/main.go
@@ -310,7 +310,9 @@ func run(ctx context.Context, log *logger.Logger, showHelp bool) error {
log.Info(ctx, "startup", "status", "model integrity checks, may take a few seconds")
- models.BuildIndex(log.Info, false)
+ if err := models.BuildIndex(log.Info, false); err != nil {
+ return fmt.Errorf("unable to build model index: %w", err)
+ }
if err := models.ReconcileCatalog(ctx, log.Info); err != nil {
log.Info(ctx, "startup", "WARNING", "reconcile catalog", "ERROR", err)
@@ -542,11 +544,28 @@ func run(ctx context.Context, log *logger.Logger, showHelp bool) error {
// -------------------------------------------------------------------------
// Start Debug Service
+ requestCtx, cancelRequests := context.WithCancel(ctx)
+ defer cancelRequests()
+
+ debugServer := http.Server{
+ Addr: cfg.Web.DebugHost,
+ Handler: debug.Mux(),
+ BaseContext: func(net.Listener) context.Context {
+ return requestCtx
+ },
+ ErrorLog: logger.NewStdLogger(log, logger.LevelError),
+ }
+ defer func() {
+ if err := debugServer.Close(); err != nil && !errors.Is(err, http.ErrServerClosed) {
+ log.Error(context.Background(), "shutdown", "status", "could not close debug server", "ERROR", err)
+ }
+ }()
+
go func() {
- log.Info(ctx, "startup", "status", "debug v1 router started", "host", cfg.Web.DebugHost)
+ log.Info(requestCtx, "startup", "status", "debug v1 router started", "host", cfg.Web.DebugHost)
- if err := http.ListenAndServe(cfg.Web.DebugHost, debug.Mux()); err != nil {
- log.Error(ctx, "shutdown", "status", "debug v1 router closed", "host", cfg.Web.DebugHost, "msg", err)
+ if err := debugServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
+ log.Error(requestCtx, "shutdown", "status", "debug v1 router closed", "host", cfg.Web.DebugHost, "msg", err)
}
}()
@@ -593,7 +612,10 @@ func run(ctx context.Context, log *logger.Logger, showHelp bool) error {
ReadTimeout: cfg.Web.ReadTimeout,
WriteTimeout: cfg.Web.WriteTimeout,
IdleTimeout: cfg.Web.IdleTimeout,
- ErrorLog: logger.NewStdLogger(log, logger.LevelError),
+ BaseContext: func(net.Listener) context.Context {
+ return requestCtx
+ },
+ ErrorLog: logger.NewStdLogger(log, logger.LevelError),
}
serverErrors := make(chan error, 1)
@@ -613,12 +635,22 @@ func run(ctx context.Context, log *logger.Logger, showHelp bool) error {
case sig := <-shutdown:
log.Info(ctx, "shutdown", "status", "shutdown started", "signal", sig)
+ cancelRequests()
- ctx, cancel := context.WithTimeout(ctx, cfg.Web.ShutdownTimeout)
+ ctx, cancel := context.WithTimeout(context.Background(), cfg.Web.ShutdownTimeout)
defer cancel()
+ if err := debugServer.Shutdown(ctx); err != nil {
+ log.Error(ctx, "shutdown", "status", "could not stop debug server gracefully", "ERROR", err)
+ if closeErr := debugServer.Close(); closeErr != nil && !errors.Is(closeErr, http.ErrServerClosed) {
+ log.Error(ctx, "shutdown", "status", "could not close debug server", "ERROR", closeErr)
+ }
+ }
+
if err := api.Shutdown(ctx); err != nil {
- api.Close()
+ if closeErr := api.Close(); closeErr != nil && !errors.Is(closeErr, http.ErrServerClosed) {
+ return errors.Join(fmt.Errorf("could not stop server gracefully: %w", err), fmt.Errorf("could not close server: %w", closeErr))
+ }
return fmt.Errorf("could not stop server gracefully: %w", err)
}
diff --git a/cmd/server/api/services/kronk/static/assets/index.js b/cmd/server/api/services/kronk/static/assets/index.js
index e8ad1e117..b51bee115 100644
--- a/cmd/server/api/services/kronk/static/assets/index.js
+++ b/cmd/server/api/services/kronk/static/assets/index.js
@@ -26,7 +26,7 @@ Please change the parent to e!==void 0&&Number.isFinite(e)?Math.round(e*1e3)/1e3:e,a=new Set,o=[],s=e=>`t=${i(e.temperature)}|p=${i(e.top_p)}|k=${e.top_k}|m=${i(e.min_p)}|rp=${i(e.repeat_penalty)}|rn=${e.repeat_last_n}|fp=${i(e.frequency_penalty)}|pp=${i(e.presence_penalty)}|dm=${i(e.dry_multiplier)}|db=${i(e.dry_base)}|da=${e.dry_allowed_length}|dp=${e.dry_penalty_last_n}|xp=${i(e.xtc_probability)}|xt=${i(e.xtc_threshold)}|xk=${e.xtc_min_keep}|mt=${e.max_tokens}|et=${e.enable_thinking}|re=${e.reasoning_effort}`,c=e=>{if(n!==1/0&&o.length>=n)return;let t=s(e);a.has(t)||(a.add(t),o.push(e))},l=(e,t)=>e!==void 0&&Math.abs(e-t)<.001;if(c({...r}),n<=1)return o;let u=(e,t)=>[...e].sort((e,n)=>Math.abs(e-t)-Math.abs(n-t)),d=[{key:`temperature`,values:e.temperature},{key:`top_p`,values:e.top_p},{key:`top_k`,values:e.top_k},{key:`min_p`,values:e.min_p},{key:`repeat_penalty`,values:e.repeat_penalty},{key:`repeat_last_n`,values:e.repeat_last_n},{key:`frequency_penalty`,values:e.frequency_penalty},{key:`presence_penalty`,values:e.presence_penalty},{key:`dry_multiplier`,values:e.dry_multiplier},{key:`dry_base`,values:e.dry_base},{key:`dry_allowed_length`,values:e.dry_allowed_length},{key:`dry_penalty_last_n`,values:e.dry_penalty_last_n},{key:`xtc_probability`,values:e.xtc_probability},{key:`xtc_threshold`,values:e.xtc_threshold},{key:`xtc_min_keep`,values:e.xtc_min_keep},{key:`max_tokens`,values:e.max_tokens}].filter(e=>e.values.length>1).map(e=>{let t=r[e.key]??0;return u(e.values.filter(e=>!l(t,e)),t).map(t=>({...r,[e.key]:t}))});e.enable_thinking.length>1&&d.push(e.enable_thinking.filter(e=>e!==r.enable_thinking).map(e=>({...r,enable_thinking:e}))),e.reasoning_effort.length>1&&d.push(e.reasoning_effort.filter(e=>e!==r.reasoning_effort).map(e=>({...r,reasoning_effort:e})));for(let e=0;n===1/0||o.length=n))break;if(!t)break}let f=e.temperature.length>0?e.temperature:[r.temperature??.8],p=e.top_p.length>0?e.top_p:[r.top_p??.9],m=e.top_k.length>0?e.top_k:[r.top_k??40],h=e.min_p.length>0?e.min_p:[r.min_p??0];if(f.length>1||p.length>1||m.length>1||h.length>1){let e=Math.min(...f),t=Math.max(...f),n=Math.min(...p),i=Math.max(...p),a=Math.min(...m),o=Math.max(...m),s=Math.max(...h);[{...r,temperature:e,top_p:n},{...r,temperature:e,top_p:i},{...r,temperature:t,top_p:n},{...r,temperature:t,top_p:i},{...r,temperature:e,top_k:a},{...r,temperature:e,top_k:o},{...r,temperature:t,top_k:a},{...r,temperature:t,top_k:o},{...r,top_p:n,top_k:a},{...r,top_p:n,top_k:o},{...r,top_p:i,top_k:a},{...r,top_p:i,top_k:o},{...r,min_p:s,temperature:e},{...r,min_p:s,temperature:t},{...r,min_p:s,top_p:n},{...r,min_p:s,top_p:i}].forEach(c)}return o}var er={temperature:[.8],top_p:[.9],top_k:[40],min_p:[0],repeat_penalty:[1],repeat_last_n:[64],frequency_penalty:[0],presence_penalty:[0],dry_multiplier:[1.05],dry_base:[1.75],dry_allowed_length:[2],dry_penalty_last_n:[0],xtc_probability:[0],xtc_threshold:[.1],xtc_min_keep:[1],max_tokens:[4096],enable_thinking:[`true`],reasoning_effort:[`medium`]},tr={prefillBatchSize:{enabled:!0,values:[Bn]},contextWindow:{enabled:!0,values:[2048,4096,8192,16384,32768,65536,98304,131072]},nSeqMax:{enabled:!0,values:[1,2]},flashAttention:{enabled:!0,values:[`enabled`,`disabled`]},cacheType:{enabled:!0,values:[`f16`,`q8_0`,`q4_0`]},cacheMode:{enabled:!0,values:[`none`,`imc`]}},nr={prefillBatchSize:{enabled:!0,values:[1024,2048,4096]},contextWindow:{enabled:!0,values:[4096,8192,16384,32768]},nSeqMax:{enabled:!0,values:[1,2]},flashAttention:{enabled:!0,values:[`enabled`]},cacheType:{enabled:!0,values:[`q8_0`,`q4_0`]},cacheMode:{enabled:!0,values:[`none`,`imc`]},moeMode:{enabled:!0,values:[`experts_cpu`,`keep_top_n`]},moeKeepExpertsTopN:{enabled:!0,values:[0,4,8]},opOffloadMinBatch:{enabled:!0,values:[0,128,256,512]}};function rr(e,t,n){let r={context_window:e.context_window,prefill_batch_size:e.prefill_batch_size??2048,nseq_max:e.nseq_max},i=[];t.prefillBatchSize.enabled&&t.prefillBatchSize.values.length>0&&i.push({configKey:`prefill_batch_size`,values:t.prefillBatchSize.values}),t.contextWindow.enabled&&t.contextWindow.values.length>0&&i.push({configKey:`context_window`,values:t.contextWindow.values}),t.nSeqMax.enabled&&t.nSeqMax.values.length>0&&i.push({configKey:`nseq_max`,values:t.nSeqMax.values});let a=[...i];t.flashAttention.enabled&&t.flashAttention.values.length>0&&a.push({configKey:`flash_attention`,values:t.flashAttention.values}),t.cacheType.enabled&&t.cacheType.values.length>0&&a.push({configKey:`cache_type`,values:t.cacheType.values}),t.cacheMode.enabled&&t.cacheMode.values.length>0&&a.push({configKey:`cache_mode`,values:t.cacheMode.values});let o=t.moeMode?.enabled&&t.moeMode.values.length>0,s=t.moeKeepExpertsTopN?.enabled&&t.moeKeepExpertsTopN.values.length>0?t.moeKeepExpertsTopN.values:[],c=t.opOffloadMinBatch?.enabled&&t.opOffloadMinBatch.values.length>0?t.opOffloadMinBatch.values:[];if(a.length===0&&!o)return[{...r}];let l=[{...r}];for(let e of a){let t=[];for(let n of l)for(let r of e.values)t.push({...n,[e.configKey]:r});l=t}let u;if(!o)u=l;else{u=[];for(let e of t.moeMode.values){let t=[];e===`keep_top_n`?(s.length>0&&t.push({configKey:`moe_keep_experts_top_n`,values:s}),c.length>0&&t.push({configKey:`op_offload_min_batch`,values:c})):e===`experts_cpu`&&c.length>0&&t.push({configKey:`op_offload_min_batch`,values:c});let n=l.map(t=>({...t,moe_mode:e}));for(let e of t){let t=[];for(let r of n)for(let n of e.values)t.push({...r,[e.configKey]:n});n=t}u.push(...n)}}let d=new Set,f=[],p=e=>`cw=${e.context_window}|pbs=${e.prefill_batch_size}|ns=${e.nseq_max}|fa=${e.flash_attention}|ct=${e.cache_type}|cm=${e.cache_mode}|mm=${e.moe_mode}|mk=${e.moe_keep_experts_top_n??``}|oomb=${e.op_offload_min_batch}`;for(let e of u){let t=p(e);d.has(t)||n?.isHybrid&&(e.flash_attention===`enabled`||e.cache_type!==void 0&&e.cache_type!==`f16`)||(d.add(t),f.push(e))}return f}function ir(e,t){let n=[],r=0;if(!t)return{score:0,notes:[`No expected value defined`]};switch(t.type){case`exact`:{let i=e.trim().toLowerCase(),a=(t.value??``).trim().toLowerCase();i===a?r=100:i.includes(a)?(r=50,n.push(`Partial match: response contains "${t.value}" but has extra text`)):(r=0,n.push(`Expected "${t.value}", got "${e.trim().slice(0,100)}"`));break}case`regex`:new RegExp(t.value??``,`im`).test(e)?r=100:(r=0,n.push(`Regex /${t.value}/ did not match`));break;case`tool_call`:case`no_tool_call`:r=0,n.push(`${t.type} expected type not applicable for chat scoring`)}return e.length>2e3&&(r=Math.max(0,r-10),n.push(`Penalized: response exceeds 2000 characters`)),{score:r,notes:n}}function ar(e,t){let n=[];if(!e||e.length===0)return{score:0,notes:[`No tool calls emitted`]};let r=100,i=new Set(t.filter(e=>e.type===`function`&&e.function?.name).map(e=>e.function.name));for(let a of e){i.has(a.function.name)||(r-=40,n.push(`Tool "${a.function.name}" not in declared tools`));try{let e=JSON.parse(a.function.arguments),i=t.find(e=>e.type===`function`&&e.function?.name===a.function.name)?.function?.parameters;if(i?.required&&Array.isArray(i.required)){let t=i.required;for(let i of t)i in e||(r-=20,n.push(`Missing required field "${i}" in ${a.function.name}`))}}catch{r-=30,n.push(`Arguments for "${a.function.name}" are not valid JSON`)}}return{score:Math.max(0,Math.min(100,r)),notes:n}}function or(e,t,n){let r=[];if(e&&e.length>0){let t=e.map(e=>e.function?.name).filter(Boolean).join(`, `);return r.push(`Unexpected tool call(s): ${t}`),{score:0,notes:r}}let i=100;return t.trim().length===0&&(i-=20,r.push(`No text response produced`)),n?.value&&(new RegExp(n.value,`im`).test(t)||(i-=30,r.push(`Expected text matching /${n.value}/ but got "${t.trim().slice(0,100)}"`))),{score:Math.max(0,i),notes:r}}function sr(e,t,n,r){return new Promise((i,a)=>{if(r?.aborted)return a(new DOMException(`Aborted`,`AbortError`));let o=!1,s=``,c=[],l,u=()=>{o||(o=!0,d(),a(new DOMException(`Aborted`,`AbortError`)))},d=W.streamPlaygroundChat({session_id:e,messages:t.messages,tools:t.tools,stream:!0,temperature:n.temperature,top_p:n.top_p,top_k:n.top_k,min_p:n.min_p,max_tokens:n.max_tokens??t.max_tokens,repeat_penalty:n.repeat_penalty,repeat_last_n:n.repeat_last_n,frequency_penalty:n.frequency_penalty,presence_penalty:n.presence_penalty,dry_multiplier:n.dry_multiplier,dry_base:n.dry_base,dry_allowed_length:n.dry_allowed_length,dry_penalty_last_n:n.dry_penalty_last_n,xtc_probability:n.xtc_probability,xtc_threshold:n.xtc_threshold,xtc_min_keep:n.xtc_min_keep,adaptive_p_target:n.adaptive_p_target,adaptive_p_decay:n.adaptive_p_decay,enable_thinking:n.enable_thinking,reasoning_effort:n.reasoning_effort,grammar:n.grammar,stream_options:{include_usage:!0}},e=>{let t=e.choices?.[0];if(t?.delta?.content&&(s+=t.delta.content),t?.delta?.tool_calls)for(let e of t.delta.tool_calls){let t=c.find(t=>t.index===e.index);t?(e.id&&!t.id&&(t.id=e.id),e.type&&!t.type&&(t.type=e.type),e.function?.name&&!t.function.name&&(t.function.name=e.function.name),e.function?.arguments&&(t.function.arguments+=e.function.arguments)):c.push({id:e.id||``,index:e.index,type:e.type||`function`,function:{name:e.function?.name||``,arguments:e.function?.arguments||``}})}e.usage&&(l=e.usage)},e=>{o||(o=!0,r?.removeEventListener(`abort`,u),d(),a(Error(e)))},()=>{if(o)return;o=!0,r?.removeEventListener(`abort`,u);let e;e=t.expected?.type===`tool_call`?ar(c,t.tools??[]):t.expected?.type===`no_tool_call`?or(c,s,t.expected):ir(s,t.expected),i({promptId:t.id,assistantText:s,toolCalls:c,usage:l,score:e.score,notes:e.notes.length>0?e.notes:void 0})});r?.addEventListener(`abort`,u,{once:!0})})}async function cr(e,t){let n={id:`probe-tool`,messages:[{role:`system`,content:q},{role:`user`,content:`What's the weather in Boston?`}],tools:K,expected:{type:`tool_call`}};try{let r=await sr(e,n,{},t);return r.toolCalls.length>0&&r.score>0}catch{return!1}}var lr={chatScore:.4,toolScore:.6,totalScore:0,avgTPS:0,avgTTFT:0,tps0:0,tps20:0,tps50:0,tps80:0,ttft0:0,ttft20:0,ttft50:0,ttft80:0},ur={chatScore:0,toolScore:0,totalScore:0,avgTPS:1,avgTTFT:.5,tps0:.8,tps20:.6,tps50:.4,tps80:.2,ttft0:0,ttft20:0,ttft50:0,ttft80:0};function dr(e,t){let n=t!==`config`;switch(e){case`overall`:return{chatScore:n?.4:0,toolScore:n?.6:0,totalScore:0,avgTPS:.5,avgTTFT:.3,tps0:.2,tps20:.2,tps50:.2,tps80:.2,ttft0:.1,ttft20:.1,ttft50:.1,ttft80:.1};case`0pct`:return{chatScore:n?.2:0,toolScore:n?.3:0,totalScore:0,avgTPS:.2,avgTTFT:.1,tps0:1,tps20:0,tps50:0,tps80:0,ttft0:.8,ttft20:0,ttft50:0,ttft80:0};case`80pct`:return{chatScore:n?.2:0,toolScore:n?.3:0,totalScore:0,avgTPS:.2,avgTTFT:.1,tps0:0,tps20:0,tps50:0,tps80:1,ttft0:0,ttft20:0,ttft50:0,ttft80:.8}}}function fr(e,t){let n=e.scenarioResults.find(e=>e.scenarioId===`chat`)?.score,r=e.scenarioResults.find(e=>e.scenarioId===`tool_call`)?.score,i=e.totalScore,a=e.avgTPS,o=e.avgTTFT,s=[];n!==void 0&&s.push({w:t.chatScore??0,v:n}),r!==void 0&&s.push({w:t.toolScore??0,v:r}),i!==void 0&&s.push({w:t.totalScore??0,v:i}),a!==void 0&&s.push({w:t.avgTPS??0,v:Math.min(100,Math.max(0,a))}),o!==void 0&&s.push({w:t.avgTTFT??0,v:Math.max(0,100-o/10)});let c=[{key:`0%`,w:t.tps0??0},{key:`20%`,w:t.tps20??0},{key:`50%`,w:t.tps50??0},{key:`80%`,w:t.tps80??0}];for(let{key:t,w:n}of c){let r=e.avgTPSByFill?.[t];r!==void 0&&s.push({w:n,v:Math.min(100,Math.max(0,r))})}let l=[{key:`0%`,w:t.ttft0??0},{key:`20%`,w:t.ttft20??0},{key:`50%`,w:t.ttft50??0},{key:`80%`,w:t.ttft80??0}];for(let{key:t,w:n}of l){let r=e.avgTTFTByFill?.[t];r!==void 0&&s.push({w:n,v:Math.max(0,100-r/10)})}let u=s.reduce((e,t)=>e+t.w,0);return u<=0?i??n??r??0:Math.round(s.reduce((e,t)=>e+t.w*t.v,0)/u*100)/100}var pr=6;async function mr(e,t,n,r){let i=Array(e.length),a=0,o=Array.from({length:Math.min(t,e.length)},async()=>{for(;!r.aborted;){let t=a++;if(t>=e.length)break;i[t]=await n(e[t],t)}});return await Promise.all(o),i}function hr(e,t,n,r,i,a,o,s,c,l,u,d){let f=new Set(t.filter(e=>e.includeInScore===!1).map(e=>e.id)),p=n.filter(e=>!f.has(e.promptId)),m=p.length>0?Math.round(p.reduce((e,t)=>e+t.score,0)/p.length*100)/100:0,h={},g={},_={};for(let e of[`0%`,`20%`,`50%`,`80%`]){let t=s[e],n=c[e];t!==void 0&&n!==void 0&&n>0&&(h[e]=t/n);let r=l[e],i=u[e];r!==void 0&&i!==void 0&&i>0&&(g[e]=r/i),d[e]!==void 0&&(_[e]=d[e])}return{scenarioId:e,promptResults:[...n],score:m,avgTPS:i>0?r/i:void 0,avgTTFT:o>0?a/o:void 0,...Object.keys(h).length>0&&{avgTPSByFill:h},...Object.keys(g).length>0&&{avgTTFTByFill:g},...Object.keys(_).length>0&&{promptTokensByFill:_}}}function gr(e){let t=e.scenarioResults.find(e=>e.scenarioId===`chat`),n=e.scenarioResults.find(e=>e.scenarioId===`tool_call`),r=t??n;r?.avgTPS!==void 0&&(e.avgTPS=r.avgTPS),r?.avgTTFT!==void 0&&(e.avgTTFT=r.avgTTFT);let i=t??n;i?.avgTPSByFill&&Object.keys(i.avgTPSByFill).length>0&&(e.avgTPSByFill=i.avgTPSByFill),i?.avgTTFTByFill&&Object.keys(i.avgTTFTByFill).length>0&&(e.avgTTFTByFill=i.avgTTFTByFill)}function _r(e,t,n){let r=e.scenarioResults.findIndex(e=>e.scenarioId===t.scenarioId);r>=0?e.scenarioResults[r]=t:e.scenarioResults.push(t),gr(e),n({...e,scenarioResults:[...e.scenarioResults]})}function vr(e,t,n,r){let i=e.usage?.tokens_per_second,a=e.usage?.completion_tokens;if(r&&i&&i>0&&a!==void 0){let e=Math.max(0,a-1);e>0&&(n.genTokens+=e,n.genSeconds+=e/i)}if(r&&e.usage?.time_to_first_token_ms&&e.usage.time_to_first_token_ms>0&&(n.ttft+=e.usage.time_to_first_token_ms,n.ttftCount++),t.contextFill){let r=t.contextFill.label;if(i&&i>0&&a!==void 0){let e=Math.max(0,a-1);e>0&&(n.fillGenTokens[r]=(n.fillGenTokens[r]??0)+e,n.fillGenSeconds[r]=(n.fillGenSeconds[r]??0)+e/i)}e.usage?.time_to_first_token_ms&&e.usage.time_to_first_token_ms>0&&(n.fillTTFT[r]=(n.fillTTFT[r]??0)+e.usage.time_to_first_token_ms,n.fillTTFTCount[r]=(n.fillTTFTCount[r]??0)+1),e.usage?.prompt_tokens&&(n.actualFills[r]=e.usage.prompt_tokens)}}function yr(e,t){e.logEntries||=[],e.logEntries.push({timestamp:new Date().toISOString(),message:t})}function br(e){let t=[...e.messages].reverse().find(e=>e.role===`user`);if(!t)return;let n=t.content;if(typeof n==`string`)return n.slice(0,160);if(Array.isArray(n)){let e=n.filter(e=>e?.type===`text`).map(e=>e.text??``).join(` `);return e?e.slice(0,160):void 0}}async function xr(e,t,n,r,i,a,o){let s=[],c=0,l=0,u=0,d=0,f={},p={},m={},h={},g={};yr(i,`Starting scenario: ${n.name} (${n.prompts.length} prompts, ${r}x repeats)`),a({...i});for(let _=0;_1?` (${y}x)`:``}`),i.activePrompts=[{scenarioId:n.id,promptId:v.id,promptIndex:_,repeats:y,repeatIndex:1,preview:br(v),startedAt:new Date().toISOString()}],a({...i});let S=[],C=[],w=``,T=[],E=0,D=0,O=0,k=0,A,j=!1,M=!1,N=``;for(let n=0;n1&&n>0&&(i.activePrompts=[{...i.activePrompts[0],repeatIndex:n+1}],a({...i}));try{let r=await sr(e,v,t,o);if(S.push(r.score),r.notes&&C.push(...r.notes),n===0&&(w=r.assistantText,T=r.toolCalls),A=r.usage,!b){let e=r.usage?.tokens_per_second,t=r.usage?.completion_tokens;if(e&&e>0&&t!==void 0){let n=Math.max(0,t-1);n>0&&(E+=n,D+=n/e)}r.usage?.time_to_first_token_ms&&r.usage.time_to_first_token_ms>0&&(O+=r.usage.time_to_first_token_ms,k++)}if(v.contextFill){let e=v.contextFill.label,t=r.usage?.tokens_per_second,n=r.usage?.completion_tokens;if(t&&t>0&&n!==void 0){let r=Math.max(0,n-1);r>0&&(f[e]=(f[e]??0)+r,p[e]=(p[e]??0)+r/t)}r.usage?.time_to_first_token_ms&&r.usage.time_to_first_token_ms>0&&(m[e]=(m[e]??0)+r.usage.time_to_first_token_ms,h[e]=(h[e]??0)+1),r.usage?.prompt_tokens&&(g[e]=r.usage.prompt_tokens)}}catch(e){if(e instanceof DOMException&&e.name===`AbortError`){j=!0;break}let t=e instanceof Error?e.message:String(e);if(t.includes(`Stream terminated`)){yr(i,`Prompt ${x} failed: ${t}`),i.activePrompts=void 0,i.status=`failed`,a({...i});return}S.push(0),N=`Error: ${t}`,M=!0}}if(j){i.activePrompts=void 0,i.status=`cancelled`,a({...i});return}let P=S.length>0?Math.round(S.reduce((e,t)=>e+t,0)/S.length*100)/100:0,F=C.length>0?[...new Set(C)]:void 0;s.push({promptId:v.id,assistantText:w,toolCalls:T,usage:A,score:P,notes:M&&!F?[N]:F});let I=!!v.contextFill;!b&&!I&&(c+=E,l+=D,u+=O,d+=k),_r(i,hr(n.id,n.prompts,s,c,l,u,d,f,p,m,h,g),a)}i.activePrompts=void 0,a({...i})}async function Sr(e,t,n,r,i,a,o,s){let c=Array(n.prompts.length),l={genTokens:0,genSeconds:0,ttft:0,ttftCount:0,fillGenTokens:{},fillGenSeconds:{},fillTTFT:{},fillTTFTCount:{},actualFills:{}};yr(a,`Starting scenario: ${n.name} (${n.prompts.length} prompts, concurrency=${i}, ${r}x repeats)`),o({...a});let u=new AbortController,d=u.signal,f=()=>u.abort();s.addEventListener(`abort`,f,{once:!0});let p=performance.now(),m=new Map,h=()=>{a.activePrompts=[...m.values()],o({...a})};try{await mr(n.prompts,i,async(i,s)=>{if(d.aborted)return;let f=i.contextFill==null?r:1;m.set(s,{scenarioId:n.id,promptId:i.id,promptIndex:s,repeats:f,repeatIndex:1,preview:br(i),startedAt:new Date().toISOString()}),h();let p=[],g=[],_=``,v=[],y,b=!1,x=``;for(let n=0;n1&&n>0){let e=m.get(s);e&&(m.set(s,{...e,repeatIndex:n+1}),h())}try{let r=await sr(e,i,t,d);p.push(r.score),r.notes&&g.push(...r.notes),n===0&&(_=r.assistantText,v=r.toolCalls),y=r.usage;let a=s!==0&&!i.contextFill;vr(r,i,l,a)}catch(e){if(e instanceof DOMException&&e.name===`AbortError`)break;let t=e instanceof Error?e.message:String(e);if(t.includes(`Stream terminated`)){yr(a,`Prompt ${i.id} failed: ${t}`),a.activePrompts=void 0,a.status=`failed`,o({...a}),u.abort();return}p.push(0),x=`Error: ${t}`,b=!0}}if(d.aborted){m.delete(s);return}let S=p.length>0?p.reduce((e,t)=>e+t,0)/p.length:0,C=g.length>0?[...new Set(g)]:void 0;c[s]={promptId:i.id,assistantText:_,toolCalls:v,usage:y,score:S,notes:b&&!C?[x]:C},m.delete(s);let w=c.filter(Boolean),T=hr(n.id,n.prompts,w,l.genTokens,l.genSeconds,l.ttft,l.ttftCount,l.fillGenTokens,l.fillGenSeconds,l.fillTTFT,l.fillTTFTCount,l.actualFills);a.activePrompts=[...m.values()],_r(a,T,o)},d)}finally{s.removeEventListener(`abort`,f)}if(a.activePrompts=void 0,a.status===`failed`)return;if(d.aborted){a.status=`cancelled`,o({...a});return}let g=(performance.now()-p)/1e3,_=g>0&&l.genTokens>0?l.genTokens/g:void 0,v=c.filter(Boolean),y=hr(n.id,n.prompts,v,l.genTokens,l.genSeconds,l.ttft,l.ttftCount,l.fillGenTokens,l.fillGenSeconds,l.fillTTFT,l.fillTTFTCount,l.actualFills);_!==void 0&&(y.avgTPS=_),_r(a,y,o)}async function Cr(e,t,n,r,i,a,o=3,s){let c=`trial-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,l=Math.max(1,Math.floor(o)),u=Math.min(Math.max(1,s?.concurrency??1),pr),d={id:c,status:`running`,candidate:t,startedAt:new Date().toISOString(),scenarioResults:[],logEntries:[]};yr(d,`Trial started (${n.length} scenario${n.length===1?``:`s`})`),r({...d});for(let a=0;a0){yr(d,`Pausing ${Vn/1e3}s before next scenario…`),r({...d});try{await Wn(Vn,i)}catch(e){if(e instanceof DOMException&&e.name===`AbortError`)return d.status=`cancelled`,d.finishedAt=new Date().toISOString(),r({...d}),d;throw e}}if(u>1&&o.prompts.length>0){yr(d,`Warming up cache for concurrent scenario: ${o.name}`),r({...d});try{await sr(e,o.prompts[0],{...t,max_tokens:1},i)}catch(e){if(e instanceof DOMException&&e.name===`AbortError`)return d.status=`cancelled`,r({...d}),d}}if(u>1?await Sr(e,t,o,l,u,d,r,i):await xr(e,t,o,l,d,r,i),d.status===`cancelled`||d.status===`failed`)return d}let f=new Map;for(let e of d.scenarioResults)f.set(e.scenarioId,{score:e.score,avgTPS:e.avgTPS,avgTTFT:e.avgTTFT});let p=f.get(`tool_call`),m=f.get(`chat`),h=a??lr;if(p&&m){let e=h.chatScore,t=h.toolScore,n=e+t,r=n>0?(t*p.score+e*m.score)/n:(p.score+m.score)/2;d.totalScore=Math.round(r*100)/100}else p?d.totalScore=p.score:m&&(d.totalScore=m.score);let g=m??p;d.avgTPS=g?.avgTPS,d.avgTTFT=g?.avgTTFT;let _=d.scenarioResults.find(e=>e.scenarioId===`chat`);return _?.avgTPSByFill&&Object.keys(_.avgTPSByFill).length>0&&(d.avgTPSByFill=_.avgTPSByFill),_?.avgTTFTByFill&&Object.keys(_.avgTTFTByFill).length>0&&(d.avgTTFTByFill=_.avgTTFTByFill),d.finishedAt=new Date().toISOString(),d.status=`completed`,r({...d}),d}var wr=`kronk_chat_messages`,Tr=`kronk_chat_history`,Er=`kronk:chatHistory`,Dr=1,Or=`session`,kr=`history`,Ar=`meta`;function jr(e){if(!e)return;let t=e;if(typeof t.output_tokens!=`number`)return e;let{output_tokens:n,reasoning_tokens:r,...i}=t;return{...i,completion_tokens:n,completion_tokens_details:{reasoning_tokens:r??0},total_tokens:e.total_tokens??e.prompt_tokens+n}}function Mr(e){return e.map(e=>({...e,usage:jr(e.usage)}))}function Nr(e){return new Promise((t,n)=>{e.onsuccess=()=>t(e.result),e.onerror=()=>n(e.error)})}function Pr(e){return new Promise((t,n)=>{e.oncomplete=()=>t(),e.onerror=()=>n(e.error),e.onabort=()=>n(e.error)})}var Fr=null;function Ir(){return Fr||(Fr=new Promise((e,t)=>{let n=indexedDB.open(Er,Dr);n.onupgradeneeded=()=>{let e=n.result;e.objectStoreNames.contains(Or)||e.createObjectStore(Or,{keyPath:`key`}),e.objectStoreNames.contains(kr)||e.createObjectStore(kr,{keyPath:`id`}).createIndex(`by_savedAt`,`savedAt`),e.objectStoreNames.contains(Ar)||e.createObjectStore(Ar,{keyPath:`key`})},n.onsuccess=()=>e(n.result),n.onerror=()=>{Fr=null,t(n.error)}}),Fr)}var Lr=!1,Rr=null;async function zr(e){if(!Lr)return Rr||(Rr=Br(e),Rr)}async function Br(e){if(await Nr(e.transaction(Ar,`readonly`).objectStore(Ar).get(`migratedFromLocalStorage`))){Lr=!0;return}let t=e.transaction([Or,kr],`readonly`),n=await Nr(t.objectStore(Or).count()),r=await Nr(t.objectStore(kr).count());if(n>0||r>0){let t=e.transaction(Ar,`readwrite`);t.objectStore(Ar).put({key:`migratedFromLocalStorage`,value:!0}),await Pr(t),Lr=!0;return}try{let t=e.transaction([Or,kr,Ar],`readwrite`),n=!1,r=localStorage.getItem(wr);if(r){let e=JSON.parse(r);Array.isArray(e)&&e.length>0&&(t.objectStore(Or).put({key:`messages`,value:e}),n=!0)}let i=localStorage.getItem(Tr);if(i){let e=JSON.parse(i);if(Array.isArray(e)){let r=t.objectStore(kr);for(let t of e)r.put(t);e.length>0&&(n=!0)}}t.objectStore(Ar).put({key:`migratedFromLocalStorage`,value:!0}),await Pr(t),n&&(localStorage.removeItem(wr),localStorage.removeItem(Tr)),Lr=!0;return}catch{}let i=e.transaction(Ar,`readwrite`);i.objectStore(Ar).put({key:`migratedFromLocalStorage`,value:!0}),await Pr(i),Lr=!0}async function Vr(){let e=await Ir();return await zr(e),e}function Hr(){try{let e=localStorage.getItem(wr);if(!e)return[];let t=JSON.parse(e);return Array.isArray(t)?Mr(t):[]}catch{return[]}}function Ur(e){try{e.length>0?localStorage.setItem(wr,JSON.stringify(e)):localStorage.removeItem(wr)}catch{}}function Wr(){try{let e=localStorage.getItem(Tr);if(!e)return[];let t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}function Gr(e){try{e.length>0?localStorage.setItem(Tr,JSON.stringify(e)):localStorage.removeItem(Tr)}catch{}}async function Kr(){try{let e=await Nr((await Vr()).transaction(Or,`readonly`).objectStore(Or).get(`messages`));return e&&Array.isArray(e.value)?Mr(e.value):[]}catch{return Hr()}}async function qr(e){try{let t=(await Vr()).transaction(Or,`readwrite`);e.length===0?t.objectStore(Or).delete(`messages`):t.objectStore(Or).put({key:`messages`,value:e}),await Pr(t)}catch{Ur(e)}}async function Jr(){await qr([])}async function Yr(){try{return(await Nr((await Vr()).transaction(kr,`readonly`).objectStore(kr).index(`by_savedAt`).getAll())).reverse()}catch{return Wr()}}async function Xr(e){try{let t=(await Vr()).transaction(kr,`readwrite`);t.objectStore(kr).put(e),await Pr(t)}catch{let t=Wr().filter(t=>t.id!==e.id);t.unshift(e),Gr(t)}}async function Zr(e){if(e.length!==0)try{let t=(await Vr()).transaction(kr,`readwrite`),n=t.objectStore(kr);for(let t of e)n.delete(t);await Pr(t)}catch{let t=new Set(e);Gr(Wr().filter(e=>!t.has(e.id)))}}async function Qr(){try{let e=(await Vr()).transaction(kr,`readwrite`);e.objectStore(kr).clear(),await Pr(e)}catch{try{localStorage.removeItem(Tr)}catch{}}}var $r=`playground:autoTestHistory:v1`,ei=`playground:autoTestHistory:updatedAt`,ti=`playground:autoTestHistory`,ni=1,ri=`entries`,ii=`meta`;function ai(e){return new Promise((t,n)=>{e.onsuccess=()=>t(e.result),e.onerror=()=>n(e.error)})}function oi(e){return new Promise((t,n)=>{e.oncomplete=()=>t(),e.onerror=()=>n(e.error),e.onabort=()=>n(e.error)})}var si=null;function ci(){return si||(si=new Promise((e,t)=>{let n=indexedDB.open(ti,ni);n.onupgradeneeded=()=>{let e=n.result;e.objectStoreNames.contains(ri)||e.createObjectStore(ri,{keyPath:`id`}).createIndex(`by_savedAt`,`savedAt`),e.objectStoreNames.contains(ii)||e.createObjectStore(ii,{keyPath:`key`})},n.onsuccess=()=>e(n.result),n.onerror=()=>{si=null,t(n.error)}}),si)}var li=!1;async function ui(e){if(li)return;if(await ai(e.transaction(ii,`readonly`).objectStore(ii).get(`migratedFromLocalStorage`))){li=!0;return}if(await ai(e.transaction(ri,`readonly`).objectStore(ri).count())>0){let t=e.transaction(ii,`readwrite`);t.objectStore(ii).put({key:`migratedFromLocalStorage`,value:!0}),await oi(t),li=!0;return}try{let t=localStorage.getItem($r);if(t){let n=JSON.parse(t);if(Array.isArray(n)){let t=n.filter(di);if(t.length>0){let n=e.transaction([ri,ii],`readwrite`),r=n.objectStore(ri);for(let e of t)r.put(e);n.objectStore(ii).put({key:`migratedFromLocalStorage`,value:!0}),await oi(n),localStorage.removeItem($r),li=!0;return}}}}catch{}let t=e.transaction(ii,`readwrite`);t.objectStore(ii).put({key:`migratedFromLocalStorage`,value:!0}),await oi(t),li=!0}function di(e){if(typeof e!=`object`||!e)return!1;let t=e;if(t.version!==1||typeof t.id!=`string`||t.id.length===0||typeof t.savedAt!=`string`||!Number.isFinite(Date.parse(t.savedAt))||t.sweepMode!==`sampling`&&t.sweepMode!==`config`||typeof t.run!=`object`||t.run===null)return!1;let n=t.run;return!!Array.isArray(n.trials)}function fi(e){let t=structuredClone(e);for(let e of t.trials)e.activePrompts=void 0,e.logEntries=void 0;return t}function pi(e){let t=structuredClone(e);for(let e of t.run.trials)for(let t of e.scenarioResults)for(let e of t.promptResults)e.usage=jr(e.usage);return t}function mi(e){let t;for(let n of e.trials)n.finishedAt&&(!t||n.finishedAt>t)&&(t=n.finishedAt);return t??e.runStartedAt}async function hi(e){let t=e.transaction(ri,`readwrite`),n=await ai(t.objectStore(ri).index(`by_savedAt`).getAllKeys());if(n.length<=500)return;let r=n.slice(0,n.length-500),i=t.objectStore(ri);for(let e of r)i.delete(e);await oi(t)}function gi(){window.dispatchEvent(new Event(`autotest-history-updated`));try{localStorage.setItem(ei,String(Date.now()))}catch{}}async function _i(){let e=await ci();return await ui(e),e}function vi(){try{let e=localStorage.getItem($r);if(!e)return[];let t=JSON.parse(e);return Array.isArray(t)?t.filter(di).map(pi):[]}catch{return[]}}function yi(e){try{localStorage.setItem($r,JSON.stringify(e.slice(0,500)))}catch{}}async function bi(){try{return(await ai((await _i()).transaction(ri,`readonly`).objectStore(ri).index(`by_savedAt`).getAll())).filter(di).map(pi).reverse()}catch{return vi()}}async function xi(e){let t=fi(e),n=e.kind===`sampling`?e.sessionSeed?.model_id:e.sessionSeed.model_id,r={version:1,id:e.runId,savedAt:new Date().toISOString(),completedAt:mi(e),modelId:n,sweepMode:e.kind,run:t};try{let e=await _i(),t=e.transaction(ri,`readwrite`);t.objectStore(ri).put(r),await oi(t),await hi(e)}catch{let t=vi().filter(t=>t.id!==e.runId);t.unshift(r),yi(t)}gi()}async function Si(e,t){try{let n=await _i(),r=await ai(n.transaction(ri,`readonly`).objectStore(ri).get(e));if(!r)return;let i=t(r),a=n.transaction(ri,`readwrite`);a.objectStore(ri).put(i),await oi(a)}catch{let n=vi(),r=n.findIndex(t=>t.id===e);r>=0&&(n[r]=t(n[r]),yi(n))}gi()}async function Ci(e){try{let t=(await _i()).transaction(ri,`readwrite`);t.objectStore(ri).delete(e),await oi(t)}catch{yi(vi().filter(t=>t.id!==e))}gi()}async function wi(e){if(e.length!==0){try{let t=(await _i()).transaction(ri,`readwrite`),n=t.objectStore(ri);for(let t of e)n.delete(t);await oi(t)}catch{let t=new Set(e);yi(vi().filter(e=>!t.has(e.id)))}gi()}}async function Ti(){let e=await bi(),t={schemaVersion:1,exportedAt:new Date().toISOString(),entries:e};return new Blob([JSON.stringify(t,null,2)],{type:`application/json`})}async function Ei(e){let t;try{t=JSON.parse(e)}catch{throw Error(`Invalid JSON file`)}if(typeof t!=`object`||!t||!(`schemaVersion`in t)||t.schemaVersion!==1||!(`entries`in t)||!Array.isArray(t.entries))throw Error(`Invalid export file format`);let n=t.entries,r=new Map;for(let e of n){if(!di(e))continue;let t=pi({...e,run:fi(e.run)}),n=r.get(t.id);(!n||t.savedAt>n.savedAt)&&r.set(t.id,t)}let i=Array.from(r.values());if(i.length===0)return{imported:0,skipped:n.length};let a=0,o=0;try{let e=await _i(),t=e.transaction(ri,`readonly`),n=new Set(await ai(t.objectStore(ri).getAllKeys())),r=e.transaction(ri,`readwrite`),s=r.objectStore(ri);for(let e of i)if(n.has(e.id)){let t=await ai(s.get(e.id));t&&e.savedAt>t.savedAt?(s.put(e),a++):o++}else s.put(e),a++;await oi(r),await hi(e)}catch{let e=vi(),t=new Map(e.map(e=>[e.id,e]));for(let e of i){let n=t.get(e.id);n?e.savedAt>n.savedAt?(t.set(e.id,e),a++):o++:(t.set(e.id,e),a++)}yi(Array.from(t.values()))}return gi(),{imported:a,skipped:o}}function Di(e,t,n){let r=[...e,...t,...n??[]],i=new Set;return r.filter(e=>{let t=`${e.timestamp}|${e.message}`;return!i.has(t)&&(i.add(t),!0)})}function Oi(e,t){return new Promise((n,r)=>{if(t.aborted){r(new DOMException(`Aborted`,`AbortError`));return}let i=setTimeout(()=>{t.removeEventListener(`abort`,a),n()},e);function a(){clearTimeout(i),r(new DOMException(`Aborted`,`AbortError`))}t.addEventListener(`abort`,a,{once:!0})})}async function ki(e){let t=-1/0,n=-1/0,r,i=!1;if(e.initialDelayMs&&e.initialDelayMs>0){e.onInitialDelayStart?.();try{await Oi(e.initialDelayMs,e.signal)}catch(t){if(e.onInitialDelayEnd?.(),t instanceof DOMException&&t.name===`AbortError`)return r;throw t}if(e.signal.aborted||e.isStale())return e.onInitialDelayEnd?.(),r;e.onInitialDelayEnd?.()}for(;!(e.signal.aborted||e.isStale());){if(i)try{await Oi(Hn,e.signal)}catch(e){if(e instanceof DOMException&&e.name===`AbortError`)break;throw e}if(e.signal.aborted||e.isStale())break;let a=e.getNextQueuedTrialId();if(a===void 0)break;let o=e.claimTrial(a);if(o<0)continue;if(i=!0,e.signal.aborted||e.isStale())break;let s=new AbortController;e.trialAbortRef&&(e.trialAbortRef.current=s);let c=()=>s.abort();e.signal.addEventListener(`abort`,c,{once:!0});let l=null,u=!1;try{l=await e.executeTrial(a,o,s.signal)}catch(t){if(t instanceof DOMException&&t.name===`AbortError`){if(s.signal.aborted&&!e.signal.aborted)u=!0,e.onTrialStopped?.(a,o);else break}else throw t}finally{e.signal.removeEventListener(`abort`,c),e.trialAbortRef&&(e.trialAbortRef.current=null)}if(u||!l||e.isStale())continue;let d=fr(l,e.weights),f=l.avgTPS??-1/0;(d>t+1e-6||Math.abs(d-t)<=1e-6&&f>n)&&(t=d,n=f,r=l.id),e.onTrialResult(a,o,l,r)}return r}var Ai=(0,x.createContext)(null);function ji({children:e}){let[t,n]=(0,x.useState)(null),r=(0,x.useRef)(null),i=(0,x.useCallback)(e=>{let t=r.current,i=typeof e==`function`?e(t):e;r.current=i,n(i)},[]);(0,x.useEffect)(()=>{r.current=t},[t]);let a=(0,x.useRef)(null),o=(0,x.useRef)(null),s=(0,x.useRef)(null),c=(0,x.useRef)(null),l=(0,x.useRef)(0),u=(0,x.useRef)(null),d=(0,x.useRef)(null),[f,p]=(0,x.useState)(!1),m=(0,x.useRef)(new Set);(0,x.useEffect)(()=>{t&&t.status===`completed`&&(m.current.has(t.runId)||(m.current.add(t.runId),xi(t)))},[t?.runId,t?.status]),(0,x.useEffect)(()=>{if(!t||t.status!==`cancelled`)return;let e=t.runId,n=setTimeout(()=>{i(t=>t&&t.runId===e&&t.status===`cancelled`?null:t)},8e3);return()=>clearTimeout(n)},[t?.runId,t?.status]),(0,x.useEffect)(()=>()=>{a.current?.abort(),c.current?.abort();let e=o.current;e&&W.deletePlaygroundSession(e).catch(()=>{}),o.current=null;let t=s.current;t&&W.deletePlaygroundSession(t).catch(()=>{}),s.current=null},[]);let h=(0,x.useCallback)(({sessionId:e,sessionSeed:t,enabledScenarios:n,sweepDef:o,maxTrials:d,weights:f,repeats:m,effectiveConfig:h})=>{if(u.current)return;let g=++l.current,_=()=>l.current!==g,v=`run-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,y=new AbortController;a.current=y;let b,x=new Promise(e=>{b=e});u.current={runId:v,done:x},p(!0),i({runId:v,kind:`sampling`,status:`repairing_template`,enabledScenarios:n,currentTrialIndex:0,totalTrials:0,sessionId:e??``,sessionSeed:t,sweepDef:o,maxTrials:d,trials:[],repeats:m,weights:f}),(async()=>{try{let a=e??``,l=h;if(!a&&t?.model_id){i(e=>e&&!_()?{...e,templateRepairStatus:`Creating session…`}:e);let e=await W.createPlaygroundSession({model_id:t.model_id,template_mode:t.template_mode,template_name:t.template_name,template_script:t.template_script,config:t.base_config??{}});if(a=e.session_id,l=e.effective_config,s.current=a,y.signal.aborted||_()){W.deletePlaygroundSession(a).catch(()=>{}),s.current=null;return}i(e=>e&&!_()?{...e,sessionId:a,templateRepairStatus:`Session created ✓`}:e)}if(!a){_()||i(e=>e&&{...e,status:`error`,errorMessage:`No session available`});return}let u=[];if(n.chat&&u.push(Gn),n.tool_call&&u.push(Zn),n.tool_call){i(e=>e&&!_()?{...e,templateRepairStatus:`Probing template for tool calling compatibility...`}:e);let e=await cr(a,y.signal);if(_())return;if(e)i(e=>e&&!_()?{...e,templateRepairStatus:`Template OK ✓`}:e);else{i(e=>e&&!_()?{...e,templateRepairStatus:`Template probe failed — running chat-only tests`}:e);let e=u.findIndex(e=>e.id===`tool_call`);e!==-1&&u.splice(e,1)}}if(u.length===0){_()||i(e=>e&&{...e,status:`error`,errorMessage:`No runnable scenarios — template probe failed and chat is disabled`});return}if(n.chat){let e=Xn(l);if(e&&e>0){i(e=>e&&!_()?{...e,calibrationStatus:`Calibrating context fill prompts...`}:e);try{let t=await Yn(a,e,y.signal);if(_())return;if(t.length>0){let e=u.findIndex(e=>e.id===`chat`);e>=0&&(u[e]={...u[e],prompts:[...u[e].prompts,...t]}),i(e=>e&&!_()?{...e,calibrationStatus:`Calibrated ${t.length} context fill levels ✓`}:e)}else i(e=>e&&!_()?{...e,calibrationStatus:`Context window too small for fill tests`}:e)}catch{if(_())return;i(e=>e&&!_()?{...e,calibrationStatus:`Context fill calibration failed — skipping fill tests`}:e)}}}let p=$n(o,d),g=p.map((e,t)=>({id:`${v}-trial-${t}`,status:`queued`,candidate:e,scenarioResults:[]}));i(e=>e&&!_()?{...e,status:`running_trials`,runStartedAt:new Date().toISOString(),totalTrials:p.length,currentTrialIndex:0,trials:g}:e),await ki({signal:y.signal,weights:f,isStale:_,initialDelayMs:Un,onInitialDelayStart:()=>{i(e=>e&&!_()?{...e,initialDelayUntil:new Date(Date.now()+Un).toISOString()}:e)},onInitialDelayEnd:()=>{i(e=>e&&!_()?{...e,initialDelayUntil:void 0}:e)},trialAbortRef:c,onTrialStopped:(e,t)=>{i(t=>{if(!t||t.kind!==`sampling`||_())return t;let n=t.trials.findIndex(t=>t.id===e);if(n<0)return t;let r=[...t.trials];return r[n]={...r[n],status:`cancelled`,finishedAt:new Date().toISOString()},{...t,trials:r}})},getNextQueuedTrialId:()=>{let e=r.current;if(e&&e.status===`running_trials`)return e.trials.find(e=>e.status===`queued`)?.id},claimTrial:e=>{let t=new Date().toISOString(),n=-1;return i(r=>{if(!r||r.kind!==`sampling`||_())return r;let i=r.trials.findIndex(t=>t.id===e);if(i<0||r.trials[i].status!==`queued`)return r;let a=[...r.trials];return a[i]={...a[i],status:`running`,startedAt:t},n=i,{...r,trials:a}}),n},executeTrial:async(e,t,n)=>{let o=r.current?.trials.find(t=>t.id===e);if(!o)return null;let s=o.candidate;return{...await Cr(a,s,u,t=>{i(n=>{if(!n||n.kind!==`sampling`||_())return n;let r=n.trials.findIndex(t=>t.id===e);if(r<0)return n;let i=[...n.trials],a=Di(i[r].logEntries??[],[],t.logEntries),{id:o,...s}=t;return i[r]={...i[r],...s,id:e,logEntries:a},{...n,trials:i}})},n,f,m),id:e}},onTrialResult:(e,t,n,r)=>{i(t=>{if(!t||t.kind!==`sampling`||_())return t;let i=t.trials.findIndex(t=>t.id===e);if(i<0)return t;let a=[...t.trials];return a[i]=n,{...t,trials:a,currentTrialIndex:i+1,bestTrialId:r}})}}),_()||i(e=>e&&{...e,status:y.signal.aborted?`cancelled`:`completed`})}catch(e){if(_())return;e instanceof DOMException&&e.name===`AbortError`?i(e=>e&&{...e,status:`cancelled`}):i(t=>t&&{...t,errorMessage:e.message||`Automated testing failed`,status:`error`})}finally{let e=s.current;e&&(await W.deletePlaygroundSession(e).catch(()=>{}),s.current=null),a.current=null,u.current=null,p(!1),b()}})()},[]),g=(0,x.useCallback)(({sessionSeed:e,enabledScenarios:t,configSweepDef:n,weights:s,repeats:d,availableVRAMGB:f})=>{if(u.current)return;let m=++l.current,h=()=>l.current!==m,g=`run-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,_=new AbortController;a.current=_;let v,y=new Promise(e=>{v=e});u.current={runId:g,done:y},p(!0),i({runId:g,kind:`config`,status:`running_trials`,enabledScenarios:t,currentTrialIndex:0,totalTrials:0,sessionSeed:e,configSweepDef:n,trials:[],repeats:d,weights:s}),(async()=>{try{let a={},l=null;try{let t=await W.createPlaygroundSession({model_id:e.model_id,template_mode:e.template_mode,template_name:e.template_name,template_script:e.template_script,config:{}});l=t.session_id,a={isHybrid:t.effective_config?.is_hybrid_model===!0}}catch{}finally{l&&await W.deletePlaygroundSession(l).catch(()=>{})}if(h())return;let u=rr(e.base_config,n,a);if(u.length===0){h()||i(e=>e&&{...e,errorMessage:`No valid config candidates generated (check sweep values; hybrid models require f16 cache type and disable flash attention)`,status:`error`});return}let p=u,m;try{i(e=>e&&!h()?{...e,calibrationStatus:`Estimating VRAM per candidate…`}:e);let t=(await W.showModel(e.model_id)).vram?.input;if(t){m=new Map;let n=await Promise.all(u.map(async n=>{let r=n.context_window??t.context_window,i=n.nseq_max??t.slots,a=t.bytes_per_element;n.cache_type===`q8_0`?a=1:n.cache_type===`q4_0`?a=.5625:n.cache_type!==void 0&&(a=2);let o=n.moe_keep_experts_top_n??t.expert_layers_on_gpu??0;try{return{candidate:n,total:(await W.calculateVRAM({model_id:e.model_id,context_window:r,bytes_per_element:a,slots:i,expert_layers_on_gpu:o})).total_vram}}catch{return{candidate:n,total:void 0}}}));for(let e of n)e.total!==void 0&&m.set(e.candidate,e.total)}}catch{}if(f&&f>0){let e=f*1024*1024*1024;if(m){p=u.filter(t=>{let n=m.get(t);return n===void 0||n<=e});let t=u.length-p.length;i(t>0?e=>e&&!h()?{...e,calibrationStatus:`Skipped ${t} of ${u.length} candidates exceeding ${f} GB VRAM`}:e:e=>e&&!h()?{...e,calibrationStatus:void 0}:e)}else i(e=>e&&!h()?{...e,calibrationStatus:`VRAM estimation failed — running all candidates`}:e);if(h())return;if(p.length===0){h()||i(e=>e&&{...e,errorMessage:`All ${u.length} candidates exceed ${f} GB VRAM — lower context window, slots, or increase VRAM limit`,status:`error`});return}}else i(e=>e&&!h()?{...e,calibrationStatus:void 0}:e);let v=[Qn],y={temperature:0,top_p:1,top_k:1,min_p:0,repeat_penalty:1,frequency_penalty:0,presence_penalty:0},b=p.map((e,t)=>({id:`${g}-trial-${t}`,status:`queued`,candidate:y,scenarioResults:[],config:e,estimatedVRAM:m?.get(e)}));i(e=>e&&!h()?{...e,status:`running_trials`,runStartedAt:new Date().toISOString(),totalTrials:p.length,currentTrialIndex:0,trials:b}:e),await ki({signal:_.signal,weights:s,isStale:h,initialDelayMs:Un,onInitialDelayStart:()=>{i(e=>e&&!h()?{...e,initialDelayUntil:new Date(Date.now()+Un).toISOString()}:e)},onInitialDelayEnd:()=>{i(e=>e&&!h()?{...e,initialDelayUntil:void 0}:e)},trialAbortRef:c,onTrialStopped:(e,t)=>{i(t=>{if(!t||t.kind!==`config`||h())return t;let n=t.trials.findIndex(t=>t.id===e);if(n<0)return t;let r=[...t.trials];return r[n]={...r[n],status:`cancelled`,finishedAt:new Date().toISOString()},{...t,trials:r}})},getNextQueuedTrialId:()=>{let e=r.current;if(e&&e.kind===`config`&&e.status===`running_trials`)return e.trials.find(e=>e.status===`queued`)?.id},claimTrial:e=>{let t=new Date().toISOString(),n=-1;return i(r=>{if(!r||r.kind!==`config`||h())return r;let i=r.trials.findIndex(t=>t.id===e);if(i<0||r.trials[i].status!==`queued`)return r;let a=[...r.trials];return a[i]={...a[i],status:`running`,startedAt:t,logEntries:[]},n=i,{...r,trials:a}}),n},executeTrial:async(n,a,c)=>{let l=r.current?.trials.find(e=>e.id===n);if(!l?.config)return null;let u=l.config,f=[],p=e=>{let t={timestamp:new Date().toISOString(),message:e};f.push(t),i(e=>{if(!e||e.kind!==`config`||h())return e;let t=e.trials.findIndex(e=>e.id===n);if(t<0)return e;let r=[...e.trials];return r[t]={...r[t],logEntries:[...f]},{...e,trials:r}})},{cache_type:m,cache_mode:g,moe_mode:_,moe_keep_experts_top_n:b,...x}=u,S={...x,...m!==void 0&&{cache_type_k:m,cache_type_v:m},...g!==void 0&&{incremental_cache:g===`imc`},..._!==void 0&&{moe_mode:_},..._!==void 0&&_!==`keep_top_n`&&{moe_keep_experts_top_n:null},...b!==void 0&&{moe_keep_experts_top_n:b}},C=null;try{p(`Creating session with config overrides…`);let r=await W.createPlaygroundSession({model_id:e.model_id,template_mode:e.template_mode,template_name:e.template_name,template_script:e.template_script,config:{...e.base_config,...S}});if(C=r.session_id,o.current=C,c.aborted||h())throw new DOMException(`Aborted`,`AbortError`);p(`Session created ✓`);let a=[...v];if(a.length===0)throw Error(`No runnable scenarios for this config — template probe failed and chat is disabled`);if(t.chat){let t=Xn(r.effective_config,e.base_config);if(t&&t>0){p(`Calibrating context fill prompts (ctx=${t})…`);try{let e=await Yn(C,t,c);if(h())throw new DOMException(`Aborted`,`AbortError`);if(e.length>0){let t=a.findIndex(e=>e.id===`chat`);t>=0&&(a[t]={...a[t],prompts:[...a[t].prompts,...e]}),p(`Calibrated ${e.length} fill levels ✓`)}else p(`Context window too small for fill tests`)}catch{p(`Context fill calibration failed — skipping`)}}}p(`Running scenarios…`);let l=e=>{i(t=>{if(!t||t.kind!==`config`||h())return t;let r=t.trials.findIndex(e=>e.id===n);if(r<0)return t;let i=[...t.trials],a=Di(i[r].logEntries??[],f,e.logEntries),{id:o,...s}=e;return i[r]={...i[r],...s,id:n,config:u,logEntries:a},{...t,trials:i}})},m=u.nseq_max??e.base_config.nseq_max??1,g=await Cr(C,y,a,l,c,s,d,m>1?{concurrency:m}:void 0);return{...g,id:n,config:u,logEntries:Di([],f,g.logEntries)}}catch(e){if(e instanceof DOMException&&e.name===`AbortError`)throw e;let t=e instanceof Error?e.message:String(e);return h()||i(e=>{if(!e||e.kind!==`config`)return e;let r=e.trials.findIndex(e=>e.id===n);if(r<0)return e;let i=[...e.trials],a=i[r];return i[r]={...a,id:a?.id??n,status:`failed`,startedAt:a?.startedAt??new Date().toISOString(),finishedAt:new Date().toISOString(),scenarioResults:[],totalScore:void 0,avgTPS:void 0,config:u,error:t},{...e,trials:i,currentTrialIndex:r+1}}),null}finally{C&&(await W.deletePlaygroundSession(C).catch(()=>{}),o.current===C&&(o.current=null))}},onTrialResult:(e,t,n,r)=>{i(t=>{if(!t||t.kind!==`config`||h())return t;let i=t.trials.findIndex(t=>t.id===e);if(i<0)return t;let a=[...t.trials];return a[i]=n,{...t,trials:a,currentTrialIndex:i+1,bestTrialId:r}})}}),h()||i(e=>e&&{...e,status:_.signal.aborted?`cancelled`:`completed`})}catch(e){if(h())return;e instanceof DOMException&&e.name===`AbortError`?i(e=>e&&{...e,status:`cancelled`}):i(t=>t&&{...t,errorMessage:e.message||`Automated testing failed`,status:`error`})}finally{let e=o.current;e&&(await W.deletePlaygroundSession(e).catch(()=>{}),o.current=null),a.current=null,u.current=null,p(!1),v()}})()},[]),_=(0,x.useCallback)(()=>{let e=r.current;if(!e||u.current||!e.trials.some(e=>e.status===`queued`))return;let t=++l.current,n=()=>l.current!==t,d=new AbortController;a.current=d;let f,m=new Promise(e=>{f=e});u.current={runId:e.runId,done:m},p(!0),i(e=>e&&{...e,status:`running_trials`,initialDelayUntil:void 0}),(async()=>{try{if(e.kind===`sampling`){let t=e,a=t.sessionId;if(t.sessionSeed?.model_id)try{a=(await W.createPlaygroundSession({model_id:t.sessionSeed.model_id,template_mode:t.sessionSeed.template_mode,template_name:t.sessionSeed.template_name,template_script:t.sessionSeed.template_script,config:t.sessionSeed.base_config??{}})).session_id,s.current=a,i(e=>e&&e.kind===`sampling`?{...e,sessionId:a}:e)}catch{i(e=>e&&{...e,status:`error`,errorMessage:`Failed to recreate session for rerun`});return}if(!a){i(e=>e&&{...e,status:`error`,errorMessage:`No session available for rerun`});return}let o=[];t.enabledScenarios.chat&&o.push(Gn),t.enabledScenarios.tool_call&&o.push(Zn),await ki({signal:d.signal,weights:t.weights,isStale:n,trialAbortRef:c,onTrialStopped:e=>{i(t=>{if(!t||t.kind!==`sampling`||n())return t;let r=t.trials.findIndex(t=>t.id===e);if(r<0)return t;let i=[...t.trials];return i[r]={...i[r],status:`cancelled`,finishedAt:new Date().toISOString()},{...t,trials:i}})},getNextQueuedTrialId:()=>{let e=r.current;if(e&&e.status===`running_trials`)return e.trials.find(e=>e.status===`queued`)?.id},claimTrial:e=>{let t=new Date().toISOString(),r=-1;return i(i=>{if(!i||i.kind!==`sampling`||n())return i;let a=i.trials.findIndex(t=>t.id===e);if(a<0||i.trials[a].status!==`queued`)return i;let o=[...i.trials];return o[a]={...o[a],status:`running`,startedAt:t},r=a,{...i,trials:o}}),r},executeTrial:async(e,s,c)=>{let l=r.current?.trials.find(t=>t.id===e);if(!l)return null;let u=l.candidate;return{...await Cr(a,u,o,t=>{i(r=>{if(!r||r.kind!==`sampling`||n())return r;let i=r.trials.findIndex(t=>t.id===e);if(i<0)return r;let a=[...r.trials],o=Di(a[i].logEntries??[],[],t.logEntries),{id:s,...c}=t;return a[i]={...a[i],...c,id:e,logEntries:o},{...r,trials:a}})},c,t.weights,t.repeats),id:e}},onTrialResult:(e,t,r,a)=>{i(t=>{if(!t||t.kind!==`sampling`||n())return t;let i=t.trials.findIndex(t=>t.id===e);if(i<0)return t;let o=[...t.trials];return o[i]=r,{...t,trials:o,currentTrialIndex:i+1,bestTrialId:a}})}})}else{let t=e,a=t.sessionSeed,s=[Qn];await ki({signal:d.signal,weights:t.weights,isStale:n,trialAbortRef:c,onTrialStopped:e=>{i(t=>{if(!t||t.kind!==`config`||n())return t;let r=t.trials.findIndex(t=>t.id===e);if(r<0)return t;let i=[...t.trials];return i[r]={...i[r],status:`cancelled`,finishedAt:new Date().toISOString()},{...t,trials:i}})},getNextQueuedTrialId:()=>{let e=r.current;if(e&&e.status===`running_trials`)return e.trials.find(e=>e.status===`queued`)?.id},claimTrial:e=>{let t=new Date().toISOString(),r=-1;return i(i=>{if(!i||i.kind!==`config`||n())return i;let a=i.trials.findIndex(t=>t.id===e);if(a<0||i.trials[a].status!==`queued`)return i;let o=[...i.trials];return o[a]={...o[a],status:`running`,startedAt:t},r=a,{...i,trials:o}}),r},executeTrial:async(e,c,l)=>{let u=r.current;if(!u||u.kind!==`config`)return null;let f=u.trials.find(t=>t.id===e);if(!f)return null;let p=f.config;if(!p)return null;let m=``,h=[],g={temperature:0,top_p:1,top_k:1,min_p:0,repeat_penalty:1,frequency_penalty:0,presence_penalty:0},_=s,v=t.repeats,y=t.weights;try{let t={...g,...p};if(m=(await W.createPlaygroundSession({model_id:a.model_id,template_mode:a.template_mode,template_name:a.template_name,template_script:a.template_script,config:t})).session_id,o.current=m,d.signal.aborted||n())return await W.deletePlaygroundSession(m).catch(()=>{}),o.current=null,null;let r=t=>{i(r=>{if(!r||r.kind!==`config`||n())return r;let i=r.trials.findIndex(t=>t.id===e);if(i<0)return r;let a=[...r.trials],o=Di(a[i].logEntries??[],h,t.logEntries),{id:s,...c}=t;return a[i]={...a[i],...c,id:e,config:p,logEntries:o},{...r,trials:a}})},s=p.nseq_max??a.base_config.nseq_max??1,c=await Cr(m,g,_,r,l,y,v,s>1?{concurrency:s}:void 0);return{...c,id:e,config:p,logEntries:Di([],h,c.logEntries)}}catch(t){if(t instanceof DOMException&&t.name===`AbortError`)throw t;let r=t instanceof Error?t.message:String(t);return n()||i(t=>{if(!t||t.kind!==`config`)return t;let n=t.trials.findIndex(t=>t.id===e);if(n<0)return t;let i=[...t.trials],a=i[n];return i[n]={...a,id:a?.id??e,status:`failed`,startedAt:a?.startedAt??new Date().toISOString(),finishedAt:new Date().toISOString(),scenarioResults:[],totalScore:void 0,avgTPS:void 0,config:p,error:r},{...t,trials:i,currentTrialIndex:n+1}}),null}finally{m&&(await W.deletePlaygroundSession(m).catch(()=>{}),o.current===m&&(o.current=null))}},onTrialResult:(e,t,r,a)=>{i(t=>{if(!t||t.kind!==`config`||n())return t;let i=t.trials.findIndex(t=>t.id===e);if(i<0)return t;let o=[...t.trials];return o[i]=r,{...t,trials:o,currentTrialIndex:i+1,bestTrialId:a}})}})}n()||i(e=>e&&{...e,status:d.signal.aborted?`cancelled`:`completed`})}catch(e){if(n())return;e instanceof DOMException&&e.name===`AbortError`?i(e=>e&&{...e,status:`cancelled`}):i(t=>t&&{...t,errorMessage:e.message||`Rerun failed`,status:`error`})}finally{let e=s.current;e&&(await W.deletePlaygroundSession(e).catch(()=>{}),s.current=null);let t=o.current;t&&(await W.deletePlaygroundSession(t).catch(()=>{}),o.current=null),a.current=null,u.current=null,p(!1),f()}})()},[]);d.current=_;let v=(0,x.useCallback)(()=>{++l.current,a.current?.abort(),c.current?.abort(),i(e=>{if(!e)return e;let t=e.trials.map(e=>e.status===`running`?{...e,status:`cancelled`,finishedAt:new Date().toISOString()}:e);return{...e,status:`cancelled`,initialDelayUntil:void 0,trials:t}})},[]),y=(0,x.useCallback)(()=>{u.current||i(null)},[]),b=(0,x.useCallback)(e=>{i(t=>{if(!t||t.status!==`completed`)return t;let n=-1/0,r=-1/0,i;for(let a of t.trials){if(!a||a.status===`skipped`||a.totalScore===void 0||a.totalScore===null||t.kind===`config`&&a.error)continue;let o=fr(a,e),s=a.avgTPS??-1/0;(o>n+1e-6||Math.abs(o-n)<=1e-6&&s>r)&&(n=o,r=s,i=a.id)}return{...t,bestTrialId:i}})},[]),S=(0,x.useCallback)(({trialId:e,direction:t})=>{i(n=>{if(!n||n.status!==`running_trials`)return n;let r=n.trials.findIndex(t=>t.id===e);if(r<0||n.trials[r].status!==`queued`)return n;let i=t===`up`?r-1:r+1;if(i<0||i>=n.trials.length||n.trials[i].status!==`queued`)return n;let a=[...n.trials];return[a[r],a[i]]=[a[i],a[r]],{...n,trials:a}})},[]),C=(0,x.useCallback)(({trialId:e,targetId:t})=>{e!==t&&i(n=>{if(!n||n.status!==`running_trials`)return n;let r=n.trials.findIndex(t=>t.id===e),i=n.trials.findIndex(e=>e.id===t);if(r<0||i<0||n.trials[r].status!==`queued`)return n;let a=[...n.trials],[o]=a.splice(r,1);return a.splice(i,0,o),{...n,trials:a}})},[]),w=(0,x.useCallback)(({trialId:e})=>{i(t=>{if(!t||t.status!==`running_trials`)return t;let n=t.trials.findIndex(t=>t.id===e);if(n<0||t.trials[n].status!==`queued`)return t;let r=[...t.trials];return r[n]={...r[n],status:`skipped`,finishedAt:new Date().toISOString()},{...t,trials:r}})},[]),T=(0,x.useCallback)(({trialId:e})=>{i(t=>{if(!t||t.status!==`running_trials`)return t;let n=t.trials.findIndex(t=>t.id===e);if(n<0||t.trials[n].status!==`skipped`)return t;let r=[...t.trials];return r[n]={...r[n],status:`queued`,finishedAt:void 0},{...t,trials:r}})},[]),E=(0,x.useCallback)(()=>{c.current?.abort()},[]),D=(0,x.useCallback)(({trialId:e})=>{let t=!1;i(n=>{if(!n||n.status!==`running_trials`&&n.status!==`completed`&&n.status!==`cancelled`)return n;let r=n.trials.findIndex(t=>t.id===e);if(r<0)return n;let i=n.trials[r];if(i.status!==`completed`&&i.status!==`cancelled`&&i.status!==`failed`)return n;let a=[...n.trials],o={id:i.id,status:`queued`,candidate:i.candidate,scenarioResults:[]},s;s=n.kind===`config`?{...o,config:i.config}:o,a.splice(r,1);let c=a.findIndex(e=>e.status===`queued`);c>=0?a.splice(c,0,s):a.push(s);let l=n.bestTrialId===e?void 0:n.bestTrialId;return(n.status===`completed`||n.status===`cancelled`)&&(t=!0),{...n,trials:a,bestTrialId:l}}),t&&setTimeout(()=>_(),0)},[_]);return(0,G.jsx)(Ai.Provider,{value:{run:t,isRunning:f,startSamplingRun:h,startConfigRun:g,stopRun:v,clearRun:y,reevaluateBestTrial:b,moveQueuedTrial:S,reorderQueuedTrial:C,skipTrial:w,unskipTrial:T,stopTrial:E,rerunTrial:D},children:e})}function Mi(){let e=(0,x.useContext)(Ai);if(!e)throw Error(`useAutoTestRunner must be used within an AutoTestRunnerProvider`);return e}function Ni(e){let t=e.toLowerCase();return!t.includes(`embed`)&&!t.includes(`rerank`)}var Pi=(0,x.createContext)(null);function Fi({children:e}){let{models:t,loadModels:n}=In(),[r,i]=(0,x.useState)(`manual`),[a,o]=(0,x.useState)(``),s=(0,x.useRef)(null),[c,l]=(0,x.useState)(null);function u(){l(null)}(0,x.useEffect)(()=>{if(!c)return;let e=setTimeout(()=>l(null),1e4);return()=>clearTimeout(e)},[c]);function d(e){return!s.current&&(s.current=e,l(null),!0)}function f(e){s.current===e&&(s.current=null)}let[p,m]=(0,x.useState)(null),[h,g]=(0,x.useState)(`line`),[_,v]=(0,x.useState)(null),[y,b]=(0,x.useState)(``),[S,C]=(0,x.useState)(!1),[w,T]=(0,x.useState)(null),E=(0,x.useRef)(null),[D,O]=(0,x.useState)(new Set),[k,A]=(0,x.useState)(5),[j,M]=(0,x.useState)([]),[N,P]=(0,x.useState)(!1),[F,I]=(0,x.useState)(new Set),L=(0,x.useRef)(!1),R=(0,x.useRef)(null),[z,ee]=(0,x.useState)(new Set),[B,V]=(0,x.useState)(``),[te,H]=(0,x.useState)([]),[ne,re]=(0,x.useState)(!1),[ie,ae]=(0,x.useState)(`columns`),oe=(0,x.useRef)(!1),se=(0,x.useRef)(null);function ce(e){s.current||o(e)}(0,x.useEffect)(()=>{n()},[n]),(0,x.useEffect)(()=>{if(!s.current&&t?.data&&t.data.length>0){let e=t.data.filter(e=>Ni(e.id));!e.some(e=>e.id===a)&&e.length>0&&o(e[0].id)}},[t,a]),(0,x.useEffect)(()=>{T(null),M([]),I(new Set),O(new Set)},[a]),(0,x.useEffect)(()=>{H([])},[B,z]),(0,x.useEffect)(()=>{let e=!1;return W.listAccuracyFunctions().then(t=>{e||(m(t.data),t.data.length>0&&(b(t.data[0].identifier),V(t.data[0].identifier)))}).catch(t=>{e||v(t instanceof Error?t.message:`Failed to read functions`)}),()=>{e=!0}},[]);async function le(){if(!a||!y||!d(`manual`))return;let e=new AbortController;E.current=e,C(!0),v(null),T(null);try{let t=await W.runAccuracy(a,y,e.signal);T(t),l({mode:`manual`,ok:!0,title:`Accuracy test done`,summary:`${y} · ${t.match_percent.toFixed(0)}% match`})}catch(t){if(e.signal.aborted)return;v(t instanceof Error?t.message:`Test failed`),l({mode:`manual`,ok:!1,title:`Accuracy test failed`,summary:y})}finally{E.current===e&&(E.current=null),C(!1),f(`manual`)}}function ue(){E.current?.abort()}function de(){T(null),v(null)}function fe(e){O(t=>{let n=new Set(t);if(n.has(e))n.delete(e);else{if(n.size>=5)return t;n.add(e)}return n})}function pe(){L.current=!0,O(new Set),M([]),I(new Set)}function me(){let e=(p??[]).map(e=>e.identifier),t=Math.max(1,Math.min(k,5,e.length)),n=[...e];for(let e=n.length-1;e>0;e--){let t=Math.floor(Math.random()*(e+1));[n[e],n[t]]=[n[t],n[e]]}O(new Set(n.slice(0,t)))}async function he(){if(!a||D.size===0||!d(`batch`))return;let e=(p??[]).filter(e=>D.has(e.identifier));P(!0),v(null),I(new Set),L.current=!1;let t=e.map(e=>({identifier:e.identifier,line:e.line,loc:e.loc,status:`pending`}));M(t);let n=0,r=0,i=0;try{for(let t=0;te.map(e=>e.identifier===o?{...e,status:`running`}:e));let s=new AbortController;R.current=s;try{let e=await W.runAccuracy(a,o,s.signal);n++,i+=e.match_percent,M(t=>t.map(t=>t.identifier===o?{...t,status:`done`,result:e}:t))}catch(e){if(s.signal.aborted){M(e=>e.map(e=>e.identifier===o?{...e,status:`pending`}:e));break}r++,M(t=>t.map(t=>t.identifier===o?{...t,status:`error`,error:e instanceof Error?e.message:`failed`}:t))}finally{R.current=null}}}finally{if(P(!1),f(`batch`),!L.current){let t=e.length,a=n>0?Math.round(i/n):0;l({mode:`batch`,ok:r===0,title:`Accuracy batch done`,summary:`${n}/${t} · avg ${a}% match`+(r>0?` · ${r} error${r>1?`s`:``}`:``)})}}}function ge(){L.current=!0,R.current?.abort()}function _e(e){I(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})}function ve(e){ee(t=>{let n=new Set(t);if(n.has(e))return n.delete(e),n;if(n.size>=2){let e=n.values().next().value;e!==void 0&&n.delete(e)}return n.add(e),n})}function ye(){oe.current=!0,se.current?.abort(),ee(new Set),H([])}async function be(){let e=Array.from(z);if(e.length===0||!B||!d(`compare`))return;re(!0),v(null),oe.current=!1;let t=e.map(e=>({model:e,status:`pending`}));H(t);let n=0,r=0;try{for(let t=0;te.map(e=>e.model===i?{...e,status:`running`}:e));let a=new AbortController;se.current=a;try{let e=await W.runAccuracy(i,B,a.signal);n++,H(t=>t.map(t=>t.model===i?{...t,status:`done`,result:e}:t))}catch(e){if(a.signal.aborted){H(e=>e.map(e=>e.model===i?{...e,status:`pending`}:e));break}r++,H(t=>t.map(t=>t.model===i?{...t,status:`error`,error:e instanceof Error?e.message:`failed`}:t))}finally{se.current=null}}}finally{re(!1),f(`compare`),oe.current||l({mode:`compare`,ok:r===0,title:`Accuracy compare done`,summary:`${n}/${e.length} models`+(r>0?` · ${r} error${r>1?`s`:``}`:``)})}}function xe(){oe.current=!0,se.current?.abort()}let Se=S||N||ne,Ce=null;if(S){let e=p?.find(e=>e.identifier===y)?.loc;Ce={mode:`manual`,label:e==null?y:`${y} (${e} loc)`,done:0,total:1}}else if(N){let e=j.filter(e=>e.status===`done`||e.status===`error`).length;Ce={mode:`batch`,label:`${e}/${j.length} functions`,done:e,total:j.length}}else if(ne){let e=te.filter(e=>e.status===`done`||e.status===`error`).length;Ce={mode:`compare`,label:`${e}/${te.length} models`,done:e,total:te.length}}function we(){S?ue():N?ge():ne&&xe()}return(0,G.jsx)(Pi.Provider,{value:{mode:r,setMode:i,selectedModel:a,setSelectedModel:ce,functions:p,sortBy:h,setSortBy:g,error:_,setError:v,selectedFn:y,setSelectedFn:b,running:S,result:w,runManual:le,stopManual:ue,clearManual:de,checked:D,setChecked:O,randomCount:k,setRandomCount:A,rows:j,batchRunning:N,expanded:F,toggle:fe,clearAll:pe,pickRandom:me,runBatch:he,stopBatch:ge,toggleExpand:_e,compareModels:z,compareFn:B,setCompareFn:V,compareCells:te,comparing:ne,compareLayout:ie,setCompareLayout:ae,toggleCompareModel:ve,clearCompare:ye,runCompare:be,stopCompare:xe,isRunning:Se,activeRun:Ce,completedRun:c,dismissCompleted:u,stopActive:we},children:e})}function Ii(){let e=(0,x.useContext)(Pi);if(!e)throw Error(`useAccuracyRunner must be used within an AccuracyRunnerProvider`);return e}function Li(e){let t=e.toLowerCase();return!t.includes(`embed`)&&!t.includes(`rerank`)}var Ri=(0,x.createContext)(null);function zi({children:e}){let{loadModels:t}=In(),[n,r]=(0,x.useState)(new Set),[i,a]=(0,x.useState)(``),[o,s]=(0,x.useState)(512),[c,l]=(0,x.useState)(new Map),[u,d]=(0,x.useState)(null),f=(0,x.useRef)(null),[p,m]=(0,x.useState)(null),h=(0,x.useRef)(null),g=(0,x.useRef)(!1),_=(0,x.useRef)(new Set);(0,x.useEffect)(()=>{t()},[t]),(0,x.useEffect)(()=>{if(!u)return;let e=setTimeout(()=>d(null),1e4);return()=>clearTimeout(e)},[u]);function v(){d(null)}function y(e){f.current||(r(t=>{let n=new Set(t);if(n.has(e))return n.delete(e),n;if(n.size>=2){let e=n.values().next().value;e!==void 0&&n.delete(e)}return n.add(e),n}),l(t=>{let n=new Map(t);return n.delete(e),n}))}function b(){f.current||(a(``),l(new Map))}function S(e,t){l(n=>{let r=new Map(n);return r.set(e,t),r})}async function C(e){if(!i.trim())return!1;f.current=e,m(e),S(e,{status:_.current.has(e)?`running`:`loading`});let t=new AbortController;h.current=t;try{let n=await W.runEfficiency(e,i,o,t.signal);return _.current.add(e),S(e,{status:`done`,result:n}),!0}catch(n){return t.signal.aborted?(S(e,{status:`idle`}),!1):(S(e,{status:`error`,error:n instanceof Error?n.message:`failed`}),!1)}finally{h.current=null,f.current=null,m(null)}}function w(e){f.current||n.has(e)&&C(e)}async function T(){if(f.current)return;let e=Array.from(n);if(e.length===0||!i.trim())return;g.current=!1,d(null);let t=0,r=0;for(let n of e){if(g.current)break;await C(n)?t++:g.current||r++}g.current||d({ok:r===0,title:`Efficiency run done`,summary:`${t}/${e.length} models`+(r>0?` · ${r} error${r>1?`s`:``}`:``)})}function E(){g.current=!0,h.current?.abort()}let D=p!==null,O=null;if(p){let e=c.get(p),t=n.size,r=Array.from(c.values()).filter(e=>e.status===`done`||e.status===`error`).length;O={model:p,status:e?.status??`running`,done:r,total:t}}return(0,G.jsx)(Ri.Provider,{value:{selectedModels:n,toggleModel:y,prompt:i,setPrompt:a,maxTokens:o,setMaxTokens:s,clear:b,runs:c,runModel:w,runAll:T,stopActive:E,isRunning:D,activeRun:O,completedRun:u,dismissCompleted:v},children:e})}function Bi(){let e=(0,x.useContext)(Ri);if(!e)throw Error(`useEfficiencyRunner must be used within an EfficiencyRunnerProvider`);return e}var Vi=(0,x.createContext)(null);function Hi({children:e}){let[t,n]=(0,x.useState)(null),[r,i]=(0,x.useState)([]),[a,o]=(0,x.useState)(``),[s,c]=(0,x.useState)(`automated`),[l,u]=(0,x.useState)(`sampling`),[d,f]=(0,x.useState)(`chat`),[p,m]=(0,x.useState)(`You are a helpful assistant.`),[h,g]=(0,x.useState)(null),[_,v]=(0,x.useState)(`builtin`),[y,b]=(0,x.useState)(``),[S,C]=(0,x.useState)(``),[w,T]=(0,x.useState)(8192),[E,D]=(0,x.useState)(Bn),[O,k]=(0,x.useState)(1),[A,j]=(0,x.useState)(`auto`),[M,N]=(0,x.useState)(``),[P,F]=(0,x.useState)(`auto`),[I,L]=(0,x.useState)(`none`),[R,z]=(0,x.useState)(``),[ee,B]=(0,x.useState)(0),[V,te]=(0,x.useState)([]),[H,ne]=(0,x.useState)(``),re=(0,x.useMemo)(()=>({session:t,setSession:n,chatMessages:r,setChatMessages:i,selectedModel:a,setSelectedModel:o,playgroundMode:s,setPlaygroundMode:c,sweepMode:l,setSweepMode:u,activeTab:d,setActiveTab:f,systemPrompt:p,setSystemPrompt:m,lastTPS:h,setLastTPS:g,templateMode:_,setTemplateMode:v,selectedTemplate:y,setSelectedTemplate:b,customScript:S,setCustomScript:C,contextWindow:w,setContextWindow:T,prefillBatchSize:E,setPrefillBatchSize:D,nSeqMax:O,setNSeqMax:k,flashAttention:A,setFlashAttention:j,cacheType:M,setCacheType:N,loadMode:P,setLoadMode:F,cacheMode:I,setCacheMode:L,moeMode:R,setMoeMode:z,moeKeepTopN:ee,setMoeKeepTopN:B,tensorBuftOverrides:V,setTensorBuftOverrides:te,hydratedModelId:H,setHydratedModelId:ne}),[t,r,a,s,l,d,p,h,_,y,S,w,E,O,A,M,P,I,R,ee,V,H]);return(0,G.jsx)(Vi.Provider,{value:re,children:e})}function Ui(){let e=(0,x.useContext)(Vi);if(!e)throw Error(`usePlayground must be used within a PlaygroundProvider`);return e}var Wi=`theme`,Gi=(0,x.createContext)(null);function Ki({children:e}){let[t,n]=(0,x.useState)(()=>localStorage.getItem(Wi)||`light`);(0,x.useEffect)(()=>{localStorage.setItem(Wi,t),document.documentElement.dataset.theme=t},[t]);let r=(0,x.useCallback)(()=>{n(e=>e===`light`?`dark`:`light`)},[]);return(0,G.jsx)(Gi.Provider,{value:{theme:t,toggleTheme:r},children:e})}function qi(){let e=(0,x.useContext)(Gi);if(!e)throw Error(`useTheme must be used within a ThemeProvider`);return e}function Ji({onAuthenticated:e}){let[t,n]=(0,x.useState)(``),[r,i]=(0,x.useState)(!1),[a,o]=(0,x.useState)(``);return(0,G.jsx)(`div`,{className:`auth-screen`,children:(0,G.jsxs)(`form`,{className:`auth-card`,onSubmit:async n=>{n.preventDefault(),i(!0),o(``);try{let n=await fetch(`/admin/api/login`,{method:`POST`,credentials:`same-origin`,headers:{"Content-Type":`application/json`},body:JSON.stringify({password:t})});if(n.ok){e();return}o(n.status===401?`Invalid password.`:`Unable to sign in. Please try again.`)}catch{o(`Unable to reach the server. Please try again.`)}finally{i(!1)}},children:[(0,G.jsx)(`img`,{src:`/admin/kronk-logo.png`,alt:`Kronk`}),(0,G.jsx)(`h1`,{children:`Kronk Admin`}),(0,G.jsx)(`p`,{children:`Sign in to manage this model server.`}),(0,G.jsx)(`label`,{htmlFor:`admin-password`,children:`Admin password`}),(0,G.jsx)(`input`,{id:`admin-password`,type:`password`,autoComplete:`current-password`,autoFocus:!0,required:!0,value:t,onChange:e=>n(e.target.value)}),a&&(0,G.jsx)(`div`,{className:`alert alert-error`,role:`alert`,children:a}),(0,G.jsx)(`button`,{className:`btn btn-primary`,type:`submit`,disabled:r||!t,children:r?`Signing in…`:`Sign in`})]})})}var Yi=(0,x.createContext)(null);function Xi({children:e}){let[t,n]=(0,x.useState)(`loading`),[r,i]=(0,x.useState)(!0),a=(0,x.useCallback)(async()=>{try{let e=await fetch(`/admin/api/session`,{credentials:`same-origin`}),t=await e.json();i(t.authentication_required),n(e.ok&&t.authenticated?`authenticated`:`anonymous`)}catch{n(`anonymous`)}},[]);(0,x.useEffect)(()=>{localStorage.removeItem(`kronk_token`),a();let e=()=>n(`anonymous`);return window.addEventListener(Mn,e),()=>window.removeEventListener(Mn,e)},[a]);let o=(0,x.useCallback)(async()=>{try{await fetch(`/admin/api/logout`,{method:`POST`,credentials:`same-origin`})}finally{n(`anonymous`)}},[]);return t===`loading`?(0,G.jsx)(`div`,{className:`auth-screen`,children:(0,G.jsx)(`div`,{className:`auth-card auth-loading`,children:`Loading Kronk…`})}):t===`anonymous`?(0,G.jsx)(Ji,{onAuthenticated:()=>n(`authenticated`)}):(0,G.jsx)(Yi.Provider,{value:{authenticationRequired:r,logout:o},children:e})}function Zi(){let e=(0,x.useContext)(Yi);if(!e)throw Error(`useAuth must be used within an AuthProvider`);return e}var Qi=[{id:`apps`,label:`Apps`,items:[{page:`chat`,label:`Chat`},{page:`decision`,label:`Decision`},{page:`vram-calculator`,label:`VRAM Calculator`},{page:`translator`,label:`Translator`},{page:`image-generator`,label:`Image Generator`}]},{id:`running`,label:`System`,items:[{page:`model-ps`,label:`Running`},{page:`slots`,label:`Slots`},{page:`imc-sessions`,label:`IMC Sessions`},{page:`diagnose`,label:`Info`}]},{id:`kronk`,label:`Kronk`,subcategories:[{id:`model`,label:`Models`,items:[{page:`model-list`,label:`List`},{page:`model-pull`,label:`HF Pull`},{page:`kms-pull`,label:`KMS Pull`}]},{id:`catalog`,label:`Catalog`,items:[{page:`catalog-list`,label:`List`}]},{id:`libs`,label:`Libs`,items:[{page:`libs-pull`,label:`Manage`}]}]},{id:`bucky`,label:`Bucky`,subcategories:[{id:`bucky-model`,label:`Models`,items:[{page:`bucky-model-list`,label:`List`}]},{id:`bucky-libs`,label:`Libs`,items:[{page:`bucky-libs`,label:`Manage`}]}]},{id:`malina`,label:`Malina`,subcategories:[{id:`malina-model`,label:`Models`,items:[{page:`malina-model-list`,label:`List`}]},{id:`malina-libs`,label:`Libs`,items:[{page:`malina-libs`,label:`Manage`}]}]},{id:`security`,label:`Security`,subcategories:[{id:`security-key`,label:`Key`,items:[{page:`security-key-list`,label:`List`},{page:`security-key-create`,label:`Create`},{page:`security-key-delete`,label:`Delete`}]},{id:`security-token`,label:`Token`,items:[{page:`security-token-create`,label:`Create`},{page:`settings`,label:`Session`}]}]},{id:`testing`,label:`Testing`,items:[{page:`accuracy`,label:`Accuracy`},{page:`efficiency`,label:`Efficiency`},{page:`testing-basic`,label:`Basic`},{page:`testing-sampling`,label:`Sampling`},{page:`testing-configurator`,label:`Configuration`}]},{id:`docs`,label:`Docs`,subcategories:[{id:`docs-manual-sub`,label:`Manual`,items:[{page:`docs-manual`,label:`Introduction`,hash:`chapter-1-introduction`},{page:`docs-manual`,label:`Installation & Quick Start`,hash:`chapter-2-installation-quick-start`},{page:`docs-manual`,label:`Model Configuration`,hash:`chapter-3-model-configuration`},{page:`docs-manual`,label:`Batch Processing`,hash:`chapter-4-batch-processing`},{page:`docs-manual`,label:`Message Caching`,hash:`chapter-5-message-caching`},{page:`docs-manual`,label:`Speculative Decoding & MTP`,hash:`chapter-6-speculative-decoding-mtp`},{page:`docs-manual`,label:`YaRN Extended Context`,hash:`chapter-7-yarn-extended-context`},{page:`docs-manual`,label:`Model Server`,hash:`chapter-8-model-server`},{page:`docs-manual`,label:`API Endpoints`,hash:`chapter-9-api-endpoints`},{page:`docs-manual`,label:`Request Parameters`,hash:`chapter-10-request-parameters`},{page:`docs-manual`,label:`Multi-Modal Models`,hash:`chapter-11-multi-modal-models`},{page:`docs-manual`,label:`Security & Authentication`,hash:`chapter-12-security-authentication`},{page:`docs-manual`,label:`Browser UI (BUI)`,hash:`chapter-13-browser-ui-bui`},{page:`docs-manual`,label:`Client Integration`,hash:`chapter-14-client-integration`},{page:`docs-manual`,label:`Observability`,hash:`chapter-15-observability`},{page:`docs-manual`,label:`MCP Service`,hash:`chapter-16-mcp-service`},{page:`docs-manual`,label:`Troubleshooting`,hash:`chapter-17-troubleshooting`},{page:`docs-manual`,label:`Bucky (Audio Transcription)`,hash:`chapter-18-bucky-audio-transcription`},{page:`docs-manual`,label:`Malina (Image Generation)`,hash:`chapter-19-malina-image-generation`},{page:`docs-manual`,label:`Developer Guide`,hash:`chapter-20-developer-guide`}]},{id:`docs-sdk`,label:`SDK`,items:[{page:`docs-sdk-kronk`,label:`Kronk`},{page:`docs-sdk-model`,label:`Model`},{page:`docs-sdk-pool`,label:`Pool`},{page:`docs-sdk-bucky`,label:`Bucky`},{page:`docs-sdk-bucky-model`,label:`Bucky Model`},{page:`docs-sdk-malina`,label:`Malina`},{page:`docs-sdk-malina-model`,label:`Malina Model`},{page:`docs-sdk-examples`,label:`Examples`,children:[{page:`docs-sdk-examples`,label:`Agent`,hash:`example-agent`},{page:`docs-sdk-examples`,label:`Audio`,hash:`example-audio`},{page:`docs-sdk-examples`,label:`Bucky`,hash:`example-bucky`},{page:`docs-sdk-examples`,label:`Bucky-Diar`,hash:`example-bucky-diar`},{page:`docs-sdk-examples`,label:`Bucky-Stream`,hash:`example-bucky-stream`},{page:`docs-sdk-examples`,label:`Chat`,hash:`example-chat`},{page:`docs-sdk-examples`,label:`Concurrency`,hash:`example-concurrency`},{page:`docs-sdk-examples`,label:`Decision (Jev-Style)`,hash:`example-decision-jevstyle`},{page:`docs-sdk-examples`,label:`Decision (OpenJEV)`,hash:`example-decision-openjev`},{page:`docs-sdk-examples`,label:`Embedding`,hash:`example-embedding`},{page:`docs-sdk-examples`,label:`Grammar`,hash:`example-grammar`},{page:`docs-sdk-examples`,label:`Malina`,hash:`example-malina`},{page:`docs-sdk-examples`,label:`Malina-Adetailer`,hash:`example-malina-adetailer`},{page:`docs-sdk-examples`,label:`Malina-Animatediff`,hash:`example-malina-animatediff`},{page:`docs-sdk-examples`,label:`Malina-Controlnet`,hash:`example-malina-controlnet`},{page:`docs-sdk-examples`,label:`Malina-Img2img`,hash:`example-malina-img2img`},{page:`docs-sdk-examples`,label:`Malina-S2v`,hash:`example-malina-s2v`},{page:`docs-sdk-examples`,label:`Malina-Sd-Encode`,hash:`example-malina-sd-encode`},{page:`docs-sdk-examples`,label:`Malina-System`,hash:`example-malina-system`},{page:`docs-sdk-examples`,label:`Malina-Upscale`,hash:`example-malina-upscale`},{page:`docs-sdk-examples`,label:`Pool`,hash:`example-pool`},{page:`docs-sdk-examples`,label:`Question`,hash:`example-question`},{page:`docs-sdk-examples`,label:`Rag`,hash:`example-rag`},{page:`docs-sdk-examples`,label:`Rerank`,hash:`example-rerank`},{page:`docs-sdk-examples`,label:`Response`,hash:`example-response`},{page:`docs-sdk-examples`,label:`Session-Store`,hash:`example-session-store`},{page:`docs-sdk-examples`,label:`Vision`,hash:`example-vision`}]}]},{id:`docs-cli-sub`,label:`CLI`,items:[{page:`docs-cli-bucky`,label:`bucky`},{page:`docs-cli-catalog`,label:`catalog`},{page:`docs-cli-completion`,label:`completion`},{page:`docs-cli-devices`,label:`devices`},{page:`docs-cli-diagnose`,label:`diagnose`},{page:`docs-cli-libs`,label:`libs`},{page:`docs-cli-launch`,label:`launch`},{page:`docs-cli-model`,label:`model`},{page:`docs-cli-security`,label:`security`},{page:`docs-cli-server`,label:`server`}]},{id:`docs-api-sub`,label:`Web API`,items:[{page:`docs-api-chat`,label:`Chat`},{page:`docs-api-messages`,label:`Messages`},{page:`docs-api-responses`,label:`Responses`},{page:`docs-api-embeddings`,label:`Embeddings`},{page:`docs-api-rerank`,label:`Rerank`},{page:`docs-api-decision`,label:`Decision`},{page:`docs-api-tokenize`,label:`Tokenize`},{page:`docs-api-tools`,label:`Tools`}]}]}],$i={running:(0,G.jsx)(`svg`,{width:`18`,height:`18`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:(0,G.jsx)(`polyline`,{points:`3 12 7 12 10 4 14 20 17 12 21 12`})}),kronk:(0,G.jsxs)(`svg`,{width:`18`,height:`18`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,G.jsx)(`path`,{d:`M12 2l9 5v10l-9 5-9-5V7z`}),(0,G.jsx)(`path`,{d:`M12 22V12`}),(0,G.jsx)(`path`,{d:`M3 7l9 5 9-5`})]}),bucky:(0,G.jsxs)(`svg`,{width:`18`,height:`18`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,G.jsx)(`rect`,{x:`9`,y:`2`,width:`6`,height:`12`,rx:`3`}),(0,G.jsx)(`path`,{d:`M5 11a7 7 0 0 0 14 0`}),(0,G.jsx)(`line`,{x1:`12`,y1:`18`,x2:`12`,y2:`22`}),(0,G.jsx)(`line`,{x1:`8`,y1:`22`,x2:`16`,y2:`22`})]}),malina:(0,G.jsxs)(`svg`,{width:`18`,height:`18`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,G.jsx)(`rect`,{x:`3`,y:`3`,width:`18`,height:`18`,rx:`2`}),(0,G.jsx)(`circle`,{cx:`8.5`,cy:`8.5`,r:`1.5`}),(0,G.jsx)(`path`,{d:`M21 15l-5-5L5 21`})]}),apps:(0,G.jsxs)(`svg`,{width:`18`,height:`18`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,G.jsx)(`rect`,{x:`3`,y:`3`,width:`7`,height:`7`,rx:`1`}),(0,G.jsx)(`rect`,{x:`14`,y:`3`,width:`7`,height:`7`,rx:`1`}),(0,G.jsx)(`rect`,{x:`3`,y:`14`,width:`7`,height:`7`,rx:`1`}),(0,G.jsx)(`rect`,{x:`14`,y:`14`,width:`7`,height:`7`,rx:`1`})]}),security:(0,G.jsx)(`svg`,{width:`18`,height:`18`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:(0,G.jsx)(`path`,{d:`M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z`})}),docs:(0,G.jsxs)(`svg`,{width:`18`,height:`18`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,G.jsx)(`path`,{d:`M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z`}),(0,G.jsx)(`path`,{d:`M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z`})]}),testing:(0,G.jsxs)(`svg`,{width:`18`,height:`18`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,G.jsx)(`path`,{d:`M9 2h6`}),(0,G.jsx)(`path`,{d:`M10 2v6.5L5 18a2 2 0 0 0 1.8 3h10.4A2 2 0 0 0 19 18l-5-9.5V2`}),(0,G.jsx)(`path`,{d:`M7.5 14h9`})]})};function ea({children:e}){let t=at(),n=ct(),r=Nx[t.pathname]||`home`,[i,a]=(0,x.useState)(new Set),{download:o,isDownloading:s}=zn(),{run:c,isRunning:l,stopRun:u}=Mi(),{activeRun:d,stopActive:f,completedRun:p,dismissCompleted:m}=Ii(),{activeRun:h,stopActive:g,completedRun:_,dismissCompleted:v}=Bi(),{session:y,setSession:b,selectedModel:S,setChatMessages:C}=Ui(),{theme:w,toggleTheme:T}=qi(),{authenticationRequired:E,logout:D}=Zi(),[O,k]=(0,x.useState)(!1),A=async()=>{if(y){k(!0);try{await W.deletePlaygroundSession(y.session_id),b(null),C([])}catch{b(null)}finally{k(!1)}}},[j,M]=(0,x.useState)(()=>{try{return localStorage.getItem(`sidebar-collapsed`)===`true`}catch{return!1}}),N=()=>{M(e=>{let t=!e;try{localStorage.setItem(`sidebar-collapsed`,String(t))}catch{}return t})},P=e=>{if(e.items&&e.items.length>0){let t=e.items[0],n=Mx[t.page];return t.hash?`${n}#${t.hash}`:n}if(e.subcategories)for(let t of e.subcategories){let e=P(t);if(e)return e}return null},F=(()=>{if(!c)return``;if(l)return`Testing...`;switch(c.status){case`completed`:return`Completed`;case`cancelled`:return`Cancelled`;case`error`:return`Failed`;default:return`Testing`}})(),I=(()=>{if(c){if(c.status===`error`&&c.errorMessage)return c.errorMessage;if(l&&c.totalTrials===0)return c.calibrationStatus??c.templateRepairStatus??`Preparing...`;if(c.totalTrials>0)return`Trial ${Math.min(c.currentTrialIndex+ +!!l,c.totalTrials)}/${c.totalTrials}`}})(),L=(()=>{if(!c||!l)return;let e=c.trials.find(e=>e?.status===`running`)?.logEntries;if(e&&e.length>0)return e[e.length-1].message})(),R=(()=>{if(!c||!l||c.totalTrials===0)return;let e=c.trials.filter(e=>e?.startedAt&&e?.finishedAt).length;if(e===0||e>=c.totalTrials)return;let t=c.trials.filter(e=>e?.startedAt&&e?.finishedAt).map(e=>Date.parse(e.finishedAt)-Date.parse(e.startedAt)).filter(e=>Number.isFinite(e)&&e>0);if(t.length===0)return;let n=t.reduce((e,t)=>e+t,0)/t.length,r=Math.max(0,c.totalTrials-e),i=n*r+Hn*r,a=Math.round(i/1e3);if(a<60)return`ETA ~${a}s`;let o=Math.floor(a/60),s=a%60;return o<60?`ETA ~${o}m ${s}s`:`ETA ~${Math.floor(o/60)}h ${o%60}m`})(),z=(()=>{if(!o||!s||!o.progress)return;let{totalBytes:e,currentBytes:t,mbPerSec:n,startedAtMs:r}=o.progress;if((Date.now()-r)/1e3<5||e<=0||t>=e||n<=0)return;let i=(e-t)/(n*1e3*1e3);if(i<60)return`ETA ~${Math.round(i)}s`;let a=Math.floor(i/60),c=Math.round(i%60);return a<60?`ETA ~${a}m ${c}s`:`ETA ~${Math.floor(a/60)}h ${a%60}m`})(),ee=!!c,B=!!o,V=!!d||!!p,te=!!h||!!_,H=!!y,ne=o?.origin===`catalog`?Mx[`catalog-list`]:o?.origin===`bucky`?Mx[`bucky-model-list`]:o?.origin===`malina`?Mx[`malina-model-list`]:Mx[`model-pull`],re=d?d.mode===`manual`?`Accuracy test...`:d.mode===`batch`?`Accuracy batch...`:`Accuracy compare...`:``;(0,x.useEffect)(()=>{let e=(t,n)=>{for(let r of t){if(r.items?.some(e=>e.page===n))return[r.id];if(r.subcategories){let t=e(r.subcategories,n);if(t.length>0)return[r.id,...t]}}return[]},t=e(Qi,r),n=[],i=e=>{if(e)for(let t of e)t.children&&t.page===r&&!t.hash&&n.push(`menu-item:${t.page}`),i(t.children)},o=e=>{for(let t of e)i(t.items),t.subcategories&&o(t.subcategories)};o(Qi),(t.length>0||n.length>0)&&a(e=>{let r=new Set(e);return t.forEach(e=>r.add(e)),n.forEach(e=>r.add(e)),r})},[r]),(0,x.useEffect)(()=>{jn.default.highlightAll()},[r]);let ie=e=>{a(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},ae=e=>e.items?e.items.some(e=>e.page===r):e.subcategories?e.subcategories.some(e=>ae(e)):!1,oe=e=>{let a=Mx[e.page],o=r===e.page&&!e.hash;if(e.children&&e.children.length>0){let t=`menu-item:${e.page}${e.hash?`#${e.hash}`:``}`,r=i.has(t),s=e.hash?`${a}#${e.hash}`:a;return(0,G.jsxs)(`div`,{className:`menu-item-group`,children:[(0,G.jsxs)(`a`,{href:s,onClick:e=>{e.preventDefault(),ie(t),o||n(s)},className:`menu-item menu-item-parent ${o?`active`:``}`,children:[(0,G.jsx)(`span`,{className:`menu-item-label`,children:e.label}),(0,G.jsx)(`span`,{className:`menu-category-arrow ${r?`expanded`:``}`,children:`▶`})]}),(0,G.jsx)(`div`,{className:`menu-items menu-item-children ${r?`expanded`:``}`,children:e.children.map(oe)})]},t)}if(e.hash){let i=r===e.page&&t.hash===`#${e.hash}`;return(0,G.jsx)(`a`,{href:`${a}#${e.hash}`,onClick:t=>{t.preventDefault(),n(`${a}#${e.hash}`)},className:`menu-item ${i?`active`:``}`,children:e.label},`${e.page}-${e.hash}`)}return(0,G.jsx)(vn,{to:a,className:`menu-item ${o?`active`:``}`,children:e.label},e.page)},se=(e,t=!1)=>{let r=i.has(e.id),a=ae(e);return(0,G.jsxs)(`div`,{className:`menu-category ${t?`submenu`:``}`,children:[(0,G.jsxs)(`div`,{className:`menu-category-header ${a?`active`:``}`,onClick:()=>{if(j&&!t){let t=P(e);t&&n(t)}else if(ie(e.id),!r){let t=P(e);t&&n(t)}},title:j?e.label:void 0,children:[!t&&$i[e.id]&&(0,G.jsx)(`span`,{className:`menu-category-icon`,"aria-hidden":`true`,children:$i[e.id]}),(0,G.jsx)(`span`,{className:`menu-category-label`,children:e.label}),(0,G.jsx)(`span`,{className:`menu-category-arrow ${r?`expanded`:``}`,children:`▶`})]}),(0,G.jsxs)(`div`,{className:`menu-items ${r?`expanded`:``}`,...!t&&{"data-label":e.label},children:[e.subcategories?.map(e=>se(e,!0)),e.items?.map(oe)]})]},e.id)};return(0,G.jsxs)(`div`,{className:`app`,children:[(0,G.jsxs)(`aside`,{className:`sidebar ${j?`sidebar-collapsed`:``}`,children:[(0,G.jsx)(`div`,{className:`sidebar-header`,children:(0,G.jsxs)(vn,{to:`/`,style:{textDecoration:`none`,color:`inherit`},className:`sidebar-brand`,children:[(0,G.jsx)(`img`,{src:`/admin/kronk-logo.png`,alt:`Kronk Logo`,className:`sidebar-logo`}),(0,G.jsx)(`h1`,{children:`Model Server`})]})}),(0,G.jsx)(`nav`,{children:Qi.map(e=>se(e))}),(ee||B||V||te||H)&&(0,G.jsxs)(`div`,{className:`sidebar-indicators`,children:[H&&(0,G.jsx)(`div`,{className:`download-indicator`,children:(0,G.jsxs)(`div`,{className:`download-indicator-link autotest-indicator-link`,children:[(0,G.jsxs)(vn,{to:Mx[`testing-basic`],className:`autotest-indicator-top`,children:[(0,G.jsxs)(`div`,{className:`download-indicator-header`,children:[(0,G.jsx)(`span`,{className:`download-indicator-icon success`,children:`●`}),(0,G.jsx)(`span`,{className:`download-indicator-title`,children:`Session running`})]}),(0,G.jsx)(`div`,{className:`download-indicator-url`,title:S,children:S?S.split(`/`).pop():`Basic`})]}),(0,G.jsx)(`button`,{type:`button`,className:`autotest-indicator-stop`,onClick:A,disabled:O,"aria-label":`Unload session`,title:`Unload session`,children:O?`…`:`⏏`})]})}),ee&&(0,G.jsx)(`div`,{className:`download-indicator`,children:(0,G.jsxs)(`div`,{className:`download-indicator-link autotest-indicator-link`,children:[(0,G.jsxs)(vn,{to:Mx[c?.kind===`config`?`testing-configurator`:`testing-sampling`],className:`autotest-indicator-top`,children:[(0,G.jsxs)(`div`,{className:`download-indicator-header`,children:[l?(0,G.jsx)(`span`,{className:`download-indicator-spinner`}):c.status===`completed`?(0,G.jsx)(`span`,{className:`download-indicator-icon success`,children:`✓`}):(0,G.jsx)(`span`,{className:`download-indicator-icon error`,children:`✗`}),(0,G.jsx)(`span`,{className:`download-indicator-title`,children:F})]}),I&&(0,G.jsx)(`div`,{className:`download-indicator-url`,title:I,"aria-live":`polite`,children:I}),L&&(0,G.jsx)(`div`,{className:`autotest-indicator-log`,title:L,children:L}),R&&(0,G.jsx)(`div`,{className:`download-indicator-url`,title:R,children:R})]}),l&&(0,G.jsx)(`button`,{type:`button`,className:`autotest-indicator-stop`,onClick:u,"aria-label":`Stop automated testing`,title:`Stop automated testing`,children:`■`})]})}),B&&(0,G.jsx)(`div`,{className:`download-indicator`,children:(0,G.jsxs)(vn,{to:ne,className:`download-indicator-link`,children:[(0,G.jsxs)(`div`,{className:`download-indicator-header`,children:[s?(0,G.jsx)(`span`,{className:`download-indicator-spinner`}):o.status===`complete`?(0,G.jsx)(`span`,{className:`download-indicator-icon success`,children:`✓`}):(0,G.jsx)(`span`,{className:`download-indicator-icon error`,children:`✗`}),(0,G.jsx)(`span`,{className:`download-indicator-title`,children:s?`Downloading...`:o.status===`complete`?`Complete`:`Failed`})]}),(0,G.jsx)(`div`,{className:`download-indicator-url`,title:o.modelUrl,children:o.modelUrl.split(`/`).pop()}),z&&(0,G.jsx)(`div`,{className:`download-indicator-url`,title:z,children:z})]})}),V&&d&&(0,G.jsx)(`div`,{className:`download-indicator`,children:(0,G.jsxs)(`div`,{className:`download-indicator-link autotest-indicator-link`,children:[(0,G.jsxs)(vn,{to:Mx.accuracy,className:`autotest-indicator-top`,children:[(0,G.jsxs)(`div`,{className:`download-indicator-header`,children:[(0,G.jsx)(`span`,{className:`download-indicator-spinner`}),(0,G.jsx)(`span`,{className:`download-indicator-title`,children:re})]}),(0,G.jsx)(`div`,{className:`download-indicator-url`,title:d.label,children:d.label})]}),(0,G.jsx)(`button`,{type:`button`,className:`autotest-indicator-stop`,onClick:f,"aria-label":`Stop accuracy run`,title:`Stop accuracy run`,children:`■`})]})}),V&&!d&&p&&(0,G.jsx)(`div`,{className:`download-indicator`,children:(0,G.jsxs)(`div`,{className:`download-indicator-link autotest-indicator-link`,children:[(0,G.jsxs)(vn,{to:Mx.accuracy,className:`autotest-indicator-top`,children:[(0,G.jsxs)(`div`,{className:`download-indicator-header`,children:[p.ok?(0,G.jsx)(`span`,{className:`download-indicator-icon success`,children:`✓`}):(0,G.jsx)(`span`,{className:`download-indicator-icon error`,children:`✗`}),(0,G.jsx)(`span`,{className:`download-indicator-title`,children:p.title})]}),(0,G.jsx)(`div`,{className:`download-indicator-url`,title:p.summary,children:p.summary})]}),(0,G.jsx)(`button`,{type:`button`,className:`autotest-indicator-stop`,onClick:m,"aria-label":`Dismiss accuracy result`,title:`Dismiss`,children:`✕`})]})}),te&&h&&(0,G.jsx)(`div`,{className:`download-indicator`,children:(0,G.jsxs)(`div`,{className:`download-indicator-link autotest-indicator-link`,children:[(0,G.jsxs)(vn,{to:Mx.efficiency,className:`autotest-indicator-top`,children:[(0,G.jsxs)(`div`,{className:`download-indicator-header`,children:[(0,G.jsx)(`span`,{className:`download-indicator-spinner`}),(0,G.jsx)(`span`,{className:`download-indicator-title`,children:h.status===`loading`?`Loading model…`:`Efficiency run…`})]}),(0,G.jsx)(`div`,{className:`download-indicator-url`,title:h.model,children:h.model.split(`/`).pop()})]}),(0,G.jsx)(`button`,{type:`button`,className:`autotest-indicator-stop`,onClick:g,"aria-label":`Stop efficiency run`,title:`Stop efficiency run`,children:`■`})]})}),te&&!h&&_&&(0,G.jsx)(`div`,{className:`download-indicator`,children:(0,G.jsxs)(`div`,{className:`download-indicator-link autotest-indicator-link`,children:[(0,G.jsxs)(vn,{to:Mx.efficiency,className:`autotest-indicator-top`,children:[(0,G.jsxs)(`div`,{className:`download-indicator-header`,children:[_.ok?(0,G.jsx)(`span`,{className:`download-indicator-icon success`,children:`✓`}):(0,G.jsx)(`span`,{className:`download-indicator-icon error`,children:`✗`}),(0,G.jsx)(`span`,{className:`download-indicator-title`,children:_.title})]}),(0,G.jsx)(`div`,{className:`download-indicator-url`,title:_.summary,children:_.summary})]}),(0,G.jsx)(`button`,{type:`button`,className:`autotest-indicator-stop`,onClick:v,"aria-label":`Dismiss efficiency result`,title:`Dismiss`,children:`✕`})]})})]}),E&&(0,G.jsx)(`button`,{className:`sidebar-logout`,type:`button`,onClick:()=>void D(),title:`Sign out`,children:`Sign out`}),(0,G.jsx)(`button`,{className:`sidebar-toggle`,onClick:T,"aria-label":w===`light`?`Switch to dark mode`:`Switch to light mode`,title:w===`light`?`Switch to dark mode`:`Switch to light mode`,children:w===`light`?(0,G.jsx)(`svg`,{width:`16`,height:`16`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:(0,G.jsx)(`path`,{d:`M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z`})}):(0,G.jsxs)(`svg`,{width:`16`,height:`16`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,G.jsx)(`circle`,{cx:`12`,cy:`12`,r:`5`}),(0,G.jsx)(`line`,{x1:`12`,y1:`1`,x2:`12`,y2:`3`}),(0,G.jsx)(`line`,{x1:`12`,y1:`21`,x2:`12`,y2:`23`}),(0,G.jsx)(`line`,{x1:`4.22`,y1:`4.22`,x2:`5.64`,y2:`5.64`}),(0,G.jsx)(`line`,{x1:`18.36`,y1:`18.36`,x2:`19.78`,y2:`19.78`}),(0,G.jsx)(`line`,{x1:`1`,y1:`12`,x2:`3`,y2:`12`}),(0,G.jsx)(`line`,{x1:`21`,y1:`12`,x2:`23`,y2:`12`}),(0,G.jsx)(`line`,{x1:`4.22`,y1:`19.78`,x2:`5.64`,y2:`18.36`}),(0,G.jsx)(`line`,{x1:`18.36`,y1:`5.64`,x2:`19.78`,y2:`4.22`})]})}),(0,G.jsx)(`button`,{className:`sidebar-toggle`,onClick:N,"aria-label":j?`Expand sidebar`:`Collapse sidebar`,"aria-expanded":!j,title:j?`Expand sidebar`:`Collapse sidebar`,children:j?(0,G.jsx)(`svg`,{width:`16`,height:`16`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:(0,G.jsx)(`polyline`,{points:`9 18 15 12 9 6`})}):(0,G.jsx)(`svg`,{width:`16`,height:`16`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:(0,G.jsx)(`polyline`,{points:`15 18 9 12 15 6`})})})]}),(0,G.jsx)(`main`,{className:`main-content`,children:e})]})}function J(e){if(e===0)return`0 B`;let t=1024,n=[`B`,`KB`,`MB`,`GB`,`TB`],r=Math.floor(Math.log(e)/Math.log(t));return parseFloat((e/t**r).toFixed(2))+` `+n[r]}function ta(e,t=2){return typeof e==`number`?e.toFixed(t):`—`}function na(e){return e==null?`—`:typeof e==`object`?JSON.stringify(e):String(e)}function ra(e){return e.endsWith(`/AGENT`)?e.slice(0,-6):e}var ia={temperature:`Scales the probability distribution to control randomness. Lower values (e.g. 0.2) make output more focused and deterministic; higher values (e.g. 1.5) increase variety and creativity. Leave empty to use the model default.`,top_p:`Nucleus sampling — samples only from the smallest set of tokens whose cumulative probability reaches this value. Lower values (e.g. 0.5) focus on the most likely tokens; 1.0 effectively disables top-p filtering. Works alongside temperature.`,top_k:`Limits sampling to the top K most probable tokens at each step. Lower values (e.g. 10) make output more predictable; higher values allow more variety. Set very high to approximate no limit. Leave empty to use the model default.`,min_p:`Filters out tokens whose probability is below this fraction of the top token's probability. For example, 0.05 removes tokens less than 5% as likely as the best choice. Higher = stricter filtering. 0 disables.`,repeat_penalty:`Penalizes tokens that appeared in the recent context window (controlled by Repeat Last N). Values above 1.0 discourage repetition; 1.0 means no penalty. Typical range is 1.0–1.3. Too high can make text incoherent.`,repeat_last_n:`How many recent tokens to check when applying the repeat penalty. Larger values look further back for repetitions. To disable repetition penalties, set Repeat Penalty to 1.0 instead.`,frequency_penalty:`Reduces the likelihood of a token proportional to how many times it has appeared. Positive values discourage overused tokens; negative values encourage them. Common range: -2.0 to 2.0. 0 disables.`,presence_penalty:`Applies a flat penalty to any token that has appeared at all, regardless of how often. Positive values encourage the model to use new tokens; negative values favor staying on existing ones. 0 disables.`,dry_multiplier:`Strength of the DRY (Don't Repeat Yourself) anti-repetition penalty. Higher values more aggressively penalize repeated n-gram patterns. Leave empty to use the model default.`,dry_base:`Base for exponential DRY penalty growth. Higher values make the penalty increase faster for longer repeated sequences. Typical values are 1.5–2.0.`,dry_allowed_length:`Minimum n-gram length that DRY penalizes. Repeats of length ≥ this value are penalized; shorter repeats are ignored. Useful for allowing common short phrases. Higher values are more lenient.`,dry_penalty_last_n:`How many recent tokens DRY examines when looking for repeated patterns. Larger values detect repetitions from further back. 0 means use the full context.`,xtc_probability:`Chance of enabling XTC (eXtreme Token Culling) on each token sampling step. When active, XTC removes very high-probability ("obvious") tokens to increase variety. 0 disables XTC entirely, 1 always applies it.`,xtc_threshold:`Probability cutoff for XTC culling. When XTC is active, tokens with probability ≥ this threshold are candidates for removal (with safeguards to keep output coherent). Lower thresholds make XTC more aggressive.`,xtc_min_keep:`Minimum number of token candidates to keep after XTC culling, preventing over-aggressive filtering. Ensures at least this many choices remain available.`,max_tokens:`Maximum number of tokens (word-pieces) to generate. Rule of thumb: 1 token ≈ 0.75 words in English. Output may stop earlier on end-of-sequence or when the context window is full. Higher values allow longer answers but take more time.`,enable_thinking:`Enables reasoning/thinking mode in the prompt template (model-dependent). May improve accuracy on complex tasks but increases token usage and latency. Some models ignore this or keep reasoning internal.`,reasoning_effort:`Requested reasoning level (model/provider dependent): none, minimal, low, medium, high. When omitted, the model template chooses its default. Higher effort may produce more thorough reasoning but uses more tokens and time. Unsupported models ignore this.`,prefillBatchSize:`Maximum prompt tokens contributed by the current prefill owner in one decode iteration. Larger values can reach generation in fewer calls but increase compute-buffer memory and make each call longer for other active slots.`,contextWindow:`Maximum number of tokens (input + output combined) the model can handle at once. Larger windows support longer conversations but increase VRAM usage proportionally via the KV cache. Models with RoPE can extend beyond native context using YaRN (up to ~4× recommended).`,nSeqMax:`Maximum number of concurrent request slots. Each slot handles one user request simultaneously. More slots = better concurrency, but each slot reserves memory for its KV cache.`,flashAttention:`Optimized attention algorithm that reduces VRAM usage and can improve speed. "Enabled" forces it on, "Disabled" forces it off, "Auto" lets the server decide based on model compatibility.`,cacheType:`KV cache precision. f16 = full precision (best quality), q8_0 = 8-bit quantized (less VRAM, minimal quality loss), q4_0 = 4-bit quantized (most VRAM savings, slight quality trade-off especially at long context).`,cacheMode:`Caching strategy. None = clears KV state after each request. IMC (Incremental Message Cache) = keeps the conversation's KV state in a dedicated slot for fast multi-turn follow-ups.`,moeMode:`How to distribute expert weights between GPU and CPU. "Recommended" auto-detects the best option for your hardware. "Save GPU Memory" moves experts to CPU (most common for consumer GPUs). "Maximum Speed" keeps everything on GPU (requires very large VRAM; exact need depends on model, quantization, context, and slots). "Balanced" lets you choose how many layers stay on GPU.`,moeKeepExpertsTopN:`Slide right for more speed (keeps more expert layers on GPU), slide left to save VRAM (offloads to CPU). The highest-numbered layers stay on GPU first. 0 = all experts on CPU.`,moeTipBatch:`For MoE models with CPU experts, a Prefill Batch Size of at least 4096 is recommended for optimal prompt processing speed.`,moeTipFlashAttention:`Flash Attention is strongly recommended for MoE models — it significantly reduces VRAM usage and improves performance.`,moeTipComputeBuffer:`A larger Prefill Batch Size increases compute buffer VRAM usage. Monitor with the VRAM calculator when tuning it.`,availableVRAM:`Total GPU VRAM available (in GB). When set, config candidates estimated to exceed this are auto-skipped before the sweep runs. Set to 0 or leave empty to disable VRAM filtering.`,loadMode:`Controls how model weights are loaded. auto uses mmap when every selected device supports it and otherwise uses ordinary loading; mmap forces memory mapping; none disables it; mlock requests resident pages without forcing mmap; mmap+mlock combines both behaviors; direct-io bypasses the OS page cache where supported.`,numa:`NUMA (Non-Uniform Memory Access) strategy for multi-socket systems. "distribute" spreads memory across NUMA nodes (recommended for MoE CPU-expert setups). "isolate" pins to one node. "numactl" defers to system numactl. "mirror" mirrors across nodes. Leave empty to disable.`,opOffloadMinBatch:`Minimum batch size before enabling GPU offload for certain host-side operations during prompt processing. 0 = use server default. For large MoE models with many CPU weights, values of 200–500+ may improve prompt ingestion speed.`,kvCacheOnCPU:`Moves the KV cache from GPU VRAM to system RAM. Frees GPU memory but may reduce generation speed — significant on discrete GPUs (PCIe bottleneck), minimal on Apple Silicon (unified memory).`,gpuCount:`Number of GPUs to distribute the model across. Weights are split between GPUs using tensor parallelism. More GPUs reduce per-GPU VRAM but add inter-GPU communication overhead.`,tensorSplit:`Proportional distribution of model weights across GPUs (e.g. "0.6,0.4" puts 60% on GPU 0 and 40% on GPU 1). Leave empty for equal distribution. Useful when GPUs have different VRAM capacities.`,expertLayersOnGPU:`For MoE models: how many transformer block expert layers to keep on GPU. More layers on GPU = faster inference but more VRAM. Layers are kept top-down (highest-numbered first). 0 = all experts on CPU.`,autoFit:`Finds the fastest layer and expert placement that fits the selected hardware. The calculator changes placement only when you choose this action. On unified-memory systems, CPU offload does not reduce the total physical memory required.`,gpuLayers:`Number of transformer layers offloaded to GPU (-ngl). All layers on GPU gives maximum speed. Reducing layers saves VRAM by moving weights to system RAM at the cost of inference speed — significant on discrete GPUs (PCIe bottleneck), minimal on Apple Silicon (unified memory).`,modelSize:`Total size of the quantized GGUF model file. For dense models this approximates the GPU VRAM needed for weights alone; for MoE models the actual GPU portion depends on how many expert layers are offloaded to CPU.`,blockCount:`Number of transformer blocks (layers) in the model. More layers = larger model. KV cache scales linearly with this value.`,headCountKV:`Number of key-value attention heads. Along with key/value lengths, determines the per-token KV cache size. Some models use fewer KV heads than query heads (grouped-query attention) to save memory.`,keyLength:`Dimension of each attention key vector (in elements). Together with value length and head count, determines the per-token-per-layer KV cache size.`,valueLength:`Dimension of each attention value vector (in elements). Together with key length and head count, determines the per-token-per-layer KV cache size.`,expertCount:`Total number of expert sub-networks in a Mixture-of-Experts model. Only a subset (top-k) are activated per token, but all must be stored in memory.`,activeExperts:`Number of experts activated per token (top-k routing). Fewer active experts = faster inference per token but the full expert set still occupies memory.`,sharedExperts:`Whether the model has shared (always-active) experts in addition to routed ones. Shared experts run on every token and their weights are always loaded on GPU.`,modelWeights:`GPU memory consumed by the model's weight tensors. For dense models this equals the model file size; for MoE models it includes only the always-active weights plus any expert layers kept on GPU.`,alwaysActiveWeights:`Memory for non-expert weights that are always loaded on GPU: embeddings, attention layers, normalization, output head, and any shared experts.`,expertWeightsGPU:`Memory for the expert layers kept on GPU. Increasing "Expert Layers on GPU" moves more expert blocks from CPU to GPU for faster inference at the cost of VRAM.`,expertWeightsCPU:`Memory for expert layers kept in system RAM (CPU-resident). Saves VRAM but typically reduces throughput vs keeping those layers on GPU.`,kvCache:`Total KV cache memory across all slots. Formula: slots × context_window × block_count × head_count_kv × (key_length + value_length) × bytes_per_element.`,kvPerSlot:`KV cache memory for a single inference slot. Each concurrent request gets its own slot with a full KV cache allocation.`,kvPerTokenPerLayer:`KV cache memory for one token in one transformer layer. This is the fundamental unit — total KV = this × context_window × block_count × slots.`,computeBuffer:`Estimated temporary GPU memory for scratch/intermediate tensors during inference. This calculator uses a heuristic based on model size and embedding dimensions; actual usage may vary with backend and batch settings.`,totalEstimatedVRAM:`Sum of model weights on GPU, KV cache (if on GPU), and estimated compute buffer. In multi-GPU setups this is the total across all GPUs — see the per-GPU breakdown for individual allocations. On unified-memory systems, the calculator instead shows the complete shared-memory footprint.`,totalEstimatedSystemRAM:`Estimated system RAM usage from MoE expert weights on CPU and/or KV cache offloaded to system RAM. Does not include OS or application overhead.`,modelArchitecture:`The neural network architecture family (e.g. llama, qwen2, gemma). Determines how the model processes tokens and which optimizations apply.`,sizeLabel:`Human-readable size label from the model publisher (e.g. "8B", "70B"). Indicates the approximate parameter count.`,quantization:`The GGUF quantization format used to compress model weights. Lower-bit formats (Q4) save memory at some quality cost; higher-bit formats (Q8, F16) preserve more quality.`,contextLength:`The native context window the model was trained on. Input + output tokens must fit within this limit unless extended via YaRN/RoPE scaling.`,embeddingDimension:`Size of each token's hidden-state vector. Larger embeddings capture more information per token but increase memory and compute proportionally.`,attentionHeadsQ:`Number of query attention heads. More heads allow the model to attend to different representation subspaces simultaneously. Together with KV heads, determines the attention pattern.`,ropeDimension:`Number of dimensions used for Rotary Position Embeddings (RoPE). Controls how positional information is encoded into attention. Typically equals the head dimension.`,feedForwardLength:`Size of the feed-forward (MLP) intermediate layer in each transformer block. Larger values increase model capacity but also VRAM usage.`,expertFFNLength:`Size of the feed-forward layer inside each MoE expert sub-network. Similar to Feed Forward Length but specific to the routed expert MLPs.`,sharedExpertFFNLength:`Size of the feed-forward layer in shared (always-active) experts. These experts run on every token in addition to the top-k routed experts.`,ssmInnerSize:`Dimension of the inner state in the SSM (State Space Model) layers. Larger values increase the model's recurrent memory capacity.`,ssmStateSize:`Size of the discrete state in SSM layers. Controls how much information the recurrent state can carry between tokens.`,ssmConvKernel:`Convolution kernel width in SSM layers. Determines how many neighboring tokens are mixed in the local convolution before the SSM recurrence.`,ssmTimeStepRank:`Rank of the time-step projection in SSM layers. Controls the expressiveness of the learned discretization step.`,ssmGroupCount:`Number of groups in the SSM layers. Groups partition the state dimensions for more efficient computation, similar to grouped convolution.`,fullAttentionInterval:`In hybrid models, how often a full attention layer appears among SSM layers (e.g. every N layers). Balances the efficiency of SSM with the global context of attention.`,tokenizerModel:`The tokenizer algorithm used (e.g. BPE, SentencePiece, Unigram). Determines how text is split into tokens that the model processes.`,eosTokenId:`End-of-sequence token ID. When the model generates this token, it signals that the response is complete.`,bosTokenId:`Beginning-of-sequence token ID. Prepended to the input to signal the start of a new sequence to the model.`,paddingTokenId:`Padding token ID used to fill sequences to a uniform length in batch processing. Not used during generation.`,nthreads:`Number of CPU threads used for single-token generation. More threads can speed up CPU-bound work but may cause contention on busy systems. 0 or empty = Yzma's hardware-aware default.`,nthreadsBatch:`Number of CPU threads used for prompt processing and other multi-token batches. 0 or empty = Yzma's hardware-aware default.`,cacheTypeK:`Precision format for the key portion of the KV cache. f16 = full precision (best quality), q8_0 = 8-bit quantized (less VRAM, minimal quality loss), q4_0 = 4-bit (most savings).`,cacheTypeV:`Precision format for the value portion of the KV cache. Same options as Cache Type K. Some models benefit from asymmetric K/V quantization.`,cacheMinTokens:`Minimum token count required before cache reuse kicks in. Higher values avoid caching very short prompts; lower values maximize reuse but can consume more memory for small requests.`,imcSessionCapacity:`Number of reusable IMC conversation identities retained by the model. Larger values reduce cache rebuilds across interleaved conversations but can retain more snapshot data in RAM or on disk.`,offloadKQV:`Offloads key/query/value attention operations to GPU. Can improve performance on GPU-backed inference but increases VRAM usage.`,opOffload:`Allows selected host-side tensor operations to be offloaded to GPU during prompt processing. Can improve throughput for large or CPU-heavy workloads.`,projOnCpu:`Forces the multimodal projector (mmproj) onto the CPU regardless of GPU availability. Use this for audio models hit by llama.cpp Metal kernel regressions; the main LLM still runs on GPU.`,projDevice:`Backend device used by the multimodal projector (mmproj), such as CUDA1 or MTL0. Automatic lets the runtime choose. Cannot be combined with proj-on-cpu enabled.`,mainGpu:`Primary GPU index used in multi-GPU configurations. Relevant when using split mode or explicit device placement. Leave empty on single-GPU systems.`,devices:`Explicit list of devices for inference (e.g. CUDA0,CUDA1). Leave empty to let the runtime auto-select.`,ropeFreqScale:`RoPE frequency scale multiplier for context extension. Usually left at the model default unless reproducing a known long-context configuration.`,yarnBetaFast:`YaRN beta-fast parameter for short-range frequency transition behavior. Advanced tuning option; usually leave unset unless matching a known config.`,yarnBetaSlow:`YaRN beta-slow parameter for long-range frequency transition behavior. Advanced tuning option; usually leave unset unless matching a known config.`,draftGpuLayers:`Number of draft-model layers offloaded to GPU. More GPU layers speed up speculative decoding but use more VRAM.`,draftDevice:`Device for running the draft model. Useful in multi-device setups when you want the draft model placed separately from the main model.`,grammar:`Grammar constraint to force output into a specific syntax (e.g. JSON or a custom GBNF grammar). Improves structured output reliability but can over-constrain generation if the grammar is too strict.`,ngpuLayers:`Number of model layers offloaded to GPU. 0 = all layers on GPU (default). -1 = all layers on CPU. Positive N = first N layers on GPU. Lower values save VRAM but reduce speed.`,splitMode:`How model weights are distributed across multiple GPUs. "layer" assigns whole layers per GPU, "row" splits individual tensor rows. "none" uses a single GPU.`,swaFull:`Use full-context KV storage for sliding-window attention (SWA) layers instead of retaining only the model-defined sliding window. This can greatly increase memory at long contexts. It has no effect on models without SWA layers. Default: on.`,incrementalCache:`Keeps the full conversation KV state in a dedicated slot between requests. Enables fast multi-turn follow-ups by only processing new tokens instead of the entire history.`,ropeScaling:`Type of RoPE (Rotary Position Embedding) scaling used to extend the model's context window beyond its native training length. "yarn" is the most common method.`,yarnOrigCtx:`The model's original (native) context length before YaRN extension. YaRN uses this as the baseline to calculate scaling factors. "auto" reads it from the model metadata.`,ropeFreqBase:`Base frequency for RoPE position embeddings. Higher values stretch the positional encoding, allowing longer contexts. Typically set automatically by YaRN configuration.`,yarnExtFactor:`YaRN extension factor controlling how aggressively context is extended. -1 = auto-calculate based on context ratio. Higher values extend more but may reduce quality.`,yarnAttnFactor:`YaRN attention scaling factor that adjusts attention weight magnitude at extended positions. Fine-tunes quality at long context lengths.`,draftModel:`Speculative decoding draft model — a smaller, faster model that proposes candidate tokens which the main model then verifies. Speeds up generation when acceptance rate is high.`,draftTokens:`Number of tokens the draft model proposes per speculative decoding step. More tokens = potentially faster generation, but too many reduces acceptance rate.`,mtpNDraft:`Fixed number of draft tokens per round for the auto-detected MTP head baked into this model. Leave empty to use the default of 3.`,draftMainGpu:`Primary GPU index for the draft model in multi-GPU setups. Leave empty to use the same GPU as the main model.`,draftTensorSplit:`Proportional weight distribution for the draft model across GPUs. Same format as the main model tensor-split.`,tensorBuftOverrides:`Manual tensor buffer type overrides for specific layers. Advanced option for fine-grained control of where individual tensors are placed.`,hasProjection:`Whether the model includes a multi-modal projection file (mmproj). Required for vision or audio input — the projection maps image/audio embeddings into the model's token space.`,validated:`Whether the model has been validated against the Kronk catalog. Validated models have confirmed-working configurations, templates, and recommended settings.`,mtpSource:`How the model supplies its multi-token prediction drafter: embedded in the model GGUF or provided as a separate companion GGUF file.`,budgetPercent:`Percentage of detected GPU VRAM and system RAM the pool is allowed to commit to loaded models. Reservations beyond this percentage trigger eviction of idle models. Default: 80%.`,budgetHeadroom:`Per-GPU safety margin subtracted from each device's budget after the percentage is applied. Reserves a small cushion so the resman never hands out memory that would just-barely OOM under driver/compute-buffer overhead. Default: 256 MB.`,budgetDeviceTotal:`Total physical memory the device reports. For GPUs this is dedicated VRAM; for the System RAM row this is the host's total RAM. On Apple Silicon (unified memory), the GPU shares this same pool.`,budgetDeviceBudget:`How many bytes the resource manager will allow loaded models to consume on this device. Equals (Total × BudgetPercent / 100) − Headroom.`,budgetDeviceUsed:`Currently reserved bytes on this device, summed across all live model reservations.`,budgetDevicePctOfBudget:`Used ÷ Budget. Approaches 100% as more models are kept warm; passing 100% would have triggered eviction first.`,budgetDeviceFree:`Bytes still available within the budget on this device. New models that exceed this trigger eviction of an idle model before loading.`,budgetUsageBar:`Visual scaled to the device's physical Total. Filled segment = currently reserved bytes (green < 60% of Budget, amber 60–85%, red > 85%). The vertical tick marks the Budget cap (Total × BudgetPercent − Headroom). The dim tail to the right of the tick is physical memory the resman intentionally won't hand out — it's reserved for OS/driver overhead and the configured headroom.`,budgetReservationKey:`Cache/reservation key. For catalog loads this is the model ID; playground sessions use modelID/playground/ so each session is tracked separately.`,budgetReservationTotal:`Total bytes the resman has charged for this reservation, summed across VRAM and system memory. This is the number that counts against the overall budget.`,budgetReservationVRAM:`Bytes charged against discrete GPU VRAM budgets. Zero on systems with no GPU and on Apple Silicon unified memory (where the GPU shares the system pool).`,budgetReservationSystem:`Bytes charged against the system-memory budget. On unified-memory systems (Apple Silicon Metal) the entire model footprint is charged here because the GPU and CPU share one physical pool.`,budgetReservationPerDevice:`Per-device byte allocation for this reservation. Populated when the reservation was split across multiple GPUs via tensor-split. Empty (—) when the reservation is on a single device or on system memory.`,budgetReservationUnified:`Bytes charged against the unified memory budget. On Apple Silicon the GPU (Metal) and CPU share a single physical pool, so the resman tracks one combined number instead of splitting VRAM from system memory (which would double-count the same bytes).`,runningModelID:`Cache key for the loaded model. Catalog models use the model ID directly; playground/custom sessions use modelID/playground/.`,runningModelBackend:`Which pool owns this entry. "kronk" is the llama.cpp pool (chat / embed / rerank / vision / audio LLMs); "bucky" is the whisper.cpp pool (speech-to-text via /v1/audio/transcriptions). Both pools share the same resource manager.`,runningModelOwner:`Publisher namespace from the model file path (e.g. unsloth, google, meta-llama).`,runningModelFamily:`Model family / repo name as it appears in the catalog.`,runningModelSize:`On-disk size of the GGUF file(s) backing this model.`,runningModelVRAMTotal:`Predicted total memory footprint computed by CalculateVRAM: model weights + KV cache + estimated compute buffer. Hardware-agnostic — on Apple unified memory this same number lives in system RAM.`,runningModelKVCache:`Memory consumed by the KV cache across all slots at the current context window and slot count.`,runningModelSlots:`Number of parallel sequences (NSeqMax) configured for this model. Each slot can host one in-flight request.`,runningModelExpiresAt:`Wall-clock time at which the pool will idle-evict this model unless it is touched again. Shows Never when pool TTL is 0.`,runningModelActiveStreams:`Number of in-flight chat/embed/rerank streams currently using this model. The pool refuses to evict a model with active streams.`,runningModelStatus:`Lifecycle stage in the pool. "loaded" means the GGUF is open in llama.cpp and the model can serve requests. "loading" means the resource manager has reserved memory for the load but the GGUF is still being SHA-verified and read from disk; the model is not servable yet but the budget already accounts for it.`,slotIteration:`Latest scheduler loop iteration published by this model. It advances while requests are active or waiting.`,slotBatchSizing:`Configured prefill contribution, effective physical micro-batch capacity (NUBatch), and effective logical batch capacity (NBatch) used by the loaded model.`,slotQueue:`Requests in the engine input channel plus requests already drained into the engine that are waiting for a free slot.`,slotPrefillSelector:`Prefill stage 2 decodes the remaining request-owned tokens that were not available in the IMC session. The large value is the active slot; Next always shows the next eligible slot or round-robin cursor; Waiting lists all currently eligible slots.`,slotIMCSelector:`Prefill stage 1 decodes new stable-prefix tokens, such as completed tool calls, to extend an IMC session. The active slot retains ownership until its extension is complete; Next always shows the next eligible slot or round-robin cursor; Waiting lists all slots with extensions to decode.`,slotEligible:`Slot IDs with uncached request-tail tokens waiting for prefill stage 2. They remain listed while generation priority or another stage 2 owner delays their work.`,slotID:`Stable inference slot and llama.cpp sequence index within this loaded model.`,slotPhase:`Current request phase. Prefill stage 1 restores reusable IMC sequence state into the slot. Prefill stage 2 decodes new tokens into that sequence. Generation produces output tokens.`,slotRequest:`Current request identifier. Empty for an idle slot.`,slotAge:`Elapsed wall-clock time since this request entered the slot. Useful for identifying unusually long or stalled work.`,slotPrefillProgress:`Tokens decoded into the slot during prefill stage 2. This includes stable-prefix IMC extensions such as completed tool calls and remaining request-tail tokens.`,slotIMCProgress:`Prefill stage 1 copies reusable sequence state from an IMC session into the slot. This is a state restore, not token decoding, and may complete between screen refreshes.`,slotGeneration:`Generated output-token count plus this slot’s generation mode and row contribution to the latest scheduler iteration.`,slotPastTokens:`Current next position in this slot’s model KV sequence.`,imcModelID:`Cache key for the loaded model that owns this bounded set of Incremental Message Cache entries.`,imcSessionID:`Stable index of this entry in the model's bounded IMC cache pool. It is not an inference slot or a historical request ID.`,imcState:`Current cache-entry state. Active means a request holds the entry; Idle means it contains a reusable snapshot; Empty means it has no cached snapshot.`,imcContext:`Tokens represented by the current working cache. Kronk normally extends this snapshot when the next rendered prompt has the same prefix.`,imcAllocated:`Largest physical context retained by the current working cache. It does not include the System cache allocation.`,imcSnapshotBytes:`Peak backing storage retained by the working cache for its target snapshot, compatible draft snapshot, and saved MTP hidden row. The configured session store determines whether these bytes reside in RAM or elsewhere.`,imcSystemCacheID:`Stable index of this entry in the model's bounded System cache pool.`,imcSystemContext:`Tokens represented by this immutable system-only cache. Kronk can preload a working cache from it when no working cache matches.`,imcSystemAllocated:`Largest token context represented by this System cache entry.`,imcSystemSnapshotBytes:`RAM occupied by the target snapshot, compatible draft snapshot, and saved MTP hidden row.`,imcSystemRestores:`Number of working caches preloaded from this System cache entry.`,imcSystemActiveRestores:`Number of requests currently restoring this entry. An entry in use cannot be replaced.`,imcPeakContext:`All-time largest live context observed for this cache entry across every request, including input and generated output. It may come from an earlier request.`,imcMessages:`Number of complete messages represented by the current working cache.`,imcInputMessages:`Number of messages in the latest completed request. The current snapshot is published during prompt setup, so it can temporarily contain more messages while a newer request is generating.`,imcInputTokens:`Complete input tokens in the latest completed request, including the stable conversation render and generation-template tail. Current tokens can temporarily be larger while a newer request is generating.`,imcOutputTokens:`Reasoning and completion tokens generated by the latest completed request.`,imcRequestTotal:`Total live context reached by the latest completed request: complete input tokens, including the generation-template tail, plus generated output tokens.`,imcRequestUtilization:`Latest completed request input plus output tokens divided by the configured context window.`,imcContextWindow:`Maximum configured context window for the model that owns this entry.`,imcUtilization:`The session's largest observed live context, including generated output, divided by the configured context window.`,imcLastUsed:`Current eviction/LRU timestamp for this cache entry.`,imcMedia:`Whether the retained cache snapshot includes image or audio content.`,bundleArch:`Target CPU architecture for this library bundle download (amd64 or arm64). Each bundle lives in its own folder under the libraries root and does not replace the active install.`,bundleOS:`Target operating system for this library bundle download (linux, bookworm, trixie, darwin, windows). Each bundle lives in its own folder under the libraries root and does not replace the active install.`,bundleProcessor:`Target processor backend for this library bundle download (cpu, cuda, metal, openvino, rocm, vulkan). OpenVINO is a preview backend supported only for Intel CPU, GPU, and NPU targets on published Linux/Windows amd64 combinations. Only published combinations can be chosen.`,bundleVersion:`Exact upstream library version to install. Leave empty to use the version pinned by this Kronk release.`,bundleRemove:`Delete this bundle directory. Does not affect the active install unless this bundle is the active one.`,peerLibsHost:`Address of another Kronk server on the local network in the form ip:port. The peer must be running with download enabled. Useful in workshop environments where Internet access is slow or unavailable.`,peerLibsConnect:`Query the peer Kronk server for the list of library bundles it has installed and is willing to share.`,peerLibsDownload:`Download this library bundle from the peer over the local network. The peer builds a zip on demand on first request, sends it with a sha256 digest for integrity verification, and the zip is unpacked into the matching bundle directory on this server.`,peerKMSHost:`Address of another Kronk server on the local network in the form ip:port. Connect to list the models that peer has downloaded and pull any of them into this server. The peer must be running with the download endpoint enabled.`,translatorModel:`Installed whisper.cpp model to use for this run. Multilingual models (e.g. ggml-large-v3) can transcribe many languages and translate any of them to English. English-only models (filenames containing ".en") only accept English audio and cannot translate.`,translatorSourceLanguage:`Hint for the language spoken in the audio. Leave on "Auto-detect" to let whisper identify the language from the first ~30 seconds. Set explicitly for short clips, heavy accents, or when auto-detect picks the wrong language.`,translatorTranslate:`When on, whisper translates the source audio to English instead of transcribing in the source language. Whisper can only translate to English — no other target languages are supported by the model. Disabled for English-only models.`,translatorPrompt:`Optional text passed to whisper as decoder context. Useful to bias spelling of proper nouns, technical terms, or to provide style/punctuation hints. Keep it short (a sentence or two).`,translatorRealtimeFactor:`Audio duration divided by wall-clock time. A value of 5x means the run processed 5 seconds of audio per second of real time. Higher is faster.`,translatorNoSpeechProb:`Whisper's estimated probability that this segment contains no speech. Values close to 1 typically indicate silence or background noise.`,imageGeneratorModel:`Installed Malina stable-diffusion model bundle used to generate the image.`,imageGeneratorMode:`Text to image creates an image from the prompt alone. Image to image uses an uploaded PNG or JPEG as the starting composition.`,imageGeneratorPrompt:`Text description of the image to generate. Include the subject, setting, composition, lighting, and style details that matter.`,imageGeneratorSource:`PNG or JPEG used as the starting image. It is resized to the selected output dimensions before generation.`,imageGeneratorNegativePrompt:`Features to discourage in the generated image, such as blur, artifacts, or unwanted objects.`,imageGeneratorSize:`Output dimensions. Automatic uses 512×512 for text generation and preserves the uploaded image aspect ratio for image-to-image generation.`,imageGeneratorSteps:`Number of denoising iterations. More steps can improve detail but increase generation time. The model default is 20.`,imageGeneratorCFGScale:`How strongly generation follows the prompt. Higher values adhere more closely but can reduce natural variation. The model default is 7.`,imageGeneratorSeed:`Positive values reproduce a result. Values of 0 or below choose a random seed for each generation.`,imageGeneratorStrength:`How much the generated result may depart from the uploaded image. Lower values preserve more of the source; 1 allows the largest transformation.`,decisionModel:`Decision-capable model from the catalog. It must be downloaded and pass integrity validation before it can evaluate questions.`,decisionState:`The customer message included in the shared state evaluated by every question.`,decisionAccountTier:`Account tier included in the shared state. Change it to see whether customer context affects the answers.`};function aa(e){let t=e.tooltipKey?ia[e.tooltipKey]:e.text,n=(0,x.useRef)(null),r=(0,x.useRef)(null),i=(0,x.useCallback)(()=>{let e=n.current,t=r.current;if(!e||!t)return;let i=e.getBoundingClientRect(),a=t.offsetWidth,o=t.offsetHeight,s=i.top-o-8,c=i.left,l=c+a-window.innerWidth+8;l>0&&(c-=l),c<8&&(c=8),t.style.left=`${c}px`,t.style.top=`${s}px`;let u=Math.max(10,Math.min(a-10,i.left-c+i.width/2));t.style.setProperty(`--arrow-left`,`${u}px`)},[]);return(0,G.jsxs)(`span`,{className:`param-tooltip-wrapper`,ref:n,onMouseEnter:i,children:[(0,G.jsx)(`span`,{className:`param-tooltip-icon`,children:`ⓘ`}),(0,G.jsx)(`span`,{className:`param-tooltip-text`,ref:r,children:t})]})}function Y(e,t){return(0,G.jsxs)(G.Fragment,{children:[e,` `,(0,G.jsx)(aa,{tooltipKey:t})]})}function X({children:e,tooltipKey:t,after:n,...r}){return(0,G.jsxs)(`label`,{...r,children:[e,t&&(0,G.jsx)(aa,{tooltipKey:t}),n]})}function oa(e){return e>=1e6?`${+(e/1e6).toFixed(1)}M`:e>=1e3?`${+(e/1e3).toFixed(1)}K`:e.toLocaleString()}function sa(e){if(!e)return null;let t=e[`general.architecture`]||``;if(!t)return null;let n=e[`${t}.context_length`];if(!n)return null;let r=Number(n);if(isNaN(r)||r<=0)return null;let i=e[`${t}.rope.dimension_count`]!==void 0||e[`${t}.rope.freq_base`]!==void 0;return{native:r,max:i?r*4:r,hasRoPE:i}}function ca(e){let t=oa(e.native);return!e.hasRoPE||e.max<=e.native?`Context: ${t}`:`Context: ${t} (Max ~${oa(e.max)} via YaRN)`}function la({rows:e}){return e.length===0?null:(0,G.jsx)(`dl`,{className:`kv-table`,children:e.map((e,t)=>(0,G.jsxs)(`div`,{className:`kv-row`,children:[(0,G.jsx)(`dt`,{className:`kv-label`,children:e.label}),(0,G.jsx)(`dd`,{className:`kv-value`,children:e.value})]},e.key??t))})}function ua(e){return e.split(` `).filter(Boolean).map(e=>e.length<=2?e.toUpperCase():e[0].toUpperCase()+e.slice(1)).join(` `)}function da(e,t){return ua((t.startsWith(e+`.`)?t.slice(e.length+1):t).replace(/[._]/g,` `).replace(/\s+/g,` `).trim())}function fa(e){let t={};for(let[n,r]of Object.entries(e)){let e=n.includes(`.`)?n.split(`.`)[0]:`other`;(t[e]||=[]).push([n,r])}let n=e=>e===`general`?0:e===`tokenizer`?1:10;return Object.entries(t).sort(([e],[t])=>n(e)-n(t)||e.localeCompare(t)).map(([e,t])=>({prefix:e,entries:t.sort(([e],[t])=>e.localeCompare(t))}))}function pa({metadata:e,excludeKeys:t=[]}){let n=fa(Object.fromEntries(Object.entries(e).filter(([e])=>!t.includes(e))));return n.length===0?(0,G.jsx)(`div`,{className:`empty-state`,children:(0,G.jsx)(`p`,{children:`No metadata available for this model.`})}):(0,G.jsx)(`div`,{className:`meta-sections`,children:n.map(e=>{let t=e.entries.map(([t,n])=>({key:t,label:da(e.prefix,t),value:na(n)}));return(0,G.jsxs)(`section`,{className:`meta-section`,children:[(0,G.jsx)(`div`,{className:`meta-section-header`,children:(0,G.jsx)(`h4`,{className:`meta-section-title`,children:ua(e.prefix)})}),(0,G.jsx)(la,{rows:t})]},e.prefix)})})}var ma={0:`All F32`,1:`Mostly F16`,2:`Mostly Q4_0`,3:`Mostly Q4_1`,7:`Mostly Q8_0`,8:`Mostly Q5_0`,9:`Mostly Q5_1`,10:`Mostly Q2_K`,11:`Mostly Q3_K_S`,12:`Mostly Q3_K_M`,13:`Mostly Q3_K_L`,14:`Mostly Q4_K_S`,15:`Mostly Q4_K_M`,16:`Mostly Q5_K_S`,17:`Mostly Q5_K_M`,18:`Mostly Q6_K`,19:`Mostly IQ2_XXS`,20:`Mostly IQ2_XS`,21:`Mostly Q2_K_S`,22:`Mostly IQ3_XS`,23:`Mostly IQ3_XXS`,24:`Mostly IQ1_S`,25:`Mostly IQ4_NL`,26:`Mostly IQ3_S`,27:`Mostly IQ3_M`,28:`Mostly IQ2_S`,29:`Mostly IQ2_M`,30:`Mostly IQ4_XS`,31:`Mostly IQ1_M`,32:`Mostly BF16`,36:`Mostly TQ1_0`,37:`Mostly TQ2_0`,38:`Mostly MXFP4_MOE`,39:`Mostly NVFP4`,40:`Mostly Q1_0`,41:`Mostly Q2_0`};function ha(e){let t=Number(e);return isNaN(t)?e:t.toLocaleString()}function ga(e){return e>=1e6?`${+(e/1e6).toFixed(1)}M`:e>=1e3?`${+(e/1e3).toFixed(1)}K`:e.toLocaleString()}function _a(e){return ma[e]||`File Type ${e}`}function va({metadata:e,excludeKeys:t=[],quantization:n,webPage:r}){let i=[...t,`tokenizer.chat_template`],a=Object.keys(e).length>0;if(!a&&!n&&!r)return(0,G.jsx)(`div`,{className:`empty-state`,children:(0,G.jsx)(`p`,{children:`No metadata available for this model.`})});let o=t=>e[t],s=o(`general.architecture`)||``;function c(e){return e.filter(([,e])=>o(e)!==void 0).map(([e,t,n])=>({key:t,label:n?Y(e,n):e,value:na(o(t))}))}let l=c([[`Name`,`general.name`],[`Architecture`,`general.architecture`,`modelArchitecture`],[`Size Label`,`general.size_label`,`sizeLabel`],[`Tags`,`general.tags`]]),u=o(`general.file_type`),d=n||(u===void 0?``:_a(u));d&&l.push({key:`general.file_type`,label:Y(`Quantization`,`quantization`),value:d});let f=o(`general.quantized_by`);f!==void 0&&l.push({key:`general.quantized_by`,label:`Quantized By`,value:na(f)});let p=o(`general.license`)||o(`general.license.link`);p!==void 0&&l.push({key:`general.license`,label:`License`,value:na(p)});let m=c([[`Layers`,`${s}.block_count`,`blockCount`],[`Context Length`,`${s}.context_length`,`contextLength`],[`Embedding Dimension`,`${s}.embedding_length`,`embeddingDimension`],[`Attention Heads (Q)`,`${s}.attention.head_count`,`attentionHeadsQ`],[`Attention Heads (KV)`,`${s}.attention.head_count_kv`,`headCountKV`],[`Key Length`,`${s}.attention.key_length`,`keyLength`],[`Value Length`,`${s}.attention.value_length`,`valueLength`],[`RoPE Dimension`,`${s}.rope.dimension_count`,`ropeDimension`],[`RoPE Freq Base`,`${s}.rope.freq_base`,`ropeFreqBase`],[`Feed Forward Length`,`${s}.feed_forward_length`,`feedForwardLength`]]),h=o(`${s}.context_length`);if(h!==void 0){let e=m.findIndex(e=>e.key===`${s}.context_length`);if(e>=0){let t=Number(h),n=ha(h);if(!isNaN(t)&&t>=1e3){if(n+=` (${ga(t)}`,o(`${s}.rope.dimension_count`)!==void 0||o(`${s}.rope.freq_base`)!==void 0){let e=t*4;n+=`, max ~${ga(e)} via YaRN`}n+=`)`}m[e]={...m[e],value:n}}}let g=o(`${s}.rope.freq_base`);if(g!==void 0){let e=m.findIndex(e=>e.key===`${s}.rope.freq_base`);e>=0&&(m[e]={...m[e],value:ha(g)})}let _=o(`${s}.expert_count`)===void 0?[]:c([[`Expert Count`,`${s}.expert_count`,`expertCount`],[`Experts Used`,`${s}.expert_used_count`,`activeExperts`],[`Expert FFN Length`,`${s}.expert_feed_forward_length`,`expertFFNLength`],[`Shared Expert FFN Length`,`${s}.expert_shared_feed_forward_length`,`sharedExpertFFNLength`]]),v=o(`${s}.ssm.inner_size`)===void 0?[]:c([[`SSM Inner Size`,`${s}.ssm.inner_size`,`ssmInnerSize`],[`SSM State Size`,`${s}.ssm.state_size`,`ssmStateSize`],[`SSM Conv Kernel`,`${s}.ssm.conv_kernel`,`ssmConvKernel`],[`SSM Time Step Rank`,`${s}.ssm.time_step_rank`,`ssmTimeStepRank`],[`SSM Group Count`,`${s}.ssm.group_count`,`ssmGroupCount`],[`Full Attention Interval`,`${s}.full_attention_interval`,`fullAttentionInterval`]]),y=c([[`Model`,`tokenizer.ggml.model`,`tokenizerModel`],[`EOS Token ID`,`tokenizer.ggml.eos_token_id`,`eosTokenId`],[`BOS Token ID`,`tokenizer.ggml.bos_token_id`,`bosTokenId`],[`Padding Token ID`,`tokenizer.ggml.padding_token_id`,`paddingTokenId`]]),b=[{title:`Identity`,rows:l},{title:`Architecture`,rows:m}];return _.length>0&&b.push({title:`Mixture of Experts`,rows:_}),v.length>0&&b.push({title:`Hybrid / SSM`,rows:v}),y.length>0&&b.push({title:`Tokenizer`,rows:y}),(0,G.jsxs)(G.Fragment,{children:[r&&(0,G.jsxs)(`div`,{style:{marginBottom:`16px`},children:[(0,G.jsx)(`h4`,{className:`meta-section-title`,style:{marginBottom:`8px`},children:`Source`}),(0,G.jsx)(`p`,{children:(0,G.jsx)(`a`,{href:r,target:`_blank`,rel:`noopener noreferrer`,children:r})})]}),a&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`div`,{className:`meta-sections`,children:b.filter(e=>e.rows.length>0).map(e=>(0,G.jsxs)(`section`,{className:`meta-section`,children:[(0,G.jsx)(`div`,{className:`meta-section-header`,children:(0,G.jsx)(`h4`,{className:`meta-section-title`,children:e.title})}),(0,G.jsx)(la,{rows:e.rows})]},e.title))}),(0,G.jsxs)(`details`,{className:`model-card-raw-toggle`,children:[(0,G.jsx)(`summary`,{children:`Advanced / Raw Metadata`}),(0,G.jsx)(pa,{metadata:e,excludeKeys:i})]})]})]})}Prism.languages.go=Prism.languages.extend(`clike`,{string:{pattern:/(^|[^\\])"(?:\\.|[^"\\\r\n])*"|`[^`]*`/,lookbehind:!0,greedy:!0},keyword:/\b(?:break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(?:to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/,boolean:/\b(?:_|false|iota|nil|true)\b/,number:[/\b0(?:b[01_]+|o[0-7_]+)i?\b/i,/\b0x(?:[a-f\d_]+(?:\.[a-f\d_]*)?|\.[a-f\d_]+)(?:p[+-]?\d+(?:_\d+)*)?i?(?!\w)/i,/(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?[\d_]+)?i?(?!\w)/i],operator:/[*\/%^!=]=?|\+[=+]?|-[=-]?|\|[=|]?|&(?:=|&|\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\.\.\./,builtin:/\b(?:append|bool|byte|cap|close|complex|complex(?:64|128)|copy|delete|error|float(?:32|64)|u?int(?:8|16|32|64)?|imag|len|make|new|panic|print(?:ln)?|real|recover|rune|string|uintptr)\b/}),Prism.languages.insertBefore(`go`,`string`,{char:{pattern:/'(?:\\.|[^'\\\r\n]){0,10}'/,greedy:!0}}),delete Prism.languages.go[`class-name`],Prism.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0,greedy:!0},"string-interpolation":{pattern:/(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,lookbehind:!0,inside:{"format-spec":{pattern:/(:)[^:(){}]+(?=\}$)/,lookbehind:!0},"conversion-option":{pattern://,alias:`punctuation`},rest:null}},string:/[\s\S]+/}},"triple-quoted-string":{pattern:/(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i,greedy:!0,alias:`string`},string:{pattern:/(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,greedy:!0},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)\w+/i,lookbehind:!0},decorator:{pattern:/(^[\t ]*)@\w+(?:\.\w+)*/m,lookbehind:!0,alias:[`annotation`,`punctuation`],inside:{punctuation:/\./}},keyword:/\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,builtin:/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,boolean:/\b(?:False|None|True)\b/,number:/\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i,operator:/[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},Prism.languages.python[`string-interpolation`].inside.interpolation.inside.rest=Prism.languages.python,Prism.languages.py=Prism.languages.python,Prism.languages.javascript=Prism.languages.extend(`clike`,{"class-name":[Prism.languages.clike[`class-name`],{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\})\s*)catch\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],function:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,number:{pattern:RegExp(`(^|[^\\w$])(?:NaN|Infinity|0[bB][01]+(?:_[01]+)*n?|0[oO][0-7]+(?:_[0-7]+)*n?|0[xX][\\dA-Fa-f]+(?:_[\\dA-Fa-f]+)*n?|\\d+(?:_\\d+)*n|(?:\\d+(?:_\\d+)*(?:\\.(?:\\d+(?:_\\d+)*)?)?|\\.\\d+(?:_\\d+)*)(?:[Ee][+-]?\\d+(?:_\\d+)*)?)(?![\\w$])`),lookbehind:!0},operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),Prism.languages.javascript[`class-name`][0].pattern=/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/,Prism.languages.insertBefore(`javascript`,`keyword`,{regex:{pattern:RegExp(`((?:^|[^$\\w\\xA0-\\uFFFF."'\\])\\s]|\\b(?:return|yield))\\s*)\\/(?:(?:\\[(?:[^\\]\\\\\\r\\n]|\\\\.)*\\]|\\\\.|[^/\\\\\\[\\r\\n])+\\/[dgimyus]{0,7}|(?:\\[(?:[^[\\]\\\\\\r\\n]|\\\\.|\\[(?:[^[\\]\\\\\\r\\n]|\\\\.|\\[(?:[^[\\]\\\\\\r\\n]|\\\\.)*\\])*\\])*\\]|\\\\.|[^/\\\\\\[\\r\\n])+\\/[dgimyus]{0,7}v[dgimyus]{0,7})(?=(?:\\s|\\/\\*(?:[^*]|\\*(?!\\/))*\\*\\/)*(?:$|[\\r\\n,.;:})\\]]|\\/\\/))`),lookbehind:!0,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:`language-regex`,inside:Prism.languages.regex},"regex-delimiter":/^\/|\/$/,"regex-flags":/^[a-z]+$/}},"function-variable":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,alias:`function`},parameter:[{pattern:/(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,lookbehind:!0,inside:Prism.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),Prism.languages.insertBefore(`javascript`,`string`,{hashbang:{pattern:/^#!.*/,greedy:!0,alias:`comment`},"template-string":{pattern:/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:`string`},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:`punctuation`},rest:Prism.languages.javascript}},string:/[\s\S]+/}},"string-property":{pattern:/((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,lookbehind:!0,greedy:!0,alias:`property`}}),Prism.languages.insertBefore(`javascript`,`operator`,{"literal-property":{pattern:/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,lookbehind:!0,alias:`property`}}),Prism.languages.markup&&(Prism.languages.markup.tag.addInlined(`script`,`javascript`),Prism.languages.markup.tag.addAttribute(`on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)`,`javascript`)),Prism.languages.js=Prism.languages.javascript,(function(e){e.languages.typescript=e.languages.extend(`javascript`,{"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|type)\s+)(?!keyof\b)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?:\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>)?/,lookbehind:!0,greedy:!0,inside:null},builtin:/\b(?:Array|Function|Promise|any|boolean|console|never|number|string|symbol|unknown)\b/}),e.languages.typescript.keyword.push(/\b(?:abstract|declare|is|keyof|readonly|require)\b/,/\b(?:asserts|infer|interface|module|namespace|type)\b(?=\s*(?:[{_$a-zA-Z\xA0-\uFFFF]|$))/,/\btype\b(?=\s*(?:[\{*]|$))/),delete e.languages.typescript.parameter,delete e.languages.typescript[`literal-property`];var t=e.languages.extend(`typescript`,{});delete t[`class-name`],e.languages.typescript[`class-name`].inside=t,e.languages.insertBefore(`typescript`,`function`,{decorator:{pattern:/@[$\w\xA0-\uFFFF]+/,inside:{at:{pattern:/^@/,alias:`operator`},function:/^[\s\S]+/}},"generic-function":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,greedy:!0,inside:{function:/^#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/,generic:{pattern:/<[\s\S]+/,alias:`class-name`,inside:t}}}}),e.languages.ts=e.languages.typescript})(Prism),(function(e){for(var t=`\\/\\*(?:[^*/]|\\*(?!\\/)|\\/(?!\\*)|)*\\*\\/`,n=0;n<2;n++)t=t.replace(//g,function(){return t});t=t.replace(//g,function(){return`[^\\s\\S]`}),e.languages.rust={comment:[{pattern:RegExp(`(^|[^\\\\])`+t),lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/b?"(?:\\[\s\S]|[^\\"])*"|b?r(#*)"(?:[^"]|"(?!\1))*"\1/,greedy:!0},char:{pattern:/b?'(?:\\(?:x[0-7][\da-fA-F]|u\{(?:[\da-fA-F]_*){1,6}\}|.)|[^\\\r\n\t'])'/,greedy:!0},attribute:{pattern:/#!?\[(?:[^\[\]"]|"(?:\\[\s\S]|[^\\"])*")*\]/,greedy:!0,alias:`attr-name`,inside:{string:null}},"closure-params":{pattern:/([=(,:]\s*|\bmove\s*)\|[^|]*\||\|[^|]*\|(?=\s*(?:\{|->))/,lookbehind:!0,greedy:!0,inside:{"closure-punctuation":{pattern:/^\||\|$/,alias:`punctuation`},rest:null}},"lifetime-annotation":{pattern:/'\w+/,alias:`symbol`},"fragment-specifier":{pattern:/(\$\w+:)[a-z]+/,lookbehind:!0,alias:`punctuation`},variable:/\$\w+/,"function-definition":{pattern:/(\bfn\s+)\w+/,lookbehind:!0,alias:`function`},"type-definition":{pattern:/(\b(?:enum|struct|trait|type|union)\s+)\w+/,lookbehind:!0,alias:`class-name`},"module-declaration":[{pattern:/(\b(?:crate|mod)\s+)[a-z][a-z_\d]*/,lookbehind:!0,alias:`namespace`},{pattern:/(\b(?:crate|self|super)\s*)::\s*[a-z][a-z_\d]*\b(?:\s*::(?:\s*[a-z][a-z_\d]*\s*::)*)?/,lookbehind:!0,alias:`namespace`,inside:{punctuation:/::/}}],keyword:[/\b(?:Self|abstract|as|async|await|become|box|break|const|continue|crate|do|dyn|else|enum|extern|final|fn|for|if|impl|in|let|loop|macro|match|mod|move|mut|override|priv|pub|ref|return|self|static|struct|super|trait|try|type|typeof|union|unsafe|unsized|use|virtual|where|while|yield)\b/,/\b(?:bool|char|f(?:32|64)|[ui](?:8|16|32|64|128|size)|str)\b/],function:/\b[a-z_]\w*(?=\s*(?:::\s*<|\())/,macro:{pattern:/\b\w+!/,alias:`property`},constant:/\b[A-Z_][A-Z_\d]+\b/,"class-name":/\b[A-Z]\w*\b/,namespace:{pattern:/(?:\b[a-z][a-z_\d]*\s*::\s*)*\b[a-z][a-z_\d]*\s*::(?!\s*<)/,inside:{punctuation:/::/}},number:/\b(?:0x[\dA-Fa-f](?:_?[\dA-Fa-f])*|0o[0-7](?:_?[0-7])*|0b[01](?:_?[01])*|(?:(?:\d(?:_?\d)*)?\.)?\d(?:_?\d)*(?:[Ee][+-]?\d+)?)(?:_?(?:f32|f64|[iu](?:8|16|32|64|size)?))?\b/,boolean:/\b(?:false|true)\b/,punctuation:/->|\.\.=|\.{1,3}|::|[{}[\];(),:]/,operator:/[-+*\/%!^]=?|=[=>]?|&[&=]?|\|[|=]?|<=?|>>?=?|[@?]/},e.languages.rust[`closure-params`].inside.rest=e.languages.rust,e.languages.rust.attribute.inside.string=e.languages.rust.string})(Prism),Prism.languages.sql={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|(?:--|\/\/|#).*)/,lookbehind:!0},variable:[{pattern:/@(["'`])(?:\\[\s\S]|(?!\1)[^\\])+\1/,greedy:!0},/@[\w.$]+/],string:{pattern:/(^|[^@\\])("|')(?:\\[\s\S]|(?!\2)[^\\]|\2\2)*\2/,greedy:!0,lookbehind:!0},identifier:{pattern:/(^|[^@\\])`(?:\\[\s\S]|[^`\\]|``)*`/,greedy:!0,lookbehind:!0,inside:{punctuation:/^`|`$/}},function:/\b(?:AVG|COUNT|FIRST|FORMAT|LAST|LCASE|LEN|MAX|MID|MIN|MOD|NOW|ROUND|SUM|UCASE)(?=\s*\()/i,keyword:/\b(?:ACTION|ADD|AFTER|ALGORITHM|ALL|ALTER|ANALYZE|ANY|APPLY|AS|ASC|AUTHORIZATION|AUTO_INCREMENT|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADED?|CASE|CHAIN|CHAR(?:ACTER|SET)?|CHECK(?:POINT)?|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMNS?|COMMENT|COMMIT(?:TED)?|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS(?:TABLE)?|CONTINUE|CONVERT|CREATE|CROSS|CURRENT(?:_DATE|_TIME|_TIMESTAMP|_USER)?|CURSOR|CYCLE|DATA(?:BASES?)?|DATE(?:TIME)?|DAY|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DELIMITERS?|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DROP|DUMMY|DUMP(?:FILE)?|DUPLICATE|ELSE(?:IF)?|ENABLE|ENCLOSED|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPED?|EXCEPT|EXEC(?:UTE)?|EXISTS|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR(?: EACH ROW)?|FORCE|FOREIGN|FREETEXT(?:TABLE)?|FROM|FULL|FUNCTION|GEOMETRY(?:COLLECTION)?|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|HOUR|IDENTITY(?:COL|_INSERT)?|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTERVAL|INTO|INVOKER|ISOLATION|ITERATE|JOIN|KEYS?|KILL|LANGUAGE|LAST|LEAVE|LEFT|LEVEL|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONG(?:BLOB|TEXT)|LOOP|MATCH(?:ED)?|MEDIUM(?:BLOB|INT|TEXT)|MERGE|MIDDLEINT|MINUTE|MODE|MODIFIES|MODIFY|MONTH|MULTI(?:LINESTRING|POINT|POLYGON)|NATIONAL|NATURAL|NCHAR|NEXT|NO|NONCLUSTERED|NULLIF|NUMERIC|OFF?|OFFSETS?|ON|OPEN(?:DATASOURCE|QUERY|ROWSET)?|OPTIMIZE|OPTION(?:ALLY)?|ORDER|OUT(?:ER|FILE)?|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREPARE|PREV|PRIMARY|PRINT|PRIVILEGES|PROC(?:EDURE)?|PUBLIC|PURGE|QUICK|RAISERROR|READS?|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEAT(?:ABLE)?|REPLACE|REPLICATION|REQUIRE|RESIGNAL|RESTORE|RESTRICT|RETURN(?:ING|S)?|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROW(?:COUNT|GUIDCOL|S)?|RTREE|RULE|SAVE(?:POINT)?|SCHEMA|SECOND|SELECT|SERIAL(?:IZABLE)?|SESSION(?:_USER)?|SET(?:USER)?|SHARE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|SQL|START(?:ING)?|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLES?|TABLESPACE|TEMP(?:ORARY|TABLE)?|TERMINATED|TEXT(?:SIZE)?|THEN|TIME(?:STAMP)?|TINY(?:BLOB|INT|TEXT)|TOP?|TRAN(?:SACTIONS?)?|TRIGGER|TRUNCATE|TSEQUAL|TYPES?|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNIQUE|UNLOCK|UNPIVOT|UNSIGNED|UPDATE(?:TEXT)?|USAGE|USE|USER|USING|VALUES?|VAR(?:BINARY|CHAR|CHARACTER|YING)|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH(?: ROLLUP|IN)?|WORK|WRITE(?:TEXT)?|YEAR)\b/i,boolean:/\b(?:FALSE|NULL|TRUE)\b/i,number:/\b0x[\da-f]+\b|\b\d+(?:\.\d*)?|\B\.\d+\b/i,operator:/[-+*\/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|DIV|ILIKE|IN|IS|LIKE|NOT|OR|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i,punctuation:/[;[\]()`,.]/},Prism.languages.json={property:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?=\s*:)/,lookbehind:!0,greedy:!0},string:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?!\s*:)/,lookbehind:!0,greedy:!0},comment:{pattern:/\/\/.*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},number:/-?\b\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,punctuation:/[{}[\],]/,operator:/:/,boolean:/\b(?:false|true)\b/,null:{pattern:/\bnull\b/,alias:`keyword`}},Prism.languages.webmanifest=Prism.languages.json,(function(e){var t=/[*&][^\s[\]{},]+/,n=/!(?:<[\w\-%#;/?:@&=+$,.!~*'()[\]]+>|(?:[a-zA-Z\d-]*!)?[\w\-%#;/?:@&=+$.~*'()]+)?/,r=`(?:`+n.source+`(?:[ ]+`+t.source+`)?|`+t.source+`(?:[ ]+`+n.source+`)?)`,i=`(?:[^\\s\\x00-\\x08\\x0e-\\x1f!"#%&'*,\\-:>?@[\\]\`{|}\\x7f-\\x84\\x86-\\x9f\\ud800-\\udfff\\ufffe\\uffff]|[?:-])(?:[ \\t]*(?:(?![#:])|:))*`.replace(//g,function(){return`[^\\s\\x00-\\x08\\x0e-\\x1f,[\\]{}\\x7f-\\x84\\x86-\\x9f\\ud800-\\udfff\\ufffe\\uffff]`}),a=`"(?:[^"\\\\\\r\\n]|\\\\.)*"|'(?:[^'\\\\\\r\\n]|\\\\.)*'`;function o(e,t){t=(t||``).replace(/m/g,``)+`m`;var n=`([:\\-,[{]\\s*(?:\\s<>[ \\t]+)?)(?:<>)(?=[ \\t]*(?:$|,|\\]|\\}|(?:[\\r\\n]\\s*)?#))`.replace(/<>/g,function(){return r}).replace(/<>/g,function(){return e});return RegExp(n,t)}e.languages.yaml={scalar:{pattern:RegExp(`([\\-:]\\s*(?:\\s<>[ \\t]+)?[|>])[ \\t]*(?:((?:\\r?\\n|\\r)[ \\t]+)\\S[^\\r\\n]*(?:\\2[^\\r\\n]+)*)`.replace(/<>/g,function(){return r})),lookbehind:!0,alias:`string`},comment:/#.*/,key:{pattern:RegExp(`((?:^|[:\\-,[{\\r\\n?])[ \\t]*(?:<>[ \\t]+)?)<>(?=\\s*:\\s)`.replace(/<>/g,function(){return r}).replace(/<>/g,function(){return`(?:`+i+`|`+a+`)`})),lookbehind:!0,greedy:!0,alias:`atrule`},directive:{pattern:/(^[ \t]*)%.+/m,lookbehind:!0,alias:`important`},datetime:{pattern:o(`\\d{4}-\\d\\d?-\\d\\d?(?:[tT]|[ \\t]+)\\d\\d?:\\d{2}:\\d{2}(?:\\.\\d*)?(?:[ \\t]*(?:Z|[-+]\\d\\d?(?::\\d{2})?))?|\\d{4}-\\d{2}-\\d{2}|\\d\\d?:\\d{2}(?::\\d{2}(?:\\.\\d*)?)?`),lookbehind:!0,alias:`number`},boolean:{pattern:o(`false|true`,`i`),lookbehind:!0,alias:`important`},null:{pattern:o(`null|~`,`i`),lookbehind:!0,alias:`important`},string:{pattern:o(a),lookbehind:!0,greedy:!0},number:{pattern:o(`[+-]?(?:0x[\\da-f]+|0o[0-7]+|(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:e[+-]?\\d+)?|\\.inf|\\.nan)`,`i`),lookbehind:!0},tag:n,important:t,punctuation:/---|[:[\]{}\-,|>?]|\.\.\./},e.languages.yml=e.languages.yaml})(Prism),(function(e){var t=`\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b`,n={pattern:/(^(["']?)\w+\2)[ \t]+\S.*/,lookbehind:!0,alias:`punctuation`,inside:null},r={bash:n,environment:{pattern:RegExp(`\\$`+t),alias:`constant`},variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,greedy:!0,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--|\+\+|\*\*=?|<<=?|>>=?|&&|\|\||[=!+\-*/%<>^&|]=?|[?~:]/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/,greedy:!0,inside:{variable:/^\$\(|^`|\)$|`$/}},{pattern:/\$\{[^}]+\}/,greedy:!0,inside:{operator:/:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,punctuation:/[\[\]]/,environment:{pattern:RegExp(`(\\{)`+t),lookbehind:!0,alias:`constant`}}},/\$(?:\w+|[#?*!@$])/],entity:/\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|U[0-9a-fA-F]{8}|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{1,2})/};e.languages.bash={shebang:{pattern:/^#!\s*\/.*/,alias:`important`},comment:{pattern:/(^|[^"{\\$])#.*/,lookbehind:!0},"function-name":[{pattern:/(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/,lookbehind:!0,alias:`function`},{pattern:/\b[\w-]+(?=\s*\(\s*\)\s*\{)/,alias:`function`}],"for-or-select":{pattern:/(\b(?:for|select)\s+)\w+(?=\s+in\s)/,alias:`variable`,lookbehind:!0},"assign-left":{pattern:/(^|[\s;|&]|[<>]\()\w+(?:\.\w+)*(?=\+?=)/,inside:{environment:{pattern:RegExp(`(^|[\\s;|&]|[<>]\\()`+t),lookbehind:!0,alias:`constant`}},alias:`variable`,lookbehind:!0},parameter:{pattern:/(^|\s)-{1,2}(?:\w+:[+-]?)?\w+(?:\.\w+)*(?=[=\s]|$)/,alias:`variable`,lookbehind:!0},string:[{pattern:/((?:^|[^<])<<-?\s*)(\w+)\s[\s\S]*?(?:\r?\n|\r)\2/,lookbehind:!0,greedy:!0,inside:r},{pattern:/((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s[\s\S]*?(?:\r?\n|\r)\3/,lookbehind:!0,greedy:!0,inside:{bash:n}},{pattern:/(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/,lookbehind:!0,greedy:!0,inside:r},{pattern:/(^|[^$\\])'[^']*'/,lookbehind:!0,greedy:!0},{pattern:/\$'(?:[^'\\]|\\[\s\S])*'/,greedy:!0,inside:{entity:r.entity}}],environment:{pattern:RegExp(`\\$?`+t),alias:`constant`},variable:r.variable,function:{pattern:/(^|[\s;|&]|[<>]\()(?:add|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cargo|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|docker|docker-compose|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|java|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|node|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|podman|podman-compose|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|sysctl|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vcpkg|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\s;|&]|[<>]\()(?:case|do|done|elif|else|esac|fi|for|function|if|in|select|then|until|while)(?=$|[)\s;|&])/,lookbehind:!0},builtin:{pattern:/(^|[\s;|&]|[<>]\()(?:\.|:|alias|bind|break|builtin|caller|cd|command|continue|declare|echo|enable|eval|exec|exit|export|getopts|hash|help|let|local|logout|mapfile|printf|pwd|read|readarray|readonly|return|set|shift|shopt|source|test|times|trap|type|typeset|ulimit|umask|unalias|unset)(?=$|[)\s;|&])/,lookbehind:!0,alias:`class-name`},boolean:{pattern:/(^|[\s;|&]|[<>]\()(?:false|true)(?=$|[)\s;|&])/,lookbehind:!0},"file-descriptor":{pattern:/\B&\d\b/,alias:`important`},operator:{pattern:/\d?<>|>\||\+=|=[=~]?|!=?|<<[<-]?|[&\d]?>>|\d[<>]&?|[<>][&=]?|&[>&]?|\|[&|]?/,inside:{"file-descriptor":{pattern:/^\d/,alias:`important`}}},punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/,number:{pattern:/(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/,lookbehind:!0}},n.inside=e.languages.bash;for(var i=[`comment`,`function-name`,`for-or-select`,`assign-left`,`parameter`,`string`,`environment`,`function`,`keyword`,`builtin`,`boolean`,`file-descriptor`,`operator`,`punctuation`,`number`],a=r.variable[1].inside,o=0;o=a.length);c++){var l=s[c];if(typeof l==`string`||l.content&&typeof l.content==`string`){var u=a[i],d=n.tokenStack[u],f=typeof l==`string`?l:l.content,p=t(r,u),m=f.indexOf(p);if(m>-1){++i;var h=f.substring(0,m),g=new e.Token(r,e.tokenize(d,n.grammar),`language-`+r,d),_=f.substring(m+p.length),v=[];h&&v.push.apply(v,o([h])),v.push(g),_&&v.push.apply(v,o([_])),typeof l==`string`?s.splice.apply(s,[c,1].concat(v)):l.content=v}}else l.content&&o(l.content)}return s}o(n.tokens)}}})})(Prism),(function(e){e.languages.django={comment:/^\{#[\s\S]*?#\}$/,tag:{pattern:/(^\{%[+-]?\s*)\w+/,lookbehind:!0,alias:`keyword`},delimiter:{pattern:/^\{[{%][+-]?|[+-]?[}%]\}$/,alias:`punctuation`},string:{pattern:/("|')(?:\\.|(?!\1)[^\\\r\n])*\1/,greedy:!0},filter:{pattern:/(\|)\w+/,lookbehind:!0,alias:`function`},test:{pattern:/(\bis\s+(?:not\s+)?)(?!not\b)\w+/,lookbehind:!0,alias:`function`},function:/\b[a-z_]\w+(?=\s*\()/i,keyword:/\b(?:and|as|by|else|for|if|import|in|is|loop|not|or|recursive|with|without)\b/,operator:/[-+%=]=?|!=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,number:/\b\d+(?:\.\d+)?\b/,boolean:/[Ff]alse|[Nn]one|[Tt]rue/,variable:/\b\w+\b/,punctuation:/[{}[\](),.:;]/};var t=/\{\{[\s\S]*?\}\}|\{%[\s\S]*?%\}|\{#[\s\S]*?#\}/g,n=e.languages[`markup-templating`];e.hooks.add(`before-tokenize`,function(e){n.buildPlaceholders(e,`django`,t)}),e.hooks.add(`after-tokenize`,function(e){n.tokenizePlaceholders(e,`django`)}),e.languages.jinja2=e.languages.django,e.hooks.add(`before-tokenize`,function(e){n.buildPlaceholders(e,`jinja2`,t)}),e.hooks.add(`after-tokenize`,function(e){n.tokenizePlaceholders(e,`jinja2`)})})(Prism),jn.default.languages.bash&&!jn.default.languages.shell&&(jn.default.languages.shell=jn.default.languages.bash),jn.default.languages.django&&!jn.default.languages.jinja2&&(jn.default.languages.jinja2=jn.default.languages.django);function ya({code:e,language:t=`go`,collapsible:n=!1}){let r=(0,x.useRef)(null),[i,a]=(0,x.useState)(!1),[o,s]=(0,x.useState)(!1),[c,l]=(0,x.useState)(0);(0,x.useEffect)(()=>{if(r.current){jn.default.highlightElement(r.current);let t=e.split(`
+`)}`})}return u.push({role:`user`,content:s}),{id:`ctxfill-${t.replace(`%`,``)}`,messages:u,max_tokens:i,expected:void 0,contextFill:{ratio:e,label:t},includeInScore:!1}}async function Yn(e,t,n){let r=[{ratio:0,label:`0%`},{ratio:.2,label:`20%`},{ratio:.5,label:`50%`},{ratio:.8,label:`80%`}],i=[],a=3.5,o=1024,s=Jn(.5,`50%`,o,a,1);try{if(!n?.aborted){let t=(await sr(e,{...s,max_tokens:1},{},n)).usage?.prompt_tokens;t&&t>0&&(a=o/t*a)}}catch{}for(let{ratio:e,label:n}of r){if(e===0){i.push(Jn(0,n,0,a,64));continue}let r=Math.floor(t*e)-256;r<100||i.push(Jn(e,n,r,a,64))}return i}function Xn(e,t){if(e){let t=e.context_window??e[`context-window`];if(typeof t==`number`&&t>0)return t}if(t){let e=t.context_window;if(typeof e==`number`&&e>0)return e}}var Zn={id:`tool_call`,name:`Tool Calling`,prompts:[{id:`weather-tool`,messages:[{role:`system`,content:q},{role:`user`,content:`What's the weather in Boston?`}],tools:K,expected:{type:`tool_call`}},{id:`add-tool`,messages:[{role:`system`,content:q},{role:`user`,content:`What is 15 + 28?`}],tools:K,expected:{type:`tool_call`}},{id:`multi-turn-tool`,messages:[{role:`system`,content:q},{role:`user`,content:`What's the weather in Boston?`},{role:`assistant`,content:``,tool_calls:[{id:`tc1`,index:0,type:`function`,function:{name:`get_weather`,arguments:`{"location":"Boston"}`}}]},{role:`user`,content:`Now check the weather in London too.`}],tools:K,expected:{type:`tool_call`}},{id:`weather-tokyo`,messages:[{role:`system`,content:q},{role:`user`,content:`What's the weather like in Tokyo right now?`}],tools:K,expected:{type:`tool_call`}},{id:`weather-celsius`,messages:[{role:`system`,content:q},{role:`user`,content:`Tell me the weather in Paris in celsius.`}],tools:K,expected:{type:`tool_call`}},{id:`add-large`,messages:[{role:`system`,content:q},{role:`user`,content:`Calculate 1234 + 5678 for me.`}],tools:K,expected:{type:`tool_call`}},{id:`add-decimals`,messages:[{role:`system`,content:q},{role:`user`,content:`What is 3.14 + 2.72?`}],tools:K,expected:{type:`tool_call`}},{id:`search-laptop`,messages:[{role:`system`,content:q},{role:`user`,content:`Search for laptops under $1000.`}],tools:K,expected:{type:`tool_call`}},{id:`search-headphones`,messages:[{role:`system`,content:q},{role:`user`,content:`Find me wireless headphones in the electronics category.`}],tools:K,expected:{type:`tool_call`}},{id:`send-email`,messages:[{role:`system`,content:q},{role:`user`,content:`Send an email to alice@example.com with subject "Meeting Tomorrow" and body "Let's meet at 3pm."`}],tools:K,expected:{type:`tool_call`}},{id:`stock-price-aapl`,messages:[{role:`system`,content:q},{role:`user`,content:`What's Apple's current stock price?`}],tools:K,expected:{type:`tool_call`}},{id:`stock-price-tsla`,messages:[{role:`system`,content:q},{role:`user`,content:`Check the stock price of Tesla.`}],tools:K,expected:{type:`tool_call`}},{id:`convert-usd-eur`,messages:[{role:`system`,content:q},{role:`user`,content:`Convert 100 USD to EUR.`}],tools:K,expected:{type:`tool_call`}},{id:`convert-gbp-jpy`,messages:[{role:`system`,content:q},{role:`user`,content:`How much is 500 British pounds in Japanese yen?`}],tools:K,expected:{type:`tool_call`}},{id:`calendar-meeting`,messages:[{role:`system`,content:q},{role:`user`,content:`Schedule a team meeting for 2025-03-15 at 10:00 for 60 minutes.`}],tools:K,expected:{type:`tool_call`}},{id:`calendar-lunch`,messages:[{role:`system`,content:q},{role:`user`,content:`Create a lunch event on 2025-04-01 at 12:30.`}],tools:K,expected:{type:`tool_call`}},{id:`translate-hello-spanish`,messages:[{role:`system`,content:q},{role:`user`,content:`Translate 'Hello, how are you?' to Spanish.`}],tools:K,expected:{type:`tool_call`}},{id:`translate-goodbye-german`,messages:[{role:`system`,content:q},{role:`user`,content:`Translate 'Goodbye and thank you' to German.`}],tools:K,expected:{type:`tool_call`}},{id:`directions-sf-la`,messages:[{role:`system`,content:q},{role:`user`,content:`Get me driving directions from San Francisco to Los Angeles.`}],tools:K,expected:{type:`tool_call`}},{id:`directions-walking`,messages:[{role:`system`,content:q},{role:`user`,content:`How do I walk from Central Park to Times Square?`}],tools:K,expected:{type:`tool_call`}},{id:`reminder-dentist`,messages:[{role:`system`,content:q},{role:`user`,content:`Remind me about my dentist appointment at 2025-03-20T09:00:00.`}],tools:K,expected:{type:`tool_call`}},{id:`reminder-groceries`,messages:[{role:`system`,content:q},{role:`user`,content:`Set a reminder to buy groceries tomorrow at 5pm.`}],tools:K,expected:{type:`tool_call`}},{id:`multi-turn-tool-add`,messages:[{role:`system`,content:q},{role:`user`,content:`What is 10 + 20?`},{role:`assistant`,content:``,tool_calls:[{id:`tc2`,index:0,type:`function`,function:{name:`add`,arguments:`{"a":10,"b":20}`}}]},{role:`user`,content:`Now add 30 + 40.`}],tools:K,expected:{type:`tool_call`}},{id:`multi-turn-tool-weather-3`,messages:[{role:`system`,content:q},{role:`user`,content:`What's the weather in Boston?`},{role:`assistant`,content:``,tool_calls:[{id:`tc3`,index:0,type:`function`,function:{name:`get_weather`,arguments:`{"location":"Boston"}`}}]},{role:`user`,content:`Now check the weather in London too.`},{role:`assistant`,content:``,tool_calls:[{id:`tc4`,index:0,type:`function`,function:{name:`get_weather`,arguments:`{"location":"London"}`}}]},{role:`user`,content:`And what about Sydney?`}],tools:K,expected:{type:`tool_call`}},{id:`multi-turn-tool-stock-follow`,messages:[{role:`system`,content:q},{role:`user`,content:`What's Apple's stock price?`},{role:`assistant`,content:``,tool_calls:[{id:`tc5`,index:0,type:`function`,function:{name:`get_stock_price`,arguments:`{"symbol":"AAPL"}`}}]},{role:`user`,content:`Now check Google too.`}],tools:K,expected:{type:`tool_call`}},{id:`search-books`,messages:[{role:`system`,content:q},{role:`user`,content:`Search for science fiction books, show me the top 5 results.`}],tools:K,expected:{type:`tool_call`}},{id:`directions-transit`,messages:[{role:`system`,content:q},{role:`user`,content:`How do I get from Brooklyn to Manhattan by transit?`}],tools:K,expected:{type:`tool_call`}},{id:`tc2-weather-fahrenheit-nyc`,messages:[{role:`system`,content:q},{role:`user`,content:`What's the weather in New York in fahrenheit?`}],tools:K,expected:{type:`tool_call`}},{id:`tc2-weather-berlin-celsius`,messages:[{role:`system`,content:q},{role:`user`,content:`Get the weather in Berlin in celsius.`}],tools:K,expected:{type:`tool_call`}},{id:`tc2-add-negative`,messages:[{role:`system`,content:q},{role:`user`,content:`What is -15 + 42?`}],tools:K,expected:{type:`tool_call`}},{id:`tc2-add-small`,messages:[{role:`system`,content:q},{role:`user`,content:`Add 7 + 13.`}],tools:K,expected:{type:`tool_call`}},{id:`tc2-search-kitchen-max3`,messages:[{role:`system`,content:q},{role:`user`,content:`Search for "coffee mug" in category kitchen and return at most 3 results.`}],tools:K,expected:{type:`tool_call`}},{id:`tc2-search-usbc-max1`,messages:[{role:`system`,content:q},{role:`user`,content:`Search for USB-C cable and limit to 1 result.`}],tools:K,expected:{type:`tool_call`}},{id:`tc2-send-email-brief`,messages:[{role:`system`,content:q},{role:`user`,content:`Email bob@example.com with subject "Status" and body "All tests passed."`}],tools:K,expected:{type:`tool_call`}},{id:`tc2-stock-msft`,messages:[{role:`system`,content:q},{role:`user`,content:`Get the stock price for MSFT.`}],tools:K,expected:{type:`tool_call`}},{id:`tc2-convert-eur-usd`,messages:[{role:`system`,content:q},{role:`user`,content:`Convert 49.99 EUR to USD.`}],tools:K,expected:{type:`tool_call`}},{id:`tc2-calendar-duration-30`,messages:[{role:`system`,content:q},{role:`user`,content:`Create a calendar event titled "1:1" on 2025-05-20 at 09:30 for 30 minutes.`}],tools:K,expected:{type:`tool_call`}},{id:`tc2-translate-en-fr`,messages:[{role:`system`,content:q},{role:`user`,content:`Translate "Where is the train station?" from English to French.`}],tools:K,expected:{type:`tool_call`}},{id:`tc2-directions-transit-mode`,messages:[{role:`system`,content:q},{role:`user`,content:`Get transit directions from "Union Square, San Francisco" to "SFO Airport".`}],tools:K,expected:{type:`tool_call`}},{id:`tc2-mt-weather-unit-followup`,messages:[{role:`system`,content:q},{role:`user`,content:`What's the weather in Boston?`},{role:`assistant`,content:``,tool_calls:[{id:`tc2w1`,index:0,type:`function`,function:{name:`get_weather`,arguments:`{"location":"Boston"}`}}]},{role:`user`,content:`Same city, but in fahrenheit.`}],tools:K,expected:{type:`tool_call`}},{id:`tc2-mt-search-then-email`,messages:[{role:`system`,content:q},{role:`user`,content:`Search for running shoes.`},{role:`assistant`,content:``,tool_calls:[{id:`tc2se1`,index:0,type:`function`,function:{name:`search_products`,arguments:`{"query":"running shoes"}`}}]},{role:`user`,content:`Email those results to alice@example.com with subject "Shoe Options" and body "Here are the running shoes I found."`}],tools:K,expected:{type:`tool_call`}},{id:`tc2-mt-stock-then-reminder`,messages:[{role:`system`,content:q},{role:`user`,content:`What's Apple's stock price?`},{role:`assistant`,content:``,tool_calls:[{id:`tc2sr1`,index:0,type:`function`,function:{name:`get_stock_price`,arguments:`{"symbol":"AAPL"}`}}]},{role:`user`,content:`Set a reminder at 2025-06-01T09:00:00 to check again.`}],tools:K,expected:{type:`tool_call`}},{id:`tc2-mt-currency-then-calendar`,messages:[{role:`system`,content:q},{role:`user`,content:`Convert 100 USD to EUR.`},{role:`assistant`,content:``,tool_calls:[{id:`tc2cc1`,index:0,type:`function`,function:{name:`convert_currency`,arguments:`{"amount":100,"from":"USD","to":"EUR"}`}}]},{role:`user`,content:`Schedule a budget review for 2025-07-10 at 14:00 for 45 minutes.`}],tools:K,expected:{type:`tool_call`}},{id:`tc2-mt-directions-then-weather`,messages:[{role:`system`,content:q},{role:`user`,content:`Get me driving directions from Seattle to Portland.`},{role:`assistant`,content:``,tool_calls:[{id:`tc2dw1`,index:0,type:`function`,function:{name:`get_directions`,arguments:`{"origin":"Seattle","destination":"Portland"}`}}]},{role:`user`,content:`What's the weather in Portland in celsius?`}],tools:K,expected:{type:`tool_call`}},{id:`tc2-mt-translate-then-email`,messages:[{role:`system`,content:q},{role:`user`,content:`Translate "Meeting postponed to next week" to Spanish.`},{role:`assistant`,content:``,tool_calls:[{id:`tc2te1`,index:0,type:`function`,function:{name:`translate_text`,arguments:`{"text":"Meeting postponed to next week","target_language":"es"}`}}]},{role:`user`,content:`Send that translation to carlos@example.com with subject "Update" and body "Reunión pospuesta para la próxima semana."`}],tools:K,expected:{type:`tool_call`}},{id:`tc2-mt-reminder-reschedule`,messages:[{role:`system`,content:q},{role:`user`,content:`Set a reminder for "Submit report" at 2025-04-10T17:00:00.`},{role:`assistant`,content:``,tool_calls:[{id:`tc2rr1`,index:0,type:`function`,function:{name:`set_reminder`,arguments:`{"message":"Submit report","datetime":"2025-04-10T17:00:00"}`}}]},{role:`user`,content:`Actually set it for 2025-04-11T10:00:00 instead.`}],tools:K,expected:{type:`tool_call`}},{id:`tc2-mt-add-then-convert`,messages:[{role:`system`,content:q},{role:`user`,content:`What is 19.99 + 5.00?`},{role:`assistant`,content:``,tool_calls:[{id:`tc2ac1`,index:0,type:`function`,function:{name:`add`,arguments:`{"a":19.99,"b":5.00}`}}]},{role:`assistant`,content:`The total is 24.99 USD.`},{role:`user`,content:`Convert 24.99 USD to GBP.`}],tools:K,expected:{type:`tool_call`}},{id:`tc2-mt-calendar-then-directions`,messages:[{role:`system`,content:q},{role:`user`,content:`Create a calendar event titled "Dinner at Luigi's" on 2025-08-15 at 19:00.`},{role:`assistant`,content:``,tool_calls:[{id:`tc2cd1`,index:0,type:`function`,function:{name:`create_calendar_event`,arguments:`{"title":"Dinner at Luigi's","date":"2025-08-15","time":"19:00"}`}}]},{role:`user`,content:`Get me walking directions from home to Luigi's Restaurant.`}],tools:K,expected:{type:`tool_call`}},{id:`tc2-mt-trip-planner`,messages:[{role:`system`,content:q},{role:`user`,content:`What's the weather in Rome in celsius?`},{role:`assistant`,content:``,tool_calls:[{id:`tc2tp1`,index:0,type:`function`,function:{name:`get_weather`,arguments:`{"location":"Rome","unit":"celsius"}`}}]},{role:`user`,content:`Search for travel umbrella in category travel, max 3 results.`},{role:`assistant`,content:``,tool_calls:[{id:`tc2tp2`,index:0,type:`function`,function:{name:`search_products`,arguments:`{"query":"travel umbrella","category":"travel","max_results":3}`}}]},{role:`user`,content:`Convert 200 USD to EUR.`},{role:`assistant`,content:``,tool_calls:[{id:`tc2tp3`,index:0,type:`function`,function:{name:`convert_currency`,arguments:`{"amount":200,"from":"USD","to":"EUR"}`}}]},{role:`user`,content:`Create a calendar event titled "Flight to Rome" on 2025-09-01 at 08:00 for 30 minutes.`},{role:`assistant`,content:``,tool_calls:[{id:`tc2tp4`,index:0,type:`function`,function:{name:`create_calendar_event`,arguments:`{"title":"Flight to Rome","date":"2025-09-01","time":"08:00","duration_minutes":30}`}}]},{role:`user`,content:`Email me the trip checklist at traveler@example.com with subject "Rome Trip Checklist" and body "Umbrella, euros, and flight booked."`}],tools:K,expected:{type:`tool_call`}},{id:`tc2-mt-meeting-runner`,messages:[{role:`system`,content:q},{role:`user`,content:`Create a calendar event titled "Client Meeting" on 2025-06-15 at 14:00 for 60 minutes.`},{role:`assistant`,content:``,tool_calls:[{id:`tc2mr1`,index:0,type:`function`,function:{name:`create_calendar_event`,arguments:`{"title":"Client Meeting","date":"2025-06-15","time":"14:00","duration_minutes":60}`}}]},{role:`user`,content:`Get driving directions from "123 Main St" to "456 Oak Ave".`},{role:`assistant`,content:``,tool_calls:[{id:`tc2mr2`,index:0,type:`function`,function:{name:`get_directions`,arguments:`{"origin":"123 Main St","destination":"456 Oak Ave","mode":"driving"}`}}]},{role:`user`,content:`What's the weather at 456 Oak Ave in fahrenheit?`},{role:`assistant`,content:``,tool_calls:[{id:`tc2mr3`,index:0,type:`function`,function:{name:`get_weather`,arguments:`{"location":"456 Oak Ave","unit":"fahrenheit"}`}}]},{role:`user`,content:`Translate "Running 10 minutes late" to Spanish.`},{role:`assistant`,content:``,tool_calls:[{id:`tc2mr4`,index:0,type:`function`,function:{name:`translate_text`,arguments:`{"text":"Running 10 minutes late","target_language":"es"}`}}]},{role:`user`,content:`Send an email to client@example.com with subject "On My Way" and body "Llego 10 minutos tarde."`}],tools:K,expected:{type:`tool_call`}},{id:`tc2-mt-shopping-budget`,messages:[{role:`system`,content:q},{role:`user`,content:`Search for headphones in electronics, max 5 results.`},{role:`assistant`,content:``,tool_calls:[{id:`tc2sb1`,index:0,type:`function`,function:{name:`search_products`,arguments:`{"query":"headphones","category":"electronics","max_results":5}`}}]},{role:`user`,content:`Add 79.99 + 12.50.`},{role:`assistant`,content:``,tool_calls:[{id:`tc2sb2`,index:0,type:`function`,function:{name:`add`,arguments:`{"a":79.99,"b":12.50}`}}]},{role:`user`,content:`Convert 92.49 USD to GBP.`},{role:`assistant`,content:``,tool_calls:[{id:`tc2sb3`,index:0,type:`function`,function:{name:`convert_currency`,arguments:`{"amount":92.49,"from":"USD","to":"GBP"}`}}]},{role:`user`,content:`Set a reminder at 2025-07-01T12:00:00 to check for price drops.`},{role:`assistant`,content:``,tool_calls:[{id:`tc2sb4`,index:0,type:`function`,function:{name:`set_reminder`,arguments:`{"message":"Check for price drops","datetime":"2025-07-01T12:00:00"}`}}]},{role:`user`,content:`Email the budget summary to finance@example.com with subject "Headphone Budget" and body "Total: 92.49 USD / ~73 GBP."`}],tools:K,expected:{type:`tool_call`}},{id:`tc2-mt-multicity-itinerary`,messages:[{role:`system`,content:q},{role:`user`,content:`What's the weather in Seattle?`},{role:`assistant`,content:``,tool_calls:[{id:`tc2mi1`,index:0,type:`function`,function:{name:`get_weather`,arguments:`{"location":"Seattle"}`}}]},{role:`user`,content:`What's the weather in Vancouver in celsius?`},{role:`assistant`,content:``,tool_calls:[{id:`tc2mi2`,index:0,type:`function`,function:{name:`get_weather`,arguments:`{"location":"Vancouver","unit":"celsius"}`}}]},{role:`user`,content:`Get transit directions from Seattle to Vancouver.`},{role:`assistant`,content:``,tool_calls:[{id:`tc2mi3`,index:0,type:`function`,function:{name:`get_directions`,arguments:`{"origin":"Seattle","destination":"Vancouver","mode":"transit"}`}}]},{role:`user`,content:`Convert 100 USD to CAD.`},{role:`assistant`,content:``,tool_calls:[{id:`tc2mi4`,index:0,type:`function`,function:{name:`convert_currency`,arguments:`{"amount":100,"from":"USD","to":"CAD"}`}}]},{role:`user`,content:`Create a calendar event titled "Cross-border day trip" on 2025-08-20 at 07:00 for 480 minutes.`}],tools:K,expected:{type:`tool_call`}},{id:`tc2-mt-language-lunch-flow`,messages:[{role:`system`,content:q},{role:`user`,content:`Translate "I would like a table for two, please" to Italian.`},{role:`assistant`,content:``,tool_calls:[{id:`tc2ll1`,index:0,type:`function`,function:{name:`translate_text`,arguments:`{"text":"I would like a table for two, please","target_language":"it"}`}}]},{role:`user`,content:`Send that phrase to host@example.com with subject "Reservation Request" and body "Vorrei un tavolo per due, per favore."`},{role:`assistant`,content:``,tool_calls:[{id:`tc2ll2`,index:0,type:`function`,function:{name:`send_email`,arguments:`{"to":"host@example.com","subject":"Reservation Request","body":"Vorrei un tavolo per due, per favore."}`}}]},{role:`user`,content:`Create a calendar event titled "Lunch at Trattoria" on 2025-09-05 at 12:30.`},{role:`assistant`,content:``,tool_calls:[{id:`tc2ll3`,index:0,type:`function`,function:{name:`create_calendar_event`,arguments:`{"title":"Lunch at Trattoria","date":"2025-09-05","time":"12:30"}`}}]},{role:`user`,content:`Get walking directions from "Hotel Bella Vista" to "Trattoria Roma".`},{role:`assistant`,content:``,tool_calls:[{id:`tc2ll4`,index:0,type:`function`,function:{name:`get_directions`,arguments:`{"origin":"Hotel Bella Vista","destination":"Trattoria Roma","mode":"walking"}`}}]},{role:`user`,content:`Set a reminder at 2025-09-05T12:00:00 to leave for lunch.`}],tools:K,expected:{type:`tool_call`}},{id:`tc3-parallel-weather-2cities`,messages:[{role:`system`,content:q},{role:`user`,content:`What's the weather in Boston and London?`}],tools:K,expected:{type:`tool_call`}},{id:`tc3-parallel-stocks-2`,messages:[{role:`system`,content:q},{role:`user`,content:`Check the current stock prices for AAPL and TSLA.`}],tools:K,expected:{type:`tool_call`}},{id:`tc3-parallel-weather-stock`,messages:[{role:`system`,content:q},{role:`user`,content:`What's the weather in Paris and what's the current price of AAPL?`}],tools:K,expected:{type:`tool_call`}},{id:`tc3-parallel-search-convert`,messages:[{role:`system`,content:q},{role:`user`,content:`Search for "wireless headphones" and also convert 199.99 USD to EUR.`}],tools:K,expected:{type:`tool_call`}},{id:`tc3-parallel-calendar-reminder`,messages:[{role:`system`,content:q},{role:`user`,content:`Create a calendar event titled "Dentist" on 2026-03-10 at 09:00 for 30 minutes, and set a reminder for 2026-03-10T08:30:00 saying "Leave for dentist".`}],tools:K,expected:{type:`tool_call`}},{id:`tc3-parallel-convert-2`,messages:[{role:`system`,content:q},{role:`user`,content:`Convert 100 USD to EUR and 500 GBP to JPY.`}],tools:K,expected:{type:`tool_call`}},{id:`tc3-parallel-directions-weather`,messages:[{role:`system`,content:q},{role:`user`,content:`Get driving directions from San Francisco to San Jose, and tell me the weather in San Jose.`}],tools:K,expected:{type:`tool_call`}},{id:`tc3-weather-unicode`,messages:[{role:`system`,content:q},{role:`user`,content:`What's the weather in São Paulo?`}],tools:K,expected:{type:`tool_call`}},{id:`tc3-weather-unicode-umlaut`,messages:[{role:`system`,content:q},{role:`user`,content:`What's the weather in Zürich?`}],tools:K,expected:{type:`tool_call`}},{id:`tc3-stock-dot-symbol`,messages:[{role:`system`,content:q},{role:`user`,content:`Get the stock price for BRK.B.`}],tools:K,expected:{type:`tool_call`}},{id:`tc3-email-plus-address`,messages:[{role:`system`,content:q},{role:`user`,content:`Send an email to alice+test@example.com with subject "Test" and body "Hello from the test suite."`}],tools:K,expected:{type:`tool_call`}},{id:`tc3-translate-quotes`,messages:[{role:`system`,content:q},{role:`user`,content:`Translate the phrase 'He said "hello" and left' to French.`}],tools:K,expected:{type:`tool_call`}},{id:`tc3-calendar-leapday`,messages:[{role:`system`,content:q},{role:`user`,content:`Create a calendar event titled "Leap Day Party" on 2028-02-29 at 20:00.`}],tools:K,expected:{type:`tool_call`}},{id:`tc3-reminder-timezone`,messages:[{role:`system`,content:q},{role:`user`,content:`Set a reminder "Standup" for 2026-02-23T09:30:00-05:00.`}],tools:K,expected:{type:`tool_call`}},{id:`tc3-convert-large-amount`,messages:[{role:`system`,content:q},{role:`user`,content:`Convert 1000000 USD to JPY.`}],tools:K,expected:{type:`tool_call`}},{id:`tc3-directions-unicode`,messages:[{role:`system`,content:q},{role:`user`,content:`Get walking directions from "Café de Flore" to "Musée d'Orsay".`}],tools:K,expected:{type:`tool_call`}},{id:`tc3-correction-location`,messages:[{role:`system`,content:q},{role:`user`,content:`What's the weather in London—actually make that Dublin.`}],tools:K,expected:{type:`tool_call`}},{id:`tc3-correction-currency`,messages:[{role:`system`,content:q},{role:`user`,content:`Convert 100 USD to EUR—sorry, convert 100 USD to GBP instead.`}],tools:K,expected:{type:`tool_call`}},{id:`tc3-correction-destination`,messages:[{role:`system`,content:q},{role:`user`,content:`Get driving directions from Boston to New York—wait, to Philadelphia.`}],tools:K,expected:{type:`tool_call`}},{id:`tc3-mt-final-search`,messages:[{role:`system`,content:q},{role:`user`,content:`What's the weather in Tokyo?`},{role:`assistant`,content:``,tool_calls:[{id:`tc3fs1`,index:0,type:`function`,function:{name:`get_weather`,arguments:`{"location":"Tokyo"}`}}]},{role:`user`,content:`Search for "Japanese tea set" in category kitchen, max 3 results.`}],tools:K,expected:{type:`tool_call`}},{id:`tc3-mt-final-translate`,messages:[{role:`system`,content:q},{role:`user`,content:`Get walking directions from "Piazza Navona" to "Colosseum".`},{role:`assistant`,content:``,tool_calls:[{id:`tc3ft1`,index:0,type:`function`,function:{name:`get_directions`,arguments:`{"origin":"Piazza Navona","destination":"Colosseum","mode":"walking"}`}}]},{role:`user`,content:`Translate "How far is the Colosseum?" from English to Italian.`}],tools:K,expected:{type:`tool_call`}},{id:`tc3-stock-by-company`,messages:[{role:`system`,content:q},{role:`user`,content:`What is Microsoft's stock price?`}],tools:K,expected:{type:`tool_call`}},{id:`tc3-reminder-indirect`,messages:[{role:`system`,content:q},{role:`user`,content:`At 2026-04-01T12:00:00 remind me to "renew subscription".`}],tools:K,expected:{type:`tool_call`}},{id:`tc3-mt-prior-convert-then-weather`,messages:[{role:`system`,content:q},{role:`user`,content:`Convert 10 USD to EUR.`},{role:`assistant`,content:``,tool_calls:[{id:`tc3pcw1`,index:0,type:`function`,function:{name:`convert_currency`,arguments:`{"amount":10,"from":"USD","to":"EUR"}`}}]},{role:`user`,content:`Now what's the weather in Berlin?`}],tools:K,expected:{type:`tool_call`}},{id:`tc3-mt-prior-email-then-translate`,messages:[{role:`system`,content:q},{role:`user`,content:`Send an email to bob@example.com with subject "Hi" and body "Test message."`},{role:`assistant`,content:``,tool_calls:[{id:`tc3pet1`,index:0,type:`function`,function:{name:`send_email`,arguments:`{"to":"bob@example.com","subject":"Hi","body":"Test message."}`}}]},{role:`user`,content:`Now translate "Good night" to French.`}],tools:K,expected:{type:`tool_call`}},{id:`tc3-mt-prior-calendar-then-stock`,messages:[{role:`system`,content:q},{role:`user`,content:`Create a calendar event titled "Review" on 2026-01-15 at 11:00.`},{role:`assistant`,content:``,tool_calls:[{id:`tc3pcs1`,index:0,type:`function`,function:{name:`create_calendar_event`,arguments:`{"title":"Review","date":"2026-01-15","time":"11:00"}`}}]},{role:`user`,content:`What's the stock price for NVDA?`}],tools:K,expected:{type:`tool_call`}},{id:`tc3-mt-prior-reminder-then-search`,messages:[{role:`system`,content:q},{role:`user`,content:`Set a reminder "Buy gift" for 2026-05-01T10:00:00.`},{role:`assistant`,content:``,tool_calls:[{id:`tc3prs1`,index:0,type:`function`,function:{name:`set_reminder`,arguments:`{"message":"Buy gift","datetime":"2026-05-01T10:00:00"}`}}]},{role:`user`,content:`Search for "birthday gift ideas" with max 5 results.`}],tools:K,expected:{type:`tool_call`}},{id:`tc3-mt-prior-translate-then-add`,messages:[{role:`system`,content:q},{role:`user`,content:`Translate "Invoice total" to German.`},{role:`assistant`,content:``,tool_calls:[{id:`tc3pta1`,index:0,type:`function`,function:{name:`translate_text`,arguments:`{"text":"Invoice total","target_language":"de"}`}}]},{role:`user`,content:`Now add 450.00 + 67.50.`}],tools:K,expected:{type:`tool_call`}},{id:`tc3-mt-prior-directions-then-reminder`,messages:[{role:`system`,content:q},{role:`user`,content:`Get transit directions from "Grand Central" to "JFK Airport".`},{role:`assistant`,content:``,tool_calls:[{id:`tc3pdr1`,index:0,type:`function`,function:{name:`get_directions`,arguments:`{"origin":"Grand Central","destination":"JFK Airport","mode":"transit"}`}}]},{role:`user`,content:`Set a reminder at 2026-06-15T06:00:00 to leave for the airport.`}],tools:K,expected:{type:`tool_call`}},{id:`neg-simple-arithmetic`,messages:[{role:`system`,content:q},{role:`user`,content:`What's 2 + 2? Answer with only the number.`}],tools:K,expected:{type:`no_tool_call`,value:`4`}},{id:`neg-general-knowledge`,messages:[{role:`system`,content:q},{role:`user`,content:`What is the capital of Japan? Answer with only the city name.`}],tools:K,expected:{type:`no_tool_call`,value:`[Tt]okyo`}},{id:`neg-creative-writing`,messages:[{role:`system`,content:q},{role:`user`,content:`Write a haiku about snow.`}],tools:K,expected:{type:`no_tool_call`}},{id:`neg-explain-tool`,messages:[{role:`system`,content:q},{role:`user`,content:`What does the convert_currency tool do? Explain in one sentence.`}],tools:K,expected:{type:`no_tool_call`}},{id:`neg-forbid-tools`,messages:[{role:`system`,content:q},{role:`user`,content:`Do not call any tools. Just tell me what 15 + 28 is.`}],tools:K,expected:{type:`no_tool_call`,value:`43`}},{id:`neg-no-matching-tool`,messages:[{role:`system`,content:q},{role:`user`,content:`Summarize the plot of Romeo and Juliet in 2 sentences.`}],tools:K,expected:{type:`no_tool_call`}},{id:`neg-greeting`,messages:[{role:`system`,content:q},{role:`user`,content:`Hello! How are you today?`}],tools:K,expected:{type:`no_tool_call`}},{id:`neg-opinion`,messages:[{role:`system`,content:q},{role:`user`,content:`What are the pros and cons of remote work? Be brief.`}],tools:K,expected:{type:`no_tool_call`}},{id:`neg-define-word`,messages:[{role:`system`,content:q},{role:`user`,content:`Define the word "ephemeral" in one sentence.`}],tools:K,expected:{type:`no_tool_call`}},{id:`neg-count-letters`,messages:[{role:`system`,content:q},{role:`user`,content:`How many letters are in the word "banana"? Answer with only the number.`}],tools:K,expected:{type:`no_tool_call`,value:`6`}},{id:`clar-weather-no-city`,messages:[{role:`system`,content:q},{role:`user`,content:`What's the weather right now?`}],tools:K,expected:{type:`no_tool_call`}},{id:`clar-stock-no-symbol`,messages:[{role:`system`,content:q},{role:`user`,content:`What's the current stock price?`}],tools:K,expected:{type:`no_tool_call`}},{id:`clar-convert-no-source`,messages:[{role:`system`,content:q},{role:`user`,content:`Convert 100 to EUR.`}],tools:K,expected:{type:`no_tool_call`}},{id:`clar-translate-no-target`,messages:[{role:`system`,content:q},{role:`user`,content:`Translate "Good morning".`}],tools:K,expected:{type:`no_tool_call`}},{id:`clar-email-no-content`,messages:[{role:`system`,content:q},{role:`user`,content:`Send an email to alice@example.com.`}],tools:K,expected:{type:`no_tool_call`}},{id:`clar-calendar-no-datetime`,messages:[{role:`system`,content:q},{role:`user`,content:`Create a calendar event titled "Team sync".`}],tools:K,expected:{type:`no_tool_call`}},{id:`clar-directions-no-origin`,messages:[{role:`system`,content:q},{role:`user`,content:`How do I get to the airport?`}],tools:K,expected:{type:`no_tool_call`}},{id:`clar-reminder-no-time`,messages:[{role:`system`,content:q},{role:`user`,content:`Remind me to pay rent.`}],tools:K,expected:{type:`no_tool_call`}},{id:`clar-add-one-number`,messages:[{role:`system`,content:q},{role:`user`,content:`Add 42.`}],tools:K,expected:{type:`no_tool_call`}},{id:`clar-search-empty`,messages:[{role:`system`,content:q},{role:`user`,content:`Search for products.`}],tools:K,expected:{type:`no_tool_call`}},{id:`ambig-apple-stock-or-product`,messages:[{role:`system`,content:q},{role:`user`,content:`What's the price of Apple?`}],tools:K,expected:{type:`no_tool_call`}},{id:`ambig-tesla-stock-or-search`,messages:[{role:`system`,content:q},{role:`user`,content:`Find Tesla for me.`}],tools:K,expected:{type:`no_tool_call`}},{id:`ambig-translate-and-send-no-recipient`,messages:[{role:`system`,content:q},{role:`user`,content:`Translate "Hello" to French and email it.`}],tools:K,expected:{type:`no_tool_call`}},{id:`ambig-book-meeting-vague`,messages:[{role:`system`,content:q},{role:`user`,content:`Book a meeting with Alice.`}],tools:K,expected:{type:`no_tool_call`}},{id:`ambig-check-price-vague`,messages:[{role:`system`,content:q},{role:`user`,content:`Check the price for me.`}],tools:K,expected:{type:`no_tool_call`}},{id:`ambig-send-message-no-channel`,messages:[{role:`system`,content:q},{role:`user`,content:`Send a message to Bob saying "See you later".`}],tools:K,expected:{type:`no_tool_call`}}]},Qn={id:`chat`,name:`Performance`,prompts:[{id:`codegen-python-fn`,messages:[{role:`system`,content:q},{role:`user`,content:'Write a Python function called `fizzbuzz` that takes an integer n and returns a list of strings from 1 to n where multiples of 3 are "Fizz", multiples of 5 are "Buzz", and multiples of both are "FizzBuzz".'}],max_tokens:512,includeInScore:!1},{id:`codegen-js-class`,messages:[{role:`system`,content:q},{role:`user`,content:"Write a JavaScript class called `Stack` with push, pop, peek, and isEmpty methods. Include JSDoc comments for each method."}],max_tokens:512,includeInScore:!1},{id:`codegen-go-struct`,messages:[{role:`system`,content:q},{role:`user`,content:'Write a Go struct called `Config` with fields for Host (string), Port (int), and Timeout (time.Duration). Include a NewConfig constructor function and a String() method that formats it as "host:port".'}],max_tokens:512,includeInScore:!1},{id:`codegen-python-sort`,messages:[{role:`system`,content:q},{role:`user`,content:`Write a Python implementation of merge sort. Include a main function that sorts the list [38, 27, 43, 3, 9, 82, 10] and prints the result.`}],max_tokens:512,includeInScore:!1},{id:`codegen-rust-enum`,messages:[{role:`system`,content:q},{role:`user`,content:"Write a Rust enum called `Shape` with variants Circle(f64), Rectangle(f64, f64), and Triangle(f64, f64, f64). Implement a method `area()` that returns the area for each variant."}],max_tokens:512,includeInScore:!1}]};function $n(e,t=1/0){let n=t===1/0?1/0:Number.isFinite(t)?Math.max(1,Math.floor(t)):25,r={temperature:e.temperature[0]??.8,top_p:e.top_p[0]??.9,top_k:e.top_k[0]??40,min_p:e.min_p[0]??0,repeat_penalty:e.repeat_penalty[0]??1,repeat_last_n:e.repeat_last_n[0]??64,frequency_penalty:e.frequency_penalty[0]??0,presence_penalty:e.presence_penalty[0]??0,dry_multiplier:e.dry_multiplier[0]??1.05,dry_base:e.dry_base[0]??1.75,dry_allowed_length:e.dry_allowed_length[0]??2,dry_penalty_last_n:e.dry_penalty_last_n[0]??0,xtc_probability:e.xtc_probability[0]??0,xtc_threshold:e.xtc_threshold[0]??.1,xtc_min_keep:e.xtc_min_keep[0]??1,max_tokens:e.max_tokens[0]??4096,enable_thinking:e.enable_thinking[0]??`true`,reasoning_effort:e.reasoning_effort[0]??`medium`},i=e=>e!==void 0&&Number.isFinite(e)?Math.round(e*1e3)/1e3:e,a=new Set,o=[],s=e=>`t=${i(e.temperature)}|p=${i(e.top_p)}|k=${e.top_k}|m=${i(e.min_p)}|rp=${i(e.repeat_penalty)}|rn=${e.repeat_last_n}|fp=${i(e.frequency_penalty)}|pp=${i(e.presence_penalty)}|dm=${i(e.dry_multiplier)}|db=${i(e.dry_base)}|da=${e.dry_allowed_length}|dp=${e.dry_penalty_last_n}|xp=${i(e.xtc_probability)}|xt=${i(e.xtc_threshold)}|xk=${e.xtc_min_keep}|mt=${e.max_tokens}|et=${e.enable_thinking}|re=${e.reasoning_effort}`,c=e=>{if(n!==1/0&&o.length>=n)return;let t=s(e);a.has(t)||(a.add(t),o.push(e))},l=(e,t)=>e!==void 0&&Math.abs(e-t)<.001;if(c({...r}),n<=1)return o;let u=(e,t)=>[...e].sort((e,n)=>Math.abs(e-t)-Math.abs(n-t)),d=[{key:`temperature`,values:e.temperature},{key:`top_p`,values:e.top_p},{key:`top_k`,values:e.top_k},{key:`min_p`,values:e.min_p},{key:`repeat_penalty`,values:e.repeat_penalty},{key:`repeat_last_n`,values:e.repeat_last_n},{key:`frequency_penalty`,values:e.frequency_penalty},{key:`presence_penalty`,values:e.presence_penalty},{key:`dry_multiplier`,values:e.dry_multiplier},{key:`dry_base`,values:e.dry_base},{key:`dry_allowed_length`,values:e.dry_allowed_length},{key:`dry_penalty_last_n`,values:e.dry_penalty_last_n},{key:`xtc_probability`,values:e.xtc_probability},{key:`xtc_threshold`,values:e.xtc_threshold},{key:`xtc_min_keep`,values:e.xtc_min_keep},{key:`max_tokens`,values:e.max_tokens}].filter(e=>e.values.length>1).map(e=>{let t=r[e.key]??0;return u(e.values.filter(e=>!l(t,e)),t).map(t=>({...r,[e.key]:t}))});e.enable_thinking.length>1&&d.push(e.enable_thinking.filter(e=>e!==r.enable_thinking).map(e=>({...r,enable_thinking:e}))),e.reasoning_effort.length>1&&d.push(e.reasoning_effort.filter(e=>e!==r.reasoning_effort).map(e=>({...r,reasoning_effort:e})));for(let e=0;n===1/0||o.length=n))break;if(!t)break}let f=e.temperature.length>0?e.temperature:[r.temperature??.8],p=e.top_p.length>0?e.top_p:[r.top_p??.9],m=e.top_k.length>0?e.top_k:[r.top_k??40],h=e.min_p.length>0?e.min_p:[r.min_p??0];if(f.length>1||p.length>1||m.length>1||h.length>1){let e=Math.min(...f),t=Math.max(...f),n=Math.min(...p),i=Math.max(...p),a=Math.min(...m),o=Math.max(...m),s=Math.max(...h);[{...r,temperature:e,top_p:n},{...r,temperature:e,top_p:i},{...r,temperature:t,top_p:n},{...r,temperature:t,top_p:i},{...r,temperature:e,top_k:a},{...r,temperature:e,top_k:o},{...r,temperature:t,top_k:a},{...r,temperature:t,top_k:o},{...r,top_p:n,top_k:a},{...r,top_p:n,top_k:o},{...r,top_p:i,top_k:a},{...r,top_p:i,top_k:o},{...r,min_p:s,temperature:e},{...r,min_p:s,temperature:t},{...r,min_p:s,top_p:n},{...r,min_p:s,top_p:i}].forEach(c)}return o}var er={temperature:[.8],top_p:[.9],top_k:[40],min_p:[0],repeat_penalty:[1],repeat_last_n:[64],frequency_penalty:[0],presence_penalty:[0],dry_multiplier:[1.05],dry_base:[1.75],dry_allowed_length:[2],dry_penalty_last_n:[0],xtc_probability:[0],xtc_threshold:[.1],xtc_min_keep:[1],max_tokens:[4096],enable_thinking:[`true`],reasoning_effort:[`medium`]},tr={prefillBatchSize:{enabled:!0,values:[Bn]},contextWindow:{enabled:!0,values:[2048,4096,8192,16384,32768,65536,98304,131072]},nSeqMax:{enabled:!0,values:[1,2]},flashAttention:{enabled:!0,values:[`enabled`,`disabled`]},cacheType:{enabled:!0,values:[`f16`,`q8_0`,`q4_0`]},cacheMode:{enabled:!0,values:[`none`,`imc`]}},nr={prefillBatchSize:{enabled:!0,values:[1024,2048,4096]},contextWindow:{enabled:!0,values:[4096,8192,16384,32768]},nSeqMax:{enabled:!0,values:[1,2]},flashAttention:{enabled:!0,values:[`enabled`]},cacheType:{enabled:!0,values:[`q8_0`,`q4_0`]},cacheMode:{enabled:!0,values:[`none`,`imc`]},moeMode:{enabled:!0,values:[`experts_cpu`,`keep_top_n`]},moeKeepExpertsTopN:{enabled:!0,values:[0,4,8]}};function rr(e,t,n){let r={context_window:e.context_window,prefill_batch_size:e.prefill_batch_size??2048,nseq_max:e.nseq_max},i=[];t.prefillBatchSize.enabled&&t.prefillBatchSize.values.length>0&&i.push({configKey:`prefill_batch_size`,values:t.prefillBatchSize.values}),t.contextWindow.enabled&&t.contextWindow.values.length>0&&i.push({configKey:`context_window`,values:t.contextWindow.values}),t.nSeqMax.enabled&&t.nSeqMax.values.length>0&&i.push({configKey:`nseq_max`,values:t.nSeqMax.values});let a=[...i];t.flashAttention.enabled&&t.flashAttention.values.length>0&&a.push({configKey:`flash_attention`,values:t.flashAttention.values}),t.cacheType.enabled&&t.cacheType.values.length>0&&a.push({configKey:`cache_type`,values:t.cacheType.values}),t.cacheMode.enabled&&t.cacheMode.values.length>0&&a.push({configKey:`cache_mode`,values:t.cacheMode.values});let o=t.moeMode?.enabled&&t.moeMode.values.length>0,s=t.moeKeepExpertsTopN?.enabled&&t.moeKeepExpertsTopN.values.length>0?t.moeKeepExpertsTopN.values:[];if(a.length===0&&!o)return[{...r}];let c=[{...r}];for(let e of a){let t=[];for(let n of c)for(let r of e.values)t.push({...n,[e.configKey]:r});c=t}let l;if(!o)l=c;else{l=[];for(let e of t.moeMode.values){let t=[];e===`keep_top_n`&&s.length>0&&t.push({configKey:`moe_keep_experts_top_n`,values:s});let n=c.map(t=>({...t,moe_mode:e}));for(let e of t){let t=[];for(let r of n)for(let n of e.values)t.push({...r,[e.configKey]:n});n=t}l.push(...n)}}let u=new Set,d=[],f=e=>`cw=${e.context_window}|pbs=${e.prefill_batch_size}|ns=${e.nseq_max}|fa=${e.flash_attention}|ct=${e.cache_type}|cm=${e.cache_mode}|mm=${e.moe_mode}|mk=${e.moe_keep_experts_top_n??``}`;for(let e of l){let t=f(e);u.has(t)||n?.isHybrid&&(e.flash_attention===`enabled`||e.cache_type!==void 0&&e.cache_type!==`f16`)||(u.add(t),d.push(e))}return d}function ir(e,t){let n=[],r=0;if(!t)return{score:0,notes:[`No expected value defined`]};switch(t.type){case`exact`:{let i=e.trim().toLowerCase(),a=(t.value??``).trim().toLowerCase();i===a?r=100:i.includes(a)?(r=50,n.push(`Partial match: response contains "${t.value}" but has extra text`)):(r=0,n.push(`Expected "${t.value}", got "${e.trim().slice(0,100)}"`));break}case`regex`:new RegExp(t.value??``,`im`).test(e)?r=100:(r=0,n.push(`Regex /${t.value}/ did not match`));break;case`tool_call`:case`no_tool_call`:r=0,n.push(`${t.type} expected type not applicable for chat scoring`)}return e.length>2e3&&(r=Math.max(0,r-10),n.push(`Penalized: response exceeds 2000 characters`)),{score:r,notes:n}}function ar(e,t){let n=[];if(!e||e.length===0)return{score:0,notes:[`No tool calls emitted`]};let r=100,i=new Set(t.filter(e=>e.type===`function`&&e.function?.name).map(e=>e.function.name));for(let a of e){i.has(a.function.name)||(r-=40,n.push(`Tool "${a.function.name}" not in declared tools`));try{let e=JSON.parse(a.function.arguments),i=t.find(e=>e.type===`function`&&e.function?.name===a.function.name)?.function?.parameters;if(i?.required&&Array.isArray(i.required)){let t=i.required;for(let i of t)i in e||(r-=20,n.push(`Missing required field "${i}" in ${a.function.name}`))}}catch{r-=30,n.push(`Arguments for "${a.function.name}" are not valid JSON`)}}return{score:Math.max(0,Math.min(100,r)),notes:n}}function or(e,t,n){let r=[];if(e&&e.length>0){let t=e.map(e=>e.function?.name).filter(Boolean).join(`, `);return r.push(`Unexpected tool call(s): ${t}`),{score:0,notes:r}}let i=100;return t.trim().length===0&&(i-=20,r.push(`No text response produced`)),n?.value&&(new RegExp(n.value,`im`).test(t)||(i-=30,r.push(`Expected text matching /${n.value}/ but got "${t.trim().slice(0,100)}"`))),{score:Math.max(0,i),notes:r}}function sr(e,t,n,r){return new Promise((i,a)=>{if(r?.aborted)return a(new DOMException(`Aborted`,`AbortError`));let o=!1,s=``,c=[],l,u=()=>{o||(o=!0,d(),a(new DOMException(`Aborted`,`AbortError`)))},d=W.streamPlaygroundChat({session_id:e,messages:t.messages,tools:t.tools,stream:!0,temperature:n.temperature,top_p:n.top_p,top_k:n.top_k,min_p:n.min_p,max_tokens:n.max_tokens??t.max_tokens,repeat_penalty:n.repeat_penalty,repeat_last_n:n.repeat_last_n,frequency_penalty:n.frequency_penalty,presence_penalty:n.presence_penalty,dry_multiplier:n.dry_multiplier,dry_base:n.dry_base,dry_allowed_length:n.dry_allowed_length,dry_penalty_last_n:n.dry_penalty_last_n,xtc_probability:n.xtc_probability,xtc_threshold:n.xtc_threshold,xtc_min_keep:n.xtc_min_keep,adaptive_p_target:n.adaptive_p_target,adaptive_p_decay:n.adaptive_p_decay,enable_thinking:n.enable_thinking,reasoning_effort:n.reasoning_effort,grammar:n.grammar,stream_options:{include_usage:!0}},e=>{let t=e.choices?.[0];if(t?.delta?.content&&(s+=t.delta.content),t?.delta?.tool_calls)for(let e of t.delta.tool_calls){let t=c.find(t=>t.index===e.index);t?(e.id&&!t.id&&(t.id=e.id),e.type&&!t.type&&(t.type=e.type),e.function?.name&&!t.function.name&&(t.function.name=e.function.name),e.function?.arguments&&(t.function.arguments+=e.function.arguments)):c.push({id:e.id||``,index:e.index,type:e.type||`function`,function:{name:e.function?.name||``,arguments:e.function?.arguments||``}})}e.usage&&(l=e.usage)},e=>{o||(o=!0,r?.removeEventListener(`abort`,u),d(),a(Error(e)))},()=>{if(o)return;o=!0,r?.removeEventListener(`abort`,u);let e;e=t.expected?.type===`tool_call`?ar(c,t.tools??[]):t.expected?.type===`no_tool_call`?or(c,s,t.expected):ir(s,t.expected),i({promptId:t.id,assistantText:s,toolCalls:c,usage:l,score:e.score,notes:e.notes.length>0?e.notes:void 0})});r?.addEventListener(`abort`,u,{once:!0})})}async function cr(e,t){let n={id:`probe-tool`,messages:[{role:`system`,content:q},{role:`user`,content:`What's the weather in Boston?`}],tools:K,expected:{type:`tool_call`}};try{let r=await sr(e,n,{},t);return r.toolCalls.length>0&&r.score>0}catch{return!1}}var lr={chatScore:.4,toolScore:.6,totalScore:0,avgTPS:0,avgTTFT:0,tps0:0,tps20:0,tps50:0,tps80:0,ttft0:0,ttft20:0,ttft50:0,ttft80:0},ur={chatScore:0,toolScore:0,totalScore:0,avgTPS:1,avgTTFT:.5,tps0:.8,tps20:.6,tps50:.4,tps80:.2,ttft0:0,ttft20:0,ttft50:0,ttft80:0};function dr(e,t){let n=t!==`config`;switch(e){case`overall`:return{chatScore:n?.4:0,toolScore:n?.6:0,totalScore:0,avgTPS:.5,avgTTFT:.3,tps0:.2,tps20:.2,tps50:.2,tps80:.2,ttft0:.1,ttft20:.1,ttft50:.1,ttft80:.1};case`0pct`:return{chatScore:n?.2:0,toolScore:n?.3:0,totalScore:0,avgTPS:.2,avgTTFT:.1,tps0:1,tps20:0,tps50:0,tps80:0,ttft0:.8,ttft20:0,ttft50:0,ttft80:0};case`80pct`:return{chatScore:n?.2:0,toolScore:n?.3:0,totalScore:0,avgTPS:.2,avgTTFT:.1,tps0:0,tps20:0,tps50:0,tps80:1,ttft0:0,ttft20:0,ttft50:0,ttft80:.8}}}function fr(e,t){let n=e.scenarioResults.find(e=>e.scenarioId===`chat`)?.score,r=e.scenarioResults.find(e=>e.scenarioId===`tool_call`)?.score,i=e.totalScore,a=e.avgTPS,o=e.avgTTFT,s=[];n!==void 0&&s.push({w:t.chatScore??0,v:n}),r!==void 0&&s.push({w:t.toolScore??0,v:r}),i!==void 0&&s.push({w:t.totalScore??0,v:i}),a!==void 0&&s.push({w:t.avgTPS??0,v:Math.min(100,Math.max(0,a))}),o!==void 0&&s.push({w:t.avgTTFT??0,v:Math.max(0,100-o/10)});let c=[{key:`0%`,w:t.tps0??0},{key:`20%`,w:t.tps20??0},{key:`50%`,w:t.tps50??0},{key:`80%`,w:t.tps80??0}];for(let{key:t,w:n}of c){let r=e.avgTPSByFill?.[t];r!==void 0&&s.push({w:n,v:Math.min(100,Math.max(0,r))})}let l=[{key:`0%`,w:t.ttft0??0},{key:`20%`,w:t.ttft20??0},{key:`50%`,w:t.ttft50??0},{key:`80%`,w:t.ttft80??0}];for(let{key:t,w:n}of l){let r=e.avgTTFTByFill?.[t];r!==void 0&&s.push({w:n,v:Math.max(0,100-r/10)})}let u=s.reduce((e,t)=>e+t.w,0);return u<=0?i??n??r??0:Math.round(s.reduce((e,t)=>e+t.w*t.v,0)/u*100)/100}var pr=6;async function mr(e,t,n,r){let i=Array(e.length),a=0,o=Array.from({length:Math.min(t,e.length)},async()=>{for(;!r.aborted;){let t=a++;if(t>=e.length)break;i[t]=await n(e[t],t)}});return await Promise.all(o),i}function hr(e,t,n,r,i,a,o,s,c,l,u,d){let f=new Set(t.filter(e=>e.includeInScore===!1).map(e=>e.id)),p=n.filter(e=>!f.has(e.promptId)),m=p.length>0?Math.round(p.reduce((e,t)=>e+t.score,0)/p.length*100)/100:0,h={},g={},_={};for(let e of[`0%`,`20%`,`50%`,`80%`]){let t=s[e],n=c[e];t!==void 0&&n!==void 0&&n>0&&(h[e]=t/n);let r=l[e],i=u[e];r!==void 0&&i!==void 0&&i>0&&(g[e]=r/i),d[e]!==void 0&&(_[e]=d[e])}return{scenarioId:e,promptResults:[...n],score:m,avgTPS:i>0?r/i:void 0,avgTTFT:o>0?a/o:void 0,...Object.keys(h).length>0&&{avgTPSByFill:h},...Object.keys(g).length>0&&{avgTTFTByFill:g},...Object.keys(_).length>0&&{promptTokensByFill:_}}}function gr(e){let t=e.scenarioResults.find(e=>e.scenarioId===`chat`),n=e.scenarioResults.find(e=>e.scenarioId===`tool_call`),r=t??n;r?.avgTPS!==void 0&&(e.avgTPS=r.avgTPS),r?.avgTTFT!==void 0&&(e.avgTTFT=r.avgTTFT);let i=t??n;i?.avgTPSByFill&&Object.keys(i.avgTPSByFill).length>0&&(e.avgTPSByFill=i.avgTPSByFill),i?.avgTTFTByFill&&Object.keys(i.avgTTFTByFill).length>0&&(e.avgTTFTByFill=i.avgTTFTByFill)}function _r(e,t,n){let r=e.scenarioResults.findIndex(e=>e.scenarioId===t.scenarioId);r>=0?e.scenarioResults[r]=t:e.scenarioResults.push(t),gr(e),n({...e,scenarioResults:[...e.scenarioResults]})}function vr(e,t,n,r){let i=e.usage?.tokens_per_second,a=e.usage?.completion_tokens;if(r&&i&&i>0&&a!==void 0){let e=Math.max(0,a-1);e>0&&(n.genTokens+=e,n.genSeconds+=e/i)}if(r&&e.usage?.time_to_first_token_ms&&e.usage.time_to_first_token_ms>0&&(n.ttft+=e.usage.time_to_first_token_ms,n.ttftCount++),t.contextFill){let r=t.contextFill.label;if(i&&i>0&&a!==void 0){let e=Math.max(0,a-1);e>0&&(n.fillGenTokens[r]=(n.fillGenTokens[r]??0)+e,n.fillGenSeconds[r]=(n.fillGenSeconds[r]??0)+e/i)}e.usage?.time_to_first_token_ms&&e.usage.time_to_first_token_ms>0&&(n.fillTTFT[r]=(n.fillTTFT[r]??0)+e.usage.time_to_first_token_ms,n.fillTTFTCount[r]=(n.fillTTFTCount[r]??0)+1),e.usage?.prompt_tokens&&(n.actualFills[r]=e.usage.prompt_tokens)}}function yr(e,t){e.logEntries||=[],e.logEntries.push({timestamp:new Date().toISOString(),message:t})}function br(e){let t=[...e.messages].reverse().find(e=>e.role===`user`);if(!t)return;let n=t.content;if(typeof n==`string`)return n.slice(0,160);if(Array.isArray(n)){let e=n.filter(e=>e?.type===`text`).map(e=>e.text??``).join(` `);return e?e.slice(0,160):void 0}}async function xr(e,t,n,r,i,a,o){let s=[],c=0,l=0,u=0,d=0,f={},p={},m={},h={},g={};yr(i,`Starting scenario: ${n.name} (${n.prompts.length} prompts, ${r}x repeats)`),a({...i});for(let _=0;_1?` (${y}x)`:``}`),i.activePrompts=[{scenarioId:n.id,promptId:v.id,promptIndex:_,repeats:y,repeatIndex:1,preview:br(v),startedAt:new Date().toISOString()}],a({...i});let S=[],C=[],w=``,T=[],E=0,D=0,O=0,k=0,A,j=!1,M=!1,N=``;for(let n=0;n1&&n>0&&(i.activePrompts=[{...i.activePrompts[0],repeatIndex:n+1}],a({...i}));try{let r=await sr(e,v,t,o);if(S.push(r.score),r.notes&&C.push(...r.notes),n===0&&(w=r.assistantText,T=r.toolCalls),A=r.usage,!b){let e=r.usage?.tokens_per_second,t=r.usage?.completion_tokens;if(e&&e>0&&t!==void 0){let n=Math.max(0,t-1);n>0&&(E+=n,D+=n/e)}r.usage?.time_to_first_token_ms&&r.usage.time_to_first_token_ms>0&&(O+=r.usage.time_to_first_token_ms,k++)}if(v.contextFill){let e=v.contextFill.label,t=r.usage?.tokens_per_second,n=r.usage?.completion_tokens;if(t&&t>0&&n!==void 0){let r=Math.max(0,n-1);r>0&&(f[e]=(f[e]??0)+r,p[e]=(p[e]??0)+r/t)}r.usage?.time_to_first_token_ms&&r.usage.time_to_first_token_ms>0&&(m[e]=(m[e]??0)+r.usage.time_to_first_token_ms,h[e]=(h[e]??0)+1),r.usage?.prompt_tokens&&(g[e]=r.usage.prompt_tokens)}}catch(e){if(e instanceof DOMException&&e.name===`AbortError`){j=!0;break}let t=e instanceof Error?e.message:String(e);if(t.includes(`Stream terminated`)){yr(i,`Prompt ${x} failed: ${t}`),i.activePrompts=void 0,i.status=`failed`,a({...i});return}S.push(0),N=`Error: ${t}`,M=!0}}if(j){i.activePrompts=void 0,i.status=`cancelled`,a({...i});return}let P=S.length>0?Math.round(S.reduce((e,t)=>e+t,0)/S.length*100)/100:0,F=C.length>0?[...new Set(C)]:void 0;s.push({promptId:v.id,assistantText:w,toolCalls:T,usage:A,score:P,notes:M&&!F?[N]:F});let I=!!v.contextFill;!b&&!I&&(c+=E,l+=D,u+=O,d+=k),_r(i,hr(n.id,n.prompts,s,c,l,u,d,f,p,m,h,g),a)}i.activePrompts=void 0,a({...i})}async function Sr(e,t,n,r,i,a,o,s){let c=Array(n.prompts.length),l={genTokens:0,genSeconds:0,ttft:0,ttftCount:0,fillGenTokens:{},fillGenSeconds:{},fillTTFT:{},fillTTFTCount:{},actualFills:{}};yr(a,`Starting scenario: ${n.name} (${n.prompts.length} prompts, concurrency=${i}, ${r}x repeats)`),o({...a});let u=new AbortController,d=u.signal,f=()=>u.abort();s.addEventListener(`abort`,f,{once:!0});let p=performance.now(),m=new Map,h=()=>{a.activePrompts=[...m.values()],o({...a})};try{await mr(n.prompts,i,async(i,s)=>{if(d.aborted)return;let f=i.contextFill==null?r:1;m.set(s,{scenarioId:n.id,promptId:i.id,promptIndex:s,repeats:f,repeatIndex:1,preview:br(i),startedAt:new Date().toISOString()}),h();let p=[],g=[],_=``,v=[],y,b=!1,x=``;for(let n=0;n1&&n>0){let e=m.get(s);e&&(m.set(s,{...e,repeatIndex:n+1}),h())}try{let r=await sr(e,i,t,d);p.push(r.score),r.notes&&g.push(...r.notes),n===0&&(_=r.assistantText,v=r.toolCalls),y=r.usage;let a=s!==0&&!i.contextFill;vr(r,i,l,a)}catch(e){if(e instanceof DOMException&&e.name===`AbortError`)break;let t=e instanceof Error?e.message:String(e);if(t.includes(`Stream terminated`)){yr(a,`Prompt ${i.id} failed: ${t}`),a.activePrompts=void 0,a.status=`failed`,o({...a}),u.abort();return}p.push(0),x=`Error: ${t}`,b=!0}}if(d.aborted){m.delete(s);return}let S=p.length>0?p.reduce((e,t)=>e+t,0)/p.length:0,C=g.length>0?[...new Set(g)]:void 0;c[s]={promptId:i.id,assistantText:_,toolCalls:v,usage:y,score:S,notes:b&&!C?[x]:C},m.delete(s);let w=c.filter(Boolean),T=hr(n.id,n.prompts,w,l.genTokens,l.genSeconds,l.ttft,l.ttftCount,l.fillGenTokens,l.fillGenSeconds,l.fillTTFT,l.fillTTFTCount,l.actualFills);a.activePrompts=[...m.values()],_r(a,T,o)},d)}finally{s.removeEventListener(`abort`,f)}if(a.activePrompts=void 0,a.status===`failed`)return;if(d.aborted){a.status=`cancelled`,o({...a});return}let g=(performance.now()-p)/1e3,_=g>0&&l.genTokens>0?l.genTokens/g:void 0,v=c.filter(Boolean),y=hr(n.id,n.prompts,v,l.genTokens,l.genSeconds,l.ttft,l.ttftCount,l.fillGenTokens,l.fillGenSeconds,l.fillTTFT,l.fillTTFTCount,l.actualFills);_!==void 0&&(y.avgTPS=_),_r(a,y,o)}async function Cr(e,t,n,r,i,a,o=3,s){let c=`trial-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,l=Math.max(1,Math.floor(o)),u=Math.min(Math.max(1,s?.concurrency??1),pr),d={id:c,status:`running`,candidate:t,startedAt:new Date().toISOString(),scenarioResults:[],logEntries:[]};yr(d,`Trial started (${n.length} scenario${n.length===1?``:`s`})`),r({...d});for(let a=0;a0){yr(d,`Pausing ${Vn/1e3}s before next scenario…`),r({...d});try{await Wn(Vn,i)}catch(e){if(e instanceof DOMException&&e.name===`AbortError`)return d.status=`cancelled`,d.finishedAt=new Date().toISOString(),r({...d}),d;throw e}}if(u>1&&o.prompts.length>0){yr(d,`Warming up cache for concurrent scenario: ${o.name}`),r({...d});try{await sr(e,o.prompts[0],{...t,max_tokens:1},i)}catch(e){if(e instanceof DOMException&&e.name===`AbortError`)return d.status=`cancelled`,r({...d}),d}}if(u>1?await Sr(e,t,o,l,u,d,r,i):await xr(e,t,o,l,d,r,i),d.status===`cancelled`||d.status===`failed`)return d}let f=new Map;for(let e of d.scenarioResults)f.set(e.scenarioId,{score:e.score,avgTPS:e.avgTPS,avgTTFT:e.avgTTFT});let p=f.get(`tool_call`),m=f.get(`chat`),h=a??lr;if(p&&m){let e=h.chatScore,t=h.toolScore,n=e+t,r=n>0?(t*p.score+e*m.score)/n:(p.score+m.score)/2;d.totalScore=Math.round(r*100)/100}else p?d.totalScore=p.score:m&&(d.totalScore=m.score);let g=m??p;d.avgTPS=g?.avgTPS,d.avgTTFT=g?.avgTTFT;let _=d.scenarioResults.find(e=>e.scenarioId===`chat`);return _?.avgTPSByFill&&Object.keys(_.avgTPSByFill).length>0&&(d.avgTPSByFill=_.avgTPSByFill),_?.avgTTFTByFill&&Object.keys(_.avgTTFTByFill).length>0&&(d.avgTTFTByFill=_.avgTTFTByFill),d.finishedAt=new Date().toISOString(),d.status=`completed`,r({...d}),d}var wr=`kronk_chat_messages`,Tr=`kronk_chat_history`,Er=`kronk:chatHistory`,Dr=1,Or=`session`,kr=`history`,Ar=`meta`;function jr(e){if(!e)return;let t=e;if(typeof t.output_tokens!=`number`)return e;let{output_tokens:n,reasoning_tokens:r,...i}=t;return{...i,completion_tokens:n,completion_tokens_details:{reasoning_tokens:r??0},total_tokens:e.total_tokens??e.prompt_tokens+n}}function Mr(e){return e.map(e=>({...e,usage:jr(e.usage)}))}function Nr(e){return new Promise((t,n)=>{e.onsuccess=()=>t(e.result),e.onerror=()=>n(e.error)})}function Pr(e){return new Promise((t,n)=>{e.oncomplete=()=>t(),e.onerror=()=>n(e.error),e.onabort=()=>n(e.error)})}var Fr=null;function Ir(){return Fr||(Fr=new Promise((e,t)=>{let n=indexedDB.open(Er,Dr);n.onupgradeneeded=()=>{let e=n.result;e.objectStoreNames.contains(Or)||e.createObjectStore(Or,{keyPath:`key`}),e.objectStoreNames.contains(kr)||e.createObjectStore(kr,{keyPath:`id`}).createIndex(`by_savedAt`,`savedAt`),e.objectStoreNames.contains(Ar)||e.createObjectStore(Ar,{keyPath:`key`})},n.onsuccess=()=>e(n.result),n.onerror=()=>{Fr=null,t(n.error)}}),Fr)}var Lr=!1,Rr=null;async function zr(e){if(!Lr)return Rr||(Rr=Br(e),Rr)}async function Br(e){if(await Nr(e.transaction(Ar,`readonly`).objectStore(Ar).get(`migratedFromLocalStorage`))){Lr=!0;return}let t=e.transaction([Or,kr],`readonly`),n=await Nr(t.objectStore(Or).count()),r=await Nr(t.objectStore(kr).count());if(n>0||r>0){let t=e.transaction(Ar,`readwrite`);t.objectStore(Ar).put({key:`migratedFromLocalStorage`,value:!0}),await Pr(t),Lr=!0;return}try{let t=e.transaction([Or,kr,Ar],`readwrite`),n=!1,r=localStorage.getItem(wr);if(r){let e=JSON.parse(r);Array.isArray(e)&&e.length>0&&(t.objectStore(Or).put({key:`messages`,value:e}),n=!0)}let i=localStorage.getItem(Tr);if(i){let e=JSON.parse(i);if(Array.isArray(e)){let r=t.objectStore(kr);for(let t of e)r.put(t);e.length>0&&(n=!0)}}t.objectStore(Ar).put({key:`migratedFromLocalStorage`,value:!0}),await Pr(t),n&&(localStorage.removeItem(wr),localStorage.removeItem(Tr)),Lr=!0;return}catch{}let i=e.transaction(Ar,`readwrite`);i.objectStore(Ar).put({key:`migratedFromLocalStorage`,value:!0}),await Pr(i),Lr=!0}async function Vr(){let e=await Ir();return await zr(e),e}function Hr(){try{let e=localStorage.getItem(wr);if(!e)return[];let t=JSON.parse(e);return Array.isArray(t)?Mr(t):[]}catch{return[]}}function Ur(e){try{e.length>0?localStorage.setItem(wr,JSON.stringify(e)):localStorage.removeItem(wr)}catch{}}function Wr(){try{let e=localStorage.getItem(Tr);if(!e)return[];let t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}function Gr(e){try{e.length>0?localStorage.setItem(Tr,JSON.stringify(e)):localStorage.removeItem(Tr)}catch{}}async function Kr(){try{let e=await Nr((await Vr()).transaction(Or,`readonly`).objectStore(Or).get(`messages`));return e&&Array.isArray(e.value)?Mr(e.value):[]}catch{return Hr()}}async function qr(e){try{let t=(await Vr()).transaction(Or,`readwrite`);e.length===0?t.objectStore(Or).delete(`messages`):t.objectStore(Or).put({key:`messages`,value:e}),await Pr(t)}catch{Ur(e)}}async function Jr(){await qr([])}async function Yr(){try{return(await Nr((await Vr()).transaction(kr,`readonly`).objectStore(kr).index(`by_savedAt`).getAll())).reverse()}catch{return Wr()}}async function Xr(e){try{let t=(await Vr()).transaction(kr,`readwrite`);t.objectStore(kr).put(e),await Pr(t)}catch{let t=Wr().filter(t=>t.id!==e.id);t.unshift(e),Gr(t)}}async function Zr(e){if(e.length!==0)try{let t=(await Vr()).transaction(kr,`readwrite`),n=t.objectStore(kr);for(let t of e)n.delete(t);await Pr(t)}catch{let t=new Set(e);Gr(Wr().filter(e=>!t.has(e.id)))}}async function Qr(){try{let e=(await Vr()).transaction(kr,`readwrite`);e.objectStore(kr).clear(),await Pr(e)}catch{try{localStorage.removeItem(Tr)}catch{}}}var $r=`playground:autoTestHistory:v1`,ei=`playground:autoTestHistory:updatedAt`,ti=`playground:autoTestHistory`,ni=1,ri=`entries`,ii=`meta`;function ai(e){return new Promise((t,n)=>{e.onsuccess=()=>t(e.result),e.onerror=()=>n(e.error)})}function oi(e){return new Promise((t,n)=>{e.oncomplete=()=>t(),e.onerror=()=>n(e.error),e.onabort=()=>n(e.error)})}var si=null;function ci(){return si||(si=new Promise((e,t)=>{let n=indexedDB.open(ti,ni);n.onupgradeneeded=()=>{let e=n.result;e.objectStoreNames.contains(ri)||e.createObjectStore(ri,{keyPath:`id`}).createIndex(`by_savedAt`,`savedAt`),e.objectStoreNames.contains(ii)||e.createObjectStore(ii,{keyPath:`key`})},n.onsuccess=()=>e(n.result),n.onerror=()=>{si=null,t(n.error)}}),si)}var li=!1;async function ui(e){if(li)return;if(await ai(e.transaction(ii,`readonly`).objectStore(ii).get(`migratedFromLocalStorage`))){li=!0;return}if(await ai(e.transaction(ri,`readonly`).objectStore(ri).count())>0){let t=e.transaction(ii,`readwrite`);t.objectStore(ii).put({key:`migratedFromLocalStorage`,value:!0}),await oi(t),li=!0;return}try{let t=localStorage.getItem($r);if(t){let n=JSON.parse(t);if(Array.isArray(n)){let t=n.filter(di);if(t.length>0){let n=e.transaction([ri,ii],`readwrite`),r=n.objectStore(ri);for(let e of t)r.put(e);n.objectStore(ii).put({key:`migratedFromLocalStorage`,value:!0}),await oi(n),localStorage.removeItem($r),li=!0;return}}}}catch{}let t=e.transaction(ii,`readwrite`);t.objectStore(ii).put({key:`migratedFromLocalStorage`,value:!0}),await oi(t),li=!0}function di(e){if(typeof e!=`object`||!e)return!1;let t=e;if(t.version!==1||typeof t.id!=`string`||t.id.length===0||typeof t.savedAt!=`string`||!Number.isFinite(Date.parse(t.savedAt))||t.sweepMode!==`sampling`&&t.sweepMode!==`config`||typeof t.run!=`object`||t.run===null)return!1;let n=t.run;return!!Array.isArray(n.trials)}function fi(e){let t=structuredClone(e);for(let e of t.trials)e.activePrompts=void 0,e.logEntries=void 0;return t}function pi(e){let t=structuredClone(e);for(let e of t.run.trials)for(let t of e.scenarioResults)for(let e of t.promptResults)e.usage=jr(e.usage);return t}function mi(e){let t;for(let n of e.trials)n.finishedAt&&(!t||n.finishedAt>t)&&(t=n.finishedAt);return t??e.runStartedAt}async function hi(e){let t=e.transaction(ri,`readwrite`),n=await ai(t.objectStore(ri).index(`by_savedAt`).getAllKeys());if(n.length<=500)return;let r=n.slice(0,n.length-500),i=t.objectStore(ri);for(let e of r)i.delete(e);await oi(t)}function gi(){window.dispatchEvent(new Event(`autotest-history-updated`));try{localStorage.setItem(ei,String(Date.now()))}catch{}}async function _i(){let e=await ci();return await ui(e),e}function vi(){try{let e=localStorage.getItem($r);if(!e)return[];let t=JSON.parse(e);return Array.isArray(t)?t.filter(di).map(pi):[]}catch{return[]}}function yi(e){try{localStorage.setItem($r,JSON.stringify(e.slice(0,500)))}catch{}}async function bi(){try{return(await ai((await _i()).transaction(ri,`readonly`).objectStore(ri).index(`by_savedAt`).getAll())).filter(di).map(pi).reverse()}catch{return vi()}}async function xi(e){let t=fi(e),n=e.kind===`sampling`?e.sessionSeed?.model_id:e.sessionSeed.model_id,r={version:1,id:e.runId,savedAt:new Date().toISOString(),completedAt:mi(e),modelId:n,sweepMode:e.kind,run:t};try{let e=await _i(),t=e.transaction(ri,`readwrite`);t.objectStore(ri).put(r),await oi(t),await hi(e)}catch{let t=vi().filter(t=>t.id!==e.runId);t.unshift(r),yi(t)}gi()}async function Si(e,t){try{let n=await _i(),r=await ai(n.transaction(ri,`readonly`).objectStore(ri).get(e));if(!r)return;let i=t(r),a=n.transaction(ri,`readwrite`);a.objectStore(ri).put(i),await oi(a)}catch{let n=vi(),r=n.findIndex(t=>t.id===e);r>=0&&(n[r]=t(n[r]),yi(n))}gi()}async function Ci(e){try{let t=(await _i()).transaction(ri,`readwrite`);t.objectStore(ri).delete(e),await oi(t)}catch{yi(vi().filter(t=>t.id!==e))}gi()}async function wi(e){if(e.length!==0){try{let t=(await _i()).transaction(ri,`readwrite`),n=t.objectStore(ri);for(let t of e)n.delete(t);await oi(t)}catch{let t=new Set(e);yi(vi().filter(e=>!t.has(e.id)))}gi()}}async function Ti(){let e=await bi(),t={schemaVersion:1,exportedAt:new Date().toISOString(),entries:e};return new Blob([JSON.stringify(t,null,2)],{type:`application/json`})}async function Ei(e){let t;try{t=JSON.parse(e)}catch{throw Error(`Invalid JSON file`)}if(typeof t!=`object`||!t||!(`schemaVersion`in t)||t.schemaVersion!==1||!(`entries`in t)||!Array.isArray(t.entries))throw Error(`Invalid export file format`);let n=t.entries,r=new Map;for(let e of n){if(!di(e))continue;let t=pi({...e,run:fi(e.run)}),n=r.get(t.id);(!n||t.savedAt>n.savedAt)&&r.set(t.id,t)}let i=Array.from(r.values());if(i.length===0)return{imported:0,skipped:n.length};let a=0,o=0;try{let e=await _i(),t=e.transaction(ri,`readonly`),n=new Set(await ai(t.objectStore(ri).getAllKeys())),r=e.transaction(ri,`readwrite`),s=r.objectStore(ri);for(let e of i)if(n.has(e.id)){let t=await ai(s.get(e.id));t&&e.savedAt>t.savedAt?(s.put(e),a++):o++}else s.put(e),a++;await oi(r),await hi(e)}catch{let e=vi(),t=new Map(e.map(e=>[e.id,e]));for(let e of i){let n=t.get(e.id);n?e.savedAt>n.savedAt?(t.set(e.id,e),a++):o++:(t.set(e.id,e),a++)}yi(Array.from(t.values()))}return gi(),{imported:a,skipped:o}}function Di(e,t,n){let r=[...e,...t,...n??[]],i=new Set;return r.filter(e=>{let t=`${e.timestamp}|${e.message}`;return!i.has(t)&&(i.add(t),!0)})}function Oi(e,t){return new Promise((n,r)=>{if(t.aborted){r(new DOMException(`Aborted`,`AbortError`));return}let i=setTimeout(()=>{t.removeEventListener(`abort`,a),n()},e);function a(){clearTimeout(i),r(new DOMException(`Aborted`,`AbortError`))}t.addEventListener(`abort`,a,{once:!0})})}async function ki(e){let t=-1/0,n=-1/0,r,i=!1;if(e.initialDelayMs&&e.initialDelayMs>0){e.onInitialDelayStart?.();try{await Oi(e.initialDelayMs,e.signal)}catch(t){if(e.onInitialDelayEnd?.(),t instanceof DOMException&&t.name===`AbortError`)return r;throw t}if(e.signal.aborted||e.isStale())return e.onInitialDelayEnd?.(),r;e.onInitialDelayEnd?.()}for(;!(e.signal.aborted||e.isStale());){if(i)try{await Oi(Hn,e.signal)}catch(e){if(e instanceof DOMException&&e.name===`AbortError`)break;throw e}if(e.signal.aborted||e.isStale())break;let a=e.getNextQueuedTrialId();if(a===void 0)break;let o=e.claimTrial(a);if(o<0)continue;if(i=!0,e.signal.aborted||e.isStale())break;let s=new AbortController;e.trialAbortRef&&(e.trialAbortRef.current=s);let c=()=>s.abort();e.signal.addEventListener(`abort`,c,{once:!0});let l=null,u=!1;try{l=await e.executeTrial(a,o,s.signal)}catch(t){if(t instanceof DOMException&&t.name===`AbortError`){if(s.signal.aborted&&!e.signal.aborted)u=!0,e.onTrialStopped?.(a,o);else break}else throw t}finally{e.signal.removeEventListener(`abort`,c),e.trialAbortRef&&(e.trialAbortRef.current=null)}if(u||!l||e.isStale())continue;let d=fr(l,e.weights),f=l.avgTPS??-1/0;(d>t+1e-6||Math.abs(d-t)<=1e-6&&f>n)&&(t=d,n=f,r=l.id),e.onTrialResult(a,o,l,r)}return r}var Ai=(0,x.createContext)(null);function ji({children:e}){let[t,n]=(0,x.useState)(null),r=(0,x.useRef)(null),i=(0,x.useCallback)(e=>{let t=r.current,i=typeof e==`function`?e(t):e;r.current=i,n(i)},[]);(0,x.useEffect)(()=>{r.current=t},[t]);let a=(0,x.useRef)(null),o=(0,x.useRef)(null),s=(0,x.useRef)(null),c=(0,x.useRef)(null),l=(0,x.useRef)(0),u=(0,x.useRef)(null),d=(0,x.useRef)(null),[f,p]=(0,x.useState)(!1),m=(0,x.useRef)(new Set);(0,x.useEffect)(()=>{t&&t.status===`completed`&&(m.current.has(t.runId)||(m.current.add(t.runId),xi(t)))},[t?.runId,t?.status]),(0,x.useEffect)(()=>{if(!t||t.status!==`cancelled`)return;let e=t.runId,n=setTimeout(()=>{i(t=>t&&t.runId===e&&t.status===`cancelled`?null:t)},8e3);return()=>clearTimeout(n)},[t?.runId,t?.status]),(0,x.useEffect)(()=>()=>{a.current?.abort(),c.current?.abort();let e=o.current;e&&W.deletePlaygroundSession(e).catch(()=>{}),o.current=null;let t=s.current;t&&W.deletePlaygroundSession(t).catch(()=>{}),s.current=null},[]);let h=(0,x.useCallback)(({sessionId:e,sessionSeed:t,enabledScenarios:n,sweepDef:o,maxTrials:d,weights:f,repeats:m,effectiveConfig:h})=>{if(u.current)return;let g=++l.current,_=()=>l.current!==g,v=`run-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,y=new AbortController;a.current=y;let b,x=new Promise(e=>{b=e});u.current={runId:v,done:x},p(!0),i({runId:v,kind:`sampling`,status:`repairing_template`,enabledScenarios:n,currentTrialIndex:0,totalTrials:0,sessionId:e??``,sessionSeed:t,sweepDef:o,maxTrials:d,trials:[],repeats:m,weights:f}),(async()=>{try{let a=e??``,l=h;if(!a&&t?.model_id){i(e=>e&&!_()?{...e,templateRepairStatus:`Creating session…`}:e);let e=await W.createPlaygroundSession({model_id:t.model_id,template_mode:t.template_mode,template_name:t.template_name,template_script:t.template_script,config:t.base_config??{}});if(a=e.session_id,l=e.effective_config,s.current=a,y.signal.aborted||_()){W.deletePlaygroundSession(a).catch(()=>{}),s.current=null;return}i(e=>e&&!_()?{...e,sessionId:a,templateRepairStatus:`Session created ✓`}:e)}if(!a){_()||i(e=>e&&{...e,status:`error`,errorMessage:`No session available`});return}let u=[];if(n.chat&&u.push(Gn),n.tool_call&&u.push(Zn),n.tool_call){i(e=>e&&!_()?{...e,templateRepairStatus:`Probing template for tool calling compatibility...`}:e);let e=await cr(a,y.signal);if(_())return;if(e)i(e=>e&&!_()?{...e,templateRepairStatus:`Template OK ✓`}:e);else{i(e=>e&&!_()?{...e,templateRepairStatus:`Template probe failed — running chat-only tests`}:e);let e=u.findIndex(e=>e.id===`tool_call`);e!==-1&&u.splice(e,1)}}if(u.length===0){_()||i(e=>e&&{...e,status:`error`,errorMessage:`No runnable scenarios — template probe failed and chat is disabled`});return}if(n.chat){let e=Xn(l);if(e&&e>0){i(e=>e&&!_()?{...e,calibrationStatus:`Calibrating context fill prompts...`}:e);try{let t=await Yn(a,e,y.signal);if(_())return;if(t.length>0){let e=u.findIndex(e=>e.id===`chat`);e>=0&&(u[e]={...u[e],prompts:[...u[e].prompts,...t]}),i(e=>e&&!_()?{...e,calibrationStatus:`Calibrated ${t.length} context fill levels ✓`}:e)}else i(e=>e&&!_()?{...e,calibrationStatus:`Context window too small for fill tests`}:e)}catch{if(_())return;i(e=>e&&!_()?{...e,calibrationStatus:`Context fill calibration failed — skipping fill tests`}:e)}}}let p=$n(o,d),g=p.map((e,t)=>({id:`${v}-trial-${t}`,status:`queued`,candidate:e,scenarioResults:[]}));i(e=>e&&!_()?{...e,status:`running_trials`,runStartedAt:new Date().toISOString(),totalTrials:p.length,currentTrialIndex:0,trials:g}:e),await ki({signal:y.signal,weights:f,isStale:_,initialDelayMs:Un,onInitialDelayStart:()=>{i(e=>e&&!_()?{...e,initialDelayUntil:new Date(Date.now()+Un).toISOString()}:e)},onInitialDelayEnd:()=>{i(e=>e&&!_()?{...e,initialDelayUntil:void 0}:e)},trialAbortRef:c,onTrialStopped:(e,t)=>{i(t=>{if(!t||t.kind!==`sampling`||_())return t;let n=t.trials.findIndex(t=>t.id===e);if(n<0)return t;let r=[...t.trials];return r[n]={...r[n],status:`cancelled`,finishedAt:new Date().toISOString()},{...t,trials:r}})},getNextQueuedTrialId:()=>{let e=r.current;if(e&&e.status===`running_trials`)return e.trials.find(e=>e.status===`queued`)?.id},claimTrial:e=>{let t=new Date().toISOString(),n=-1;return i(r=>{if(!r||r.kind!==`sampling`||_())return r;let i=r.trials.findIndex(t=>t.id===e);if(i<0||r.trials[i].status!==`queued`)return r;let a=[...r.trials];return a[i]={...a[i],status:`running`,startedAt:t},n=i,{...r,trials:a}}),n},executeTrial:async(e,t,n)=>{let o=r.current?.trials.find(t=>t.id===e);if(!o)return null;let s=o.candidate;return{...await Cr(a,s,u,t=>{i(n=>{if(!n||n.kind!==`sampling`||_())return n;let r=n.trials.findIndex(t=>t.id===e);if(r<0)return n;let i=[...n.trials],a=Di(i[r].logEntries??[],[],t.logEntries),{id:o,...s}=t;return i[r]={...i[r],...s,id:e,logEntries:a},{...n,trials:i}})},n,f,m),id:e}},onTrialResult:(e,t,n,r)=>{i(t=>{if(!t||t.kind!==`sampling`||_())return t;let i=t.trials.findIndex(t=>t.id===e);if(i<0)return t;let a=[...t.trials];return a[i]=n,{...t,trials:a,currentTrialIndex:i+1,bestTrialId:r}})}}),_()||i(e=>e&&{...e,status:y.signal.aborted?`cancelled`:`completed`})}catch(e){if(_())return;e instanceof DOMException&&e.name===`AbortError`?i(e=>e&&{...e,status:`cancelled`}):i(t=>t&&{...t,errorMessage:e.message||`Automated testing failed`,status:`error`})}finally{let e=s.current;e&&(await W.deletePlaygroundSession(e).catch(()=>{}),s.current=null),a.current=null,u.current=null,p(!1),b()}})()},[]),g=(0,x.useCallback)(({sessionSeed:e,enabledScenarios:t,configSweepDef:n,weights:s,repeats:d,availableVRAMGB:f})=>{if(u.current)return;let m=++l.current,h=()=>l.current!==m,g=`run-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,_=new AbortController;a.current=_;let v,y=new Promise(e=>{v=e});u.current={runId:g,done:y},p(!0),i({runId:g,kind:`config`,status:`running_trials`,enabledScenarios:t,currentTrialIndex:0,totalTrials:0,sessionSeed:e,configSweepDef:n,trials:[],repeats:d,weights:s}),(async()=>{try{let a={},l=null;try{let t=await W.createPlaygroundSession({model_id:e.model_id,template_mode:e.template_mode,template_name:e.template_name,template_script:e.template_script,config:{}});l=t.session_id,a={isHybrid:t.effective_config?.is_hybrid_model===!0}}catch{}finally{l&&await W.deletePlaygroundSession(l).catch(()=>{})}if(h())return;let u=rr(e.base_config,n,a);if(u.length===0){h()||i(e=>e&&{...e,errorMessage:`No valid config candidates generated (check sweep values; hybrid models require f16 cache type and disable flash attention)`,status:`error`});return}let p=u,m;try{i(e=>e&&!h()?{...e,calibrationStatus:`Estimating VRAM per candidate…`}:e);let t=(await W.showModel(e.model_id)).vram?.input;if(t){m=new Map;let n=await Promise.all(u.map(async n=>{let r=n.context_window??t.context_window,i=n.nseq_max??t.slots,a=t.bytes_per_element;n.cache_type===`q8_0`?a=1:n.cache_type===`q4_0`?a=.5625:n.cache_type!==void 0&&(a=2);let o=n.moe_keep_experts_top_n??t.expert_layers_on_gpu??0;try{return{candidate:n,total:(await W.calculateVRAM({model_id:e.model_id,context_window:r,bytes_per_element:a,slots:i,expert_layers_on_gpu:o})).total_vram}}catch{return{candidate:n,total:void 0}}}));for(let e of n)e.total!==void 0&&m.set(e.candidate,e.total)}}catch{}if(f&&f>0){let e=f*1024*1024*1024;if(m){p=u.filter(t=>{let n=m.get(t);return n===void 0||n<=e});let t=u.length-p.length;i(t>0?e=>e&&!h()?{...e,calibrationStatus:`Skipped ${t} of ${u.length} candidates exceeding ${f} GB VRAM`}:e:e=>e&&!h()?{...e,calibrationStatus:void 0}:e)}else i(e=>e&&!h()?{...e,calibrationStatus:`VRAM estimation failed — running all candidates`}:e);if(h())return;if(p.length===0){h()||i(e=>e&&{...e,errorMessage:`All ${u.length} candidates exceed ${f} GB VRAM — lower context window, slots, or increase VRAM limit`,status:`error`});return}}else i(e=>e&&!h()?{...e,calibrationStatus:void 0}:e);let v=[Qn],y={temperature:0,top_p:1,top_k:1,min_p:0,repeat_penalty:1,frequency_penalty:0,presence_penalty:0},b=p.map((e,t)=>({id:`${g}-trial-${t}`,status:`queued`,candidate:y,scenarioResults:[],config:e,estimatedVRAM:m?.get(e)}));i(e=>e&&!h()?{...e,status:`running_trials`,runStartedAt:new Date().toISOString(),totalTrials:p.length,currentTrialIndex:0,trials:b}:e),await ki({signal:_.signal,weights:s,isStale:h,initialDelayMs:Un,onInitialDelayStart:()=>{i(e=>e&&!h()?{...e,initialDelayUntil:new Date(Date.now()+Un).toISOString()}:e)},onInitialDelayEnd:()=>{i(e=>e&&!h()?{...e,initialDelayUntil:void 0}:e)},trialAbortRef:c,onTrialStopped:(e,t)=>{i(t=>{if(!t||t.kind!==`config`||h())return t;let n=t.trials.findIndex(t=>t.id===e);if(n<0)return t;let r=[...t.trials];return r[n]={...r[n],status:`cancelled`,finishedAt:new Date().toISOString()},{...t,trials:r}})},getNextQueuedTrialId:()=>{let e=r.current;if(e&&e.kind===`config`&&e.status===`running_trials`)return e.trials.find(e=>e.status===`queued`)?.id},claimTrial:e=>{let t=new Date().toISOString(),n=-1;return i(r=>{if(!r||r.kind!==`config`||h())return r;let i=r.trials.findIndex(t=>t.id===e);if(i<0||r.trials[i].status!==`queued`)return r;let a=[...r.trials];return a[i]={...a[i],status:`running`,startedAt:t,logEntries:[]},n=i,{...r,trials:a}}),n},executeTrial:async(n,a,c)=>{let l=r.current?.trials.find(e=>e.id===n);if(!l?.config)return null;let u=l.config,f=[],p=e=>{let t={timestamp:new Date().toISOString(),message:e};f.push(t),i(e=>{if(!e||e.kind!==`config`||h())return e;let t=e.trials.findIndex(e=>e.id===n);if(t<0)return e;let r=[...e.trials];return r[t]={...r[t],logEntries:[...f]},{...e,trials:r}})},{cache_type:m,cache_mode:g,moe_mode:_,moe_keep_experts_top_n:b,...x}=u,S={...x,...m!==void 0&&{cache_type_k:m,cache_type_v:m},...g!==void 0&&{incremental_cache:g===`imc`},..._!==void 0&&{moe_mode:_},..._!==void 0&&_!==`keep_top_n`&&{moe_keep_experts_top_n:null},...b!==void 0&&{moe_keep_experts_top_n:b}},C=null;try{p(`Creating session with config overrides…`);let r=await W.createPlaygroundSession({model_id:e.model_id,template_mode:e.template_mode,template_name:e.template_name,template_script:e.template_script,config:{...e.base_config,...S}});if(C=r.session_id,o.current=C,c.aborted||h())throw new DOMException(`Aborted`,`AbortError`);p(`Session created ✓`);let a=[...v];if(a.length===0)throw Error(`No runnable scenarios for this config — template probe failed and chat is disabled`);if(t.chat){let t=Xn(r.effective_config,e.base_config);if(t&&t>0){p(`Calibrating context fill prompts (ctx=${t})…`);try{let e=await Yn(C,t,c);if(h())throw new DOMException(`Aborted`,`AbortError`);if(e.length>0){let t=a.findIndex(e=>e.id===`chat`);t>=0&&(a[t]={...a[t],prompts:[...a[t].prompts,...e]}),p(`Calibrated ${e.length} fill levels ✓`)}else p(`Context window too small for fill tests`)}catch{p(`Context fill calibration failed — skipping`)}}}p(`Running scenarios…`);let l=e=>{i(t=>{if(!t||t.kind!==`config`||h())return t;let r=t.trials.findIndex(e=>e.id===n);if(r<0)return t;let i=[...t.trials],a=Di(i[r].logEntries??[],f,e.logEntries),{id:o,...s}=e;return i[r]={...i[r],...s,id:n,config:u,logEntries:a},{...t,trials:i}})},m=u.nseq_max??e.base_config.nseq_max??1,g=await Cr(C,y,a,l,c,s,d,m>1?{concurrency:m}:void 0);return{...g,id:n,config:u,logEntries:Di([],f,g.logEntries)}}catch(e){if(e instanceof DOMException&&e.name===`AbortError`)throw e;let t=e instanceof Error?e.message:String(e);return h()||i(e=>{if(!e||e.kind!==`config`)return e;let r=e.trials.findIndex(e=>e.id===n);if(r<0)return e;let i=[...e.trials],a=i[r];return i[r]={...a,id:a?.id??n,status:`failed`,startedAt:a?.startedAt??new Date().toISOString(),finishedAt:new Date().toISOString(),scenarioResults:[],totalScore:void 0,avgTPS:void 0,config:u,error:t},{...e,trials:i,currentTrialIndex:r+1}}),null}finally{C&&(await W.deletePlaygroundSession(C).catch(()=>{}),o.current===C&&(o.current=null))}},onTrialResult:(e,t,n,r)=>{i(t=>{if(!t||t.kind!==`config`||h())return t;let i=t.trials.findIndex(t=>t.id===e);if(i<0)return t;let a=[...t.trials];return a[i]=n,{...t,trials:a,currentTrialIndex:i+1,bestTrialId:r}})}}),h()||i(e=>e&&{...e,status:_.signal.aborted?`cancelled`:`completed`})}catch(e){if(h())return;e instanceof DOMException&&e.name===`AbortError`?i(e=>e&&{...e,status:`cancelled`}):i(t=>t&&{...t,errorMessage:e.message||`Automated testing failed`,status:`error`})}finally{let e=o.current;e&&(await W.deletePlaygroundSession(e).catch(()=>{}),o.current=null),a.current=null,u.current=null,p(!1),v()}})()},[]),_=(0,x.useCallback)(()=>{let e=r.current;if(!e||u.current||!e.trials.some(e=>e.status===`queued`))return;let t=++l.current,n=()=>l.current!==t,d=new AbortController;a.current=d;let f,m=new Promise(e=>{f=e});u.current={runId:e.runId,done:m},p(!0),i(e=>e&&{...e,status:`running_trials`,initialDelayUntil:void 0}),(async()=>{try{if(e.kind===`sampling`){let t=e,a=t.sessionId;if(t.sessionSeed?.model_id)try{a=(await W.createPlaygroundSession({model_id:t.sessionSeed.model_id,template_mode:t.sessionSeed.template_mode,template_name:t.sessionSeed.template_name,template_script:t.sessionSeed.template_script,config:t.sessionSeed.base_config??{}})).session_id,s.current=a,i(e=>e&&e.kind===`sampling`?{...e,sessionId:a}:e)}catch{i(e=>e&&{...e,status:`error`,errorMessage:`Failed to recreate session for rerun`});return}if(!a){i(e=>e&&{...e,status:`error`,errorMessage:`No session available for rerun`});return}let o=[];t.enabledScenarios.chat&&o.push(Gn),t.enabledScenarios.tool_call&&o.push(Zn),await ki({signal:d.signal,weights:t.weights,isStale:n,trialAbortRef:c,onTrialStopped:e=>{i(t=>{if(!t||t.kind!==`sampling`||n())return t;let r=t.trials.findIndex(t=>t.id===e);if(r<0)return t;let i=[...t.trials];return i[r]={...i[r],status:`cancelled`,finishedAt:new Date().toISOString()},{...t,trials:i}})},getNextQueuedTrialId:()=>{let e=r.current;if(e&&e.status===`running_trials`)return e.trials.find(e=>e.status===`queued`)?.id},claimTrial:e=>{let t=new Date().toISOString(),r=-1;return i(i=>{if(!i||i.kind!==`sampling`||n())return i;let a=i.trials.findIndex(t=>t.id===e);if(a<0||i.trials[a].status!==`queued`)return i;let o=[...i.trials];return o[a]={...o[a],status:`running`,startedAt:t},r=a,{...i,trials:o}}),r},executeTrial:async(e,s,c)=>{let l=r.current?.trials.find(t=>t.id===e);if(!l)return null;let u=l.candidate;return{...await Cr(a,u,o,t=>{i(r=>{if(!r||r.kind!==`sampling`||n())return r;let i=r.trials.findIndex(t=>t.id===e);if(i<0)return r;let a=[...r.trials],o=Di(a[i].logEntries??[],[],t.logEntries),{id:s,...c}=t;return a[i]={...a[i],...c,id:e,logEntries:o},{...r,trials:a}})},c,t.weights,t.repeats),id:e}},onTrialResult:(e,t,r,a)=>{i(t=>{if(!t||t.kind!==`sampling`||n())return t;let i=t.trials.findIndex(t=>t.id===e);if(i<0)return t;let o=[...t.trials];return o[i]=r,{...t,trials:o,currentTrialIndex:i+1,bestTrialId:a}})}})}else{let t=e,a=t.sessionSeed,s=[Qn];await ki({signal:d.signal,weights:t.weights,isStale:n,trialAbortRef:c,onTrialStopped:e=>{i(t=>{if(!t||t.kind!==`config`||n())return t;let r=t.trials.findIndex(t=>t.id===e);if(r<0)return t;let i=[...t.trials];return i[r]={...i[r],status:`cancelled`,finishedAt:new Date().toISOString()},{...t,trials:i}})},getNextQueuedTrialId:()=>{let e=r.current;if(e&&e.status===`running_trials`)return e.trials.find(e=>e.status===`queued`)?.id},claimTrial:e=>{let t=new Date().toISOString(),r=-1;return i(i=>{if(!i||i.kind!==`config`||n())return i;let a=i.trials.findIndex(t=>t.id===e);if(a<0||i.trials[a].status!==`queued`)return i;let o=[...i.trials];return o[a]={...o[a],status:`running`,startedAt:t},r=a,{...i,trials:o}}),r},executeTrial:async(e,c,l)=>{let u=r.current;if(!u||u.kind!==`config`)return null;let f=u.trials.find(t=>t.id===e);if(!f)return null;let p=f.config;if(!p)return null;let m=``,h=[],g={temperature:0,top_p:1,top_k:1,min_p:0,repeat_penalty:1,frequency_penalty:0,presence_penalty:0},_=s,v=t.repeats,y=t.weights;try{let t={...g,...p};if(m=(await W.createPlaygroundSession({model_id:a.model_id,template_mode:a.template_mode,template_name:a.template_name,template_script:a.template_script,config:t})).session_id,o.current=m,d.signal.aborted||n())return await W.deletePlaygroundSession(m).catch(()=>{}),o.current=null,null;let r=t=>{i(r=>{if(!r||r.kind!==`config`||n())return r;let i=r.trials.findIndex(t=>t.id===e);if(i<0)return r;let a=[...r.trials],o=Di(a[i].logEntries??[],h,t.logEntries),{id:s,...c}=t;return a[i]={...a[i],...c,id:e,config:p,logEntries:o},{...r,trials:a}})},s=p.nseq_max??a.base_config.nseq_max??1,c=await Cr(m,g,_,r,l,y,v,s>1?{concurrency:s}:void 0);return{...c,id:e,config:p,logEntries:Di([],h,c.logEntries)}}catch(t){if(t instanceof DOMException&&t.name===`AbortError`)throw t;let r=t instanceof Error?t.message:String(t);return n()||i(t=>{if(!t||t.kind!==`config`)return t;let n=t.trials.findIndex(t=>t.id===e);if(n<0)return t;let i=[...t.trials],a=i[n];return i[n]={...a,id:a?.id??e,status:`failed`,startedAt:a?.startedAt??new Date().toISOString(),finishedAt:new Date().toISOString(),scenarioResults:[],totalScore:void 0,avgTPS:void 0,config:p,error:r},{...t,trials:i,currentTrialIndex:n+1}}),null}finally{m&&(await W.deletePlaygroundSession(m).catch(()=>{}),o.current===m&&(o.current=null))}},onTrialResult:(e,t,r,a)=>{i(t=>{if(!t||t.kind!==`config`||n())return t;let i=t.trials.findIndex(t=>t.id===e);if(i<0)return t;let o=[...t.trials];return o[i]=r,{...t,trials:o,currentTrialIndex:i+1,bestTrialId:a}})}})}n()||i(e=>e&&{...e,status:d.signal.aborted?`cancelled`:`completed`})}catch(e){if(n())return;e instanceof DOMException&&e.name===`AbortError`?i(e=>e&&{...e,status:`cancelled`}):i(t=>t&&{...t,errorMessage:e.message||`Rerun failed`,status:`error`})}finally{let e=s.current;e&&(await W.deletePlaygroundSession(e).catch(()=>{}),s.current=null);let t=o.current;t&&(await W.deletePlaygroundSession(t).catch(()=>{}),o.current=null),a.current=null,u.current=null,p(!1),f()}})()},[]);d.current=_;let v=(0,x.useCallback)(()=>{++l.current,a.current?.abort(),c.current?.abort(),i(e=>{if(!e)return e;let t=e.trials.map(e=>e.status===`running`?{...e,status:`cancelled`,finishedAt:new Date().toISOString()}:e);return{...e,status:`cancelled`,initialDelayUntil:void 0,trials:t}})},[]),y=(0,x.useCallback)(()=>{u.current||i(null)},[]),b=(0,x.useCallback)(e=>{i(t=>{if(!t||t.status!==`completed`)return t;let n=-1/0,r=-1/0,i;for(let a of t.trials){if(!a||a.status===`skipped`||a.totalScore===void 0||a.totalScore===null||t.kind===`config`&&a.error)continue;let o=fr(a,e),s=a.avgTPS??-1/0;(o>n+1e-6||Math.abs(o-n)<=1e-6&&s>r)&&(n=o,r=s,i=a.id)}return{...t,bestTrialId:i}})},[]),S=(0,x.useCallback)(({trialId:e,direction:t})=>{i(n=>{if(!n||n.status!==`running_trials`)return n;let r=n.trials.findIndex(t=>t.id===e);if(r<0||n.trials[r].status!==`queued`)return n;let i=t===`up`?r-1:r+1;if(i<0||i>=n.trials.length||n.trials[i].status!==`queued`)return n;let a=[...n.trials];return[a[r],a[i]]=[a[i],a[r]],{...n,trials:a}})},[]),C=(0,x.useCallback)(({trialId:e,targetId:t})=>{e!==t&&i(n=>{if(!n||n.status!==`running_trials`)return n;let r=n.trials.findIndex(t=>t.id===e),i=n.trials.findIndex(e=>e.id===t);if(r<0||i<0||n.trials[r].status!==`queued`)return n;let a=[...n.trials],[o]=a.splice(r,1);return a.splice(i,0,o),{...n,trials:a}})},[]),w=(0,x.useCallback)(({trialId:e})=>{i(t=>{if(!t||t.status!==`running_trials`)return t;let n=t.trials.findIndex(t=>t.id===e);if(n<0||t.trials[n].status!==`queued`)return t;let r=[...t.trials];return r[n]={...r[n],status:`skipped`,finishedAt:new Date().toISOString()},{...t,trials:r}})},[]),T=(0,x.useCallback)(({trialId:e})=>{i(t=>{if(!t||t.status!==`running_trials`)return t;let n=t.trials.findIndex(t=>t.id===e);if(n<0||t.trials[n].status!==`skipped`)return t;let r=[...t.trials];return r[n]={...r[n],status:`queued`,finishedAt:void 0},{...t,trials:r}})},[]),E=(0,x.useCallback)(()=>{c.current?.abort()},[]),D=(0,x.useCallback)(({trialId:e})=>{let t=!1;i(n=>{if(!n||n.status!==`running_trials`&&n.status!==`completed`&&n.status!==`cancelled`)return n;let r=n.trials.findIndex(t=>t.id===e);if(r<0)return n;let i=n.trials[r];if(i.status!==`completed`&&i.status!==`cancelled`&&i.status!==`failed`)return n;let a=[...n.trials],o={id:i.id,status:`queued`,candidate:i.candidate,scenarioResults:[]},s;s=n.kind===`config`?{...o,config:i.config}:o,a.splice(r,1);let c=a.findIndex(e=>e.status===`queued`);c>=0?a.splice(c,0,s):a.push(s);let l=n.bestTrialId===e?void 0:n.bestTrialId;return(n.status===`completed`||n.status===`cancelled`)&&(t=!0),{...n,trials:a,bestTrialId:l}}),t&&setTimeout(()=>_(),0)},[_]);return(0,G.jsx)(Ai.Provider,{value:{run:t,isRunning:f,startSamplingRun:h,startConfigRun:g,stopRun:v,clearRun:y,reevaluateBestTrial:b,moveQueuedTrial:S,reorderQueuedTrial:C,skipTrial:w,unskipTrial:T,stopTrial:E,rerunTrial:D},children:e})}function Mi(){let e=(0,x.useContext)(Ai);if(!e)throw Error(`useAutoTestRunner must be used within an AutoTestRunnerProvider`);return e}function Ni(e){let t=e.toLowerCase();return!t.includes(`embed`)&&!t.includes(`rerank`)}var Pi=(0,x.createContext)(null);function Fi({children:e}){let{models:t,loadModels:n}=In(),[r,i]=(0,x.useState)(`manual`),[a,o]=(0,x.useState)(``),s=(0,x.useRef)(null),[c,l]=(0,x.useState)(null);function u(){l(null)}(0,x.useEffect)(()=>{if(!c)return;let e=setTimeout(()=>l(null),1e4);return()=>clearTimeout(e)},[c]);function d(e){return!s.current&&(s.current=e,l(null),!0)}function f(e){s.current===e&&(s.current=null)}let[p,m]=(0,x.useState)(null),[h,g]=(0,x.useState)(`line`),[_,v]=(0,x.useState)(null),[y,b]=(0,x.useState)(``),[S,C]=(0,x.useState)(!1),[w,T]=(0,x.useState)(null),E=(0,x.useRef)(null),[D,O]=(0,x.useState)(new Set),[k,A]=(0,x.useState)(5),[j,M]=(0,x.useState)([]),[N,P]=(0,x.useState)(!1),[F,I]=(0,x.useState)(new Set),L=(0,x.useRef)(!1),R=(0,x.useRef)(null),[z,ee]=(0,x.useState)(new Set),[B,V]=(0,x.useState)(``),[te,H]=(0,x.useState)([]),[ne,re]=(0,x.useState)(!1),[ie,ae]=(0,x.useState)(`columns`),oe=(0,x.useRef)(!1),se=(0,x.useRef)(null);function ce(e){s.current||o(e)}(0,x.useEffect)(()=>{n()},[n]),(0,x.useEffect)(()=>{if(!s.current&&t?.data&&t.data.length>0){let e=t.data.filter(e=>Ni(e.id));!e.some(e=>e.id===a)&&e.length>0&&o(e[0].id)}},[t,a]),(0,x.useEffect)(()=>{T(null),M([]),I(new Set),O(new Set)},[a]),(0,x.useEffect)(()=>{H([])},[B,z]),(0,x.useEffect)(()=>{let e=!1;return W.listAccuracyFunctions().then(t=>{e||(m(t.data),t.data.length>0&&(b(t.data[0].identifier),V(t.data[0].identifier)))}).catch(t=>{e||v(t instanceof Error?t.message:`Failed to read functions`)}),()=>{e=!0}},[]);async function le(){if(!a||!y||!d(`manual`))return;let e=new AbortController;E.current=e,C(!0),v(null),T(null);try{let t=await W.runAccuracy(a,y,e.signal);T(t),l({mode:`manual`,ok:!0,title:`Accuracy test done`,summary:`${y} · ${t.match_percent.toFixed(0)}% match`})}catch(t){if(e.signal.aborted)return;v(t instanceof Error?t.message:`Test failed`),l({mode:`manual`,ok:!1,title:`Accuracy test failed`,summary:y})}finally{E.current===e&&(E.current=null),C(!1),f(`manual`)}}function ue(){E.current?.abort()}function de(){T(null),v(null)}function fe(e){O(t=>{let n=new Set(t);if(n.has(e))n.delete(e);else{if(n.size>=5)return t;n.add(e)}return n})}function pe(){L.current=!0,O(new Set),M([]),I(new Set)}function me(){let e=(p??[]).map(e=>e.identifier),t=Math.max(1,Math.min(k,5,e.length)),n=[...e];for(let e=n.length-1;e>0;e--){let t=Math.floor(Math.random()*(e+1));[n[e],n[t]]=[n[t],n[e]]}O(new Set(n.slice(0,t)))}async function he(){if(!a||D.size===0||!d(`batch`))return;let e=(p??[]).filter(e=>D.has(e.identifier));P(!0),v(null),I(new Set),L.current=!1;let t=e.map(e=>({identifier:e.identifier,line:e.line,loc:e.loc,status:`pending`}));M(t);let n=0,r=0,i=0;try{for(let t=0;te.map(e=>e.identifier===o?{...e,status:`running`}:e));let s=new AbortController;R.current=s;try{let e=await W.runAccuracy(a,o,s.signal);n++,i+=e.match_percent,M(t=>t.map(t=>t.identifier===o?{...t,status:`done`,result:e}:t))}catch(e){if(s.signal.aborted){M(e=>e.map(e=>e.identifier===o?{...e,status:`pending`}:e));break}r++,M(t=>t.map(t=>t.identifier===o?{...t,status:`error`,error:e instanceof Error?e.message:`failed`}:t))}finally{R.current=null}}}finally{if(P(!1),f(`batch`),!L.current){let t=e.length,a=n>0?Math.round(i/n):0;l({mode:`batch`,ok:r===0,title:`Accuracy batch done`,summary:`${n}/${t} · avg ${a}% match`+(r>0?` · ${r} error${r>1?`s`:``}`:``)})}}}function ge(){L.current=!0,R.current?.abort()}function _e(e){I(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})}function ve(e){ee(t=>{let n=new Set(t);if(n.has(e))return n.delete(e),n;if(n.size>=2){let e=n.values().next().value;e!==void 0&&n.delete(e)}return n.add(e),n})}function ye(){oe.current=!0,se.current?.abort(),ee(new Set),H([])}async function be(){let e=Array.from(z);if(e.length===0||!B||!d(`compare`))return;re(!0),v(null),oe.current=!1;let t=e.map(e=>({model:e,status:`pending`}));H(t);let n=0,r=0;try{for(let t=0;te.map(e=>e.model===i?{...e,status:`running`}:e));let a=new AbortController;se.current=a;try{let e=await W.runAccuracy(i,B,a.signal);n++,H(t=>t.map(t=>t.model===i?{...t,status:`done`,result:e}:t))}catch(e){if(a.signal.aborted){H(e=>e.map(e=>e.model===i?{...e,status:`pending`}:e));break}r++,H(t=>t.map(t=>t.model===i?{...t,status:`error`,error:e instanceof Error?e.message:`failed`}:t))}finally{se.current=null}}}finally{re(!1),f(`compare`),oe.current||l({mode:`compare`,ok:r===0,title:`Accuracy compare done`,summary:`${n}/${e.length} models`+(r>0?` · ${r} error${r>1?`s`:``}`:``)})}}function xe(){oe.current=!0,se.current?.abort()}let Se=S||N||ne,Ce=null;if(S){let e=p?.find(e=>e.identifier===y)?.loc;Ce={mode:`manual`,label:e==null?y:`${y} (${e} loc)`,done:0,total:1}}else if(N){let e=j.filter(e=>e.status===`done`||e.status===`error`).length;Ce={mode:`batch`,label:`${e}/${j.length} functions`,done:e,total:j.length}}else if(ne){let e=te.filter(e=>e.status===`done`||e.status===`error`).length;Ce={mode:`compare`,label:`${e}/${te.length} models`,done:e,total:te.length}}function we(){S?ue():N?ge():ne&&xe()}return(0,G.jsx)(Pi.Provider,{value:{mode:r,setMode:i,selectedModel:a,setSelectedModel:ce,functions:p,sortBy:h,setSortBy:g,error:_,setError:v,selectedFn:y,setSelectedFn:b,running:S,result:w,runManual:le,stopManual:ue,clearManual:de,checked:D,setChecked:O,randomCount:k,setRandomCount:A,rows:j,batchRunning:N,expanded:F,toggle:fe,clearAll:pe,pickRandom:me,runBatch:he,stopBatch:ge,toggleExpand:_e,compareModels:z,compareFn:B,setCompareFn:V,compareCells:te,comparing:ne,compareLayout:ie,setCompareLayout:ae,toggleCompareModel:ve,clearCompare:ye,runCompare:be,stopCompare:xe,isRunning:Se,activeRun:Ce,completedRun:c,dismissCompleted:u,stopActive:we},children:e})}function Ii(){let e=(0,x.useContext)(Pi);if(!e)throw Error(`useAccuracyRunner must be used within an AccuracyRunnerProvider`);return e}function Li(e){let t=e.toLowerCase();return!t.includes(`embed`)&&!t.includes(`rerank`)}var Ri=(0,x.createContext)(null);function zi({children:e}){let{loadModels:t}=In(),[n,r]=(0,x.useState)(new Set),[i,a]=(0,x.useState)(``),[o,s]=(0,x.useState)(512),[c,l]=(0,x.useState)(new Map),[u,d]=(0,x.useState)(null),f=(0,x.useRef)(null),[p,m]=(0,x.useState)(null),h=(0,x.useRef)(null),g=(0,x.useRef)(!1),_=(0,x.useRef)(new Set);(0,x.useEffect)(()=>{t()},[t]),(0,x.useEffect)(()=>{if(!u)return;let e=setTimeout(()=>d(null),1e4);return()=>clearTimeout(e)},[u]);function v(){d(null)}function y(e){f.current||(r(t=>{let n=new Set(t);if(n.has(e))return n.delete(e),n;if(n.size>=2){let e=n.values().next().value;e!==void 0&&n.delete(e)}return n.add(e),n}),l(t=>{let n=new Map(t);return n.delete(e),n}))}function b(){f.current||(a(``),l(new Map))}function S(e,t){l(n=>{let r=new Map(n);return r.set(e,t),r})}async function C(e){if(!i.trim())return!1;f.current=e,m(e),S(e,{status:_.current.has(e)?`running`:`loading`});let t=new AbortController;h.current=t;try{let n=await W.runEfficiency(e,i,o,t.signal);return _.current.add(e),S(e,{status:`done`,result:n}),!0}catch(n){return t.signal.aborted?(S(e,{status:`idle`}),!1):(S(e,{status:`error`,error:n instanceof Error?n.message:`failed`}),!1)}finally{h.current=null,f.current=null,m(null)}}function w(e){f.current||n.has(e)&&C(e)}async function T(){if(f.current)return;let e=Array.from(n);if(e.length===0||!i.trim())return;g.current=!1,d(null);let t=0,r=0;for(let n of e){if(g.current)break;await C(n)?t++:g.current||r++}g.current||d({ok:r===0,title:`Efficiency run done`,summary:`${t}/${e.length} models`+(r>0?` · ${r} error${r>1?`s`:``}`:``)})}function E(){g.current=!0,h.current?.abort()}let D=p!==null,O=null;if(p){let e=c.get(p),t=n.size,r=Array.from(c.values()).filter(e=>e.status===`done`||e.status===`error`).length;O={model:p,status:e?.status??`running`,done:r,total:t}}return(0,G.jsx)(Ri.Provider,{value:{selectedModels:n,toggleModel:y,prompt:i,setPrompt:a,maxTokens:o,setMaxTokens:s,clear:b,runs:c,runModel:w,runAll:T,stopActive:E,isRunning:D,activeRun:O,completedRun:u,dismissCompleted:v},children:e})}function Bi(){let e=(0,x.useContext)(Ri);if(!e)throw Error(`useEfficiencyRunner must be used within an EfficiencyRunnerProvider`);return e}var Vi=(0,x.createContext)(null);function Hi({children:e}){let[t,n]=(0,x.useState)(null),[r,i]=(0,x.useState)([]),[a,o]=(0,x.useState)(``),[s,c]=(0,x.useState)(`automated`),[l,u]=(0,x.useState)(`sampling`),[d,f]=(0,x.useState)(`chat`),[p,m]=(0,x.useState)(`You are a helpful assistant.`),[h,g]=(0,x.useState)(null),[_,v]=(0,x.useState)(`builtin`),[y,b]=(0,x.useState)(``),[S,C]=(0,x.useState)(``),[w,T]=(0,x.useState)(8192),[E,D]=(0,x.useState)(Bn),[O,k]=(0,x.useState)(1),[A,j]=(0,x.useState)(`auto`),[M,N]=(0,x.useState)(``),[P,F]=(0,x.useState)(`auto`),[I,L]=(0,x.useState)(`none`),[R,z]=(0,x.useState)(``),[ee,B]=(0,x.useState)(0),[V,te]=(0,x.useState)([]),[H,ne]=(0,x.useState)(``),re=(0,x.useMemo)(()=>({session:t,setSession:n,chatMessages:r,setChatMessages:i,selectedModel:a,setSelectedModel:o,playgroundMode:s,setPlaygroundMode:c,sweepMode:l,setSweepMode:u,activeTab:d,setActiveTab:f,systemPrompt:p,setSystemPrompt:m,lastTPS:h,setLastTPS:g,templateMode:_,setTemplateMode:v,selectedTemplate:y,setSelectedTemplate:b,customScript:S,setCustomScript:C,contextWindow:w,setContextWindow:T,prefillBatchSize:E,setPrefillBatchSize:D,nSeqMax:O,setNSeqMax:k,flashAttention:A,setFlashAttention:j,cacheType:M,setCacheType:N,loadMode:P,setLoadMode:F,cacheMode:I,setCacheMode:L,moeMode:R,setMoeMode:z,moeKeepTopN:ee,setMoeKeepTopN:B,tensorBuftOverrides:V,setTensorBuftOverrides:te,hydratedModelId:H,setHydratedModelId:ne}),[t,r,a,s,l,d,p,h,_,y,S,w,E,O,A,M,P,I,R,ee,V,H]);return(0,G.jsx)(Vi.Provider,{value:re,children:e})}function Ui(){let e=(0,x.useContext)(Vi);if(!e)throw Error(`usePlayground must be used within a PlaygroundProvider`);return e}var Wi=`theme`,Gi=(0,x.createContext)(null);function Ki({children:e}){let[t,n]=(0,x.useState)(()=>localStorage.getItem(Wi)||`light`);(0,x.useEffect)(()=>{localStorage.setItem(Wi,t),document.documentElement.dataset.theme=t},[t]);let r=(0,x.useCallback)(()=>{n(e=>e===`light`?`dark`:`light`)},[]);return(0,G.jsx)(Gi.Provider,{value:{theme:t,toggleTheme:r},children:e})}function qi(){let e=(0,x.useContext)(Gi);if(!e)throw Error(`useTheme must be used within a ThemeProvider`);return e}function Ji({onAuthenticated:e}){let[t,n]=(0,x.useState)(``),[r,i]=(0,x.useState)(!1),[a,o]=(0,x.useState)(``);return(0,G.jsx)(`div`,{className:`auth-screen`,children:(0,G.jsxs)(`form`,{className:`auth-card`,onSubmit:async n=>{n.preventDefault(),i(!0),o(``);try{let n=await fetch(`/admin/api/login`,{method:`POST`,credentials:`same-origin`,headers:{"Content-Type":`application/json`},body:JSON.stringify({password:t})});if(n.ok){e();return}o(n.status===401?`Invalid password.`:`Unable to sign in. Please try again.`)}catch{o(`Unable to reach the server. Please try again.`)}finally{i(!1)}},children:[(0,G.jsx)(`img`,{src:`/admin/kronk-logo.png`,alt:`Kronk`}),(0,G.jsx)(`h1`,{children:`Kronk Admin`}),(0,G.jsx)(`p`,{children:`Sign in to manage this model server.`}),(0,G.jsx)(`label`,{htmlFor:`admin-password`,children:`Admin password`}),(0,G.jsx)(`input`,{id:`admin-password`,type:`password`,autoComplete:`current-password`,autoFocus:!0,required:!0,value:t,onChange:e=>n(e.target.value)}),a&&(0,G.jsx)(`div`,{className:`alert alert-error`,role:`alert`,children:a}),(0,G.jsx)(`button`,{className:`btn btn-primary`,type:`submit`,disabled:r||!t,children:r?`Signing in…`:`Sign in`})]})})}var Yi=(0,x.createContext)(null);function Xi({children:e}){let[t,n]=(0,x.useState)(`loading`),[r,i]=(0,x.useState)(!0),a=(0,x.useCallback)(async()=>{try{let e=await fetch(`/admin/api/session`,{credentials:`same-origin`}),t=await e.json();i(t.authentication_required),n(e.ok&&t.authenticated?`authenticated`:`anonymous`)}catch{n(`anonymous`)}},[]);(0,x.useEffect)(()=>{localStorage.removeItem(`kronk_token`),a();let e=()=>n(`anonymous`);return window.addEventListener(Mn,e),()=>window.removeEventListener(Mn,e)},[a]);let o=(0,x.useCallback)(async()=>{try{await fetch(`/admin/api/logout`,{method:`POST`,credentials:`same-origin`})}finally{n(`anonymous`)}},[]);return t===`loading`?(0,G.jsx)(`div`,{className:`auth-screen`,children:(0,G.jsx)(`div`,{className:`auth-card auth-loading`,children:`Loading Kronk…`})}):t===`anonymous`?(0,G.jsx)(Ji,{onAuthenticated:()=>n(`authenticated`)}):(0,G.jsx)(Yi.Provider,{value:{authenticationRequired:r,logout:o},children:e})}function Zi(){let e=(0,x.useContext)(Yi);if(!e)throw Error(`useAuth must be used within an AuthProvider`);return e}var Qi=[{id:`apps`,label:`Apps`,items:[{page:`chat`,label:`Chat`},{page:`decision`,label:`Decision`},{page:`vram-calculator`,label:`VRAM Calculator`},{page:`translator`,label:`Translator`},{page:`image-generator`,label:`Image Generator`}]},{id:`running`,label:`System`,items:[{page:`model-ps`,label:`Running`},{page:`slots`,label:`Slots`},{page:`imc-sessions`,label:`IMC Sessions`},{page:`diagnose`,label:`Info`}]},{id:`kronk`,label:`Kronk`,subcategories:[{id:`model`,label:`Models`,items:[{page:`model-list`,label:`List`},{page:`model-pull`,label:`HF Pull`},{page:`kms-pull`,label:`KMS Pull`}]},{id:`catalog`,label:`Catalog`,items:[{page:`catalog-list`,label:`List`}]},{id:`libs`,label:`Libs`,items:[{page:`libs-pull`,label:`Manage`}]}]},{id:`bucky`,label:`Bucky`,subcategories:[{id:`bucky-model`,label:`Models`,items:[{page:`bucky-model-list`,label:`List`}]},{id:`bucky-libs`,label:`Libs`,items:[{page:`bucky-libs`,label:`Manage`}]}]},{id:`malina`,label:`Malina`,subcategories:[{id:`malina-model`,label:`Models`,items:[{page:`malina-model-list`,label:`List`}]},{id:`malina-libs`,label:`Libs`,items:[{page:`malina-libs`,label:`Manage`}]}]},{id:`security`,label:`Security`,subcategories:[{id:`security-key`,label:`Key`,items:[{page:`security-key-list`,label:`List`},{page:`security-key-create`,label:`Create`},{page:`security-key-delete`,label:`Delete`}]},{id:`security-token`,label:`Token`,items:[{page:`security-token-create`,label:`Create`},{page:`settings`,label:`Session`}]}]},{id:`testing`,label:`Testing`,items:[{page:`accuracy`,label:`Accuracy`},{page:`efficiency`,label:`Efficiency`},{page:`testing-basic`,label:`Basic`},{page:`testing-sampling`,label:`Sampling`},{page:`testing-configurator`,label:`Configuration`}]},{id:`docs`,label:`Docs`,subcategories:[{id:`docs-manual-sub`,label:`Manual`,items:[{page:`docs-manual`,label:`Introduction`,hash:`chapter-1-introduction`},{page:`docs-manual`,label:`Installation & Quick Start`,hash:`chapter-2-installation-quick-start`},{page:`docs-manual`,label:`Model Configuration`,hash:`chapter-3-model-configuration`},{page:`docs-manual`,label:`Batch Processing`,hash:`chapter-4-batch-processing`},{page:`docs-manual`,label:`Message Caching`,hash:`chapter-5-message-caching`},{page:`docs-manual`,label:`Speculative Decoding & MTP`,hash:`chapter-6-speculative-decoding-mtp`},{page:`docs-manual`,label:`YaRN Extended Context`,hash:`chapter-7-yarn-extended-context`},{page:`docs-manual`,label:`Model Server`,hash:`chapter-8-model-server`},{page:`docs-manual`,label:`API Endpoints`,hash:`chapter-9-api-endpoints`},{page:`docs-manual`,label:`Request Parameters`,hash:`chapter-10-request-parameters`},{page:`docs-manual`,label:`Multi-Modal Models`,hash:`chapter-11-multi-modal-models`},{page:`docs-manual`,label:`Security & Authentication`,hash:`chapter-12-security-authentication`},{page:`docs-manual`,label:`Browser UI (BUI)`,hash:`chapter-13-browser-ui-bui`},{page:`docs-manual`,label:`Client Integration`,hash:`chapter-14-client-integration`},{page:`docs-manual`,label:`Observability`,hash:`chapter-15-observability`},{page:`docs-manual`,label:`MCP Service`,hash:`chapter-16-mcp-service`},{page:`docs-manual`,label:`Troubleshooting`,hash:`chapter-17-troubleshooting`},{page:`docs-manual`,label:`Bucky (Audio Transcription)`,hash:`chapter-18-bucky-audio-transcription`},{page:`docs-manual`,label:`Malina (Image Generation)`,hash:`chapter-19-malina-image-generation`},{page:`docs-manual`,label:`Developer Guide`,hash:`chapter-20-developer-guide`}]},{id:`docs-sdk`,label:`SDK`,items:[{page:`docs-sdk-kronk`,label:`Kronk`},{page:`docs-sdk-model`,label:`Model`},{page:`docs-sdk-pool`,label:`Pool`},{page:`docs-sdk-bucky`,label:`Bucky`},{page:`docs-sdk-bucky-model`,label:`Bucky Model`},{page:`docs-sdk-malina`,label:`Malina`},{page:`docs-sdk-malina-model`,label:`Malina Model`},{page:`docs-sdk-examples`,label:`Examples`,children:[{page:`docs-sdk-examples`,label:`Agent`,hash:`example-agent`},{page:`docs-sdk-examples`,label:`Audio`,hash:`example-audio`},{page:`docs-sdk-examples`,label:`Bucky`,hash:`example-bucky`},{page:`docs-sdk-examples`,label:`Bucky-Diar`,hash:`example-bucky-diar`},{page:`docs-sdk-examples`,label:`Bucky-Stream`,hash:`example-bucky-stream`},{page:`docs-sdk-examples`,label:`Chat`,hash:`example-chat`},{page:`docs-sdk-examples`,label:`Concurrency`,hash:`example-concurrency`},{page:`docs-sdk-examples`,label:`Decision (Jev-Style)`,hash:`example-decision-jevstyle`},{page:`docs-sdk-examples`,label:`Decision (OpenJEV)`,hash:`example-decision-openjev`},{page:`docs-sdk-examples`,label:`Embedding`,hash:`example-embedding`},{page:`docs-sdk-examples`,label:`Grammar`,hash:`example-grammar`},{page:`docs-sdk-examples`,label:`Malina`,hash:`example-malina`},{page:`docs-sdk-examples`,label:`Malina-Adetailer`,hash:`example-malina-adetailer`},{page:`docs-sdk-examples`,label:`Malina-Animatediff`,hash:`example-malina-animatediff`},{page:`docs-sdk-examples`,label:`Malina-Controlnet`,hash:`example-malina-controlnet`},{page:`docs-sdk-examples`,label:`Malina-Img2img`,hash:`example-malina-img2img`},{page:`docs-sdk-examples`,label:`Malina-S2v`,hash:`example-malina-s2v`},{page:`docs-sdk-examples`,label:`Malina-Sd-Encode`,hash:`example-malina-sd-encode`},{page:`docs-sdk-examples`,label:`Malina-System`,hash:`example-malina-system`},{page:`docs-sdk-examples`,label:`Malina-Upscale`,hash:`example-malina-upscale`},{page:`docs-sdk-examples`,label:`Pool`,hash:`example-pool`},{page:`docs-sdk-examples`,label:`Question`,hash:`example-question`},{page:`docs-sdk-examples`,label:`Rag`,hash:`example-rag`},{page:`docs-sdk-examples`,label:`Rerank`,hash:`example-rerank`},{page:`docs-sdk-examples`,label:`Response`,hash:`example-response`},{page:`docs-sdk-examples`,label:`Session-Store`,hash:`example-session-store`},{page:`docs-sdk-examples`,label:`Vision`,hash:`example-vision`}]}]},{id:`docs-cli-sub`,label:`CLI`,items:[{page:`docs-cli-bucky`,label:`bucky`},{page:`docs-cli-catalog`,label:`catalog`},{page:`docs-cli-completion`,label:`completion`},{page:`docs-cli-devices`,label:`devices`},{page:`docs-cli-diagnose`,label:`diagnose`},{page:`docs-cli-libs`,label:`libs`},{page:`docs-cli-launch`,label:`launch`},{page:`docs-cli-model`,label:`model`},{page:`docs-cli-security`,label:`security`},{page:`docs-cli-server`,label:`server`}]},{id:`docs-api-sub`,label:`Web API`,items:[{page:`docs-api-chat`,label:`Chat`},{page:`docs-api-messages`,label:`Messages`},{page:`docs-api-responses`,label:`Responses`},{page:`docs-api-embeddings`,label:`Embeddings`},{page:`docs-api-rerank`,label:`Rerank`},{page:`docs-api-decision`,label:`Decision`},{page:`docs-api-tokenize`,label:`Tokenize`},{page:`docs-api-tools`,label:`Tools`}]}]}],$i={running:(0,G.jsx)(`svg`,{width:`18`,height:`18`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:(0,G.jsx)(`polyline`,{points:`3 12 7 12 10 4 14 20 17 12 21 12`})}),kronk:(0,G.jsxs)(`svg`,{width:`18`,height:`18`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,G.jsx)(`path`,{d:`M12 2l9 5v10l-9 5-9-5V7z`}),(0,G.jsx)(`path`,{d:`M12 22V12`}),(0,G.jsx)(`path`,{d:`M3 7l9 5 9-5`})]}),bucky:(0,G.jsxs)(`svg`,{width:`18`,height:`18`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,G.jsx)(`rect`,{x:`9`,y:`2`,width:`6`,height:`12`,rx:`3`}),(0,G.jsx)(`path`,{d:`M5 11a7 7 0 0 0 14 0`}),(0,G.jsx)(`line`,{x1:`12`,y1:`18`,x2:`12`,y2:`22`}),(0,G.jsx)(`line`,{x1:`8`,y1:`22`,x2:`16`,y2:`22`})]}),malina:(0,G.jsxs)(`svg`,{width:`18`,height:`18`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,G.jsx)(`rect`,{x:`3`,y:`3`,width:`18`,height:`18`,rx:`2`}),(0,G.jsx)(`circle`,{cx:`8.5`,cy:`8.5`,r:`1.5`}),(0,G.jsx)(`path`,{d:`M21 15l-5-5L5 21`})]}),apps:(0,G.jsxs)(`svg`,{width:`18`,height:`18`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,G.jsx)(`rect`,{x:`3`,y:`3`,width:`7`,height:`7`,rx:`1`}),(0,G.jsx)(`rect`,{x:`14`,y:`3`,width:`7`,height:`7`,rx:`1`}),(0,G.jsx)(`rect`,{x:`3`,y:`14`,width:`7`,height:`7`,rx:`1`}),(0,G.jsx)(`rect`,{x:`14`,y:`14`,width:`7`,height:`7`,rx:`1`})]}),security:(0,G.jsx)(`svg`,{width:`18`,height:`18`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:(0,G.jsx)(`path`,{d:`M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z`})}),docs:(0,G.jsxs)(`svg`,{width:`18`,height:`18`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,G.jsx)(`path`,{d:`M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z`}),(0,G.jsx)(`path`,{d:`M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z`})]}),testing:(0,G.jsxs)(`svg`,{width:`18`,height:`18`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,G.jsx)(`path`,{d:`M9 2h6`}),(0,G.jsx)(`path`,{d:`M10 2v6.5L5 18a2 2 0 0 0 1.8 3h10.4A2 2 0 0 0 19 18l-5-9.5V2`}),(0,G.jsx)(`path`,{d:`M7.5 14h9`})]})};function ea({children:e}){let t=at(),n=ct(),r=Nx[t.pathname]||`home`,[i,a]=(0,x.useState)(new Set),{download:o,isDownloading:s}=zn(),{run:c,isRunning:l,stopRun:u}=Mi(),{activeRun:d,stopActive:f,completedRun:p,dismissCompleted:m}=Ii(),{activeRun:h,stopActive:g,completedRun:_,dismissCompleted:v}=Bi(),{session:y,setSession:b,selectedModel:S,setChatMessages:C}=Ui(),{theme:w,toggleTheme:T}=qi(),{authenticationRequired:E,logout:D}=Zi(),[O,k]=(0,x.useState)(!1),A=async()=>{if(y){k(!0);try{await W.deletePlaygroundSession(y.session_id),b(null),C([])}catch{b(null)}finally{k(!1)}}},[j,M]=(0,x.useState)(()=>{try{return localStorage.getItem(`sidebar-collapsed`)===`true`}catch{return!1}}),N=()=>{M(e=>{let t=!e;try{localStorage.setItem(`sidebar-collapsed`,String(t))}catch{}return t})},P=e=>{if(e.items&&e.items.length>0){let t=e.items[0],n=Mx[t.page];return t.hash?`${n}#${t.hash}`:n}if(e.subcategories)for(let t of e.subcategories){let e=P(t);if(e)return e}return null},F=(()=>{if(!c)return``;if(l)return`Testing...`;switch(c.status){case`completed`:return`Completed`;case`cancelled`:return`Cancelled`;case`error`:return`Failed`;default:return`Testing`}})(),I=(()=>{if(c){if(c.status===`error`&&c.errorMessage)return c.errorMessage;if(l&&c.totalTrials===0)return c.calibrationStatus??c.templateRepairStatus??`Preparing...`;if(c.totalTrials>0)return`Trial ${Math.min(c.currentTrialIndex+ +!!l,c.totalTrials)}/${c.totalTrials}`}})(),L=(()=>{if(!c||!l)return;let e=c.trials.find(e=>e?.status===`running`)?.logEntries;if(e&&e.length>0)return e[e.length-1].message})(),R=(()=>{if(!c||!l||c.totalTrials===0)return;let e=c.trials.filter(e=>e?.startedAt&&e?.finishedAt).length;if(e===0||e>=c.totalTrials)return;let t=c.trials.filter(e=>e?.startedAt&&e?.finishedAt).map(e=>Date.parse(e.finishedAt)-Date.parse(e.startedAt)).filter(e=>Number.isFinite(e)&&e>0);if(t.length===0)return;let n=t.reduce((e,t)=>e+t,0)/t.length,r=Math.max(0,c.totalTrials-e),i=n*r+Hn*r,a=Math.round(i/1e3);if(a<60)return`ETA ~${a}s`;let o=Math.floor(a/60),s=a%60;return o<60?`ETA ~${o}m ${s}s`:`ETA ~${Math.floor(o/60)}h ${o%60}m`})(),z=(()=>{if(!o||!s||!o.progress)return;let{totalBytes:e,currentBytes:t,mbPerSec:n,startedAtMs:r}=o.progress;if((Date.now()-r)/1e3<5||e<=0||t>=e||n<=0)return;let i=(e-t)/(n*1e3*1e3);if(i<60)return`ETA ~${Math.round(i)}s`;let a=Math.floor(i/60),c=Math.round(i%60);return a<60?`ETA ~${a}m ${c}s`:`ETA ~${Math.floor(a/60)}h ${a%60}m`})(),ee=!!c,B=!!o,V=!!d||!!p,te=!!h||!!_,H=!!y,ne=o?.origin===`catalog`?Mx[`catalog-list`]:o?.origin===`bucky`?Mx[`bucky-model-list`]:o?.origin===`malina`?Mx[`malina-model-list`]:Mx[`model-pull`],re=d?d.mode===`manual`?`Accuracy test...`:d.mode===`batch`?`Accuracy batch...`:`Accuracy compare...`:``;(0,x.useEffect)(()=>{let e=(t,n)=>{for(let r of t){if(r.items?.some(e=>e.page===n))return[r.id];if(r.subcategories){let t=e(r.subcategories,n);if(t.length>0)return[r.id,...t]}}return[]},t=e(Qi,r),n=[],i=e=>{if(e)for(let t of e)t.children&&t.page===r&&!t.hash&&n.push(`menu-item:${t.page}`),i(t.children)},o=e=>{for(let t of e)i(t.items),t.subcategories&&o(t.subcategories)};o(Qi),(t.length>0||n.length>0)&&a(e=>{let r=new Set(e);return t.forEach(e=>r.add(e)),n.forEach(e=>r.add(e)),r})},[r]),(0,x.useEffect)(()=>{jn.default.highlightAll()},[r]);let ie=e=>{a(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},ae=e=>e.items?e.items.some(e=>e.page===r):e.subcategories?e.subcategories.some(e=>ae(e)):!1,oe=e=>{let a=Mx[e.page],o=r===e.page&&!e.hash;if(e.children&&e.children.length>0){let t=`menu-item:${e.page}${e.hash?`#${e.hash}`:``}`,r=i.has(t),s=e.hash?`${a}#${e.hash}`:a;return(0,G.jsxs)(`div`,{className:`menu-item-group`,children:[(0,G.jsxs)(`a`,{href:s,onClick:e=>{e.preventDefault(),ie(t),o||n(s)},className:`menu-item menu-item-parent ${o?`active`:``}`,children:[(0,G.jsx)(`span`,{className:`menu-item-label`,children:e.label}),(0,G.jsx)(`span`,{className:`menu-category-arrow ${r?`expanded`:``}`,children:`▶`})]}),(0,G.jsx)(`div`,{className:`menu-items menu-item-children ${r?`expanded`:``}`,children:e.children.map(oe)})]},t)}if(e.hash){let i=r===e.page&&t.hash===`#${e.hash}`;return(0,G.jsx)(`a`,{href:`${a}#${e.hash}`,onClick:t=>{t.preventDefault(),n(`${a}#${e.hash}`)},className:`menu-item ${i?`active`:``}`,children:e.label},`${e.page}-${e.hash}`)}return(0,G.jsx)(vn,{to:a,className:`menu-item ${o?`active`:``}`,children:e.label},e.page)},se=(e,t=!1)=>{let r=i.has(e.id),a=ae(e);return(0,G.jsxs)(`div`,{className:`menu-category ${t?`submenu`:``}`,children:[(0,G.jsxs)(`div`,{className:`menu-category-header ${a?`active`:``}`,onClick:()=>{if(j&&!t){let t=P(e);t&&n(t)}else if(ie(e.id),!r){let t=P(e);t&&n(t)}},title:j?e.label:void 0,children:[!t&&$i[e.id]&&(0,G.jsx)(`span`,{className:`menu-category-icon`,"aria-hidden":`true`,children:$i[e.id]}),(0,G.jsx)(`span`,{className:`menu-category-label`,children:e.label}),(0,G.jsx)(`span`,{className:`menu-category-arrow ${r?`expanded`:``}`,children:`▶`})]}),(0,G.jsxs)(`div`,{className:`menu-items ${r?`expanded`:``}`,...!t&&{"data-label":e.label},children:[e.subcategories?.map(e=>se(e,!0)),e.items?.map(oe)]})]},e.id)};return(0,G.jsxs)(`div`,{className:`app`,children:[(0,G.jsxs)(`aside`,{className:`sidebar ${j?`sidebar-collapsed`:``}`,children:[(0,G.jsx)(`div`,{className:`sidebar-header`,children:(0,G.jsxs)(vn,{to:`/`,style:{textDecoration:`none`,color:`inherit`},className:`sidebar-brand`,children:[(0,G.jsx)(`img`,{src:`/admin/kronk-logo.png`,alt:`Kronk Logo`,className:`sidebar-logo`}),(0,G.jsx)(`h1`,{children:`Model Server`})]})}),(0,G.jsx)(`nav`,{children:Qi.map(e=>se(e))}),(ee||B||V||te||H)&&(0,G.jsxs)(`div`,{className:`sidebar-indicators`,children:[H&&(0,G.jsx)(`div`,{className:`download-indicator`,children:(0,G.jsxs)(`div`,{className:`download-indicator-link autotest-indicator-link`,children:[(0,G.jsxs)(vn,{to:Mx[`testing-basic`],className:`autotest-indicator-top`,children:[(0,G.jsxs)(`div`,{className:`download-indicator-header`,children:[(0,G.jsx)(`span`,{className:`download-indicator-icon success`,children:`●`}),(0,G.jsx)(`span`,{className:`download-indicator-title`,children:`Session running`})]}),(0,G.jsx)(`div`,{className:`download-indicator-url`,title:S,children:S?S.split(`/`).pop():`Basic`})]}),(0,G.jsx)(`button`,{type:`button`,className:`autotest-indicator-stop`,onClick:A,disabled:O,"aria-label":`Unload session`,title:`Unload session`,children:O?`…`:`⏏`})]})}),ee&&(0,G.jsx)(`div`,{className:`download-indicator`,children:(0,G.jsxs)(`div`,{className:`download-indicator-link autotest-indicator-link`,children:[(0,G.jsxs)(vn,{to:Mx[c?.kind===`config`?`testing-configurator`:`testing-sampling`],className:`autotest-indicator-top`,children:[(0,G.jsxs)(`div`,{className:`download-indicator-header`,children:[l?(0,G.jsx)(`span`,{className:`download-indicator-spinner`}):c.status===`completed`?(0,G.jsx)(`span`,{className:`download-indicator-icon success`,children:`✓`}):(0,G.jsx)(`span`,{className:`download-indicator-icon error`,children:`✗`}),(0,G.jsx)(`span`,{className:`download-indicator-title`,children:F})]}),I&&(0,G.jsx)(`div`,{className:`download-indicator-url`,title:I,"aria-live":`polite`,children:I}),L&&(0,G.jsx)(`div`,{className:`autotest-indicator-log`,title:L,children:L}),R&&(0,G.jsx)(`div`,{className:`download-indicator-url`,title:R,children:R})]}),l&&(0,G.jsx)(`button`,{type:`button`,className:`autotest-indicator-stop`,onClick:u,"aria-label":`Stop automated testing`,title:`Stop automated testing`,children:`■`})]})}),B&&(0,G.jsx)(`div`,{className:`download-indicator`,children:(0,G.jsxs)(vn,{to:ne,className:`download-indicator-link`,children:[(0,G.jsxs)(`div`,{className:`download-indicator-header`,children:[s?(0,G.jsx)(`span`,{className:`download-indicator-spinner`}):o.status===`complete`?(0,G.jsx)(`span`,{className:`download-indicator-icon success`,children:`✓`}):(0,G.jsx)(`span`,{className:`download-indicator-icon error`,children:`✗`}),(0,G.jsx)(`span`,{className:`download-indicator-title`,children:s?`Downloading...`:o.status===`complete`?`Complete`:`Failed`})]}),(0,G.jsx)(`div`,{className:`download-indicator-url`,title:o.modelUrl,children:o.modelUrl.split(`/`).pop()}),z&&(0,G.jsx)(`div`,{className:`download-indicator-url`,title:z,children:z})]})}),V&&d&&(0,G.jsx)(`div`,{className:`download-indicator`,children:(0,G.jsxs)(`div`,{className:`download-indicator-link autotest-indicator-link`,children:[(0,G.jsxs)(vn,{to:Mx.accuracy,className:`autotest-indicator-top`,children:[(0,G.jsxs)(`div`,{className:`download-indicator-header`,children:[(0,G.jsx)(`span`,{className:`download-indicator-spinner`}),(0,G.jsx)(`span`,{className:`download-indicator-title`,children:re})]}),(0,G.jsx)(`div`,{className:`download-indicator-url`,title:d.label,children:d.label})]}),(0,G.jsx)(`button`,{type:`button`,className:`autotest-indicator-stop`,onClick:f,"aria-label":`Stop accuracy run`,title:`Stop accuracy run`,children:`■`})]})}),V&&!d&&p&&(0,G.jsx)(`div`,{className:`download-indicator`,children:(0,G.jsxs)(`div`,{className:`download-indicator-link autotest-indicator-link`,children:[(0,G.jsxs)(vn,{to:Mx.accuracy,className:`autotest-indicator-top`,children:[(0,G.jsxs)(`div`,{className:`download-indicator-header`,children:[p.ok?(0,G.jsx)(`span`,{className:`download-indicator-icon success`,children:`✓`}):(0,G.jsx)(`span`,{className:`download-indicator-icon error`,children:`✗`}),(0,G.jsx)(`span`,{className:`download-indicator-title`,children:p.title})]}),(0,G.jsx)(`div`,{className:`download-indicator-url`,title:p.summary,children:p.summary})]}),(0,G.jsx)(`button`,{type:`button`,className:`autotest-indicator-stop`,onClick:m,"aria-label":`Dismiss accuracy result`,title:`Dismiss`,children:`✕`})]})}),te&&h&&(0,G.jsx)(`div`,{className:`download-indicator`,children:(0,G.jsxs)(`div`,{className:`download-indicator-link autotest-indicator-link`,children:[(0,G.jsxs)(vn,{to:Mx.efficiency,className:`autotest-indicator-top`,children:[(0,G.jsxs)(`div`,{className:`download-indicator-header`,children:[(0,G.jsx)(`span`,{className:`download-indicator-spinner`}),(0,G.jsx)(`span`,{className:`download-indicator-title`,children:h.status===`loading`?`Loading model…`:`Efficiency run…`})]}),(0,G.jsx)(`div`,{className:`download-indicator-url`,title:h.model,children:h.model.split(`/`).pop()})]}),(0,G.jsx)(`button`,{type:`button`,className:`autotest-indicator-stop`,onClick:g,"aria-label":`Stop efficiency run`,title:`Stop efficiency run`,children:`■`})]})}),te&&!h&&_&&(0,G.jsx)(`div`,{className:`download-indicator`,children:(0,G.jsxs)(`div`,{className:`download-indicator-link autotest-indicator-link`,children:[(0,G.jsxs)(vn,{to:Mx.efficiency,className:`autotest-indicator-top`,children:[(0,G.jsxs)(`div`,{className:`download-indicator-header`,children:[_.ok?(0,G.jsx)(`span`,{className:`download-indicator-icon success`,children:`✓`}):(0,G.jsx)(`span`,{className:`download-indicator-icon error`,children:`✗`}),(0,G.jsx)(`span`,{className:`download-indicator-title`,children:_.title})]}),(0,G.jsx)(`div`,{className:`download-indicator-url`,title:_.summary,children:_.summary})]}),(0,G.jsx)(`button`,{type:`button`,className:`autotest-indicator-stop`,onClick:v,"aria-label":`Dismiss efficiency result`,title:`Dismiss`,children:`✕`})]})})]}),E&&(0,G.jsx)(`button`,{className:`sidebar-logout`,type:`button`,onClick:()=>void D(),title:`Sign out`,children:`Sign out`}),(0,G.jsx)(`button`,{className:`sidebar-toggle`,onClick:T,"aria-label":w===`light`?`Switch to dark mode`:`Switch to light mode`,title:w===`light`?`Switch to dark mode`:`Switch to light mode`,children:w===`light`?(0,G.jsx)(`svg`,{width:`16`,height:`16`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:(0,G.jsx)(`path`,{d:`M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z`})}):(0,G.jsxs)(`svg`,{width:`16`,height:`16`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,G.jsx)(`circle`,{cx:`12`,cy:`12`,r:`5`}),(0,G.jsx)(`line`,{x1:`12`,y1:`1`,x2:`12`,y2:`3`}),(0,G.jsx)(`line`,{x1:`12`,y1:`21`,x2:`12`,y2:`23`}),(0,G.jsx)(`line`,{x1:`4.22`,y1:`4.22`,x2:`5.64`,y2:`5.64`}),(0,G.jsx)(`line`,{x1:`18.36`,y1:`18.36`,x2:`19.78`,y2:`19.78`}),(0,G.jsx)(`line`,{x1:`1`,y1:`12`,x2:`3`,y2:`12`}),(0,G.jsx)(`line`,{x1:`21`,y1:`12`,x2:`23`,y2:`12`}),(0,G.jsx)(`line`,{x1:`4.22`,y1:`19.78`,x2:`5.64`,y2:`18.36`}),(0,G.jsx)(`line`,{x1:`18.36`,y1:`5.64`,x2:`19.78`,y2:`4.22`})]})}),(0,G.jsx)(`button`,{className:`sidebar-toggle`,onClick:N,"aria-label":j?`Expand sidebar`:`Collapse sidebar`,"aria-expanded":!j,title:j?`Expand sidebar`:`Collapse sidebar`,children:j?(0,G.jsx)(`svg`,{width:`16`,height:`16`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:(0,G.jsx)(`polyline`,{points:`9 18 15 12 9 6`})}):(0,G.jsx)(`svg`,{width:`16`,height:`16`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:(0,G.jsx)(`polyline`,{points:`15 18 9 12 15 6`})})})]}),(0,G.jsx)(`main`,{className:`main-content`,children:e})]})}function J(e){if(e===0)return`0 B`;let t=1024,n=[`B`,`KB`,`MB`,`GB`,`TB`],r=Math.floor(Math.log(e)/Math.log(t));return parseFloat((e/t**r).toFixed(2))+` `+n[r]}function ta(e,t=2){return typeof e==`number`?e.toFixed(t):`—`}function na(e){return e==null?`—`:typeof e==`object`?JSON.stringify(e):String(e)}function ra(e){return e.endsWith(`/AGENT`)?e.slice(0,-6):e}var ia={temperature:`Scales the probability distribution to control randomness. Lower values (e.g. 0.2) make output more focused and deterministic; higher values (e.g. 1.5) increase variety and creativity. Leave empty to use the model default.`,top_p:`Nucleus sampling — samples only from the smallest set of tokens whose cumulative probability reaches this value. Lower values (e.g. 0.5) focus on the most likely tokens; 1.0 effectively disables top-p filtering. Works alongside temperature.`,top_k:`Limits sampling to the top K most probable tokens at each step. Lower values (e.g. 10) make output more predictable; higher values allow more variety. Set very high to approximate no limit. Leave empty to use the model default.`,min_p:`Filters out tokens whose probability is below this fraction of the top token's probability. For example, 0.05 removes tokens less than 5% as likely as the best choice. Higher = stricter filtering. 0 disables.`,repeat_penalty:`Penalizes tokens that appeared in the recent context window (controlled by Repeat Last N). Values above 1.0 discourage repetition; 1.0 means no penalty. Typical range is 1.0–1.3. Too high can make text incoherent.`,repeat_last_n:`How many recent tokens to check when applying the repeat penalty. Larger values look further back for repetitions. To disable repetition penalties, set Repeat Penalty to 1.0 instead.`,frequency_penalty:`Reduces the likelihood of a token proportional to how many times it has appeared. Positive values discourage overused tokens; negative values encourage them. Common range: -2.0 to 2.0. 0 disables.`,presence_penalty:`Applies a flat penalty to any token that has appeared at all, regardless of how often. Positive values encourage the model to use new tokens; negative values favor staying on existing ones. 0 disables.`,dry_multiplier:`Strength of the DRY (Don't Repeat Yourself) anti-repetition penalty. Higher values more aggressively penalize repeated n-gram patterns. Leave empty to use the model default.`,dry_base:`Base for exponential DRY penalty growth. Higher values make the penalty increase faster for longer repeated sequences. Typical values are 1.5–2.0.`,dry_allowed_length:`Minimum n-gram length that DRY penalizes. Repeats of length ≥ this value are penalized; shorter repeats are ignored. Useful for allowing common short phrases. Higher values are more lenient.`,dry_penalty_last_n:`How many recent tokens DRY examines when looking for repeated patterns. Larger values detect repetitions from further back. 0 means use the full context.`,xtc_probability:`Chance of enabling XTC (eXtreme Token Culling) on each token sampling step. When active, XTC removes very high-probability ("obvious") tokens to increase variety. 0 disables XTC entirely, 1 always applies it.`,xtc_threshold:`Probability cutoff for XTC culling. When XTC is active, tokens with probability ≥ this threshold are candidates for removal (with safeguards to keep output coherent). Lower thresholds make XTC more aggressive.`,xtc_min_keep:`Minimum number of token candidates to keep after XTC culling, preventing over-aggressive filtering. Ensures at least this many choices remain available.`,max_tokens:`Maximum number of tokens (word-pieces) to generate. Rule of thumb: 1 token ≈ 0.75 words in English. Output may stop earlier on end-of-sequence or when the context window is full. Higher values allow longer answers but take more time.`,enable_thinking:`Enables reasoning/thinking mode in the prompt template (model-dependent). May improve accuracy on complex tasks but increases token usage and latency. Some models ignore this or keep reasoning internal.`,reasoning_effort:`Requested reasoning level (model/provider dependent): none, minimal, low, medium, high. When omitted, the model template chooses its default. Higher effort may produce more thorough reasoning but uses more tokens and time. Unsupported models ignore this.`,prefillBatchSize:`Maximum prompt tokens contributed by the current prefill owner in one decode iteration. Larger values can reach generation in fewer calls but increase compute-buffer memory and make each call longer for other active slots.`,contextWindow:`Maximum number of tokens (input + output combined) the model can handle at once. Larger windows support longer conversations but increase VRAM usage proportionally via the KV cache. Models with RoPE can extend beyond native context using YaRN (up to ~4× recommended).`,nSeqMax:`Maximum number of concurrent request slots. Each slot handles one user request simultaneously. More slots = better concurrency, but each slot reserves memory for its KV cache.`,flashAttention:`Optimized attention algorithm that reduces VRAM usage and can improve speed. "Enabled" forces it on, "Disabled" forces it off, "Auto" lets the server decide based on model compatibility.`,cacheType:`KV cache precision. f16 = full precision (best quality), q8_0 = 8-bit quantized (less VRAM, minimal quality loss), q4_0 = 4-bit quantized (most VRAM savings, slight quality trade-off especially at long context).`,cacheMode:`Caching strategy. None = clears KV state after each request. IMC (Incremental Message Cache) = keeps the conversation's KV state in a dedicated slot for fast multi-turn follow-ups.`,moeMode:`How to distribute expert weights between GPU and CPU. "Recommended" auto-detects the best option for your hardware. "Save GPU Memory" moves experts to CPU (most common for consumer GPUs). "Maximum Speed" keeps everything on GPU (requires very large VRAM; exact need depends on model, quantization, context, and slots). "Balanced" lets you choose how many layers stay on GPU.`,moeKeepExpertsTopN:`Slide right for more speed (keeps more expert layers on GPU), slide left to save VRAM (offloads to CPU). The highest-numbered layers stay on GPU first. 0 = all experts on CPU.`,moeTipBatch:`For MoE models with CPU experts, a Prefill Batch Size of at least 4096 is recommended for optimal prompt processing speed.`,moeTipFlashAttention:`Flash Attention is strongly recommended for MoE models — it significantly reduces VRAM usage and improves performance.`,moeTipComputeBuffer:`A larger Prefill Batch Size increases compute buffer VRAM usage. Monitor with the VRAM calculator when tuning it.`,availableVRAM:`Total GPU VRAM available (in GB). When set, config candidates estimated to exceed this are auto-skipped before the sweep runs. Set to 0 or leave empty to disable VRAM filtering.`,loadMode:`Controls how model weights are loaded. auto uses mmap when every selected device supports it and otherwise uses ordinary loading; mmap forces memory mapping; none disables it; mlock requests resident pages without forcing mmap; mmap+mlock combines both behaviors; direct-io bypasses the OS page cache where supported.`,numa:`NUMA (Non-Uniform Memory Access) strategy for multi-socket systems. "distribute" spreads memory across NUMA nodes (recommended for MoE CPU-expert setups). "isolate" pins to one node. "numactl" defers to system numactl. "mirror" mirrors across nodes. Leave empty to disable.`,kvCacheOnCPU:`Moves the KV cache from GPU VRAM to system RAM. Frees GPU memory but may reduce generation speed — significant on discrete GPUs (PCIe bottleneck), minimal on Apple Silicon (unified memory).`,gpuCount:`Number of GPUs to distribute the model across. Weights are split between GPUs using tensor parallelism. More GPUs reduce per-GPU VRAM but add inter-GPU communication overhead.`,tensorSplit:`Proportional distribution of model weights across GPUs (e.g. "0.6,0.4" puts 60% on GPU 0 and 40% on GPU 1). Leave empty for equal distribution. Useful when GPUs have different VRAM capacities.`,expertLayersOnGPU:`For MoE models: how many transformer block expert layers to keep on GPU. More layers on GPU = faster inference but more VRAM. Layers are kept top-down (highest-numbered first). 0 = all experts on CPU.`,autoFit:`Finds the fastest layer and expert placement that fits the selected hardware. The calculator changes placement only when you choose this action. On unified-memory systems, CPU offload does not reduce the total physical memory required.`,gpuLayers:`Number of transformer layers offloaded to GPU (-ngl). All layers on GPU gives maximum speed. Reducing layers saves VRAM by moving weights to system RAM at the cost of inference speed — significant on discrete GPUs (PCIe bottleneck), minimal on Apple Silicon (unified memory).`,modelSize:`Total size of the quantized GGUF model file. For dense models this approximates the GPU VRAM needed for weights alone; for MoE models the actual GPU portion depends on how many expert layers are offloaded to CPU.`,blockCount:`Number of transformer blocks (layers) in the model. More layers = larger model. KV cache scales linearly with this value.`,headCountKV:`Number of key-value attention heads. Along with key/value lengths, determines the per-token KV cache size. Some models use fewer KV heads than query heads (grouped-query attention) to save memory.`,keyLength:`Dimension of each attention key vector (in elements). Together with value length and head count, determines the per-token-per-layer KV cache size.`,valueLength:`Dimension of each attention value vector (in elements). Together with key length and head count, determines the per-token-per-layer KV cache size.`,expertCount:`Total number of expert sub-networks in a Mixture-of-Experts model. Only a subset (top-k) are activated per token, but all must be stored in memory.`,activeExperts:`Number of experts activated per token (top-k routing). Fewer active experts = faster inference per token but the full expert set still occupies memory.`,sharedExperts:`Whether the model has shared (always-active) experts in addition to routed ones. Shared experts run on every token and their weights are always loaded on GPU.`,modelWeights:`GPU memory consumed by the model's weight tensors. For dense models this equals the model file size; for MoE models it includes only the always-active weights plus any expert layers kept on GPU.`,alwaysActiveWeights:`Memory for non-expert weights that are always loaded on GPU: embeddings, attention layers, normalization, output head, and any shared experts.`,expertWeightsGPU:`Memory for the expert layers kept on GPU. Increasing "Expert Layers on GPU" moves more expert blocks from CPU to GPU for faster inference at the cost of VRAM.`,expertWeightsCPU:`Memory for expert layers kept in system RAM (CPU-resident). Saves VRAM but typically reduces throughput vs keeping those layers on GPU.`,kvCache:`Total KV cache memory across all slots. Formula: slots × context_window × block_count × head_count_kv × (key_length + value_length) × bytes_per_element.`,kvPerSlot:`KV cache memory for a single inference slot. Each concurrent request gets its own slot with a full KV cache allocation.`,kvPerTokenPerLayer:`KV cache memory for one token in one transformer layer. This is the fundamental unit — total KV = this × context_window × block_count × slots.`,computeBuffer:`Estimated temporary GPU memory for scratch/intermediate tensors during inference. This calculator uses a heuristic based on model size and embedding dimensions; actual usage may vary with backend and batch settings.`,totalEstimatedVRAM:`Sum of model weights on GPU, KV cache (if on GPU), and estimated compute buffer. In multi-GPU setups this is the total across all GPUs — see the per-GPU breakdown for individual allocations. On unified-memory systems, the calculator instead shows the complete shared-memory footprint.`,totalEstimatedSystemRAM:`Estimated system RAM usage from MoE expert weights on CPU and/or KV cache offloaded to system RAM. Does not include OS or application overhead.`,modelArchitecture:`The neural network architecture family (e.g. llama, qwen2, gemma). Determines how the model processes tokens and which optimizations apply.`,sizeLabel:`Human-readable size label from the model publisher (e.g. "8B", "70B"). Indicates the approximate parameter count.`,quantization:`The GGUF quantization format used to compress model weights. Lower-bit formats (Q4) save memory at some quality cost; higher-bit formats (Q8, F16) preserve more quality.`,contextLength:`The native context window the model was trained on. Input + output tokens must fit within this limit unless extended via YaRN/RoPE scaling.`,embeddingDimension:`Size of each token's hidden-state vector. Larger embeddings capture more information per token but increase memory and compute proportionally.`,attentionHeadsQ:`Number of query attention heads. More heads allow the model to attend to different representation subspaces simultaneously. Together with KV heads, determines the attention pattern.`,ropeDimension:`Number of dimensions used for Rotary Position Embeddings (RoPE). Controls how positional information is encoded into attention. Typically equals the head dimension.`,feedForwardLength:`Size of the feed-forward (MLP) intermediate layer in each transformer block. Larger values increase model capacity but also VRAM usage.`,expertFFNLength:`Size of the feed-forward layer inside each MoE expert sub-network. Similar to Feed Forward Length but specific to the routed expert MLPs.`,sharedExpertFFNLength:`Size of the feed-forward layer in shared (always-active) experts. These experts run on every token in addition to the top-k routed experts.`,ssmInnerSize:`Dimension of the inner state in the SSM (State Space Model) layers. Larger values increase the model's recurrent memory capacity.`,ssmStateSize:`Size of the discrete state in SSM layers. Controls how much information the recurrent state can carry between tokens.`,ssmConvKernel:`Convolution kernel width in SSM layers. Determines how many neighboring tokens are mixed in the local convolution before the SSM recurrence.`,ssmTimeStepRank:`Rank of the time-step projection in SSM layers. Controls the expressiveness of the learned discretization step.`,ssmGroupCount:`Number of groups in the SSM layers. Groups partition the state dimensions for more efficient computation, similar to grouped convolution.`,fullAttentionInterval:`In hybrid models, how often a full attention layer appears among SSM layers (e.g. every N layers). Balances the efficiency of SSM with the global context of attention.`,tokenizerModel:`The tokenizer algorithm used (e.g. BPE, SentencePiece, Unigram). Determines how text is split into tokens that the model processes.`,eosTokenId:`End-of-sequence token ID. When the model generates this token, it signals that the response is complete.`,bosTokenId:`Beginning-of-sequence token ID. Prepended to the input to signal the start of a new sequence to the model.`,paddingTokenId:`Padding token ID used to fill sequences to a uniform length in batch processing. Not used during generation.`,nthreads:`Number of CPU threads used for single-token generation. More threads can speed up CPU-bound work but may cause contention on busy systems. 0 or empty = Yzma's hardware-aware default.`,nthreadsBatch:`Number of CPU threads used for prompt processing and other multi-token batches. 0 or empty = Yzma's hardware-aware default.`,cacheTypeK:`Precision format for the key portion of the KV cache. f16 = full precision (best quality), q8_0 = 8-bit quantized (less VRAM, minimal quality loss), q4_0 = 4-bit (most savings).`,cacheTypeV:`Precision format for the value portion of the KV cache. Same options as Cache Type K. Some models benefit from asymmetric K/V quantization.`,cacheMinTokens:`Minimum token count required before cache reuse kicks in. Higher values avoid caching very short prompts; lower values maximize reuse but can consume more memory for small requests.`,imcSessionCapacity:`Number of reusable IMC conversation identities retained by the model. Larger values reduce cache rebuilds across interleaved conversations but can retain more snapshot data in RAM or on disk.`,offloadKQV:`Offloads key/query/value attention operations to GPU. Can improve performance on GPU-backed inference but increases VRAM usage.`,opOffload:`Allows selected host-side tensor operations to be offloaded to GPU during prompt processing. Can improve throughput for large or CPU-heavy workloads.`,projOnCpu:`Forces the multimodal projector (mmproj) onto the CPU regardless of GPU availability. Use this for audio models hit by llama.cpp Metal kernel regressions; the main LLM still runs on GPU.`,projDevice:`Backend device used by the multimodal projector (mmproj), such as CUDA1 or MTL0. Automatic lets the runtime choose. Cannot be combined with proj-on-cpu enabled.`,mainGpu:`Primary GPU index used in multi-GPU configurations. Relevant when using split mode or explicit device placement. Leave empty on single-GPU systems.`,devices:`Explicit list of devices for inference (e.g. CUDA0,CUDA1). Leave empty to let the runtime auto-select.`,ropeFreqScale:`RoPE frequency scale multiplier for context extension. Usually left at the model default unless reproducing a known long-context configuration.`,yarnBetaFast:`YaRN beta-fast parameter for short-range frequency transition behavior. Advanced tuning option; usually leave unset unless matching a known config.`,yarnBetaSlow:`YaRN beta-slow parameter for long-range frequency transition behavior. Advanced tuning option; usually leave unset unless matching a known config.`,draftGpuLayers:`Number of draft-model layers offloaded to GPU. More GPU layers speed up speculative decoding but use more VRAM.`,draftDevice:`Device for running the draft model. Useful in multi-device setups when you want the draft model placed separately from the main model.`,grammar:`Grammar constraint to force output into a specific syntax (e.g. JSON or a custom GBNF grammar). Improves structured output reliability but can over-constrain generation if the grammar is too strict.`,ngpuLayers:`Number of model layers offloaded to GPU. 0 = all layers on GPU (default). -1 = all layers on CPU. Positive N = first N layers on GPU. Lower values save VRAM but reduce speed.`,splitMode:`How model weights are distributed across multiple GPUs. "layer" assigns whole layers per GPU, "row" splits individual tensor rows. "none" uses a single GPU.`,swaFull:`Use full-context KV storage for sliding-window attention (SWA) layers instead of retaining only the model-defined sliding window. This can greatly increase memory at long contexts. It has no effect on models without SWA layers. Default: on.`,incrementalCache:`Keeps the full conversation KV state in a dedicated slot between requests. Enables fast multi-turn follow-ups by only processing new tokens instead of the entire history.`,ropeScaling:`Type of RoPE (Rotary Position Embedding) scaling used to extend the model's context window beyond its native training length. "yarn" is the most common method.`,yarnOrigCtx:`The model's original (native) context length before YaRN extension. YaRN uses this as the baseline to calculate scaling factors. "auto" reads it from the model metadata.`,ropeFreqBase:`Base frequency for RoPE position embeddings. Higher values stretch the positional encoding, allowing longer contexts. Typically set automatically by YaRN configuration.`,yarnExtFactor:`YaRN extension factor controlling how aggressively context is extended. -1 = auto-calculate based on context ratio. Higher values extend more but may reduce quality.`,yarnAttnFactor:`YaRN attention scaling factor that adjusts attention weight magnitude at extended positions. Fine-tunes quality at long context lengths.`,draftModel:`Speculative decoding draft model — a smaller, faster model that proposes candidate tokens which the main model then verifies. Speeds up generation when acceptance rate is high.`,draftTokens:`Number of tokens the draft model proposes per speculative decoding step. More tokens = potentially faster generation, but too many reduces acceptance rate.`,mtpNDraft:`Fixed number of draft tokens per round for the auto-detected MTP head baked into this model. Leave empty to use the default of 3.`,draftMainGpu:`Primary GPU index for the draft model in multi-GPU setups. Leave empty to use the same GPU as the main model.`,draftTensorSplit:`Proportional weight distribution for the draft model across GPUs. Same format as the main model tensor-split.`,tensorBuftOverrides:`Manual tensor buffer type overrides for specific layers. Advanced option for fine-grained control of where individual tensors are placed.`,hasProjection:`Whether the model includes a multi-modal projection file (mmproj). Required for vision or audio input — the projection maps image/audio embeddings into the model's token space.`,validated:`Whether the model has been validated against the Kronk catalog. Validated models have confirmed-working configurations, templates, and recommended settings.`,mtpSource:`How the model supplies its multi-token prediction drafter: embedded in the model GGUF or provided as a separate companion GGUF file.`,budgetPercent:`Percentage of detected GPU VRAM and system RAM the pool is allowed to commit to loaded models. Reservations beyond this percentage trigger eviction of idle models. Default: 80%.`,budgetHeadroom:`Per-GPU safety margin subtracted from each device's budget after the percentage is applied. Reserves a small cushion so the resman never hands out memory that would just-barely OOM under driver/compute-buffer overhead. Default: 256 MB.`,budgetDeviceTotal:`Total physical memory the device reports. For GPUs this is dedicated VRAM; for the System RAM row this is the host's total RAM. On Apple Silicon (unified memory), the GPU shares this same pool.`,budgetDeviceBudget:`How many bytes the resource manager will allow loaded models to consume on this device. Equals (Total × BudgetPercent / 100) − Headroom.`,budgetDeviceUsed:`Currently reserved bytes on this device, summed across all live model reservations.`,budgetDevicePctOfBudget:`Used ÷ Budget. Approaches 100% as more models are kept warm; passing 100% would have triggered eviction first.`,budgetDeviceFree:`Bytes still available within the budget on this device. New models that exceed this trigger eviction of an idle model before loading.`,budgetUsageBar:`Visual scaled to the device's physical Total. Filled segment = currently reserved bytes (green < 60% of Budget, amber 60–85%, red > 85%). The vertical tick marks the Budget cap (Total × BudgetPercent − Headroom). The dim tail to the right of the tick is physical memory the resman intentionally won't hand out — it's reserved for OS/driver overhead and the configured headroom.`,budgetReservationKey:`Cache/reservation key. For catalog loads this is the model ID; playground sessions use modelID/playground/ so each session is tracked separately.`,budgetReservationTotal:`Total bytes the resman has charged for this reservation, summed across VRAM and system memory. This is the number that counts against the overall budget.`,budgetReservationVRAM:`Bytes charged against discrete GPU VRAM budgets. Zero on systems with no GPU and on Apple Silicon unified memory (where the GPU shares the system pool).`,budgetReservationSystem:`Bytes charged against the system-memory budget. On unified-memory systems (Apple Silicon Metal) the entire model footprint is charged here because the GPU and CPU share one physical pool.`,budgetReservationPerDevice:`Per-device byte allocation for this reservation. Populated when the reservation was split across multiple GPUs via tensor-split. Empty (—) when the reservation is on a single device or on system memory.`,budgetReservationUnified:`Bytes charged against the unified memory budget. On Apple Silicon the GPU (Metal) and CPU share a single physical pool, so the resman tracks one combined number instead of splitting VRAM from system memory (which would double-count the same bytes).`,runningModelID:`Cache key for the loaded model. Catalog models use the model ID directly; playground/custom sessions use modelID/playground/.`,runningModelBackend:`Which pool owns this entry. "kronk" is the llama.cpp pool (chat / embed / rerank / vision / audio LLMs); "bucky" is the whisper.cpp pool (speech-to-text via /v1/audio/transcriptions). Both pools share the same resource manager.`,runningModelOwner:`Publisher namespace from the model file path (e.g. unsloth, google, meta-llama).`,runningModelFamily:`Model family / repo name as it appears in the catalog.`,runningModelSize:`On-disk size of the GGUF file(s) backing this model.`,runningModelVRAMTotal:`Predicted total memory footprint computed by CalculateVRAM: model weights + KV cache + estimated compute buffer. Hardware-agnostic — on Apple unified memory this same number lives in system RAM.`,runningModelKVCache:`Memory consumed by the KV cache across all slots at the current context window and slot count.`,runningModelSlots:`Number of parallel sequences (NSeqMax) configured for this model. Each slot can host one in-flight request.`,runningModelExpiresAt:`Wall-clock time at which the pool will idle-evict this model unless it is touched again. Shows Never when pool TTL is 0.`,runningModelActiveStreams:`Number of in-flight chat/embed/rerank streams currently using this model. The pool refuses to evict a model with active streams.`,runningModelStatus:`Lifecycle stage in the pool. "loaded" means the GGUF is open in llama.cpp and the model can serve requests. "loading" means the resource manager has reserved memory for the load but the GGUF is still being SHA-verified and read from disk; the model is not servable yet but the budget already accounts for it.`,slotIteration:`Latest scheduler loop iteration published by this model. It advances while requests are active or waiting.`,slotBatchSizing:`Configured prefill contribution, effective physical micro-batch capacity (NUBatch), and effective logical batch capacity (NBatch) used by the loaded model.`,slotQueue:`Requests in the engine input channel plus requests already drained into the engine that are waiting for a free slot.`,slotPrefillSelector:`Prefill stage 2 decodes the remaining request-owned tokens that were not available in the IMC session. The large value is the active slot; Next always shows the next eligible slot or round-robin cursor; Waiting lists all currently eligible slots.`,slotIMCSelector:`Prefill stage 1 decodes new stable-prefix tokens, such as completed tool calls, to extend an IMC session. The active slot retains ownership until its extension is complete; Next always shows the next eligible slot or round-robin cursor; Waiting lists all slots with extensions to decode.`,slotEligible:`Slot IDs with uncached request-tail tokens waiting for prefill stage 2. They remain listed while generation priority or another stage 2 owner delays their work.`,slotID:`Stable inference slot and llama.cpp sequence index within this loaded model.`,slotPhase:`Current request phase. Prefill stage 1 restores reusable IMC sequence state into the slot. Prefill stage 2 decodes new tokens into that sequence. Generation produces output tokens.`,slotRequest:`Current request identifier. Empty for an idle slot.`,slotAge:`Elapsed wall-clock time since this request entered the slot. Useful for identifying unusually long or stalled work.`,slotPrefillProgress:`Tokens decoded into the slot during prefill stage 2. This includes stable-prefix IMC extensions such as completed tool calls and remaining request-tail tokens.`,slotIMCProgress:`Prefill stage 1 copies reusable sequence state from an IMC session into the slot. This is a state restore, not token decoding, and may complete between screen refreshes.`,slotGeneration:`Generated output-token count plus this slot’s generation mode and row contribution to the latest scheduler iteration.`,slotPastTokens:`Current next position in this slot’s model KV sequence.`,imcModelID:`Cache key for the loaded model that owns this bounded set of Incremental Message Cache entries.`,imcSessionID:`Stable index of this entry in the model's bounded IMC cache pool. It is not an inference slot or a historical request ID.`,imcState:`Current cache-entry state. Active means a request holds the entry; Idle means it contains a reusable snapshot; Empty means it has no cached snapshot.`,imcContext:`Tokens represented by the current working cache. Kronk normally extends this snapshot when the next rendered prompt has the same prefix.`,imcAllocated:`Largest physical context retained by the current working cache. It does not include the System cache allocation.`,imcSnapshotBytes:`Peak backing storage retained by the working cache for its target snapshot, compatible draft snapshot, and saved MTP hidden row. The configured session store determines whether these bytes reside in RAM or elsewhere.`,imcSystemCacheID:`Stable index of this entry in the model's bounded System cache pool.`,imcSystemContext:`Tokens represented by this immutable system-only cache. Kronk can preload a working cache from it when no working cache matches.`,imcSystemAllocated:`Largest token context represented by this System cache entry.`,imcSystemSnapshotBytes:`RAM occupied by the target snapshot, compatible draft snapshot, and saved MTP hidden row.`,imcSystemRestores:`Number of working caches preloaded from this System cache entry.`,imcSystemActiveRestores:`Number of requests currently restoring this entry. An entry in use cannot be replaced.`,imcPeakContext:`All-time largest live context observed for this cache entry across every request, including input and generated output. It may come from an earlier request.`,imcMessages:`Number of complete messages represented by the current working cache.`,imcInputMessages:`Number of messages in the latest completed request. The current snapshot is published during prompt setup, so it can temporarily contain more messages while a newer request is generating.`,imcInputTokens:`Complete input tokens in the latest completed request, including the stable conversation render and generation-template tail. Current tokens can temporarily be larger while a newer request is generating.`,imcOutputTokens:`Reasoning and completion tokens generated by the latest completed request.`,imcRequestTotal:`Total live context reached by the latest completed request: complete input tokens, including the generation-template tail, plus generated output tokens.`,imcRequestUtilization:`Latest completed request input plus output tokens divided by the configured context window.`,imcContextWindow:`Maximum configured context window for the model that owns this entry.`,imcUtilization:`The session's largest observed live context, including generated output, divided by the configured context window.`,imcLastUsed:`Current eviction/LRU timestamp for this cache entry.`,imcMedia:`Whether the retained cache snapshot includes image or audio content.`,bundleArch:`Target CPU architecture for this library bundle download (amd64 or arm64). Each bundle lives in its own folder under the libraries root and does not replace the active install.`,bundleOS:`Target operating system for this library bundle download (linux, bookworm, trixie, darwin, windows). Each bundle lives in its own folder under the libraries root and does not replace the active install.`,bundleProcessor:`Target processor backend for this library bundle download (cpu, cuda, metal, openvino, rocm, vulkan). OpenVINO is a preview backend supported only for Intel CPU, GPU, and NPU targets on published Linux/Windows amd64 combinations. Only published combinations can be chosen.`,bundleVersion:`Exact upstream library version to install. Leave empty to use the version pinned by this Kronk release.`,bundleRemove:`Delete this bundle directory. Does not affect the active install unless this bundle is the active one.`,peerLibsHost:`Address of another Kronk server on the local network in the form ip:port. The peer must be running with download enabled. Useful in workshop environments where Internet access is slow or unavailable.`,peerLibsConnect:`Query the peer Kronk server for the list of library bundles it has installed and is willing to share.`,peerLibsDownload:`Download this library bundle from the peer over the local network. The peer builds a zip on demand on first request, sends it with a sha256 digest for integrity verification, and the zip is unpacked into the matching bundle directory on this server.`,peerKMSHost:`Address of another Kronk server on the local network in the form ip:port. Connect to list the models that peer has downloaded and pull any of them into this server. The peer must be running with the download endpoint enabled.`,translatorModel:`Installed whisper.cpp model to use for this run. Multilingual models (e.g. ggml-large-v3) can transcribe many languages and translate any of them to English. English-only models (filenames containing ".en") only accept English audio and cannot translate.`,translatorSourceLanguage:`Hint for the language spoken in the audio. Leave on "Auto-detect" to let whisper identify the language from the first ~30 seconds. Set explicitly for short clips, heavy accents, or when auto-detect picks the wrong language.`,translatorTranslate:`When on, whisper translates the source audio to English instead of transcribing in the source language. Whisper can only translate to English — no other target languages are supported by the model. Disabled for English-only models.`,translatorPrompt:`Optional text passed to whisper as decoder context. Useful to bias spelling of proper nouns, technical terms, or to provide style/punctuation hints. Keep it short (a sentence or two).`,translatorRealtimeFactor:`Audio duration divided by wall-clock time. A value of 5x means the run processed 5 seconds of audio per second of real time. Higher is faster.`,translatorNoSpeechProb:`Whisper's estimated probability that this segment contains no speech. Values close to 1 typically indicate silence or background noise.`,imageGeneratorModel:`Installed Malina stable-diffusion model bundle used to generate the image.`,imageGeneratorMode:`Text to image creates an image from the prompt alone. Image to image uses an uploaded PNG or JPEG as the starting composition.`,imageGeneratorPrompt:`Text description of the image to generate. Include the subject, setting, composition, lighting, and style details that matter.`,imageGeneratorSource:`PNG or JPEG used as the starting image. It is resized to the selected output dimensions before generation.`,imageGeneratorNegativePrompt:`Features to discourage in the generated image, such as blur, artifacts, or unwanted objects.`,imageGeneratorSize:`Output dimensions. Automatic uses 512×512 for text generation and preserves the uploaded image aspect ratio for image-to-image generation.`,imageGeneratorSteps:`Number of denoising iterations. More steps can improve detail but increase generation time. The model default is 20.`,imageGeneratorCFGScale:`How strongly generation follows the prompt. Higher values adhere more closely but can reduce natural variation. The model default is 7.`,imageGeneratorSeed:`Positive values reproduce a result. Values of 0 or below choose a random seed for each generation.`,imageGeneratorStrength:`How much the generated result may depart from the uploaded image. Lower values preserve more of the source; 1 allows the largest transformation.`,decisionModel:`Decision-capable model from the catalog. It must be downloaded and pass integrity validation before it can evaluate questions.`,decisionState:`The customer message included in the shared state evaluated by every question.`,decisionAccountTier:`Account tier included in the shared state. Change it to see whether customer context affects the answers.`};function aa(e){let t=e.tooltipKey?ia[e.tooltipKey]:e.text,n=(0,x.useRef)(null),r=(0,x.useRef)(null),i=(0,x.useCallback)(()=>{let e=n.current,t=r.current;if(!e||!t)return;let i=e.getBoundingClientRect(),a=t.offsetWidth,o=t.offsetHeight,s=i.top-o-8,c=i.left,l=c+a-window.innerWidth+8;l>0&&(c-=l),c<8&&(c=8),t.style.left=`${c}px`,t.style.top=`${s}px`;let u=Math.max(10,Math.min(a-10,i.left-c+i.width/2));t.style.setProperty(`--arrow-left`,`${u}px`)},[]);return(0,G.jsxs)(`span`,{className:`param-tooltip-wrapper`,ref:n,onMouseEnter:i,children:[(0,G.jsx)(`span`,{className:`param-tooltip-icon`,children:`ⓘ`}),(0,G.jsx)(`span`,{className:`param-tooltip-text`,ref:r,children:t})]})}function Y(e,t){return(0,G.jsxs)(G.Fragment,{children:[e,` `,(0,G.jsx)(aa,{tooltipKey:t})]})}function X({children:e,tooltipKey:t,after:n,...r}){return(0,G.jsxs)(`label`,{...r,children:[e,t&&(0,G.jsx)(aa,{tooltipKey:t}),n]})}function oa(e){return e>=1e6?`${+(e/1e6).toFixed(1)}M`:e>=1e3?`${+(e/1e3).toFixed(1)}K`:e.toLocaleString()}function sa(e){if(!e)return null;let t=e[`general.architecture`]||``;if(!t)return null;let n=e[`${t}.context_length`];if(!n)return null;let r=Number(n);if(isNaN(r)||r<=0)return null;let i=e[`${t}.rope.dimension_count`]!==void 0||e[`${t}.rope.freq_base`]!==void 0;return{native:r,max:i?r*4:r,hasRoPE:i}}function ca(e){let t=oa(e.native);return!e.hasRoPE||e.max<=e.native?`Context: ${t}`:`Context: ${t} (Max ~${oa(e.max)} via YaRN)`}function la({rows:e}){return e.length===0?null:(0,G.jsx)(`dl`,{className:`kv-table`,children:e.map((e,t)=>(0,G.jsxs)(`div`,{className:`kv-row`,children:[(0,G.jsx)(`dt`,{className:`kv-label`,children:e.label}),(0,G.jsx)(`dd`,{className:`kv-value`,children:e.value})]},e.key??t))})}function ua(e){return e.split(` `).filter(Boolean).map(e=>e.length<=2?e.toUpperCase():e[0].toUpperCase()+e.slice(1)).join(` `)}function da(e,t){return ua((t.startsWith(e+`.`)?t.slice(e.length+1):t).replace(/[._]/g,` `).replace(/\s+/g,` `).trim())}function fa(e){let t={};for(let[n,r]of Object.entries(e)){let e=n.includes(`.`)?n.split(`.`)[0]:`other`;(t[e]||=[]).push([n,r])}let n=e=>e===`general`?0:e===`tokenizer`?1:10;return Object.entries(t).sort(([e],[t])=>n(e)-n(t)||e.localeCompare(t)).map(([e,t])=>({prefix:e,entries:t.sort(([e],[t])=>e.localeCompare(t))}))}function pa({metadata:e,excludeKeys:t=[]}){let n=fa(Object.fromEntries(Object.entries(e).filter(([e])=>!t.includes(e))));return n.length===0?(0,G.jsx)(`div`,{className:`empty-state`,children:(0,G.jsx)(`p`,{children:`No metadata available for this model.`})}):(0,G.jsx)(`div`,{className:`meta-sections`,children:n.map(e=>{let t=e.entries.map(([t,n])=>({key:t,label:da(e.prefix,t),value:na(n)}));return(0,G.jsxs)(`section`,{className:`meta-section`,children:[(0,G.jsx)(`div`,{className:`meta-section-header`,children:(0,G.jsx)(`h4`,{className:`meta-section-title`,children:ua(e.prefix)})}),(0,G.jsx)(la,{rows:t})]},e.prefix)})})}var ma={0:`All F32`,1:`Mostly F16`,2:`Mostly Q4_0`,3:`Mostly Q4_1`,7:`Mostly Q8_0`,8:`Mostly Q5_0`,9:`Mostly Q5_1`,10:`Mostly Q2_K`,11:`Mostly Q3_K_S`,12:`Mostly Q3_K_M`,13:`Mostly Q3_K_L`,14:`Mostly Q4_K_S`,15:`Mostly Q4_K_M`,16:`Mostly Q5_K_S`,17:`Mostly Q5_K_M`,18:`Mostly Q6_K`,19:`Mostly IQ2_XXS`,20:`Mostly IQ2_XS`,21:`Mostly Q2_K_S`,22:`Mostly IQ3_XS`,23:`Mostly IQ3_XXS`,24:`Mostly IQ1_S`,25:`Mostly IQ4_NL`,26:`Mostly IQ3_S`,27:`Mostly IQ3_M`,28:`Mostly IQ2_S`,29:`Mostly IQ2_M`,30:`Mostly IQ4_XS`,31:`Mostly IQ1_M`,32:`Mostly BF16`,36:`Mostly TQ1_0`,37:`Mostly TQ2_0`,38:`Mostly MXFP4_MOE`,39:`Mostly NVFP4`,40:`Mostly Q1_0`,41:`Mostly Q2_0`};function ha(e){let t=Number(e);return isNaN(t)?e:t.toLocaleString()}function ga(e){return e>=1e6?`${+(e/1e6).toFixed(1)}M`:e>=1e3?`${+(e/1e3).toFixed(1)}K`:e.toLocaleString()}function _a(e){return ma[e]||`File Type ${e}`}function va({metadata:e,excludeKeys:t=[],quantization:n,webPage:r}){let i=[...t,`tokenizer.chat_template`],a=Object.keys(e).length>0;if(!a&&!n&&!r)return(0,G.jsx)(`div`,{className:`empty-state`,children:(0,G.jsx)(`p`,{children:`No metadata available for this model.`})});let o=t=>e[t],s=o(`general.architecture`)||``;function c(e){return e.filter(([,e])=>o(e)!==void 0).map(([e,t,n])=>({key:t,label:n?Y(e,n):e,value:na(o(t))}))}let l=c([[`Name`,`general.name`],[`Architecture`,`general.architecture`,`modelArchitecture`],[`Size Label`,`general.size_label`,`sizeLabel`],[`Tags`,`general.tags`]]),u=o(`general.file_type`),d=n||(u===void 0?``:_a(u));d&&l.push({key:`general.file_type`,label:Y(`Quantization`,`quantization`),value:d});let f=o(`general.quantized_by`);f!==void 0&&l.push({key:`general.quantized_by`,label:`Quantized By`,value:na(f)});let p=o(`general.license`)||o(`general.license.link`);p!==void 0&&l.push({key:`general.license`,label:`License`,value:na(p)});let m=c([[`Layers`,`${s}.block_count`,`blockCount`],[`Context Length`,`${s}.context_length`,`contextLength`],[`Embedding Dimension`,`${s}.embedding_length`,`embeddingDimension`],[`Attention Heads (Q)`,`${s}.attention.head_count`,`attentionHeadsQ`],[`Attention Heads (KV)`,`${s}.attention.head_count_kv`,`headCountKV`],[`Key Length`,`${s}.attention.key_length`,`keyLength`],[`Value Length`,`${s}.attention.value_length`,`valueLength`],[`RoPE Dimension`,`${s}.rope.dimension_count`,`ropeDimension`],[`RoPE Freq Base`,`${s}.rope.freq_base`,`ropeFreqBase`],[`Feed Forward Length`,`${s}.feed_forward_length`,`feedForwardLength`]]),h=o(`${s}.context_length`);if(h!==void 0){let e=m.findIndex(e=>e.key===`${s}.context_length`);if(e>=0){let t=Number(h),n=ha(h);if(!isNaN(t)&&t>=1e3){if(n+=` (${ga(t)}`,o(`${s}.rope.dimension_count`)!==void 0||o(`${s}.rope.freq_base`)!==void 0){let e=t*4;n+=`, max ~${ga(e)} via YaRN`}n+=`)`}m[e]={...m[e],value:n}}}let g=o(`${s}.rope.freq_base`);if(g!==void 0){let e=m.findIndex(e=>e.key===`${s}.rope.freq_base`);e>=0&&(m[e]={...m[e],value:ha(g)})}let _=o(`${s}.expert_count`)===void 0?[]:c([[`Expert Count`,`${s}.expert_count`,`expertCount`],[`Experts Used`,`${s}.expert_used_count`,`activeExperts`],[`Expert FFN Length`,`${s}.expert_feed_forward_length`,`expertFFNLength`],[`Shared Expert FFN Length`,`${s}.expert_shared_feed_forward_length`,`sharedExpertFFNLength`]]),v=o(`${s}.ssm.inner_size`)===void 0?[]:c([[`SSM Inner Size`,`${s}.ssm.inner_size`,`ssmInnerSize`],[`SSM State Size`,`${s}.ssm.state_size`,`ssmStateSize`],[`SSM Conv Kernel`,`${s}.ssm.conv_kernel`,`ssmConvKernel`],[`SSM Time Step Rank`,`${s}.ssm.time_step_rank`,`ssmTimeStepRank`],[`SSM Group Count`,`${s}.ssm.group_count`,`ssmGroupCount`],[`Full Attention Interval`,`${s}.full_attention_interval`,`fullAttentionInterval`]]),y=c([[`Model`,`tokenizer.ggml.model`,`tokenizerModel`],[`EOS Token ID`,`tokenizer.ggml.eos_token_id`,`eosTokenId`],[`BOS Token ID`,`tokenizer.ggml.bos_token_id`,`bosTokenId`],[`Padding Token ID`,`tokenizer.ggml.padding_token_id`,`paddingTokenId`]]),b=[{title:`Identity`,rows:l},{title:`Architecture`,rows:m}];return _.length>0&&b.push({title:`Mixture of Experts`,rows:_}),v.length>0&&b.push({title:`Hybrid / SSM`,rows:v}),y.length>0&&b.push({title:`Tokenizer`,rows:y}),(0,G.jsxs)(G.Fragment,{children:[r&&(0,G.jsxs)(`div`,{style:{marginBottom:`16px`},children:[(0,G.jsx)(`h4`,{className:`meta-section-title`,style:{marginBottom:`8px`},children:`Source`}),(0,G.jsx)(`p`,{children:(0,G.jsx)(`a`,{href:r,target:`_blank`,rel:`noopener noreferrer`,children:r})})]}),a&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`div`,{className:`meta-sections`,children:b.filter(e=>e.rows.length>0).map(e=>(0,G.jsxs)(`section`,{className:`meta-section`,children:[(0,G.jsx)(`div`,{className:`meta-section-header`,children:(0,G.jsx)(`h4`,{className:`meta-section-title`,children:e.title})}),(0,G.jsx)(la,{rows:e.rows})]},e.title))}),(0,G.jsxs)(`details`,{className:`model-card-raw-toggle`,children:[(0,G.jsx)(`summary`,{children:`Advanced / Raw Metadata`}),(0,G.jsx)(pa,{metadata:e,excludeKeys:i})]})]})]})}Prism.languages.go=Prism.languages.extend(`clike`,{string:{pattern:/(^|[^\\])"(?:\\.|[^"\\\r\n])*"|`[^`]*`/,lookbehind:!0,greedy:!0},keyword:/\b(?:break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(?:to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/,boolean:/\b(?:_|false|iota|nil|true)\b/,number:[/\b0(?:b[01_]+|o[0-7_]+)i?\b/i,/\b0x(?:[a-f\d_]+(?:\.[a-f\d_]*)?|\.[a-f\d_]+)(?:p[+-]?\d+(?:_\d+)*)?i?(?!\w)/i,/(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?[\d_]+)?i?(?!\w)/i],operator:/[*\/%^!=]=?|\+[=+]?|-[=-]?|\|[=|]?|&(?:=|&|\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\.\.\./,builtin:/\b(?:append|bool|byte|cap|close|complex|complex(?:64|128)|copy|delete|error|float(?:32|64)|u?int(?:8|16|32|64)?|imag|len|make|new|panic|print(?:ln)?|real|recover|rune|string|uintptr)\b/}),Prism.languages.insertBefore(`go`,`string`,{char:{pattern:/'(?:\\.|[^'\\\r\n]){0,10}'/,greedy:!0}}),delete Prism.languages.go[`class-name`],Prism.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0,greedy:!0},"string-interpolation":{pattern:/(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,lookbehind:!0,inside:{"format-spec":{pattern:/(:)[^:(){}]+(?=\}$)/,lookbehind:!0},"conversion-option":{pattern://,alias:`punctuation`},rest:null}},string:/[\s\S]+/}},"triple-quoted-string":{pattern:/(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i,greedy:!0,alias:`string`},string:{pattern:/(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,greedy:!0},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)\w+/i,lookbehind:!0},decorator:{pattern:/(^[\t ]*)@\w+(?:\.\w+)*/m,lookbehind:!0,alias:[`annotation`,`punctuation`],inside:{punctuation:/\./}},keyword:/\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,builtin:/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,boolean:/\b(?:False|None|True)\b/,number:/\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i,operator:/[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},Prism.languages.python[`string-interpolation`].inside.interpolation.inside.rest=Prism.languages.python,Prism.languages.py=Prism.languages.python,Prism.languages.javascript=Prism.languages.extend(`clike`,{"class-name":[Prism.languages.clike[`class-name`],{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\})\s*)catch\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],function:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,number:{pattern:RegExp(`(^|[^\\w$])(?:NaN|Infinity|0[bB][01]+(?:_[01]+)*n?|0[oO][0-7]+(?:_[0-7]+)*n?|0[xX][\\dA-Fa-f]+(?:_[\\dA-Fa-f]+)*n?|\\d+(?:_\\d+)*n|(?:\\d+(?:_\\d+)*(?:\\.(?:\\d+(?:_\\d+)*)?)?|\\.\\d+(?:_\\d+)*)(?:[Ee][+-]?\\d+(?:_\\d+)*)?)(?![\\w$])`),lookbehind:!0},operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),Prism.languages.javascript[`class-name`][0].pattern=/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/,Prism.languages.insertBefore(`javascript`,`keyword`,{regex:{pattern:RegExp(`((?:^|[^$\\w\\xA0-\\uFFFF."'\\])\\s]|\\b(?:return|yield))\\s*)\\/(?:(?:\\[(?:[^\\]\\\\\\r\\n]|\\\\.)*\\]|\\\\.|[^/\\\\\\[\\r\\n])+\\/[dgimyus]{0,7}|(?:\\[(?:[^[\\]\\\\\\r\\n]|\\\\.|\\[(?:[^[\\]\\\\\\r\\n]|\\\\.|\\[(?:[^[\\]\\\\\\r\\n]|\\\\.)*\\])*\\])*\\]|\\\\.|[^/\\\\\\[\\r\\n])+\\/[dgimyus]{0,7}v[dgimyus]{0,7})(?=(?:\\s|\\/\\*(?:[^*]|\\*(?!\\/))*\\*\\/)*(?:$|[\\r\\n,.;:})\\]]|\\/\\/))`),lookbehind:!0,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:`language-regex`,inside:Prism.languages.regex},"regex-delimiter":/^\/|\/$/,"regex-flags":/^[a-z]+$/}},"function-variable":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,alias:`function`},parameter:[{pattern:/(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,lookbehind:!0,inside:Prism.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),Prism.languages.insertBefore(`javascript`,`string`,{hashbang:{pattern:/^#!.*/,greedy:!0,alias:`comment`},"template-string":{pattern:/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:`string`},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:`punctuation`},rest:Prism.languages.javascript}},string:/[\s\S]+/}},"string-property":{pattern:/((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,lookbehind:!0,greedy:!0,alias:`property`}}),Prism.languages.insertBefore(`javascript`,`operator`,{"literal-property":{pattern:/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,lookbehind:!0,alias:`property`}}),Prism.languages.markup&&(Prism.languages.markup.tag.addInlined(`script`,`javascript`),Prism.languages.markup.tag.addAttribute(`on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)`,`javascript`)),Prism.languages.js=Prism.languages.javascript,(function(e){e.languages.typescript=e.languages.extend(`javascript`,{"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|type)\s+)(?!keyof\b)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?:\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>)?/,lookbehind:!0,greedy:!0,inside:null},builtin:/\b(?:Array|Function|Promise|any|boolean|console|never|number|string|symbol|unknown)\b/}),e.languages.typescript.keyword.push(/\b(?:abstract|declare|is|keyof|readonly|require)\b/,/\b(?:asserts|infer|interface|module|namespace|type)\b(?=\s*(?:[{_$a-zA-Z\xA0-\uFFFF]|$))/,/\btype\b(?=\s*(?:[\{*]|$))/),delete e.languages.typescript.parameter,delete e.languages.typescript[`literal-property`];var t=e.languages.extend(`typescript`,{});delete t[`class-name`],e.languages.typescript[`class-name`].inside=t,e.languages.insertBefore(`typescript`,`function`,{decorator:{pattern:/@[$\w\xA0-\uFFFF]+/,inside:{at:{pattern:/^@/,alias:`operator`},function:/^[\s\S]+/}},"generic-function":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,greedy:!0,inside:{function:/^#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/,generic:{pattern:/<[\s\S]+/,alias:`class-name`,inside:t}}}}),e.languages.ts=e.languages.typescript})(Prism),(function(e){for(var t=`\\/\\*(?:[^*/]|\\*(?!\\/)|\\/(?!\\*)|)*\\*\\/`,n=0;n<2;n++)t=t.replace(//g,function(){return t});t=t.replace(//g,function(){return`[^\\s\\S]`}),e.languages.rust={comment:[{pattern:RegExp(`(^|[^\\\\])`+t),lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/b?"(?:\\[\s\S]|[^\\"])*"|b?r(#*)"(?:[^"]|"(?!\1))*"\1/,greedy:!0},char:{pattern:/b?'(?:\\(?:x[0-7][\da-fA-F]|u\{(?:[\da-fA-F]_*){1,6}\}|.)|[^\\\r\n\t'])'/,greedy:!0},attribute:{pattern:/#!?\[(?:[^\[\]"]|"(?:\\[\s\S]|[^\\"])*")*\]/,greedy:!0,alias:`attr-name`,inside:{string:null}},"closure-params":{pattern:/([=(,:]\s*|\bmove\s*)\|[^|]*\||\|[^|]*\|(?=\s*(?:\{|->))/,lookbehind:!0,greedy:!0,inside:{"closure-punctuation":{pattern:/^\||\|$/,alias:`punctuation`},rest:null}},"lifetime-annotation":{pattern:/'\w+/,alias:`symbol`},"fragment-specifier":{pattern:/(\$\w+:)[a-z]+/,lookbehind:!0,alias:`punctuation`},variable:/\$\w+/,"function-definition":{pattern:/(\bfn\s+)\w+/,lookbehind:!0,alias:`function`},"type-definition":{pattern:/(\b(?:enum|struct|trait|type|union)\s+)\w+/,lookbehind:!0,alias:`class-name`},"module-declaration":[{pattern:/(\b(?:crate|mod)\s+)[a-z][a-z_\d]*/,lookbehind:!0,alias:`namespace`},{pattern:/(\b(?:crate|self|super)\s*)::\s*[a-z][a-z_\d]*\b(?:\s*::(?:\s*[a-z][a-z_\d]*\s*::)*)?/,lookbehind:!0,alias:`namespace`,inside:{punctuation:/::/}}],keyword:[/\b(?:Self|abstract|as|async|await|become|box|break|const|continue|crate|do|dyn|else|enum|extern|final|fn|for|if|impl|in|let|loop|macro|match|mod|move|mut|override|priv|pub|ref|return|self|static|struct|super|trait|try|type|typeof|union|unsafe|unsized|use|virtual|where|while|yield)\b/,/\b(?:bool|char|f(?:32|64)|[ui](?:8|16|32|64|128|size)|str)\b/],function:/\b[a-z_]\w*(?=\s*(?:::\s*<|\())/,macro:{pattern:/\b\w+!/,alias:`property`},constant:/\b[A-Z_][A-Z_\d]+\b/,"class-name":/\b[A-Z]\w*\b/,namespace:{pattern:/(?:\b[a-z][a-z_\d]*\s*::\s*)*\b[a-z][a-z_\d]*\s*::(?!\s*<)/,inside:{punctuation:/::/}},number:/\b(?:0x[\dA-Fa-f](?:_?[\dA-Fa-f])*|0o[0-7](?:_?[0-7])*|0b[01](?:_?[01])*|(?:(?:\d(?:_?\d)*)?\.)?\d(?:_?\d)*(?:[Ee][+-]?\d+)?)(?:_?(?:f32|f64|[iu](?:8|16|32|64|size)?))?\b/,boolean:/\b(?:false|true)\b/,punctuation:/->|\.\.=|\.{1,3}|::|[{}[\];(),:]/,operator:/[-+*\/%!^]=?|=[=>]?|&[&=]?|\|[|=]?|<=?|>>?=?|[@?]/},e.languages.rust[`closure-params`].inside.rest=e.languages.rust,e.languages.rust.attribute.inside.string=e.languages.rust.string})(Prism),Prism.languages.sql={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|(?:--|\/\/|#).*)/,lookbehind:!0},variable:[{pattern:/@(["'`])(?:\\[\s\S]|(?!\1)[^\\])+\1/,greedy:!0},/@[\w.$]+/],string:{pattern:/(^|[^@\\])("|')(?:\\[\s\S]|(?!\2)[^\\]|\2\2)*\2/,greedy:!0,lookbehind:!0},identifier:{pattern:/(^|[^@\\])`(?:\\[\s\S]|[^`\\]|``)*`/,greedy:!0,lookbehind:!0,inside:{punctuation:/^`|`$/}},function:/\b(?:AVG|COUNT|FIRST|FORMAT|LAST|LCASE|LEN|MAX|MID|MIN|MOD|NOW|ROUND|SUM|UCASE)(?=\s*\()/i,keyword:/\b(?:ACTION|ADD|AFTER|ALGORITHM|ALL|ALTER|ANALYZE|ANY|APPLY|AS|ASC|AUTHORIZATION|AUTO_INCREMENT|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADED?|CASE|CHAIN|CHAR(?:ACTER|SET)?|CHECK(?:POINT)?|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMNS?|COMMENT|COMMIT(?:TED)?|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS(?:TABLE)?|CONTINUE|CONVERT|CREATE|CROSS|CURRENT(?:_DATE|_TIME|_TIMESTAMP|_USER)?|CURSOR|CYCLE|DATA(?:BASES?)?|DATE(?:TIME)?|DAY|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DELIMITERS?|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DROP|DUMMY|DUMP(?:FILE)?|DUPLICATE|ELSE(?:IF)?|ENABLE|ENCLOSED|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPED?|EXCEPT|EXEC(?:UTE)?|EXISTS|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR(?: EACH ROW)?|FORCE|FOREIGN|FREETEXT(?:TABLE)?|FROM|FULL|FUNCTION|GEOMETRY(?:COLLECTION)?|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|HOUR|IDENTITY(?:COL|_INSERT)?|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTERVAL|INTO|INVOKER|ISOLATION|ITERATE|JOIN|KEYS?|KILL|LANGUAGE|LAST|LEAVE|LEFT|LEVEL|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONG(?:BLOB|TEXT)|LOOP|MATCH(?:ED)?|MEDIUM(?:BLOB|INT|TEXT)|MERGE|MIDDLEINT|MINUTE|MODE|MODIFIES|MODIFY|MONTH|MULTI(?:LINESTRING|POINT|POLYGON)|NATIONAL|NATURAL|NCHAR|NEXT|NO|NONCLUSTERED|NULLIF|NUMERIC|OFF?|OFFSETS?|ON|OPEN(?:DATASOURCE|QUERY|ROWSET)?|OPTIMIZE|OPTION(?:ALLY)?|ORDER|OUT(?:ER|FILE)?|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREPARE|PREV|PRIMARY|PRINT|PRIVILEGES|PROC(?:EDURE)?|PUBLIC|PURGE|QUICK|RAISERROR|READS?|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEAT(?:ABLE)?|REPLACE|REPLICATION|REQUIRE|RESIGNAL|RESTORE|RESTRICT|RETURN(?:ING|S)?|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROW(?:COUNT|GUIDCOL|S)?|RTREE|RULE|SAVE(?:POINT)?|SCHEMA|SECOND|SELECT|SERIAL(?:IZABLE)?|SESSION(?:_USER)?|SET(?:USER)?|SHARE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|SQL|START(?:ING)?|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLES?|TABLESPACE|TEMP(?:ORARY|TABLE)?|TERMINATED|TEXT(?:SIZE)?|THEN|TIME(?:STAMP)?|TINY(?:BLOB|INT|TEXT)|TOP?|TRAN(?:SACTIONS?)?|TRIGGER|TRUNCATE|TSEQUAL|TYPES?|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNIQUE|UNLOCK|UNPIVOT|UNSIGNED|UPDATE(?:TEXT)?|USAGE|USE|USER|USING|VALUES?|VAR(?:BINARY|CHAR|CHARACTER|YING)|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH(?: ROLLUP|IN)?|WORK|WRITE(?:TEXT)?|YEAR)\b/i,boolean:/\b(?:FALSE|NULL|TRUE)\b/i,number:/\b0x[\da-f]+\b|\b\d+(?:\.\d*)?|\B\.\d+\b/i,operator:/[-+*\/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|DIV|ILIKE|IN|IS|LIKE|NOT|OR|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i,punctuation:/[;[\]()`,.]/},Prism.languages.json={property:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?=\s*:)/,lookbehind:!0,greedy:!0},string:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?!\s*:)/,lookbehind:!0,greedy:!0},comment:{pattern:/\/\/.*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},number:/-?\b\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,punctuation:/[{}[\],]/,operator:/:/,boolean:/\b(?:false|true)\b/,null:{pattern:/\bnull\b/,alias:`keyword`}},Prism.languages.webmanifest=Prism.languages.json,(function(e){var t=/[*&][^\s[\]{},]+/,n=/!(?:<[\w\-%#;/?:@&=+$,.!~*'()[\]]+>|(?:[a-zA-Z\d-]*!)?[\w\-%#;/?:@&=+$.~*'()]+)?/,r=`(?:`+n.source+`(?:[ ]+`+t.source+`)?|`+t.source+`(?:[ ]+`+n.source+`)?)`,i=`(?:[^\\s\\x00-\\x08\\x0e-\\x1f!"#%&'*,\\-:>?@[\\]\`{|}\\x7f-\\x84\\x86-\\x9f\\ud800-\\udfff\\ufffe\\uffff]|[?:-])(?:[ \\t]*(?:(?![#:])|:))*`.replace(//g,function(){return`[^\\s\\x00-\\x08\\x0e-\\x1f,[\\]{}\\x7f-\\x84\\x86-\\x9f\\ud800-\\udfff\\ufffe\\uffff]`}),a=`"(?:[^"\\\\\\r\\n]|\\\\.)*"|'(?:[^'\\\\\\r\\n]|\\\\.)*'`;function o(e,t){t=(t||``).replace(/m/g,``)+`m`;var n=`([:\\-,[{]\\s*(?:\\s<>[ \\t]+)?)(?:<>)(?=[ \\t]*(?:$|,|\\]|\\}|(?:[\\r\\n]\\s*)?#))`.replace(/<>/g,function(){return r}).replace(/<>/g,function(){return e});return RegExp(n,t)}e.languages.yaml={scalar:{pattern:RegExp(`([\\-:]\\s*(?:\\s<>[ \\t]+)?[|>])[ \\t]*(?:((?:\\r?\\n|\\r)[ \\t]+)\\S[^\\r\\n]*(?:\\2[^\\r\\n]+)*)`.replace(/<>/g,function(){return r})),lookbehind:!0,alias:`string`},comment:/#.*/,key:{pattern:RegExp(`((?:^|[:\\-,[{\\r\\n?])[ \\t]*(?:<>[ \\t]+)?)<>(?=\\s*:\\s)`.replace(/<>/g,function(){return r}).replace(/<>/g,function(){return`(?:`+i+`|`+a+`)`})),lookbehind:!0,greedy:!0,alias:`atrule`},directive:{pattern:/(^[ \t]*)%.+/m,lookbehind:!0,alias:`important`},datetime:{pattern:o(`\\d{4}-\\d\\d?-\\d\\d?(?:[tT]|[ \\t]+)\\d\\d?:\\d{2}:\\d{2}(?:\\.\\d*)?(?:[ \\t]*(?:Z|[-+]\\d\\d?(?::\\d{2})?))?|\\d{4}-\\d{2}-\\d{2}|\\d\\d?:\\d{2}(?::\\d{2}(?:\\.\\d*)?)?`),lookbehind:!0,alias:`number`},boolean:{pattern:o(`false|true`,`i`),lookbehind:!0,alias:`important`},null:{pattern:o(`null|~`,`i`),lookbehind:!0,alias:`important`},string:{pattern:o(a),lookbehind:!0,greedy:!0},number:{pattern:o(`[+-]?(?:0x[\\da-f]+|0o[0-7]+|(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:e[+-]?\\d+)?|\\.inf|\\.nan)`,`i`),lookbehind:!0},tag:n,important:t,punctuation:/---|[:[\]{}\-,|>?]|\.\.\./},e.languages.yml=e.languages.yaml})(Prism),(function(e){var t=`\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b`,n={pattern:/(^(["']?)\w+\2)[ \t]+\S.*/,lookbehind:!0,alias:`punctuation`,inside:null},r={bash:n,environment:{pattern:RegExp(`\\$`+t),alias:`constant`},variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,greedy:!0,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--|\+\+|\*\*=?|<<=?|>>=?|&&|\|\||[=!+\-*/%<>^&|]=?|[?~:]/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/,greedy:!0,inside:{variable:/^\$\(|^`|\)$|`$/}},{pattern:/\$\{[^}]+\}/,greedy:!0,inside:{operator:/:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,punctuation:/[\[\]]/,environment:{pattern:RegExp(`(\\{)`+t),lookbehind:!0,alias:`constant`}}},/\$(?:\w+|[#?*!@$])/],entity:/\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|U[0-9a-fA-F]{8}|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{1,2})/};e.languages.bash={shebang:{pattern:/^#!\s*\/.*/,alias:`important`},comment:{pattern:/(^|[^"{\\$])#.*/,lookbehind:!0},"function-name":[{pattern:/(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/,lookbehind:!0,alias:`function`},{pattern:/\b[\w-]+(?=\s*\(\s*\)\s*\{)/,alias:`function`}],"for-or-select":{pattern:/(\b(?:for|select)\s+)\w+(?=\s+in\s)/,alias:`variable`,lookbehind:!0},"assign-left":{pattern:/(^|[\s;|&]|[<>]\()\w+(?:\.\w+)*(?=\+?=)/,inside:{environment:{pattern:RegExp(`(^|[\\s;|&]|[<>]\\()`+t),lookbehind:!0,alias:`constant`}},alias:`variable`,lookbehind:!0},parameter:{pattern:/(^|\s)-{1,2}(?:\w+:[+-]?)?\w+(?:\.\w+)*(?=[=\s]|$)/,alias:`variable`,lookbehind:!0},string:[{pattern:/((?:^|[^<])<<-?\s*)(\w+)\s[\s\S]*?(?:\r?\n|\r)\2/,lookbehind:!0,greedy:!0,inside:r},{pattern:/((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s[\s\S]*?(?:\r?\n|\r)\3/,lookbehind:!0,greedy:!0,inside:{bash:n}},{pattern:/(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/,lookbehind:!0,greedy:!0,inside:r},{pattern:/(^|[^$\\])'[^']*'/,lookbehind:!0,greedy:!0},{pattern:/\$'(?:[^'\\]|\\[\s\S])*'/,greedy:!0,inside:{entity:r.entity}}],environment:{pattern:RegExp(`\\$?`+t),alias:`constant`},variable:r.variable,function:{pattern:/(^|[\s;|&]|[<>]\()(?:add|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cargo|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|docker|docker-compose|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|java|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|node|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|podman|podman-compose|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|sysctl|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vcpkg|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\s;|&]|[<>]\()(?:case|do|done|elif|else|esac|fi|for|function|if|in|select|then|until|while)(?=$|[)\s;|&])/,lookbehind:!0},builtin:{pattern:/(^|[\s;|&]|[<>]\()(?:\.|:|alias|bind|break|builtin|caller|cd|command|continue|declare|echo|enable|eval|exec|exit|export|getopts|hash|help|let|local|logout|mapfile|printf|pwd|read|readarray|readonly|return|set|shift|shopt|source|test|times|trap|type|typeset|ulimit|umask|unalias|unset)(?=$|[)\s;|&])/,lookbehind:!0,alias:`class-name`},boolean:{pattern:/(^|[\s;|&]|[<>]\()(?:false|true)(?=$|[)\s;|&])/,lookbehind:!0},"file-descriptor":{pattern:/\B&\d\b/,alias:`important`},operator:{pattern:/\d?<>|>\||\+=|=[=~]?|!=?|<<[<-]?|[&\d]?>>|\d[<>]&?|[<>][&=]?|&[>&]?|\|[&|]?/,inside:{"file-descriptor":{pattern:/^\d/,alias:`important`}}},punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/,number:{pattern:/(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/,lookbehind:!0}},n.inside=e.languages.bash;for(var i=[`comment`,`function-name`,`for-or-select`,`assign-left`,`parameter`,`string`,`environment`,`function`,`keyword`,`builtin`,`boolean`,`file-descriptor`,`operator`,`punctuation`,`number`],a=r.variable[1].inside,o=0;o=a.length);c++){var l=s[c];if(typeof l==`string`||l.content&&typeof l.content==`string`){var u=a[i],d=n.tokenStack[u],f=typeof l==`string`?l:l.content,p=t(r,u),m=f.indexOf(p);if(m>-1){++i;var h=f.substring(0,m),g=new e.Token(r,e.tokenize(d,n.grammar),`language-`+r,d),_=f.substring(m+p.length),v=[];h&&v.push.apply(v,o([h])),v.push(g),_&&v.push.apply(v,o([_])),typeof l==`string`?s.splice.apply(s,[c,1].concat(v)):l.content=v}}else l.content&&o(l.content)}return s}o(n.tokens)}}})})(Prism),(function(e){e.languages.django={comment:/^\{#[\s\S]*?#\}$/,tag:{pattern:/(^\{%[+-]?\s*)\w+/,lookbehind:!0,alias:`keyword`},delimiter:{pattern:/^\{[{%][+-]?|[+-]?[}%]\}$/,alias:`punctuation`},string:{pattern:/("|')(?:\\.|(?!\1)[^\\\r\n])*\1/,greedy:!0},filter:{pattern:/(\|)\w+/,lookbehind:!0,alias:`function`},test:{pattern:/(\bis\s+(?:not\s+)?)(?!not\b)\w+/,lookbehind:!0,alias:`function`},function:/\b[a-z_]\w+(?=\s*\()/i,keyword:/\b(?:and|as|by|else|for|if|import|in|is|loop|not|or|recursive|with|without)\b/,operator:/[-+%=]=?|!=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,number:/\b\d+(?:\.\d+)?\b/,boolean:/[Ff]alse|[Nn]one|[Tt]rue/,variable:/\b\w+\b/,punctuation:/[{}[\](),.:;]/};var t=/\{\{[\s\S]*?\}\}|\{%[\s\S]*?%\}|\{#[\s\S]*?#\}/g,n=e.languages[`markup-templating`];e.hooks.add(`before-tokenize`,function(e){n.buildPlaceholders(e,`django`,t)}),e.hooks.add(`after-tokenize`,function(e){n.tokenizePlaceholders(e,`django`)}),e.languages.jinja2=e.languages.django,e.hooks.add(`before-tokenize`,function(e){n.buildPlaceholders(e,`jinja2`,t)}),e.hooks.add(`after-tokenize`,function(e){n.tokenizePlaceholders(e,`jinja2`)})})(Prism),jn.default.languages.bash&&!jn.default.languages.shell&&(jn.default.languages.shell=jn.default.languages.bash),jn.default.languages.django&&!jn.default.languages.jinja2&&(jn.default.languages.jinja2=jn.default.languages.django);function ya({code:e,language:t=`go`,collapsible:n=!1}){let r=(0,x.useRef)(null),[i,a]=(0,x.useState)(!1),[o,s]=(0,x.useState)(!1),[c,l]=(0,x.useState)(0);(0,x.useEffect)(()=>{if(r.current){jn.default.highlightElement(r.current);let t=e.split(`
`).length;l(t),console.log(`CodeBlock: Lines:`,t,`Collapse?:`,t>3)}},[e]);let u=async()=>{try{if(console.log(`Attempting to copy code:`,{codeLength:e.length,code:e.substring(0,100)}),navigator.clipboard&&navigator.clipboard.writeText)await navigator.clipboard.writeText(e),console.log(`Successfully copied to clipboard`),s(!0),setTimeout(()=>s(!1),2e3);else{let t=document.createElement(`textarea`);t.value=e,t.style.position=`fixed`,t.style.left=`-999999px`,document.body.appendChild(t),t.focus(),t.select();let n=document.execCommand(`copy`);document.body.removeChild(t),n?(console.log(`Successfully copied to clipboard (fallback)`),s(!0),setTimeout(()=>s(!1),2e3)):console.error(`Fallback copy failed`)}}catch(e){console.error(`Failed to copy:`,e)}},d=n&&c>3,f=t===`go`?`code-go`:`code-block`,p=`language-${t}`,m=`${f} ${d&&!i?`collapsed`:``}`;return console.log(`CodeBlock render:`,{lineCount:c,shouldCollapse:d,isExpanded:i,preClassName:m}),(0,G.jsxs)(`div`,{className:`code-block-container`,children:[(0,G.jsxs)(`div`,{className:`code-block-header`,children:[(0,G.jsx)(`div`,{className:`code-block-info`,children:d&&(0,G.jsxs)(`button`,{className:`code-block-toggle`,onClick:()=>a(!i),"aria-label":i?`Collapse code`:`Expand code`,title:i?`Collapse`:`Expand`,children:[(0,G.jsx)(`svg`,{width:`16`,height:`16`,viewBox:`0 0 16 16`,fill:`currentColor`,children:i?(0,G.jsx)(`path`,{d:`M2 5l6 6 6-6H2z`}):(0,G.jsx)(`path`,{d:`M6 2v12l6-6-6-6z`})}),(0,G.jsx)(`span`,{className:`code-block-line-count`,children:i?`Collapse`:`Show all (${c} lines)`})]})}),(0,G.jsxs)(`button`,{className:`code-copy-btn`,onClick:u,"aria-label":`Copy code`,title:`Copy to clipboard`,children:[(0,G.jsxs)(`svg`,{width:`16`,height:`16`,viewBox:`0 0 16 16`,fill:`currentColor`,children:[(0,G.jsx)(`path`,{d:`M4 1.5H3a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v-1a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v1zm5-1v1H6v-1h3z`}),(0,G.jsx)(`path`,{d:`M4 5.5a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 .5.5v9a.5.5 0 0 1-.5.5H4.5a.5.5 0 0 1-.5-.5v-9z`})]}),(0,G.jsx)(`span`,{className:`copy-feedback ${o?`show`:``}`,children:o?`Copied!`:`Copy`})]})]}),(0,G.jsx)(`pre`,{className:m,children:(0,G.jsx)(`code`,{ref:r,className:p,children:e})})]})}var ba=[{value:1024,label:`1K`},{value:2048,label:`2K`},{value:4096,label:`4K`},{value:8192,label:`8K`},{value:16384,label:`16K`},{value:32768,label:`32K`},{value:65536,label:`64K`},{value:98304,label:`96K`},{value:131072,label:`128K`},{value:262144,label:`256K`},{value:524288,label:`512K`},{value:1048576,label:`1M`}],xa=[{value:1,label:`q8_0 / q4_0 / q4_1 / q5_0 / q5_1 (1 byte)`},{value:2,label:`f16 / bf16 (2 bytes)`},{value:4,label:`f32 (4 bytes)`}],Sa=[1,2,3,4,5],Ca=2147483647,wa=`VRAM CALCULATION FORMULA
Total VRAM ≈ Model Weights (GPU) + KV Cache (if on GPU) + Compute Buffer
@@ -172,7 +172,7 @@ Compute buffer memory is primarily allocated on the main GPU (GPU 0).
Note: Per-GPU estimates assume proportional distribution based on
tensor_split. Actual allocation by llama.cpp may differ slightly.`;function Ta({onClose:e}){return(0,G.jsx)(`div`,{className:`modal-overlay`,onClick:e,children:(0,G.jsxs)(`div`,{className:`modal-content modal-large`,onClick:e=>e.stopPropagation(),children:[(0,G.jsxs)(`div`,{className:`modal-header`,children:[(0,G.jsx)(`h3`,{children:`VRAM Calculation Formula`}),(0,G.jsx)(`button`,{className:`modal-close`,onClick:e,"aria-label":`Close`,children:`×`})]}),(0,G.jsx)(`div`,{className:`modal-body`,children:(0,G.jsx)(`pre`,{className:`vram-formula-content`,children:wa})})]})})}function Ea({blockCount:e,gpuLayers:t,onGpuLayersChange:n,variant:r=`form`}){let i=t??e,a=r===`compact`?`Layers on GPU (${i}/${e})`:`Layers on GPU (${i} of ${e})`,o=i===0?`All layers on CPU (slowest, saves most VRAM)`:i>=e?`All layers on GPU (fastest)`:`${i} layers on GPU, ${e-i} on CPU — every token pays a penalty for CPU layers`;return r===`compact`?(0,G.jsxs)(`div`,{className:`control-field`,style:{width:`100%`},children:[(0,G.jsx)(X,{htmlFor:`vram-compact-gpuLayers`,tooltipKey:`gpuLayers`,children:a}),(0,G.jsx)(`input`,{id:`vram-compact-gpuLayers`,type:`range`,min:0,max:e,value:i,onChange:e=>n?.(Number(e.target.value)),className:`form-range`}),(0,G.jsx)(`div`,{style:{fontSize:`11px`,color:`var(--color-gray-500)`,marginTop:2},children:o})]}):(0,G.jsxs)(`div`,{className:`playground-sweep-param`,style:{width:`100%`},children:[(0,G.jsx)(X,{className:`playground-sweep-param-toggle`,htmlFor:`vram-gpuLayers`,tooltipKey:`gpuLayers`,children:a}),(0,G.jsx)(`input`,{id:`vram-gpuLayers`,type:`range`,min:0,max:e,value:i,onChange:e=>n?.(Number(e.target.value)),style:{width:`100%`,marginTop:6}}),(0,G.jsx)(`div`,{style:{fontSize:`11px`,color:`var(--color-gray-500)`,marginTop:2},children:o})]})}function Da({blockCount:e,expertLayersOnGPU:t,onExpertLayersOnGPUChange:n,variant:r=`form`}){let i=Math.min(t??e,e),a=r===`compact`?`Experts on GPU (${i}/${e} layers)`:`Experts on GPU (${i} of ${e} layers)`,o=i===0?`All expert weights on CPU (always-active weights remain on GPU)`:i>=e?`All expert weights on GPU`:`Expert weights from top ${i} layers on GPU, rest on CPU — always-active weights remain on GPU`;return r===`compact`?(0,G.jsxs)(`div`,{className:`control-field`,style:{width:`100%`},children:[(0,G.jsx)(X,{htmlFor:`vram-compact-expertLayers`,tooltipKey:`expertLayersOnGPU`,children:a}),(0,G.jsx)(`input`,{id:`vram-compact-expertLayers`,type:`range`,min:0,max:e,value:i,onChange:e=>n?.(Number(e.target.value)),className:`form-range`}),(0,G.jsx)(`div`,{style:{fontSize:`11px`,color:`var(--color-gray-500)`,marginTop:2},children:o})]}):(0,G.jsxs)(`div`,{className:`playground-sweep-param`,style:{width:`100%`},children:[(0,G.jsx)(X,{className:`playground-sweep-param-toggle`,htmlFor:`vram-expertLayers`,tooltipKey:`expertLayersOnGPU`,children:a}),(0,G.jsx)(`input`,{id:`vram-expertLayers`,type:`range`,min:0,max:e,value:i,onChange:e=>n?.(Number(e.target.value)),style:{width:`100%`,marginTop:6}}),(0,G.jsx)(`div`,{style:{fontSize:`11px`,color:`var(--color-gray-500)`,marginTop:2},children:o})]})}function Oa({strategy:e,onStrategyChange:t,variant:n=`form`,disableExpert:r=!1}){let i=(e,t=!1)=>({flex:1,padding:`8px 16px`,fontSize:`13px`,fontWeight:500,border:e?`1px solid var(--color-primary)`:`1px solid var(--color-gray-300)`,background:e?`var(--color-primary)`:`var(--color-gray-100)`,color:e?`#fff`:`var(--color-text)`,cursor:t?`not-allowed`:`pointer`,opacity:t?.4:1,transition:`background 0.15s, color 0.15s, border-color 0.15s`}),a=e===`layer`?`Move entire layers to CPU. Every token pays a penalty for each CPU layer.`:`Keep always-active weights on GPU, move only expert weights to CPU. Less painful.`;return(0,G.jsxs)(`div`,{className:n===`compact`?`control-field`:`playground-sweep-param`,style:{width:`100%`},children:[(0,G.jsxs)(`label`,{className:n===`compact`?void 0:`playground-sweep-param-toggle`,children:[`Offload Strategy`,(0,G.jsx)(aa,{text:`MoE models support two offloading strategies. Layer Offloading moves entire layers to CPU. Expert Offloading keeps the always-active weights on GPU and only moves expert weights to CPU.`})]}),(0,G.jsxs)(`div`,{style:{display:`flex`,marginTop:4},children:[(0,G.jsx)(`button`,{type:`button`,style:{...i(e===`layer`),borderRadius:`4px 0 0 4px`},onClick:()=>t(`layer`),children:`Layer Offloading`}),(0,G.jsxs)(`button`,{type:`button`,style:{...i(e===`expert`,r),borderRadius:`0 4px 4px 0`,borderLeft:`none`},onClick:()=>!r&&t(`expert`),disabled:r,children:[`Expert Offloading`,r?` (MoE only)`:``]})]}),(0,G.jsx)(`div`,{style:{fontSize:`11px`,color:`var(--color-gray-500)`,marginTop:4},children:a})]})}var ka=[1,2,4,8];function Aa(e){return e!=null&&e>0?Array.from({length:e},(e,t)=>t+1):ka}function ja({contextWindow:e,onContextWindowChange:t,bytesPerElement:n,onBytesPerElementChange:r,slots:i,onSlotsChange:a,variant:o=`form`,maxDeviceCount:s,isMoE:c,blockCount:l,gpuLayers:u,onGpuLayersChange:d,expertLayersOnGPU:f,onExpertLayersOnGPUChange:p,kvCacheOnCPU:m,onKvCacheOnCPUChange:h,hasSWA:g,swaFull:_,onSwaFullChange:v,deviceCount:y,onDeviceCountChange:b,tensorSplit:S,onTensorSplitChange:C,contextInfo:w,modelSizeBytes:T,modelWeightsCPU:E,kvCpuBytes:D,totalSystemRamEst:O,systemRAMBytes:k,showHardwareOverrides:A,gpuMemoryOverrideGB:j,onGpuMemoryOverrideGBChange:M,gpuMemoryOverrideInvalid:N,systemMemoryOverrideGB:P,onSystemMemoryOverrideGBChange:F,systemMemoryOverrideInvalid:I,deviceCountOverride:L,onDeviceCountOverrideChange:R,detectedGpuTotalBytes:z,detectedSystemRAMBytes:ee,detectedDeviceCount:B,canAutoFit:V,autoFitDisabled:te,autoFitting:H,autoFitError:ne,onAutoFit:re}){let[ie,ae]=(0,x.useState)(!1),[oe,se]=(0,x.useState)(`layer`),ce=(0,x.useRef)(l);(0,x.useEffect)(()=>{if(l!==ce.current){ce.current=l,se(`layer`);return}l==null||l<=0||!c||((u??l)>=l&&(f??l){se(e),!(l==null||l<=0)&&(e===`layer`?p?.(u??l):d?.(l))},ue=e=>{d?.(e),p?.(e)};return o===`compact`?(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{className:`controls-row`,children:[(0,G.jsxs)(`div`,{className:`control-field`,children:[(0,G.jsx)(X,{htmlFor:`vram-compact-ctx`,tooltipKey:`contextWindow`,after:w&&w.hasRoPE?(0,G.jsx)(`span`,{style:{fontSize:`11px`,fontWeight:400,color:`var(--color-gray-500)`,display:`block`,textTransform:`none`,letterSpacing:`normal`},children:ca(w)}):void 0,children:`Context Window`}),(0,G.jsx)(`select`,{id:`vram-compact-ctx`,value:e,onChange:e=>t(Number(e.target.value)),className:`form-select`,children:ba.filter(e=>!w||e.value<=w.max).map(e=>(0,G.jsxs)(`option`,{value:e.value,children:[e.label,` (`,e.value.toLocaleString(),` tokens)`]},e.value))})]}),(0,G.jsxs)(`div`,{className:`control-field`,children:[(0,G.jsx)(X,{htmlFor:`vram-compact-bpe`,tooltipKey:`cacheType`,children:`Cache Type`}),(0,G.jsx)(`select`,{id:`vram-compact-bpe`,value:n,onChange:e=>r(Number(e.target.value)),className:`form-select`,children:xa.map(e=>(0,G.jsx)(`option`,{value:e.value,children:e.label},e.value))})]}),(0,G.jsxs)(`div`,{className:`control-field`,children:[(0,G.jsx)(X,{htmlFor:`vram-compact-slots`,tooltipKey:`nSeqMax`,children:`Slots`}),(0,G.jsx)(`select`,{id:`vram-compact-slots`,value:i,onChange:e=>a(Number(e.target.value)),className:`form-select`,children:Sa.map(e=>(0,G.jsx)(`option`,{value:e,children:e},e))})]}),(0,G.jsx)(Ma,{open:ie,onToggle:()=>ae(!ie)})]}),l!=null&&l>0&&(0,G.jsxs)(`div`,{style:{marginTop:`8px`},children:[(0,G.jsx)(Oa,{strategy:oe,onStrategyChange:le,variant:`compact`,disableExpert:!c}),(0,G.jsx)(`div`,{style:{marginTop:`8px`},children:oe===`layer`||!c?(0,G.jsx)(Ea,{blockCount:l,gpuLayers:u,onGpuLayersChange:c?ue:d,variant:`compact`}):(0,G.jsx)(Da,{blockCount:l,expertLayersOnGPU:f,onExpertLayersOnGPUChange:p,variant:`compact`})})]}),V&&(0,G.jsxs)(`div`,{style:{marginTop:`8px`,display:`flex`,alignItems:`center`,gap:`6px`},children:[(0,G.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:re,disabled:H||te,children:H?`Finding Fit…`:`Auto Fit`}),(0,G.jsx)(aa,{tooltipKey:`autoFit`})]}),ne&&(0,G.jsx)(`div`,{className:`status-line error`,style:{marginTop:`8px`},children:ne}),ie&&(0,G.jsx)(Na,{kvCacheOnCPU:m,onKvCacheOnCPUChange:h,hasSWA:g,swaFull:_,onSwaFullChange:v,maxDeviceCount:s,deviceCount:y,onDeviceCountChange:b,tensorSplit:S,onTensorSplitChange:C})]}):(0,G.jsxs)(`div`,{className:`playground-sweep-params`,children:[(0,G.jsxs)(`div`,{className:`playground-sweep-param`,children:[(0,G.jsx)(X,{className:`playground-sweep-param-toggle`,htmlFor:`vram-contextWindow`,tooltipKey:`contextWindow`,children:`Context Window`}),(0,G.jsx)(`select`,{id:`vram-contextWindow`,value:e,onChange:e=>t(Number(e.target.value)),className:`playground-sweep-param-values`,children:ba.filter(e=>!w||e.value<=w.max).map(e=>(0,G.jsxs)(`option`,{value:e.value,children:[e.label,` (`,e.value.toLocaleString(),` tokens)`]},e.value))}),w&&w.hasRoPE&&(0,G.jsx)(`div`,{style:{fontSize:`11px`,color:`var(--color-gray-500)`,marginTop:2},children:ca(w)})]}),(0,G.jsxs)(`div`,{className:`playground-sweep-param`,children:[(0,G.jsx)(X,{className:`playground-sweep-param-toggle`,htmlFor:`vram-bytesPerElement`,tooltipKey:`cacheType`,children:`Cache Type`}),(0,G.jsx)(`select`,{id:`vram-bytesPerElement`,value:n,onChange:e=>r(Number(e.target.value)),className:`playground-sweep-param-values`,children:xa.map(e=>(0,G.jsx)(`option`,{value:e.value,children:e.label},e.value))})]}),(0,G.jsxs)(`div`,{className:`playground-sweep-param`,children:[(0,G.jsx)(X,{className:`playground-sweep-param-toggle`,htmlFor:`vram-slots`,tooltipKey:`nSeqMax`,children:`Slots`}),(0,G.jsx)(`select`,{id:`vram-slots`,value:i,onChange:e=>a(Number(e.target.value)),className:`playground-sweep-param-values`,children:Sa.map(e=>(0,G.jsx)(`option`,{value:e,children:e},e))})]}),A&&(0,G.jsxs)(`div`,{style:{gridColumn:`1 / -1`,borderTop:`1px solid var(--color-gray-200)`,paddingTop:`16px`,marginTop:`8px`},children:[(0,G.jsx)(`h4`,{style:{margin:`0 0 12px 0`,fontSize:`14px`,fontWeight:600},children:`Hardware Configuration`}),(0,G.jsxs)(`div`,{className:`playground-sweep-params`,style:{margin:0},children:[(0,G.jsxs)(`div`,{className:`playground-sweep-param`,children:[(0,G.jsx)(X,{className:`playground-sweep-param-toggle`,htmlFor:`vram-gpuCountOverride`,tooltipKey:`gpuCount`,children:`GPU Count`}),(0,G.jsxs)(`select`,{id:`vram-gpuCountOverride`,value:L??``,onChange:e=>{let t=e.target.value;R?.(t===``?null:Number(t))},className:`playground-sweep-param-values`,children:[(0,G.jsxs)(`option`,{value:``,children:[`Auto-detect`,B==null?``:` (${B} GPU${B>1?`s`:``})`]}),ka.map(e=>(0,G.jsxs)(`option`,{value:e,children:[e,` GPU`,e>1?`s`:``]},e))]})]}),(0,G.jsxs)(`div`,{className:`playground-sweep-param`,children:[(0,G.jsxs)(`label`,{className:`playground-sweep-param-toggle`,htmlFor:`vram-gpuMemOverride`,children:[`Total GPU Memory (GB)`,(0,G.jsx)(aa,{text:`Total GPU memory across all selected GPUs. Leave empty to auto-detect from this server.`})]}),(0,G.jsx)(`input`,{id:`vram-gpuMemOverride`,type:`text`,value:j??``,onChange:e=>M?.(e.target.value),className:`playground-sweep-param-values`,placeholder:z?`Auto-detect (${(z/1073741824).toFixed(1)} GB)`:`e.g. 24`,style:N?{borderColor:`var(--color-error, #ef5350)`}:void 0}),N&&(0,G.jsx)(`div`,{style:{fontSize:`11px`,color:`var(--color-error, #ef5350)`,marginTop:2},children:`Enter a positive number in GB`}),(0,G.jsx)(`div`,{style:{fontSize:`11px`,color:`var(--color-gray-500)`,marginTop:2},children:`Total across all GPUs — assumes even per-GPU capacity`})]}),(0,G.jsxs)(`div`,{className:`playground-sweep-param`,children:[(0,G.jsxs)(`label`,{className:`playground-sweep-param-toggle`,htmlFor:`vram-sysMemOverride`,children:[`System Memory (GB)`,(0,G.jsx)(aa,{text:`Total system RAM. Used to check CPU offload feasibility. Leave empty to auto-detect from this server.`})]}),(0,G.jsx)(`input`,{id:`vram-sysMemOverride`,type:`text`,value:P??``,onChange:e=>F?.(e.target.value),className:`playground-sweep-param-values`,placeholder:ee?`Auto-detect (${(ee/1073741824).toFixed(1)} GB)`:`e.g. 64`,style:I?{borderColor:`var(--color-error, #ef5350)`}:void 0}),I&&(0,G.jsx)(`div`,{style:{fontSize:`11px`,color:`var(--color-error, #ef5350)`,marginTop:2},children:`Enter a positive number in GB`})]})]})]}),(0,G.jsx)(`div`,{className:`playground-sweep-param`,children:(0,G.jsxs)(X,{className:`playground-sweep-param-toggle`,htmlFor:`vram-kvCpu`,tooltipKey:`kvCacheOnCPU`,style:{display:`flex`,alignItems:`center`,gap:`6px`},children:[(0,G.jsx)(`input`,{id:`vram-kvCpu`,type:`checkbox`,checked:m??!1,onChange:e=>h?.(e.target.checked)}),`KV Cache on CPU`]})}),(0,G.jsxs)(`div`,{className:`playground-sweep-param`,children:[(0,G.jsxs)(X,{className:`playground-sweep-param-toggle`,htmlFor:`vram-swaFull`,tooltipKey:`swaFull`,style:{display:`flex`,alignItems:`center`,gap:`6px`},children:[(0,G.jsx)(`input`,{id:`vram-swaFull`,type:`checkbox`,checked:_??!0,onChange:e=>v?.(e.target.checked),disabled:!g}),`Full SWA Cache`]}),(0,G.jsx)(`div`,{style:{fontSize:`11px`,color:`var(--color-gray-500)`,marginTop:2},children:g?_?`Full-context cache for SWA layers`:`Compact model-defined sliding-window cache`:`No sliding-window layers detected`})]}),!A&&(0,G.jsxs)(`div`,{className:`playground-sweep-param`,children:[(0,G.jsx)(X,{className:`playground-sweep-param-toggle`,htmlFor:`vram-deviceCount`,tooltipKey:`gpuCount`,children:`GPU Count`}),(0,G.jsx)(`select`,{id:`vram-deviceCount`,value:y??1,onChange:e=>b?.(Number(e.target.value)),className:`playground-sweep-param-values`,children:Aa(s).map(e=>(0,G.jsxs)(`option`,{value:e,children:[e,` GPU`,e>1?`s`:``]},e))})]}),(y??1)>1&&(0,G.jsxs)(`div`,{className:`playground-sweep-param`,children:[(0,G.jsx)(X,{className:`playground-sweep-param-toggle`,htmlFor:`vram-tensorSplit`,tooltipKey:`tensorSplit`,children:`Tensor Split (proportions, e.g. 0.6,0.4)`}),(0,G.jsx)(`input`,{id:`vram-tensorSplit`,type:`text`,value:S??``,onChange:e=>C?.(e.target.value),className:`playground-sweep-param-values`,placeholder:`empty = equal split`}),(0,G.jsx)(`div`,{style:{fontSize:`11px`,color:`var(--color-gray-500)`,marginTop:2},children:`Leave empty for equal distribution across GPUs`})]}),l!=null&&l>0&&(0,G.jsx)(`div`,{style:{gridColumn:`1 / -1`},children:(0,G.jsx)(Oa,{strategy:oe,onStrategyChange:le,variant:`form`,disableExpert:!c})}),l!=null&&l>0&&(0,G.jsx)(`div`,{style:{gridColumn:`1 / -1`},children:oe===`layer`||!c?(0,G.jsx)(Ea,{blockCount:l,gpuLayers:u,onGpuLayersChange:c?ue:d,variant:`form`}):(0,G.jsx)(Da,{blockCount:l,expertLayersOnGPU:f,onExpertLayersOnGPUChange:p,variant:`form`})}),V&&(0,G.jsxs)(`div`,{style:{gridColumn:`1 / -1`,display:`flex`,alignItems:`center`,gap:`6px`},children:[(0,G.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:re,disabled:H||te,children:H?`Finding Fit…`:`Auto Fit`}),(0,G.jsx)(aa,{tooltipKey:`autoFit`})]}),ne&&(0,G.jsx)(`div`,{className:`status-line error`,style:{gridColumn:`1 / -1`},children:ne}),T!=null&&T>0&&(0,G.jsx)(Pa,{modelSizeBytes:T,modelWeightsCPU:E??0,kvCpuBytes:D??0,totalSystemRamEst:O??0,systemRAMBytes:k})]})}function Ma({open:e,onToggle:t}){return(0,G.jsx)(`div`,{style:{display:`flex`,alignItems:`flex-end`,flexShrink:0,paddingBottom:`8px`},children:(0,G.jsxs)(`button`,{type:`button`,onClick:t,style:{background:`none`,border:`none`,padding:0,cursor:`pointer`,fontSize:`13px`,color:`var(--color-text-secondary)`,display:`flex`,alignItems:`center`,gap:`4px`,whiteSpace:`nowrap`},children:[(0,G.jsx)(`span`,{style:{display:`inline-block`,transition:`transform 0.2s`,transform:e?`rotate(90deg)`:`rotate(0deg)`},children:`▶`}),`Advanced`]})})}function Na({kvCacheOnCPU:e,onKvCacheOnCPUChange:t,hasSWA:n,swaFull:r,onSwaFullChange:i,maxDeviceCount:a,deviceCount:o,onDeviceCountChange:s,tensorSplit:c,onTensorSplitChange:l}){return(0,G.jsxs)(`div`,{style:{marginTop:`8px`,display:`flex`,flexWrap:`wrap`,gap:`12px`},children:[(0,G.jsx)(`div`,{className:`control-field`,children:(0,G.jsxs)(X,{htmlFor:`vram-compact-kvCpu`,tooltipKey:`kvCacheOnCPU`,style:{display:`flex`,alignItems:`center`,gap:`6px`},children:[(0,G.jsx)(`input`,{id:`vram-compact-kvCpu`,type:`checkbox`,checked:e??!1,onChange:e=>t?.(e.target.checked)}),`KV Cache on CPU`]})}),(0,G.jsxs)(`div`,{className:`control-field`,children:[(0,G.jsxs)(X,{htmlFor:`vram-compact-swaFull`,tooltipKey:`swaFull`,style:{display:`flex`,alignItems:`center`,gap:`6px`},children:[(0,G.jsx)(`input`,{id:`vram-compact-swaFull`,type:`checkbox`,checked:r??!0,onChange:e=>i?.(e.target.checked),disabled:!n}),`Full SWA Cache`]}),(0,G.jsx)(`div`,{style:{fontSize:`11px`,color:`var(--color-gray-500)`,marginTop:2},children:n?r?`Full context`:`Compact window`:`No SWA layers`})]}),(0,G.jsxs)(`div`,{className:`control-field`,children:[(0,G.jsx)(X,{htmlFor:`vram-compact-deviceCount`,tooltipKey:`gpuCount`,children:`GPU Count`}),(0,G.jsx)(`select`,{id:`vram-compact-deviceCount`,value:o??1,onChange:e=>s?.(Number(e.target.value)),className:`form-select`,children:Aa(a).map(e=>(0,G.jsxs)(`option`,{value:e,children:[e,` GPU`,e>1?`s`:``]},e))})]}),(o??1)>1&&(0,G.jsxs)(`div`,{className:`control-field`,children:[(0,G.jsx)(X,{htmlFor:`vram-compact-tensorSplit`,tooltipKey:`tensorSplit`,children:`Tensor Split`}),(0,G.jsx)(`input`,{id:`vram-compact-tensorSplit`,type:`text`,value:c??``,onChange:e=>l?.(e.target.value),className:`form-input`,placeholder:`e.g. 0.6,0.4`})]})]})}function Pa({modelSizeBytes:e,modelWeightsCPU:t,kvCpuBytes:n,totalSystemRamEst:r,systemRAMBytes:i}){let a=r,o=e>0?t/e*100:0,s=`${Math.round(o)}% offloaded`,c=Math.max(1,e);return(0,G.jsxs)(`div`,{style:{gridColumn:`1 / -1`,marginTop:`4px`,marginBottom:`4px`},children:[(0,G.jsxs)(`h4`,{className:`vram-breakdown-title`,children:[`Model Weights on CPU`,a<=0&&(0,G.jsx)(`span`,{style:{fontWeight:400,opacity:.7},children:` — Everything on GPU`})]}),(0,G.jsxs)(`div`,{style:{display:`flex`,justifyContent:`space-between`,fontSize:`0.85em`,marginBottom:`2px`},children:[(0,G.jsx)(`span`,{children:t>0?`${s} — ${J(t)} on CPU`:s}),(0,G.jsxs)(`span`,{children:[J(a),i!=null&&i>0?` / ${J(i)}`:``]})]}),(0,G.jsxs)(`div`,{style:{background:`var(--color-gray-300)`,borderRadius:`4px`,height:`20px`,overflow:`hidden`,display:`flex`},children:[t>0&&(0,G.jsx)(`div`,{style:{width:`${t/c*100}%`,background:`var(--color-primary)`,height:`100%`},title:`Model weights: ${J(t)}`}),n>0&&(0,G.jsx)(`div`,{style:{width:`${n/c*100}%`,background:`var(--color-orange)`,height:`100%`},title:`KV cache: ${J(n)}`})]}),t>0&&n>0&&(0,G.jsxs)(`div`,{style:{display:`flex`,gap:`12px`,fontSize:`0.75em`,opacity:.7,marginTop:`4px`},children:[(0,G.jsx)(`span`,{style:{color:`var(--color-primary)`},children:`■ Weights`}),(0,G.jsx)(`span`,{style:{color:`var(--color-orange)`},children:`■ KV Cache`})]})]})}function Fa({totalVram:e,slotMemory:t,kvPerSlot:n,kvPerTokenPerLayer:r,input:i,moe:a,weights:o,modelWeightsGPU:s,modelWeightsCPU:c,computeBufferEst:l,alwaysActiveGPUBytes:u,alwaysActiveCPUBytes:d,expertGPUBytes:f,expertCPUBytes:p,gpuLayers:m,expertLayersOnGPU:h,kvCacheOnCPU:g,totalSystemRamEst:_,unifiedFootprint:v,perDevice:y,deviceCount:b,tensorSplit:x,isHardwareOverridden:S,isUnifiedMemory:C,fitAssessment:w,modelUrl:T,catalogConfigName:E,catalogConfigDefaults:D,recomputing:O}){let k=a?.is_moe===!0&&o!=null,A=g??!1,j=A?`System RAM`:`GPU`,M=m!=null&&m0?[{label:Y(`Always-Active Weights (CPU)`,`alwaysActiveWeights`),value:J(d)}]:[],{label:Y(`Expert Weights — GPU (${h??0} layers)`,`expertWeightsGPU`),value:J(f??0)},{label:Y(`Expert Weights — CPU`,`expertWeightsCPU`),value:J(p??0)},{label:Y(`KV Cache (${j})`,`kvCache`),value:J(t)},{label:Y(`Compute Buffer (estimate)`,`computeBuffer`),value:`~${J(l??0)}`}]:M?[{label:Y(`Weights on GPU (${m} of ${i.block_count} layers)`,`gpuLayers`),value:J(s??0)},{label:Y(`Weights on CPU (${i.block_count-m} layers)`,`gpuLayers`),value:J(c??0)},{label:Y(`KV Cache (${j})`,`kvCache`),value:J(t)},{label:Y(`KV Per Slot`,`kvPerSlot`),value:J(n)},{label:Y(`KV Per Token Per Layer`,`kvPerTokenPerLayer`),value:J(r)},{label:Y(`Compute Buffer (estimate)`,`computeBuffer`),value:`~${J(l??0)}`}]:[{label:Y(`Model Weights`,`modelWeights`),value:J(i.model_size_bytes)},{label:Y(`KV Cache (${j})`,`kvCache`),value:J(t)},{label:Y(`KV Per Slot`,`kvPerSlot`),value:J(n)},{label:Y(`KV Per Token Per Layer`,`kvPerTokenPerLayer`),value:J(r)},{label:Y(`Compute Buffer (estimate)`,`computeBuffer`),value:`~${J(l??0)}`}];let I=[{label:Y(`Model Size`,`modelSize`),value:J(i.model_size_bytes)},{label:Y(`Layers (Block Count)`,`blockCount`),value:String(i.block_count)},{label:Y(`Head Count KV`,`headCountKV`),value:String(i.head_count_kv)},{label:Y(`Key Length`,`keyLength`),value:String(i.key_length)},{label:Y(`Value Length`,`valueLength`),value:String(i.value_length)}];(i.sliding_window_layers??0)>0&&I.push({label:Y(`SWA Layers`,`swaFull`),value:`${i.sliding_window_layers} of ${i.block_count}`},{label:Y(`SWA Cache Mode`,`swaFull`),value:i.swa_full?`Full context`:`Compact (${i.sliding_window?.toLocaleString()??`model default`} tokens)`}),k&&(I.push({label:Y(`Expert Count`,`expertCount`),value:String(a.expert_count)},{label:Y(`Active Experts (top-k)`,`activeExperts`),value:String(a.expert_used_count)}),a.has_shared_experts&&I.push({label:Y(`Shared Experts`,`sharedExperts`),value:`Yes`}));let L=_??0,R=!C&&L>0;return(0,G.jsxs)(`div`,{className:`vram-results`,children:[(0,G.jsxs)(`div`,{className:`vram-hero`,style:{display:`flex`,gap:`32px`,flexWrap:`wrap`},children:[(0,G.jsxs)(`div`,{style:{flex:1,minWidth:`180px`},children:[(0,G.jsxs)(`div`,{className:`vram-hero-label`,style:{display:`flex`,alignItems:`center`,gap:`8px`},children:[Y(C?`Total Estimated Unified Memory`:`Total Estimated VRAM`,`totalEstimatedVRAM`),O&&(0,G.jsx)(`span`,{className:`vram-loading-spinner`,"aria-label":`Recomputing`})]}),(0,G.jsxs)(`div`,{className:`vram-hero-value`,style:{opacity:O?.45:1,transition:`opacity 120ms ease-out`},children:[J(N),P>0&&(0,G.jsxs)(`span`,{style:{fontSize:`0.55em`,opacity:.5},children:[` / `,J(P)]})]})]}),R&&(w?.system_ram.capacity_bytes??0)>0&&(0,G.jsxs)(`div`,{style:{minWidth:`180px`},children:[(0,G.jsx)(`div`,{className:`vram-hero-label`,children:Y(`Total Estimated System RAM`,`totalEstimatedSystemRAM`)}),(0,G.jsxs)(`div`,{className:`vram-hero-value`,children:[J(L),(0,G.jsxs)(`span`,{style:{fontSize:`0.55em`,opacity:.5},children:[` / `,J(w.system_ram.capacity_bytes)]})]})]})]}),(()=>{if(!w||w.status===`unknown`)return null;let e=w.status===`tight`,t=w.status===`does_not_fit`,n=S?`the selected hardware configuration`:`this Kronk model server`,r,i;t?(r=`❌`,i=`This model does not fit the safe memory budget on ${n}`):e?(r=`⚠️`,i=`This model will run on ${n} but it's a tight fit`):(r=`✅`,i=`This model will run on ${n} with these settings`);let a=[],o=(e,t)=>{t.status!==`unknown`&&(t.status===`does_not_fit`?a.push(`${e}: ${J(t.required_bytes)} needed, ${J(t.capacity_bytes)} available`):t.status===`tight`?a.push(`${e}: limited headroom (${J(t.headroom_bytes)} free)`):a.push(`${e}: ${J(t.headroom_bytes)} free`))};return C?o(`Unified memory`,w.unified):(o(`GPU VRAM`,w.gpu),R&&o(`System RAM`,w.system_ram)),(0,G.jsxs)(`div`,{style:{marginTop:`12px`,marginBottom:`16px`,padding:`12px 16px`,background:t?`var(--color-error-bg, rgba(239, 83, 80, 0.1))`:e?`var(--color-warning-bg, rgba(255, 167, 38, 0.1))`:`var(--color-success-bg, rgba(102, 187, 106, 0.1))`,borderLeft:`3px solid ${t?`var(--color-error, #ef5350)`:e?`var(--color-warning, #ffa726)`:`var(--color-success, #66bb6a)`}`,borderRadius:`4px`,fontSize:`0.9em`},children:[(0,G.jsxs)(`div`,{style:{fontWeight:600},children:[r,` `,i]}),a.length>0&&(0,G.jsx)(`div`,{style:{marginTop:`4px`,fontSize:`0.9em`,opacity:.8},children:a.join(` · `)})]})})(),!C&&y&&y.length>=1&&(0,G.jsxs)(`div`,{style:{marginTop:`16px`},children:[(0,G.jsx)(`h4`,{className:`vram-breakdown-title`,children:`Per-GPU VRAM Allocation (estimated)`}),y.map((e,t)=>{let n=Math.max(1,e.total_bytes);return(0,G.jsxs)(`div`,{style:{marginBottom:`8px`},children:[(0,G.jsxs)(`div`,{style:{display:`flex`,justifyContent:`space-between`,fontSize:`0.85em`,marginBottom:`2px`},children:[(0,G.jsx)(`span`,{children:e.label}),(0,G.jsx)(`span`,{children:J(e.total_bytes)})]}),(0,G.jsxs)(`div`,{style:{background:`var(--color-gray-200)`,borderRadius:`4px`,height:`20px`,overflow:`hidden`,display:`flex`},children:[e.weights_bytes>0&&(0,G.jsx)(`div`,{style:{width:`${e.weights_bytes/n*100}%`,background:`var(--color-primary)`,height:`100%`},title:`Weights: ${J(e.weights_bytes)}`}),e.kv_bytes>0&&(0,G.jsx)(`div`,{style:{width:`${e.kv_bytes/n*100}%`,background:`var(--color-orange)`,height:`100%`},title:`KV Cache: ${J(e.kv_bytes)}`}),e.compute_bytes>0&&(0,G.jsx)(`div`,{style:{width:`${e.compute_bytes/n*100}%`,background:`#8b5cf6`,height:`100%`},title:`Compute Buffer: ${J(e.compute_bytes)}`})]})]},t)}),(0,G.jsxs)(`div`,{style:{display:`flex`,gap:`12px`,fontSize:`0.75em`,opacity:.7,marginTop:`4px`},children:[(0,G.jsx)(`span`,{style:{color:`var(--color-primary)`},children:`■ Weights`}),(0,G.jsx)(`span`,{style:{color:`var(--color-orange)`},children:`■ KV Cache`}),(0,G.jsx)(`span`,{style:{color:`#8b5cf6`},children:`■ Compute`})]}),(0,G.jsxs)(`div`,{className:`alert alert-info`,style:{marginTop:`8px`,fontSize:`0.85em`},children:[(0,G.jsx)(`strong`,{children:`Note:`}),` Per-GPU allocation is estimated based on tensor split proportions. Actual distribution may vary depending on llama.cpp split mode behavior.`]})]}),(0,G.jsx)(Va,{input:i,isMoE:k,gpuLayers:m,expertLayersOnGPU:h,kvCacheOnCPU:A,deviceCount:b,tensorSplit:x,modelUrl:T,configName:E,defaults:D}),(0,G.jsxs)(`div`,{className:`vram-breakdown`,children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`h4`,{className:`vram-breakdown-title`,children:k?C?`MoE Placement and Memory Breakdown`:`MoE VRAM Breakdown`:`Breakdown`}),(0,G.jsx)(la,{rows:F})]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`h4`,{className:`vram-breakdown-title`,children:`Model Header`}),(0,G.jsx)(la,{rows:I})]})]})]})}function Ia(e){switch(e){case 4:return`f32`;case 2:return`f16`;case 1:return`q8_0`;default:return`f16`}}function La(e){if(e)return{contextWindow:e.context_window,nseqMax:e.nseq_max,cacheTypeK:e.cache_type_k,cacheTypeV:e.cache_type_v,flashAttention:e.flash_attention}}function Ra(e,t,n,r,i,a,o,s=`enabled`){let c=Ia(e.bytes_per_element),l=a??1,u=n==null||n>=e.block_count,d=null;n!=null&&n=e.block_count||(t>0?(f=`keep_top_n`,p=t):f=`experts_cpu`)}let m=``;if(l>1){let e=o?.split(`,`).map(e=>parseFloat(e.trim())).filter(e=>!isNaN(e))??[];e.length>0&&(m=e.join(`, `))}return{contextWindow:e.context_window,nseqMax:e.slots,cacheTypeK:c,cacheTypeV:c,flashAttention:s,ngpuLayers:d,offloadKQV:!i&&null,swaFull:e.swa_full,splitMode:``,tensorSplit:m,moeMode:f,moeKeepTopN:p}}function za(e){return e?` # AutoTune default`:``}function Ba(e,t,n){let r=[];return r.push(`${t??`model-name/variant`}:`),r.push(` context-window: ${e.contextWindow}${za(e.contextWindow===n?.contextWindow)}`),r.push(` nseq-max: ${e.nseqMax}${za(e.nseqMax===n?.nseqMax)}`),r.push(` cache-type-k: ${e.cacheTypeK}${za(e.cacheTypeK===n?.cacheTypeK)}`),r.push(` cache-type-v: ${e.cacheTypeV}${za(e.cacheTypeV===n?.cacheTypeV)}`),r.push(` flash-attention: ${e.flashAttention}${za(e.flashAttention===n?.flashAttention)}`),e.ngpuLayers!=null&&r.push(` ngpu-layers: ${e.ngpuLayers}`),e.offloadKQV===!1&&r.push(` offload-kqv: false`),e.swaFull||r.push(` swa-full: false`),e.moeMode&&(r.push(` moe:`),r.push(` mode: ${e.moeMode}`),e.moeMode===`keep_top_n`&&e.moeKeepTopN!=null&&r.push(` keep-experts-top-n: ${e.moeKeepTopN}`)),e.tensorSplit&&r.push(` tensor-split: [${e.tensorSplit}]`),e.splitMode&&r.push(` split-mode: ${e.splitMode}`),r.join(`
-`)}function Va({input:e,isMoE:t,gpuLayers:n,expertLayersOnGPU:r,kvCacheOnCPU:i,deviceCount:a,tensorSplit:o,configName:s,defaults:c}){let[l,u]=(0,x.useState)(!1),d=Ba(Ra(e,t,n,r,i,a,o,c?.flashAttention),s,c);return(0,G.jsxs)(`div`,{style:{marginTop:`0px`,padding:`0px 12px 25px 0px`,background:`var(--color-gray-50)`,borderRadius:`6px`},children:[(0,G.jsx)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`12px`},children:(0,G.jsxs)(`button`,{type:`button`,onClick:()=>u(!l),"aria-expanded":l,"aria-controls":`computed-catalog-config`,style:{background:`none`,border:`none`,padding:0,cursor:`pointer`,fontSize:`14px`,fontWeight:600,color:`var(--color-text)`,display:`flex`,alignItems:`center`,gap:`6px`},children:[(0,G.jsx)(`span`,{style:{display:`inline-block`,transition:`transform 0.2s`,transform:l?`rotate(90deg)`:`rotate(0deg)`,fontSize:`12px`},children:`▶`}),`Computed Catalog Configuration`]})}),l&&(0,G.jsx)(`pre`,{id:`computed-catalog-config`,style:{marginTop:`8px`,padding:`12px`,background:`var(--color-gray-100)`,borderRadius:`6px`,fontSize:`0.85em`,overflow:`auto`,whiteSpace:`pre`},children:d})]})}function Ha({controlsProps:e,resultsProps:t,variant:n=`compact`,contextInfo:r,hideControls:i,hideResults:a,modelUrl:o,catalogConfigName:s,catalogConfigDefaults:c}){return(0,G.jsxs)(G.Fragment,{children:[!i&&(0,G.jsx)(`div`,{style:n===`compact`?{marginBottom:`24px`}:void 0,children:(0,G.jsx)(ja,{...e,variant:n,contextInfo:r,modelSizeBytes:t?.isUnifiedMemory?void 0:t?.input.model_size_bytes,modelWeightsCPU:t?.vramResult.modelWeightsCPU,kvCpuBytes:t?.vramResult.kvCpuBytes,totalSystemRamEst:t?.vramResult.totalSystemRamEst,systemRAMBytes:t?.systemRAMBytes})}),t&&!a&&(0,G.jsx)(Fa,{totalVram:t.vramResult.totalVram,slotMemory:t.vramResult.slotMemory,kvPerSlot:t.vramResult.kvPerSlot,kvPerTokenPerLayer:t.vramResult.kvPerTokenPerLayer,input:t.input,moe:t.moe,weights:t.weights,modelWeightsGPU:t.vramResult.modelWeightsGPU,modelWeightsCPU:t.vramResult.modelWeightsCPU,computeBufferEst:t.vramResult.computeBufferEst,alwaysActiveGPUBytes:t.vramResult.alwaysActiveGPUBytes,alwaysActiveCPUBytes:t.vramResult.alwaysActiveCPUBytes,expertGPUBytes:t.vramResult.expertGPUBytes,expertCPUBytes:t.vramResult.expertCPUBytes,gpuLayers:t.gpuLayers,expertLayersOnGPU:t.expertLayersOnGPU,kvCacheOnCPU:t.kvCacheOnCPU,totalSystemRamEst:t.vramResult.totalSystemRamEst,unifiedFootprint:t.vramResult.unifiedFootprint,perDevice:t.perDevice,deviceCount:t.deviceCount,tensorSplit:t.tensorSplit,isHardwareOverridden:t.isHardwareOverridden,isUnifiedMemory:t.isUnifiedMemory,fitAssessment:t.fitAssessment,modelUrl:o,catalogConfigName:s,catalogConfigDefaults:c,recomputing:t.recomputing})]})}function Ua(e){return e.filter(e=>e.type.startsWith(`gpu_`))}function Wa(e){return e.replace(`gpu_`,``).replace(`cuda`,`CUDA`).replace(`metal`,`Metal`).replace(`rocm`,`ROCm`).replace(`vulkan`,`Vulkan`)}function Ga(e){let t=Ua(e.devices),n=t.length>0?Wa(t[0].type):``;return{gpuCount:e.gpu_count,gpuType:n,gpuVramBytes:e.gpu_total_bytes,ramBytes:e.system_ram_bytes,gpuDevices:t,unifiedMemory:e.unified_memory}}function Ka(){let[e,t]=(0,x.useState)(null);return(0,x.useEffect)(()=>{let e=!1;return W.getDevices().then(n=>{e||t(Ga(n))}).catch(()=>{}),()=>{e=!0}},[]),e}var qa=150;function Ja(e){let t=e.trim();if(!t)return;let n=parseFloat(t);if(!(isNaN(n)||n<=0))return Math.round(n*1024*1024*1024)}function Ya(e){let t=e.trim();if(!t)return!1;let n=parseFloat(t);return isNaN(n)||n<=0}function Xa(e,t){return e===-1?0:e===0?t:e}function Za(e){return{totalVram:e.total_vram,slotMemory:e.slot_memory,kvPerSlot:e.kv_per_slot,kvPerTokenPerLayer:e.kv_per_token_per_layer,modelWeightsGPU:e.model_weights_gpu??0,modelWeightsCPU:e.model_weights_cpu??0,computeBufferEst:e.compute_buffer_est??0,alwaysActiveGPUBytes:e.always_active_gpu_bytes??0,alwaysActiveCPUBytes:e.always_active_cpu_bytes??0,expertGPUBytes:e.expert_gpu_bytes??0,expertCPUBytes:e.expert_cpu_bytes??0,kvVramBytes:e.kv_vram_bytes??0,kvCpuBytes:e.kv_cpu_bytes??0,totalSystemRamEst:e.total_system_ram_est??0,unifiedFootprint:e.unified_footprint}}function Qa(e={}){let{initialContextWindow:t=131072,initialBytesPerElement:n=2,initialSlots:r=1,serverResponse:i,enableHardwareOverrides:a=!1,modelUrl:o,modelUrls:s,modelId:c}=e,[l,u]=(0,x.useState)(t),[d,f]=(0,x.useState)(n),[p,m]=(0,x.useState)(r),[h,g]=(0,x.useState)(0),[_,v]=(0,x.useState)(Ca),[y,b]=(0,x.useState)(!1),[S,C]=(0,x.useState)(!0),[w,T]=(0,x.useState)(1),[E,D]=(0,x.useState)(``),[O,k]=(0,x.useState)(``),[A,j]=(0,x.useState)(``),[M,N]=(0,x.useState)(null),P=Ka(),F=P?.gpuCount,I=P?.gpuVramBytes??0,L=P?.ramBytes,R=P?.gpuDevices??[],z=a?Ja(O):void 0,ee=a?Ja(A):void 0,B=a&&M!=null?M:w,V=a&&(z!=null||M!=null),te=V||a&&ee!=null,H=z??I,ne=ee??L,re=(0,x.useMemo)(()=>z==null?R.slice(0,B):[],[z,R,B]),ie=!V&&P?.unifiedMemory===!0,ae=(0,x.useRef)(!1),oe=(0,x.useCallback)(e=>{ae.current=!0,T(e)},[]);(0,x.useEffect)(()=>{!P||P.gpuCount<=0||a&&M!=null||T(e=>ae.current?Math.min(Math.max(1,e),P.gpuCount):P.gpuCount)},[P,a,M]);let se=(0,x.useRef)(null);(0,x.useEffect)(()=>{if(!i||i===se.current)return;se.current=i,ge(null);let e=i.input;e&&(u(e.context_window),f(e.bytes_per_element),m(e.slots),g(Xa(e.gpu_layers,e.block_count)),v(e.expert_layers_on_gpu),C(e.swa_full??!0))},[i]);let ce=(0,x.useMemo)(()=>E?E.split(`,`).map(e=>parseFloat(e.trim())).filter(e=>!isNaN(e)):[],[E]),[le,ue]=(0,x.useState)(i??null),[de,fe]=(0,x.useState)(!1),[pe,me]=(0,x.useState)(!1),[he,ge]=(0,x.useState)(null);(0,x.useEffect)(()=>{i&&ue(i)},[i]);let _e=(0,x.useRef)(0),ve=(0,x.useRef)(!1);(0,x.useEffect)(()=>{if(!o&&!c&&!s?.length||!le&&!i||!ve.current&&(ve.current=!0,i?.fit_assessment))return;ge(null);let e=++_e.current;fe(!0);let t=setTimeout(async()=>{let t=re.slice(0,B),n=t.length===B&&t.length>0,r={model_url:o,model_urls:s,model_id:c,context_window:l,bytes_per_element:d,slots:p,gpu_layers:h===0?-1:h,expert_layers_on_gpu:_,kv_cache_on_cpu:y,swa_full:S,device_count:B,tensor_split:ce.length>0?ce:void 0,gpu_free_bytes:n?t.map(e=>e.free_bytes):void 0,gpu_capacity_bytes:H,system_ram_bytes:ne,unified_memory:ie};try{let t=await W.calculateVRAM(r);_e.current===e&&(ue(t),fe(!1))}catch{_e.current===e&&fe(!1)}},qa);return()=>clearTimeout(t)},[o,s,c,l,d,p,h,_,y,S,B,ce,re,H,ne,ie]);let ye=(0,x.useCallback)(async()=>{let e=le??i;if(de||!e||!o&&!c&&!s?.length)return;let t=e.input.block_count;if(!t||t<=0)return;ge(null);let n=Math.max(1,B),r=re.slice(0,n),a=r.length===n&&r.length>0,u=++_e.current;me(!0);let f={model_url:o,model_urls:s,model_id:c,context_window:l,bytes_per_element:d,slots:p,kv_cache_on_cpu:y,swa_full:S,device_count:n,tensor_split:ce.length>0?ce:void 0,auto_fit:!0,gpu_free_bytes:a?r.map(e=>e.free_bytes):void 0,gpu_capacity_bytes:H,system_ram_bytes:ne,unified_memory:ie};try{let e=await W.calculateVRAM(f);if(_e.current!==u)return;if(e.auto_fit_succeeded!==!0){ge(ie?`No placement fits in the available unified memory. The current placement was preserved.`:`No placement fits in the selected GPU and system memory. The current placement was preserved.`);return}ue(e),g(Xa(e.input.gpu_layers,t)),v(e.input.expert_layers_on_gpu)}catch(e){_e.current===u&&ge(e instanceof Error?e.message:`Unable to find a fitting placement.`)}finally{me(!1)}},[le,i,o,s,c,de,ie,ne,B,re,H,l,d,p,y,S,ce]),be=le??i??null,xe=be?.input,Se=(xe?.sliding_window??0)>0&&(xe?.sliding_window_layers??0)>0,Ce=be?.moe?.is_moe===!0&&be?.weights!=null,we=(0,x.useMemo)(()=>be?Za(be):null,[be]),Te=be?.per_device;return{controlsProps:{contextWindow:l,onContextWindowChange:u,bytesPerElement:d,onBytesPerElementChange:f,slots:p,onSlotsChange:m,maxDeviceCount:F,isMoE:Ce,blockCount:xe?.block_count,gpuLayers:h,onGpuLayersChange:g,expertLayersOnGPU:_,onExpertLayersOnGPUChange:v,kvCacheOnCPU:y,onKvCacheOnCPUChange:b,hasSWA:Se,swaFull:S,onSwaFullChange:C,deviceCount:B,onDeviceCountChange:oe,tensorSplit:E,onTensorSplitChange:D,showHardwareOverrides:a,gpuMemoryOverrideGB:O,onGpuMemoryOverrideGBChange:k,gpuMemoryOverrideInvalid:Ya(O),systemMemoryOverrideGB:A,onSystemMemoryOverrideGBChange:j,systemMemoryOverrideInvalid:Ya(A),deviceCountOverride:M,onDeviceCountOverrideChange:N,detectedGpuTotalBytes:I,detectedSystemRAMBytes:L,detectedDeviceCount:F,canAutoFit:!!(be&&(o||c||s?.length)),autoFitDisabled:de,autoFitting:pe,autoFitError:he,onAutoFit:()=>{ye()}},resultsProps:we&&xe?{vramResult:we,input:xe,moe:be?.moe,weights:be?.weights,gpuLayers:h,expertLayersOnGPU:_,kvCacheOnCPU:y,swaFull:S,perDevice:Te,deviceCount:B,systemRAMBytes:ne,gpuTotalBytes:H,gpuDevices:re,tensorSplit:E,isHardwareOverridden:te,isUnifiedMemory:ie,fitAssessment:be?.fit_assessment,recomputing:de}:null,isMoE:Ce,maxGpuCount:F,gpuTotalBytes:H,systemRAM:ne,gpuDevices:re}}function $a(e,t){return e?.moe?.is_moe===!0||!!t&&Object.keys(t).some(e=>e.endsWith(`.expert_count`))}var eo=[{value:``,label:`🟢 Recommended`},{value:`experts_cpu`,label:`💾 Save GPU Memory — experts on CPU`},{value:`keep_top_n`,label:`⚖️ Balanced — keep some experts on GPU`},{value:`experts_gpu`,label:`⚡ Maximum Speed — all on GPU`},{value:`custom`,label:`🔧 Advanced`}],to={experts_cpu:`💾 Save GPU Memory`,keep_top_n:`⚖️ Balanced`,experts_gpu:`⚡ Maximum Speed`},no={"model-card":`Model Card`,"draft-card":`Draft Model Card`,config:`Model Configuration`,sampling:`Sampling Parameters`,template:`Template`,vram:`VRAM Calculator`};function ro(e,t){switch(t){case`id`:return e.id.toLowerCase();case`owner`:return(e.owned_by||``).toLowerCase();case`family`:return(e.model_family||``).toLowerCase();case`projection`:return+!!e.has_projection;case`size`:return e.size;case`modified`:return new Date(e.modified).getTime();default:return``}}function io(e){return new Date(e).toLocaleString()}function ao(){let{models:e,loading:t,error:n,loadModels:r,invalidate:i}=In(),[a,o]=(0,x.useState)(null),[s,c]=(0,x.useState)(null),[l,u]=(0,x.useState)(!1),[d,f]=(0,x.useState)(null),[p,m]=(0,x.useState)(`model-card`),[h,g]=(0,x.useState)(null),[_,v]=(0,x.useState)(!1),[y,b]=(0,x.useState)(!1),[S,C]=(0,x.useState)(null),[w,T]=(0,x.useState)(!1),[E,D]=(0,x.useState)(!1),[O,k]=(0,x.useState)(!1),[A,j]=(0,x.useState)(null),[M,N]=(0,x.useState)(null),[P,F]=(0,x.useState)(`id`),[I,L]=(0,x.useState)(!0),R=s?.vram??null,[z,ee]=(0,x.useState)(),B=La(z),{controlsProps:V,resultsProps:te}=Qa({initialContextWindow:131072,initialBytesPerElement:2,serverResponse:R,modelId:a??void 0}),H=sa(s?.metadata),[ne,re]=(0,x.useState)(!1),ie=(0,x.useRef)(null),ae=(0,x.useRef)(null);(0,x.useEffect)(()=>()=>{ie.current&&clearTimeout(ie.current),ae.current&&clearTimeout(ae.current)},[]),(0,x.useEffect)(()=>{r()},[r]),(0,x.useEffect)(()=>{if(!a){c(null),f(null),ee(void 0);return}let e=!1;return u(!0),f(null),c(null),W.showModel(a).then(t=>{e||c(t)}).catch(t=>{e||f(t?.message??`Failed to load model info`)}).finally(()=>{e||u(!1)}),ee(void 0),W.autoTuneModel({model_id:a}).then(t=>{e||ee(t.recommended)}).catch(()=>{}),()=>{e=!0}},[a]);let oe=e?.data??[],se=s?.model_config?.[`draft-model`],ce=se?.[`model-id`]??null,le=!!ce;(0,x.useEffect)(()=>{if(p!==`draft-card`||!ce){g(null);return}let e=!1;return v(!0),g(null),W.showModel(ce).then(t=>{e||g(t)}).catch(()=>{}).finally(()=>{e||v(!1)}),()=>{e=!0}},[p,ce]);let ue=e=>{P===e?L(!I):(F(e),L(!0))},de=e=>{if(a===e){o(null),c(null),D(!1);return}o(e),m(`model-card`),D(!1),j(null),N(null)},fe=async()=>{b(!0),C(null),T(!1);try{await W.rebuildModelIndex(),i(),r(),o(null),c(null),T(!0),ie.current=setTimeout(()=>T(!1),3e3)}catch(e){C(e instanceof Error?e.message:`Failed to rebuild index`)}finally{b(!1)}},pe=()=>{a&&D(!0)},me=async()=>{if(a){k(!0),D(!1),j(null),N(null);try{await W.removeModel(a),N(`Model "${a}" removed successfully`),o(null),c(null),i(),await r(),ae.current=setTimeout(()=>N(null),3e3)}catch(e){j(e instanceof Error?e.message:`Failed to remove model`)}finally{k(!1)}}},he=()=>{D(!1)},ge=oe.filter(e=>e.id.split(`/`).length===2),_e=oe.filter(e=>e.id.split(`/`).length===3),ve=[...ge].sort((e,t)=>{let n=ro(e,P),r=ro(t,P),i=I?1:-1,a;return a=typeof n==`number`&&typeof r==`number`?(n-r)*i:String(n).localeCompare(String(r))*i,a!==0||P===`size`?a:e.size-t.size});return(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{className:`page-header-with-action`,children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`h2`,{children:`GGUF Models`}),(0,G.jsx)(`p`,{className:`page-description`,children:`List of all models available in the system. Click a model to view details.`})]}),(0,G.jsxs)(`div`,{style:{display:`flex`,gap:`8px`},children:[(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:()=>{i(),r(),o(null),c(null),D(!1),j(null),N(null),f(null),C(null),T(!1)},disabled:t,children:`Refresh`}),(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:fe,disabled:y||t,children:y?`Rebuilding...`:`Rebuild Index`}),a&&!E&&(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:pe,disabled:O,children:`Remove Model`}),a&&E&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:me,disabled:O,children:O?`Removing...`:`Yes, Remove`}),(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:he,disabled:O,children:`Cancel`})]})]})]}),n&&(0,G.jsx)(`div`,{className:`alert alert-error`,children:n}),A&&(0,G.jsx)(`div`,{className:`alert alert-error`,children:A}),M&&(0,G.jsx)(`div`,{className:`alert alert-success`,children:M}),S&&(0,G.jsx)(`div`,{className:`alert alert-error`,children:S}),w&&(0,G.jsx)(`div`,{className:`alert alert-success`,children:`Index rebuilt successfully`}),(0,G.jsxs)(`div`,{className:`catalog-main-content`,children:[t&&(0,G.jsx)(`div`,{className:`loading`,children:`Loading models`}),!t&&!n&&e&&(0,G.jsx)(`div`,{className:`catalog-table-wrap`,children:oe.length>0?(0,G.jsxs)(`table`,{className:`catalog-table`,children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{style:{width:`40px`,textAlign:`center`},title:`Configuration and template confirmed working with the Kronk catalog`,children:`VAL`}),[[`id`,`Model ID`],[`owner`,`Provider`],[`family`,`Family`]].map(([e,t])=>(0,G.jsxs)(`th`,{onClick:()=>ue(e),className:`catalog-table-sortable`,children:[t,(0,G.jsx)(`span`,{className:`catalog-table-sort-indicator`,children:P===e?I?` ▲`:` ▼`:``})]},e)),(0,G.jsxs)(`th`,{style:{textAlign:`center`},onClick:()=>ue(`projection`),className:`catalog-table-sortable`,title:`Multimodal projection file present`,children:[`MTMD`,(0,G.jsx)(`span`,{className:`catalog-table-sort-indicator`,children:P===`projection`?I?` ▲`:` ▼`:``})]}),[[`size`,`Size`],[`modified`,`Modified`]].map(([e,t])=>(0,G.jsxs)(`th`,{onClick:()=>ue(e),className:`catalog-table-sortable`,children:[t,(0,G.jsx)(`span`,{className:`catalog-table-sort-indicator`,children:P===e?I?` ▲`:` ▼`:``})]},e))]})}),(0,G.jsx)(`tbody`,{children:ve.map(e=>{let t=_e.filter(t=>t.id.startsWith(e.id+`/`)),n=a===e.id,r=a?.startsWith(e.id+`/`),i=n||r;return(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(`tr`,{className:a===e.id?`active`:``,onClick:()=>de(e.id),children:[(0,G.jsx)(`td`,{style:{textAlign:`center`,color:e.validated?`inherit`:`var(--color-error)`},children:e.validated?`✓`:`✗`}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`span`,{className:`catalog-table-cell-ellipsis`,children:e.id})}),(0,G.jsx)(`td`,{children:e.owned_by||`-`}),(0,G.jsx)(`td`,{children:e.model_family||`-`}),(0,G.jsx)(`td`,{style:{textAlign:`center`},children:e.has_projection?`✓`:``}),(0,G.jsx)(`td`,{children:J(e.size)}),(0,G.jsx)(`td`,{children:io(e.modified)})]},e.id),i&&t.map(e=>(0,G.jsxs)(`tr`,{className:a===e.id?`active`:``,onClick:()=>de(e.id),children:[(0,G.jsx)(`td`,{}),(0,G.jsx)(`td`,{style:{paddingLeft:`24px`},children:(0,G.jsxs)(`span`,{className:`catalog-table-cell-ellipsis`,children:[`↳ `,e.id]})}),(0,G.jsx)(`td`,{}),(0,G.jsx)(`td`,{children:`Configuration Profile`}),(0,G.jsx)(`td`,{}),(0,G.jsx)(`td`,{}),(0,G.jsx)(`td`,{})]},e.id))]})})})]}):(0,G.jsxs)(`div`,{className:`empty-state`,children:[(0,G.jsx)(`h3`,{children:`No models found`}),(0,G.jsx)(`p`,{children:`Pull a model to get started`})]})}),d&&(0,G.jsx)(`div`,{className:`alert alert-error`,style:{marginTop:`16px`},children:d}),l&&(0,G.jsx)(`div`,{style:{marginTop:`16px`},children:(0,G.jsx)(`div`,{className:`loading`,children:`Loading model details`})}),a&&s&&!l&&(0,G.jsxs)(`div`,{style:{marginTop:`16px`,borderTop:`1px solid var(--color-gray-200)`,paddingTop:`16px`},children:[(0,G.jsx)(`div`,{className:`tabs`,children:Object.keys(no).filter(e=>e!==`draft-card`||le).map(e=>(0,G.jsx)(`button`,{className:`tab ${p===e?`active`:``}`,onClick:()=>m(e),children:no[e]},e))}),p===`config`&&(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`h3`,{style:{marginBottom:`16px`},children:a}),s.desc&&(0,G.jsx)(`div`,{style:{marginBottom:`16px`},children:(0,G.jsx)(`p`,{children:s.desc})}),(0,G.jsx)(la,{rows:[{key:`owner`,label:`Provider`,value:s.owned_by},{key:`size`,label:`Size`,value:J(s.size)},...s.quantization?[{key:`quantization`,label:Y(`Quantization`,`quantization`),value:s.quantization}]:[],{key:`created`,label:`Created`,value:new Date(s.created).toLocaleString()},{key:`projection`,label:Y(`Has Projection`,`hasProjection`),value:(0,G.jsx)(`span`,{className:`badge ${s.has_projection?`badge-yes`:`badge-no`}`,children:s.has_projection?`Yes`:`No`})},{key:`validated`,label:Y(`Validated`,`validated`),value:(()=>{let e=oe.find(e=>e.id===a);return e?(0,G.jsx)(`span`,{style:{color:e.validated?`inherit`:`var(--color-error)`},children:e.validated?`✓`:`✗`}):`-`})()}]}),s.model_config&&(0,G.jsxs)(`div`,{style:{marginTop:`24px`},children:[(0,G.jsx)(`h4`,{className:`meta-section-title`,style:{marginBottom:`8px`},children:`Configuration`}),(0,G.jsx)(la,{rows:(()=>{let e=s.model_config,t=e=>(0,G.jsx)(`span`,{className:`badge ${e?`badge-yes`:`badge-no`}`,children:e?`Yes`:`No`});return[{key:`cache-min-tokens`,label:Y(`cache-min-tokens`,`cacheMinTokens`),value:na(e[`cache-min-tokens`])},{key:`cache-type-k`,label:Y(`cache-type-k`,`cacheTypeK`),value:e[`cache-type-k`]||`default`},{key:`cache-type-v`,label:Y(`cache-type-v`,`cacheTypeV`),value:e[`cache-type-v`]||`default`},{key:`context-window`,label:Y(`context-window`,`contextWindow`),value:na(e[`context-window`])},{key:`devices`,label:Y(`devices`,`devices`),value:e.devices?.join(`, `)||`—`},{key:`draft-model.devices`,label:Y(`draft-model.devices`,`draftDevice`),value:e[`draft-model`]?.devices?.join(`, `)||`—`},{key:`draft-model.main-gpu`,label:Y(`draft-model.main-gpu`,`draftMainGpu`),value:na(e[`draft-model`]?.[`main-gpu`])},{key:`draft-model.model-id`,label:Y(`draft-model.model-id`,`draftModel`),value:e[`draft-model`]?.[`model-id`]||`—`},{key:`draft-model.ndraft`,label:Y(`draft-model.ndraft`,`draftTokens`),value:na(e[`draft-model`]?.ndraft)},{key:`draft-model.ngpu-layers`,label:Y(`draft-model.ngpu-layers`,`draftGpuLayers`),value:na(e[`draft-model`]?.[`ngpu-layers`])},{key:`draft-model.tensor-split`,label:Y(`draft-model.tensor-split`,`draftTensorSplit`),value:e[`draft-model`]?.[`tensor-split`]?.join(`, `)||`—`},{key:`flash-attention`,label:Y(`flash-attention`,`flashAttention`),value:e[`flash-attention`]||`default`},{key:`imc-session-capacity`,label:Y(`imc-session-capacity`,`imcSessionCapacity`),value:na(e[`imc-session-capacity`])},{key:`incremental-cache`,label:Y(`incremental-cache`,`incrementalCache`),value:t(e[`incremental-cache`])},{key:`load-mode`,label:Y(`load-mode`,`loadMode`),value:e[`load-mode`]||`auto`},{key:`main-gpu`,label:Y(`main-gpu`,`mainGpu`),value:na(e[`main-gpu`])},{key:`moe.keep-experts-top-n`,label:Y(`moe.keep-experts-top-n`,`moeKeepExpertsTopN`),value:na(e.moe?.[`keep-experts-top-n`])},{key:`moe.mode`,label:Y(`moe.mode`,`moeMode`),value:e.moe?.mode||`—`},{key:`prefill-batch-size`,label:Y(`Prefill Batch Size`,`prefillBatchSize`),value:na(e[`prefill-batch-size`])},{key:`ngpu-layers`,label:Y(`ngpu-layers`,`ngpuLayers`),value:na(e[`ngpu-layers`]??`auto`)},{key:`nseq-max`,label:Y(`nseq-max`,`nSeqMax`),value:na(e[`nseq-max`])},{key:`nthreads`,label:Y(`nthreads`,`nthreads`),value:na(e.nthreads)},{key:`nthreads-batch`,label:Y(`nthreads-batch`,`nthreadsBatch`),value:na(e[`nthreads-batch`])},{key:`numa`,label:Y(`numa`,`numa`),value:e.numa||`—`},{key:`offload-kqv`,label:Y(`offload-kqv`,`offloadKQV`),value:na(e[`offload-kqv`])},{key:`op-offload`,label:Y(`op-offload`,`opOffload`),value:na(e[`op-offload`])},{key:`op-offload-min-batch`,label:Y(`op-offload-min-batch`,`opOffloadMinBatch`),value:na(e[`op-offload-min-batch`])},{key:`proj-on-cpu`,label:Y(`proj-on-cpu`,`projOnCpu`),value:na(e[`proj-on-cpu`])},{key:`proj-device`,label:Y(`proj-device`,`projDevice`),value:e[`proj-device`]||`automatic`},{key:`rope-freq-base`,label:Y(`rope-freq-base`,`ropeFreqBase`),value:na(e[`rope-freq-base`])},{key:`rope-freq-scale`,label:Y(`rope-freq-scale`,`ropeFreqScale`),value:na(e[`rope-freq-scale`])},{key:`rope-scaling-type`,label:Y(`rope-scaling-type`,`ropeScaling`),value:e[`rope-scaling-type`]||`—`},{key:`split-mode`,label:Y(`split-mode`,`splitMode`),value:e[`split-mode`]||`default`},{key:`swa-full`,label:Y(`swa-full`,`swaFull`),value:e[`swa-full`]==null?(0,G.jsx)(`span`,{className:`badge badge-yes`,children:`Yes (default)`}):t(e[`swa-full`])},{key:`tensor-buft-overrides`,label:Y(`tensor-buft-overrides`,`tensorBuftOverrides`),value:e[`tensor-buft-overrides`]?.join(`, `)||`—`},{key:`tensor-split`,label:Y(`tensor-split`,`tensorSplit`),value:e[`tensor-split`]?.join(`, `)||`—`},{key:`yarn-attn-factor`,label:Y(`yarn-attn-factor`,`yarnAttnFactor`),value:na(e[`yarn-attn-factor`])},{key:`yarn-beta-fast`,label:Y(`yarn-beta-fast`,`yarnBetaFast`),value:na(e[`yarn-beta-fast`])},{key:`yarn-beta-slow`,label:Y(`yarn-beta-slow`,`yarnBetaSlow`),value:na(e[`yarn-beta-slow`])},{key:`yarn-ext-factor`,label:Y(`yarn-ext-factor`,`yarnExtFactor`),value:na(e[`yarn-ext-factor`])},{key:`yarn-orig-ctx`,label:Y(`yarn-orig-ctx`,`yarnOrigCtx`),value:na(e[`yarn-orig-ctx`])}]})()})]})]}),p===`sampling`&&(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`h3`,{style:{marginBottom:`16px`},children:`Sampling Parameters`}),s.model_config?.[`sampling-parameters`]?(()=>{let e=s.model_config[`sampling-parameters`];return(0,G.jsx)(la,{rows:[{key:`dry_allowed_length`,label:Y(`dry_allowed_length`,`dry_allowed_length`),value:na(e.dry_allowed_length)},{key:`dry_base`,label:Y(`dry_base`,`dry_base`),value:na(e.dry_base)},{key:`dry_multiplier`,label:Y(`dry_multiplier`,`dry_multiplier`),value:na(e.dry_multiplier)},{key:`dry_penalty_last_n`,label:Y(`dry_penalty_last_n`,`dry_penalty_last_n`),value:na(e.dry_penalty_last_n)},{key:`enable_thinking`,label:Y(`enable_thinking`,`enable_thinking`),value:na(e.enable_thinking??`—`)},{key:`frequency_penalty`,label:Y(`frequency_penalty`,`frequency_penalty`),value:ta(e.frequency_penalty)},{key:`grammar`,label:Y(`grammar`,`grammar`),value:na(e.grammar||`—`)},{key:`max_tokens`,label:Y(`max_tokens`,`max_tokens`),value:na(e.max_tokens)},{key:`min_p`,label:Y(`min_p`,`min_p`),value:ta(e.min_p)},{key:`presence_penalty`,label:Y(`presence_penalty`,`presence_penalty`),value:ta(e.presence_penalty)},{key:`reasoning_effort`,label:Y(`reasoning_effort`,`reasoning_effort`),value:na(e.reasoning_effort??`—`)},{key:`repeat_last_n`,label:Y(`repeat_last_n`,`repeat_last_n`),value:na(e.repeat_last_n)},{key:`repeat_penalty`,label:Y(`repeat_penalty`,`repeat_penalty`),value:ta(e.repeat_penalty)},{key:`temperature`,label:Y(`temperature`,`temperature`),value:ta(e.temperature)},{key:`top_k`,label:Y(`top_k`,`top_k`),value:na(e.top_k)},{key:`top_p`,label:Y(`top_p`,`top_p`),value:ta(e.top_p)},{key:`xtc_min_keep`,label:Y(`xtc_min_keep`,`xtc_min_keep`),value:na(e.xtc_min_keep)},{key:`xtc_probability`,label:Y(`xtc_probability`,`xtc_probability`),value:na(e.xtc_probability)},{key:`xtc_threshold`,label:Y(`xtc_threshold`,`xtc_threshold`),value:na(e.xtc_threshold)}]})})():(0,G.jsx)(`div`,{className:`empty-state`,children:(0,G.jsx)(`p`,{children:`No sampling parameters configured for this model.`})})]}),p===`model-card`&&(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`h3`,{style:{marginBottom:`16px`},children:`Model Card`}),(0,G.jsx)(va,{metadata:s.metadata??{},quantization:s.quantization,webPage:s.web_page})]}),p===`draft-card`&&le&&(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`h3`,{style:{marginBottom:`16px`},children:`Draft Model Card`}),(0,G.jsxs)(`div`,{style:{marginBottom:`24px`},children:[(0,G.jsx)(`h4`,{className:`meta-section-title`,style:{marginBottom:`8px`},children:`Draft Settings`}),(0,G.jsx)(la,{rows:[{key:`draft-id`,label:Y(`Model ID`,`draftModel`),value:ce??`-`},...se?[{key:`draft-ndraft`,label:Y(`Draft Tokens`,`draftTokens`),value:na(se.ndraft)},...se[`ngpu-layers`]==null?[]:[{key:`draft-ngpu`,label:Y(`GPU Layers`,`ngpuLayers`),value:na(se[`ngpu-layers`])}],...se.devices?.length?[{key:`draft-devices`,label:Y(`Devices`,`devices`),value:se.devices.join(`, `)}]:[]]:[]]})]}),_&&(0,G.jsx)(`div`,{className:`loading`,children:`Loading draft model details`}),h&&(0,G.jsxs)(`div`,{style:{marginBottom:`24px`},children:[(0,G.jsx)(`h4`,{className:`meta-section-title`,style:{marginBottom:`8px`},children:`Model Details`}),(0,G.jsx)(la,{rows:[{key:`draft-owner`,label:`Provider`,value:h.owned_by},{key:`draft-size`,label:`Size`,value:J(h.size)},...h.quantization?[{key:`draft-quantization`,label:Y(`Quantization`,`quantization`),value:h.quantization}]:[]]})]}),h?(0,G.jsx)(va,{metadata:h.metadata??{},quantization:h.quantization,webPage:h.web_page}):!_&&(0,G.jsx)(`div`,{className:`empty-state`,children:(0,G.jsx)(`p`,{children:`No metadata available for the draft model.`})})]}),p===`template`&&(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`h3`,{style:{marginBottom:`16px`},children:`Chat Template`}),s.metadata?.[`tokenizer.chat_template`]?(0,G.jsx)(ya,{code:s.metadata[`tokenizer.chat_template`],language:`django`}):(0,G.jsx)(`div`,{className:`empty-state`,children:(0,G.jsx)(`p`,{children:`No chat template found in metadata.`})})]}),p===`vram`&&(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{style:{display:`flex`,justifyContent:`space-between`,alignItems:`center`,marginBottom:`16px`},children:[(0,G.jsx)(`h3`,{children:`VRAM Calculator`}),(0,G.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:()=>re(!0),children:`Learn More`})]}),ne&&(0,G.jsx)(Ta,{onClose:()=>re(!1)}),te?(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`p`,{style:{fontSize:`13px`,color:`var(--color-text-secondary)`,marginBottom:`16px`},children:`Computed locally from GGUF header. Adjust parameters below to see how they affect VRAM.`}),(0,G.jsx)(Ha,{controlsProps:V,resultsProps:te,variant:`compact`,contextInfo:H,catalogConfigName:a??void 0,catalogConfigDefaults:B})]}):(0,G.jsx)(`div`,{className:`empty-state`,children:(0,G.jsx)(`p`,{children:`No VRAM data available for this model.`})})]})]})]})]})}function oo({label:e,sublabel:t,used:n,budget:r,total:i}){let a=Math.max(i,1),o=Math.max(r,0),s=Math.max(n,0),c=s/a*100,l=o/a*100,u=o>0?s/o*100:0,d=`usage-bar-fill usage-bar-fill-low`;return u>=85?d=`usage-bar-fill usage-bar-fill-high`:u>=60&&(d=`usage-bar-fill usage-bar-fill-mid`),(0,G.jsxs)(`div`,{className:`usage-bar-row`,children:[(0,G.jsxs)(`div`,{className:`usage-bar-label`,children:[(0,G.jsx)(`strong`,{children:e}),t&&(0,G.jsxs)(`span`,{className:`usage-bar-sublabel`,children:[` `,t]})]}),(0,G.jsxs)(`div`,{className:`usage-bar-track`,title:`Used ${J(s)} / Budget ${J(o)} / Total ${J(i)}`,children:[(0,G.jsx)(`div`,{className:d,style:{width:`${Math.min(c,100)}%`}}),l<100&&(0,G.jsx)(`div`,{className:`usage-bar-cap-marker`,style:{left:`${Math.min(l,100)}%`}})]}),(0,G.jsxs)(`div`,{className:`usage-bar-readout`,children:[(0,G.jsx)(`span`,{className:`usage-bar-used`,children:J(s)}),(0,G.jsx)(`span`,{className:`usage-bar-sep`,children:` / `}),(0,G.jsx)(`span`,{className:`usage-bar-budget`,children:J(o)}),(0,G.jsxs)(`span`,{className:`usage-bar-pct`,children:[` (`,u.toFixed(1),`%)`]}),` `,(0,G.jsx)(aa,{tooltipKey:`budgetUsageBar`})]})]})}function so(e){if(!e)return`—`;if(e.startsWith(`0001-01-01`))return`Never`;let t=new Date(e);return Number.isNaN(t.getTime())?`—`:t.toLocaleString()}function co(e,t){return t<=0?`0%`:`${(e/t*100).toFixed(1)}%`}function lo(){let[e,t]=(0,x.useState)(null),[n,r]=(0,x.useState)(null),[i,a]=(0,x.useState)(!0),[o,s]=(0,x.useState)(null),[c,l]=(0,x.useState)(null);(0,x.useEffect)(()=>{u();let e=window.setInterval(()=>{u(!0)},5e3);return()=>window.clearInterval(e)},[]);let u=async(e=!1)=>{e||a(!0),s(null);try{let[e,n]=await Promise.all([W.listRunningModels(),W.getPoolBudget()]);t(e),r(n)}catch(e){s(e instanceof Error?e.message:`Failed to load running models`)}finally{e||a(!1)}},d=async e=>{if(confirm(`Unload model "${e}"?`)){l(e),s(null);try{await W.unloadModel(e),await u()}catch(e){s(e instanceof Error?e.message:`Failed to unload model`)}finally{l(null)}}};return(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{className:`page-header-with-action`,children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`h2`,{children:`Running Models`}),(0,G.jsx)(`p`,{className:`page-description`,children:`Models currently loaded in cache and the pool's resource budget`})]}),(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:()=>u(),disabled:i,children:`Refresh`})]}),n&&(0,G.jsxs)(`div`,{className:`card`,children:[(0,G.jsxs)(`h3`,{style:{marginTop:0},children:[`Resource Budget — `,n.budget_percent,`% of detected hardware`,` `,(0,G.jsx)(aa,{tooltipKey:`budgetPercent`})]}),(0,G.jsxs)(`p`,{style:{marginTop:0,marginBottom:16,color:`var(--text-muted, #888)`},children:[`Headroom per GPU: `,J(n.headroom_bytes),` `,(0,G.jsx)(aa,{tooltipKey:`budgetHeadroom`})]}),n.unified_memory&&(0,G.jsx)(`p`,{style:{marginTop:0,marginBottom:16,color:`var(--text-muted, #888)`},children:(0,G.jsxs)(`em`,{children:[`Apple Silicon unified memory detected. The GPU (Metal) and CPU share a single physical pool, so the resman tracks just one budget under `,(0,G.jsx)(`strong`,{children:`Unified Memory`}),` below to avoid double-counting the same bytes against two budgets.`]})}),(0,G.jsxs)(`div`,{className:`usage-bar-list`,children:[n.devices.map(e=>(0,G.jsx)(oo,{label:e.name,sublabel:e.type,used:e.used_bytes,budget:e.budget_bytes,total:e.total_bytes},`bar-${e.index}-${e.name}`)),(n.ram_total>0||n.ram_budget>0)&&(0,G.jsx)(oo,{label:n.unified_memory?`Unified Memory`:`System RAM`,sublabel:n.unified_memory?`metal+ram`:`ram`,used:n.ram_used,budget:n.ram_budget,total:n.ram_total>0?n.ram_total:n.ram_budget})]}),(0,G.jsx)(`div`,{className:`table-container`,children:(0,G.jsxs)(`table`,{children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{children:`Device`}),(0,G.jsx)(`th`,{children:`Type`}),(0,G.jsx)(`th`,{style:{textAlign:`right`},children:Y(`Total`,`budgetDeviceTotal`)}),(0,G.jsx)(`th`,{style:{textAlign:`right`},children:Y(`Budget`,`budgetDeviceBudget`)}),(0,G.jsx)(`th`,{style:{textAlign:`right`},children:Y(`Used`,`budgetDeviceUsed`)}),(0,G.jsx)(`th`,{style:{textAlign:`right`},children:Y(`% of Budget`,`budgetDevicePctOfBudget`)}),(0,G.jsx)(`th`,{style:{textAlign:`right`},children:Y(`Free in Budget`,`budgetDeviceFree`)})]})}),(0,G.jsxs)(`tbody`,{children:[n.devices.map(e=>(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:e.name}),(0,G.jsx)(`td`,{children:e.type}),(0,G.jsx)(`td`,{style:{textAlign:`right`},children:J(e.total_bytes)}),(0,G.jsx)(`td`,{style:{textAlign:`right`},children:J(e.budget_bytes)}),(0,G.jsx)(`td`,{style:{textAlign:`right`},children:J(e.used_bytes)}),(0,G.jsx)(`td`,{style:{textAlign:`right`},children:co(e.used_bytes,e.budget_bytes)}),(0,G.jsx)(`td`,{style:{textAlign:`right`},children:J(Math.max(e.budget_bytes-e.used_bytes,0))})]},`${e.index}-${e.name}`)),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:n.unified_memory?`Unified Memory`:`System RAM`}),(0,G.jsx)(`td`,{children:n.unified_memory?`metal+ram`:`ram`}),(0,G.jsx)(`td`,{style:{textAlign:`right`},children:n.ram_total>0?J(n.ram_total):`—`}),(0,G.jsx)(`td`,{style:{textAlign:`right`},children:J(n.ram_budget)}),(0,G.jsx)(`td`,{style:{textAlign:`right`},children:J(n.ram_used)}),(0,G.jsx)(`td`,{style:{textAlign:`right`},children:co(n.ram_used,n.ram_budget)}),(0,G.jsx)(`td`,{style:{textAlign:`right`},children:J(Math.max(n.ram_budget-n.ram_used,0))})]})]})]})}),n.reservations.length>0&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(`h4`,{style:{marginTop:24,marginBottom:4},children:[`Active Reservations (`,n.reservations.length,`)`]}),(0,G.jsx)(`p`,{style:{marginTop:0,marginBottom:12,color:`var(--text-muted, #888)`},children:`Bytes currently charged against the resource budget by the resman. May briefly differ from Loaded Models during load or unload.`}),(0,G.jsx)(`div`,{className:`table-container`,children:(0,G.jsxs)(`table`,{children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{children:Y(`Key`,`budgetReservationKey`)}),(0,G.jsx)(`th`,{style:{textAlign:`right`},children:Y(`Total`,`budgetReservationTotal`)}),n.unified_memory?(0,G.jsx)(`th`,{style:{textAlign:`right`},children:Y(`Unified Memory`,`budgetReservationUnified`)}):(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`th`,{style:{textAlign:`right`},children:Y(`VRAM`,`budgetReservationVRAM`)}),(0,G.jsx)(`th`,{style:{textAlign:`right`},children:Y(`System`,`budgetReservationSystem`)})]}),(0,G.jsx)(`th`,{children:Y(`Per-Device`,`budgetReservationPerDevice`)})]})}),(0,G.jsx)(`tbody`,{children:n.reservations.map(e=>(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{style:{whiteSpace:`nowrap`},children:e.key}),(0,G.jsx)(`td`,{style:{textAlign:`right`,fontWeight:`bold`,whiteSpace:`nowrap`},children:J(e.vram_bytes+e.ram_bytes)}),n.unified_memory?(0,G.jsx)(`td`,{style:{textAlign:`right`,whiteSpace:`nowrap`},children:J(e.vram_bytes+e.ram_bytes)}):(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`td`,{style:{textAlign:`right`,whiteSpace:`nowrap`},children:J(e.vram_bytes)}),(0,G.jsx)(`td`,{style:{textAlign:`right`,whiteSpace:`nowrap`},children:J(e.ram_bytes)})]}),(0,G.jsx)(`td`,{children:e.per.length===0?`—`:e.per.map(e=>`${e.name}: ${J(e.bytes)}`).join(`, `)})]},e.key))})]})})]})]}),(0,G.jsxs)(`div`,{className:`card`,children:[(0,G.jsx)(`h3`,{style:{marginTop:0,marginBottom:4},children:`Loaded Models`}),(0,G.jsx)(`p`,{style:{marginTop:0,marginBottom:16,color:`var(--text-muted, #888)`},children:`Models currently in cache and serving traffic.`}),i&&(0,G.jsx)(`div`,{className:`loading`,children:`Loading running models`}),o&&(0,G.jsx)(`div`,{className:`alert alert-error`,children:o}),!i&&!o&&e&&(0,G.jsx)(`div`,{className:`table-container`,children:e.length>0?(0,G.jsxs)(`table`,{children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{children:Y(`ID`,`runningModelID`)}),(0,G.jsx)(`th`,{children:Y(`Backend`,`runningModelBackend`)}),(0,G.jsx)(`th`,{children:Y(`Status`,`runningModelStatus`)}),(0,G.jsx)(`th`,{children:Y(`Owner`,`runningModelOwner`)}),(0,G.jsx)(`th`,{children:Y(`Family`,`runningModelFamily`)}),(0,G.jsx)(`th`,{style:{textAlign:`right`},children:Y(`Size`,`runningModelSize`)}),(0,G.jsx)(`th`,{style:{textAlign:`right`},children:Y(`VRAM`,`runningModelVRAMTotal`)}),(0,G.jsx)(`th`,{style:{textAlign:`right`},children:Y(`KV`,`runningModelKVCache`)}),(0,G.jsx)(`th`,{style:{textAlign:`right`},children:Y(`Slots`,`runningModelSlots`)}),(0,G.jsx)(`th`,{children:Y(`Expires`,`runningModelExpiresAt`)}),(0,G.jsx)(`th`,{style:{textAlign:`right`},children:Y(`Streams`,`runningModelActiveStreams`)}),(0,G.jsx)(`th`,{})]})}),(0,G.jsx)(`tbody`,{children:e.map(e=>{let t=e.status===`loading`;return(0,G.jsxs)(`tr`,{style:t?{opacity:.7,fontStyle:`italic`}:void 0,children:[(0,G.jsx)(`td`,{children:e.id}),(0,G.jsx)(`td`,{style:{whiteSpace:`nowrap`},children:e.backend||`—`}),(0,G.jsx)(`td`,{style:{whiteSpace:`nowrap`},children:t?(0,G.jsx)(`span`,{style:{color:`var(--text-muted, #888)`},children:`Loading…`}):`loaded`}),(0,G.jsx)(`td`,{children:e.owned_by||`—`}),(0,G.jsx)(`td`,{children:e.model_family||`—`}),(0,G.jsx)(`td`,{style:{textAlign:`right`,whiteSpace:`nowrap`},children:e.size>0?J(e.size):`—`}),(0,G.jsx)(`td`,{style:{textAlign:`right`,whiteSpace:`nowrap`},children:J(e.vram_total)}),(0,G.jsx)(`td`,{style:{textAlign:`right`,whiteSpace:`nowrap`},children:t||e.kv_cache===0?`—`:J(e.kv_cache)}),(0,G.jsx)(`td`,{style:{textAlign:`right`},children:t?`—`:e.slots}),(0,G.jsx)(`td`,{style:{whiteSpace:`nowrap`},children:t?`—`:so(e.expires_at)}),(0,G.jsx)(`td`,{style:{textAlign:`right`},children:t?`—`:e.active_streams}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`button`,{className:`btn btn-primary btn-sm`,onClick:()=>d(e.id),disabled:c===e.id||e.active_streams>0||t,title:t?`Cannot unload while the model is still loading`:e.active_streams>0?`Cannot unload while streams are active`:`Unload model from cache`,children:c===e.id?`Unloading…`:`Unload`})})]},e.id)})}),e.length>1&&(0,G.jsx)(`tfoot`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{colSpan:6,style:{textAlign:`right`,fontWeight:`bold`},children:`Total:`}),(0,G.jsx)(`td`,{style:{textAlign:`right`,fontWeight:`bold`,whiteSpace:`nowrap`},children:J(e.reduce((e,t)=>e+t.vram_total,0))}),(0,G.jsx)(`td`,{style:{textAlign:`right`,fontWeight:`bold`,whiteSpace:`nowrap`},children:J(e.reduce((e,t)=>e+(t.status===`loading`?0:t.kv_cache),0))}),(0,G.jsx)(`td`,{style:{textAlign:`right`,fontWeight:`bold`,whiteSpace:`nowrap`},children:e.reduce((e,t)=>e+(t.status===`loading`?0:t.slots),0)}),(0,G.jsx)(`td`,{colSpan:3})]})})]}):(0,G.jsxs)(`div`,{className:`empty-state`,children:[(0,G.jsx)(`h3`,{children:`No running models`}),(0,G.jsx)(`p`,{children:`Models will appear here when loaded into cache`})]})})]})]})}var uo=``,fo={active:0,idle:1,empty:2},po=[[`Model`,`imcModelID`],[`Cache Entry`,`imcSessionID`],[`State`,`imcState`],[`Current Messages`,`imcMessages`],[`Current Tokens`,`imcContext`],[`Current Allocated`,`imcAllocated`],[`Latest Request Input`,`imcInputTokens`],[`Latest Request Output`,`imcOutputTokens`],[`Latest Request Context`,`imcRequestTotal`],[`Peak Context`,`imcPeakContext`],[`Peak Memory`,`imcSnapshotBytes`],[`Peak Used`,`imcUtilization`],[`Media`,`imcMedia`],[`Last Used`,`imcLastUsed`]],mo=[[`Model`,`imcModelID`],[`Cache Entry`,`imcSystemCacheID`],[`System Tokens`,`imcSystemContext`],[`Allocated`,`imcSystemAllocated`],[`Snapshot Memory`,`imcSystemSnapshotBytes`],[`Restores`,`imcSystemRestores`],[`Active Restores`,`imcSystemActiveRestores`],[`Last Used`,`imcLastUsed`]],ho=`kronk-imc-view`,go=`kronk-imc-model`;function _o(){try{return sessionStorage.getItem(ho)===`system`?`system`:`current`}catch{return`current`}}function vo(){try{return sessionStorage.getItem(go)??uo}catch{return uo}}function yo(e){if(!e||e.startsWith(`0001-01-01`))return`—`;let t=new Date(e);return Number.isNaN(t.getTime())?`—`:t.toLocaleString()}function bo(e,t){return t>0?`${(e/t*100).toFixed(1)}%`:`0%`}function xo(){let[e,t]=(0,x.useState)(null),[n,r]=(0,x.useState)(null),[i,a]=(0,x.useState)(_o),[o,s]=(0,x.useState)(vo),[c,l]=(0,x.useState)(`last_used`),[u,d]=(0,x.useState)(!1),[f,p]=(0,x.useState)(`last_used`),[m,h]=(0,x.useState)(!1),[g,_]=(0,x.useState)(!0),[v,y]=(0,x.useState)(null),[b,S]=(0,x.useState)(!1),C=async(e=!1)=>{e||_(!0),y(null);try{let[e,n]=await Promise.all([W.listIMCSessions(),W.listIMCSystemCaches()]);t(e),r(n);let i=new Set([...e,...n].map(e=>e.model_id));s(e=>e===uo||i.has(e)?e:uo)}catch(e){y(e instanceof Error?e.message:`Failed to load IMC caches`)}finally{e||_(!1)}};(0,x.useEffect)(()=>{C();let e=window.setInterval(()=>C(!0),5e3);return()=>window.clearInterval(e)},[]),(0,x.useEffect)(()=>{try{sessionStorage.setItem(ho,i)}catch{}},[i]),(0,x.useEffect)(()=>{try{sessionStorage.setItem(go,o)}catch{}},[o]),(0,x.useEffect)(()=>{if(!b)return;let e=e=>e.key===`Escape`&&S(!1);return document.addEventListener(`keydown`,e),()=>document.removeEventListener(`keydown`,e)},[b]);let w=e=>{e===c?d(e=>!e):(l(e),d(!0))},T=e=>{e===f?h(e=>!e):(p(e),h(!0))},E=e=>c===e?u?` ▲`:` ▼`:``,D=e=>f===e?m?` ▲`:` ▼`:``,O=[...new Set([...e??[],...n??[]].map(e=>e.model_id))].sort((e,t)=>e.localeCompare(t)),k=(e??[]).filter(e=>o===uo||e.model_id===o),A=(n??[]).filter(e=>o===uo||e.model_id===o),j=k.sort((e,t)=>{let n;switch(c){case`model_id`:n=e.model_id.localeCompare(t.model_id);break;case`id`:n=e.id-t.id;break;case`state`:n=fo[e.state]-fo[t.state];break;case`messages`:n=e.messages-t.messages;break;case`context`:n=e.context-t.context;break;case`allocated`:n=e.allocated-t.allocated;break;case`snapshot_bytes`:n=e.snapshot_bytes-t.snapshot_bytes;break;case`input_tokens`:n=e.input_tokens-t.input_tokens;break;case`output_tokens`:n=e.output_tokens-t.output_tokens;break;case`request_context`:n=e.input_tokens+e.output_tokens-t.input_tokens-t.output_tokens;break;case`peak_context`:n=e.peak_context-t.peak_context;break;case`utilization`:n=So(e)-So(t);break;case`has_media`:n=Number(e.has_media)-Number(t.has_media);break;case`last_used`:n=Date.parse(e.last_used)-Date.parse(t.last_used)}return n||=e.model_id.localeCompare(t.model_id)||e.id-t.id,u?n:-n}),M=A.sort((e,t)=>{let n;switch(f){case`model_id`:n=e.model_id.localeCompare(t.model_id);break;case`id`:n=e.id-t.id;break;case`tokens`:n=e.tokens-t.tokens;break;case`allocated`:n=e.allocated-t.allocated;break;case`snapshot_bytes`:n=e.snapshot_bytes-t.snapshot_bytes;break;case`restore_count`:n=e.restore_count-t.restore_count;break;case`active_restores`:n=e.active_restores-t.active_restores;break;case`last_used`:n=Date.parse(e.last_used)-Date.parse(t.last_used)}return n||=e.model_id.localeCompare(t.model_id)||e.id-t.id,m?n:-n});return(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{className:`page-header-with-action`,children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`h2`,{children:`IMC Sessions`}),(0,G.jsx)(`p`,{className:`page-description`,children:`Working sessions and reusable System prompt caches for loaded models`})]}),(0,G.jsxs)(`div`,{style:{display:`flex`,gap:`8px`},children:[(0,G.jsx)(`button`,{className:`btn btn-secondary`,onClick:()=>S(!0),children:`Field Guide`}),(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:()=>C(),disabled:g,children:`Refresh`})]})]}),(0,G.jsxs)(`div`,{className:`tabs`,role:`tablist`,"aria-label":`IMC cache type`,children:[(0,G.jsx)(`button`,{type:`button`,role:`tab`,"aria-selected":i===`current`,className:`tab ${i===`current`?`active`:``}`,onClick:()=>a(`current`),children:`Working Sessions`}),(0,G.jsx)(`button`,{type:`button`,role:`tab`,"aria-selected":i===`system`,className:`tab ${i===`system`?`active`:``}`,onClick:()=>a(`system`),children:`System Caches`})]}),b&&(0,G.jsx)(`div`,{className:`modal-overlay`,role:`dialog`,"aria-modal":`true`,"aria-labelledby":`imc-field-guide-title`,onClick:()=>S(!1),children:(0,G.jsxs)(`div`,{className:`modal-content`,onClick:e=>e.stopPropagation(),children:[(0,G.jsxs)(`div`,{className:`modal-header`,children:[(0,G.jsxs)(`h3`,{id:`imc-field-guide-title`,children:[`IMC `,i===`current`?`Working Session`:`System Cache`,` Field Guide`]}),(0,G.jsx)(`button`,{className:`modal-close`,onClick:()=>S(!1),"aria-label":`Close field guide`,children:`×`})]}),(0,G.jsx)(`div`,{className:`modal-body`,children:(0,G.jsx)(`dl`,{style:{margin:0,display:`grid`,gap:`20px`},children:(i===`current`?po:mo).map(([e,t])=>(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`dt`,{children:(0,G.jsx)(`strong`,{children:e})}),(0,G.jsx)(`dd`,{style:{margin:`4px 0 0`},children:ia[t]})]},t))})})]})}),v&&(0,G.jsx)(`div`,{className:`alert alert-error`,children:v}),O.length>0&&(0,G.jsxs)(`div`,{className:`tabs imc-model-tabs`,role:`tablist`,"aria-label":`IMC caches by model`,children:[(0,G.jsx)(`button`,{type:`button`,role:`tab`,"aria-selected":o===uo,className:`tab ${o===uo?`active`:``}`,onClick:()=>s(uo),children:`All`}),O.map(e=>(0,G.jsx)(`button`,{type:`button`,role:`tab`,"aria-selected":o===e,className:`tab imc-model-tab ${o===e?`active`:``}`,title:e,onClick:()=>s(e),children:(0,G.jsx)(`span`,{className:`imc-model-tab-label`,children:ra(e)})},e))]}),(0,G.jsx)(`div`,{className:`card`,children:g&&!e?(0,G.jsx)(`div`,{className:`loading`,children:`Loading IMC caches...`}):i===`current`?(0,G.jsx)(Co,{data:j,sort:w,indicator:E}):(0,G.jsx)(wo,{data:M,sort:T,indicator:D})})]})}function So(e){return e.context_window>0?e.peak_context/e.context_window:0}function Co({data:e,sort:t,indicator:n}){if(e.length===0)return(0,G.jsxs)(`div`,{className:`empty-state`,children:[(0,G.jsx)(`h3`,{children:`No IMC working sessions`}),(0,G.jsx)(`p`,{children:`Entries appear when an IMC-enabled model is loaded`})]});let r=(e,r,i,a=!1)=>(0,G.jsxs)(`th`,{onClick:()=>t(i),className:`catalog-table-sortable`,style:a?{textAlign:`right`}:void 0,children:[Y(e,r),(0,G.jsx)(`span`,{className:`catalog-table-sort-indicator`,children:n(i)})]});return(0,G.jsx)(`div`,{style:{overflowX:`auto`},children:(0,G.jsxs)(`table`,{className:`imc-sessions-table`,children:[(0,G.jsxs)(`thead`,{children:[(0,G.jsxs)(`tr`,{className:`imc-table-groups`,children:[(0,G.jsx)(`th`,{colSpan:3,className:`imc-table-group imc-table-group-session`,children:`Session`}),(0,G.jsx)(`th`,{colSpan:3,className:`imc-table-group imc-table-group-request`,children:`Latest Request`}),(0,G.jsx)(`th`,{colSpan:3,className:`imc-table-group imc-table-group-current`,children:`Working Cache`}),(0,G.jsx)(`th`,{colSpan:3,className:`imc-table-group imc-table-group-capacity`,children:`Peak / Usage`}),(0,G.jsx)(`th`,{colSpan:2,className:`imc-table-group imc-table-group-details`,children:`Details`})]}),(0,G.jsxs)(`tr`,{className:`imc-table-columns`,children:[r(`Model`,`imcModelID`,`model_id`),r(`Cache Entry`,`imcSessionID`,`id`),r(`State`,`imcState`,`state`),r(`Input`,`imcInputTokens`,`input_tokens`,!0),r(`Output`,`imcOutputTokens`,`output_tokens`,!0),r(`Context`,`imcRequestTotal`,`request_context`,!0),r(`Messages`,`imcMessages`,`messages`,!0),r(`Tokens`,`imcContext`,`context`,!0),r(`Allocated`,`imcAllocated`,`allocated`,!0),r(`Peak Context`,`imcPeakContext`,`peak_context`,!0),r(`Peak Memory`,`imcSnapshotBytes`,`snapshot_bytes`,!0),r(`Peak Used`,`imcUtilization`,`utilization`,!0),r(`Media`,`imcMedia`,`has_media`),r(`Last Used`,`imcLastUsed`,`last_used`)]})]}),(0,G.jsx)(`tbody`,{children:e.map(e=>(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:e.model_id}),(0,G.jsx)(`td`,{children:e.id}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`span`,{className:`badge badge-${e.state}`,children:e.state})}),(0,G.jsx)(`td`,{className:`imc-request-cell`,style:{textAlign:`right`},children:e.input_tokens.toLocaleString()}),(0,G.jsx)(`td`,{className:`imc-request-cell`,style:{textAlign:`right`},children:e.output_tokens.toLocaleString()}),(0,G.jsx)(`td`,{className:`imc-request-cell`,style:{textAlign:`right`},children:(e.input_tokens+e.output_tokens).toLocaleString()}),(0,G.jsx)(`td`,{className:`imc-current-cell`,style:{textAlign:`right`},children:e.messages.toLocaleString()}),(0,G.jsx)(`td`,{className:`imc-current-cell`,style:{textAlign:`right`},children:e.context.toLocaleString()}),(0,G.jsx)(`td`,{className:`imc-current-cell`,style:{textAlign:`right`},children:e.allocated.toLocaleString()}),(0,G.jsx)(`td`,{className:`imc-capacity-cell`,style:{textAlign:`right`},children:e.peak_context.toLocaleString()}),(0,G.jsx)(`td`,{className:`imc-capacity-cell`,style:{textAlign:`right`},children:J(e.snapshot_bytes)}),(0,G.jsx)(`td`,{className:`imc-capacity-cell`,style:{textAlign:`right`},children:bo(e.peak_context,e.context_window)}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`span`,{className:`badge badge-${e.has_media?`yes`:`no`}`,children:e.has_media?`yes`:`no`})}),(0,G.jsx)(`td`,{style:{whiteSpace:`nowrap`},children:yo(e.last_used)})]},`${e.model_id}-${e.id}`))})]})})}function wo({data:e,sort:t,indicator:n}){if(e.length===0)return(0,G.jsxs)(`div`,{className:`empty-state`,children:[(0,G.jsx)(`h3`,{children:`No System caches`}),(0,G.jsx)(`p`,{children:`Entries appear after requests with System prompts`})]});let r=(e,r,i,a=!1)=>(0,G.jsxs)(`th`,{onClick:()=>t(i),className:`catalog-table-sortable`,style:a?{textAlign:`right`}:void 0,children:[Y(e,r),(0,G.jsx)(`span`,{className:`catalog-table-sort-indicator`,children:n(i)})]});return(0,G.jsx)(`div`,{style:{overflowX:`auto`},children:(0,G.jsxs)(`table`,{className:`imc-sessions-table`,children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[r(`Model`,`imcModelID`,`model_id`),r(`Cache Entry`,`imcSystemCacheID`,`id`),r(`System Tokens`,`imcSystemContext`,`tokens`,!0),r(`Allocated`,`imcSystemAllocated`,`allocated`,!0),r(`Snapshot Memory`,`imcSystemSnapshotBytes`,`snapshot_bytes`,!0),r(`Restores`,`imcSystemRestores`,`restore_count`,!0),r(`Active Restores`,`imcSystemActiveRestores`,`active_restores`,!0),r(`Last Used`,`imcLastUsed`,`last_used`)]})}),(0,G.jsx)(`tbody`,{children:e.map(e=>(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:e.model_id}),(0,G.jsx)(`td`,{children:e.id}),(0,G.jsx)(`td`,{className:`imc-system-cell`,style:{textAlign:`right`},children:e.tokens.toLocaleString()}),(0,G.jsx)(`td`,{className:`imc-system-cell`,style:{textAlign:`right`},children:e.allocated.toLocaleString()}),(0,G.jsx)(`td`,{className:`imc-system-cell`,style:{textAlign:`right`},children:J(e.snapshot_bytes)}),(0,G.jsx)(`td`,{style:{textAlign:`right`},children:e.restore_count.toLocaleString()}),(0,G.jsx)(`td`,{style:{textAlign:`right`},children:e.active_restores.toLocaleString()}),(0,G.jsx)(`td`,{style:{whiteSpace:`nowrap`},children:yo(e.last_used)})]},`${e.model_id}-${e.id}`))})]})})}function To(e){return e&&e.length>0?e.join(`, `):`None`}function Eo(e){return e>=0?`Slot ${e}`:`—`}function Do(e,t,n,r){if(e.slots.length===0)return`—`;for(let i=0;i=0?(n+1)%e.slots.length:r}`}function Oo(e){return e<=0?`—`:e<6e4?`${(e/1e3).toFixed(1)}s`:`${Math.floor(e/6e4)}m ${Math.floor(e%6e4/1e3)}s`}function ko(e){return e.phase===`imc-restore`?`Restoring session state`:`—`}function Ao(e){if(e.phase===`prefill-imc`)return`${e.imc_prepared_tokens.toLocaleString()} / ${e.imc_total_tokens.toLocaleString()} · IMC extension`;if(e.phase!==`prefill`)return`—`;let t=e.prefilled_tokens,n=t+e.prefill_remaining;return`${t.toLocaleString()} / ${n.toLocaleString()}${e.prefill_owner?` (owner)`:``}`}function jo(e){return e.request_id.replace(/^chatcmpl-/,``)||`—`}function Mo(e){return e.generation_mode?`${e.generated_tokens.toLocaleString()} tokens · ${e.generation_mode} · ${e.generation_rows} rows`:`—`}function No(e){return e===`imc-restore`?`prefill stage 1 · restore`:e===`prefill-imc`?`prefill stage 2 · IMC`:e===`prefill`?`prefill stage 2 · request`:e===`media-prefill`?`prefill stage 2 · media`:e}function Po(e){return e.mtp?`MTP · nDraft ${e.ndraft}`:e.ndraft>0?`Speculative · nDraft ${e.ndraft}`:`Non-MTP`}function Fo({model:e}){let t=Do(e,e.eligible_imc_slots,e.imc_selector_selected,e.imc_selector_next),n=Do(e,e.eligible_prefill_slots,e.prefill_selector_selected,e.prefill_selector_selected>=0?(e.prefill_selector_selected+1)%e.slots.length:e.prefill_selector_next);return(0,G.jsxs)(`div`,{className:`card slot-model-card`,children:[(0,G.jsxs)(`div`,{className:`slot-model-heading`,children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`h3`,{title:e.model_id,children:ra(e.model_id)}),(0,G.jsx)(`span`,{className:`slot-mode-badge`,children:Po(e)})]}),(0,G.jsxs)(`span`,{className:`slot-iteration`,children:[`Iteration `,e.iteration.toLocaleString()]})]}),(0,G.jsxs)(`div`,{className:`slot-summary-grid`,children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`span`,{children:Y(`Batch sizing`,`slotBatchSizing`)}),(0,G.jsxs)(`strong`,{children:[e.prefill_batch_size.toLocaleString(),` / `,e.nubatch.toLocaleString(),` / `,e.nbatch.toLocaleString()]}),(0,G.jsx)(`small`,{children:`Prefill batch / NUBatch / NBatch`})]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`span`,{children:Y(`Request queue`,`slotQueue`)}),(0,G.jsx)(`strong`,{children:e.queued_requests+e.pending_requests}),(0,G.jsxs)(`small`,{children:[e.queued_requests,` channel + `,e.pending_requests,` pending`]})]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`span`,{children:Y(`Prefill stage 1 · IMC extension`,`slotIMCSelector`)}),(0,G.jsx)(`strong`,{children:Eo(e.imc_selector_selected)}),(0,G.jsxs)(`small`,{children:[`Next: `,t,` · Waiting: `,To(e.eligible_imc_slots)]})]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`span`,{children:Y(`Prefill stage 2 · request`,`slotPrefillSelector`)}),(0,G.jsx)(`strong`,{children:Eo(e.prefill_selector_selected)}),(0,G.jsxs)(`small`,{children:[`Next: `,n,` · Waiting: `,To(e.eligible_prefill_slots)]})]})]}),(0,G.jsx)(`div`,{className:`table-container`,children:(0,G.jsxs)(`table`,{className:`slots-table`,children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{children:Y(`Slot`,`slotID`)}),(0,G.jsx)(`th`,{children:Y(`Phase`,`slotPhase`)}),(0,G.jsx)(`th`,{children:Y(`Request`,`slotRequest`)}),(0,G.jsx)(`th`,{children:Y(`Age`,`slotAge`)}),(0,G.jsx)(`th`,{children:Y(`Stage 1 · restore`,`slotIMCProgress`)}),(0,G.jsx)(`th`,{children:Y(`Stage 2 · decode`,`slotPrefillProgress`)}),(0,G.jsx)(`th`,{children:Y(`Generation`,`slotGeneration`)}),(0,G.jsx)(`th`,{style:{textAlign:`right`},children:Y(`Past`,`slotPastTokens`)})]})}),(0,G.jsx)(`tbody`,{children:e.slots.map(e=>(0,G.jsxs)(`tr`,{className:e.prefill_owner?`slot-prefill-owner`:void 0,children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`strong`,{children:e.id})}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`span`,{className:`slot-phase slot-phase-${e.phase}`,children:No(e.phase)})}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{className:`slot-request-id`,title:e.request_id||void 0,children:jo(e)})}),(0,G.jsx)(`td`,{className:`slot-request-age`,children:Oo(e.request_age_ms)}),(0,G.jsx)(`td`,{children:ko(e)}),(0,G.jsx)(`td`,{children:Ao(e)}),(0,G.jsx)(`td`,{children:Mo(e)}),(0,G.jsx)(`td`,{style:{textAlign:`right`},children:e.past_tokens.toLocaleString()})]},e.id))})]})})]})}function Io(){let[e,t]=(0,x.useState)(null),[n,r]=(0,x.useState)(!0),[i,a]=(0,x.useState)(null),o=async(e=!1)=>{e||r(!0),a(null);try{t(await W.listBatchEngineSlots())}catch(e){a(e instanceof Error?e.message:`Failed to load batch engine slots`)}finally{e||r(!1)}};return(0,x.useEffect)(()=>{o();let e=window.setInterval(()=>o(!0),1e3);return()=>window.clearInterval(e)},[]),(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{className:`page-header-with-action`,children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`h2`,{children:`Batch Engine Slots`}),(0,G.jsx)(`p`,{className:`page-description`,children:`Live scheduler, prefill, generation, and IMC preparation state for loaded generation models`})]}),(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:()=>o(),disabled:n,children:`Refresh`})]}),i&&(0,G.jsx)(`div`,{className:`alert alert-error`,children:i}),n&&!e&&(0,G.jsx)(`div`,{className:`loading`,children:`Loading slot state…`}),!n&&e?.length===0&&(0,G.jsx)(`div`,{className:`empty-state`,children:`No loaded generation models expose batch-engine slots.`}),e?.map(e=>(0,G.jsx)(Fo,{model:e},e.model_id))]})}var Lo=`unsloth/Qwen3-0.6B-Q8_0`;function Ro(e){return e?J(e*1024*1024):`—`}function zo({commands:e,open:t}){return!e||e.length===0?null:(0,G.jsx)(`div`,{style:{marginTop:12},children:e.map((e,n)=>(0,G.jsxs)(`details`,{open:t,style:{marginBottom:12},children:[(0,G.jsxs)(`summary`,{style:{cursor:`pointer`,fontFamily:`"SF Mono", "Monaco", "Inconsolata", "Fira Code", monospace`,fontSize:`14px`,color:`var(--color-gray-900)`,padding:`4px 0`},children:[`$ `,e.cmd]}),e.err&&(0,G.jsxs)(`p`,{style:{color:`var(--color-error)`,margin:`8px 0 0`,fontSize:`13px`},children:[`error: `,e.err]}),(0,G.jsx)(`pre`,{className:`code-block`,style:{marginTop:8,whiteSpace:`pre`},children:e.output||`(no output)`})]},`${e.cmd}-${n}`))})}function Bo(){let[e,t]=(0,x.useState)(null),[n,r]=(0,x.useState)(!0),[i,a]=(0,x.useState)(null),[o,s]=(0,x.useState)(`summary`),[c,l]=(0,x.useState)(!1),[u,d]=(0,x.useState)(!1),[f,p]=(0,x.useState)(``);(0,x.useEffect)(()=>{m()},[]);let m=async()=>{r(!0),a(null),d(!1);try{let e=await W.getDiagnose();t(e)}catch(e){a(e instanceof Error?e.message:`Failed to load diagnostics`)}finally{r(!1)}},h=async()=>{l(!0),a(null);try{let e=await W.getDiagnose(!0,f);t(e),d(!0),s(`summary`)}catch(e){a(e instanceof Error?e.message:`Failed to run benchmark`)}finally{l(!1)}},g=e?JSON.stringify(e,null,2):``,_=Array.from(new Set([...(e?.llama.backends??[]).map(e=>e.processor),`cpu`]));return(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{className:`page-header-with-action`,children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`h2`,{children:`Info`}),(0,G.jsxs)(`p`,{className:`page-description`,children:[`Host environment diagnostics — versions, system, and the llama.cpp backends and devices Kronk can see. Use `,(0,G.jsx)(`strong`,{children:`Run benchmark`}),` `,`to measure inference throughput; it loads a model and takes a few seconds.`]})]}),(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:m,disabled:n||c,children:`Refresh`})]}),e&&(0,G.jsxs)(`div`,{className:`tabs`,children:[(0,G.jsx)(`button`,{className:`tab ${o===`summary`?`active`:``}`,onClick:()=>s(`summary`),children:`Summary`}),(0,G.jsx)(`button`,{className:`tab ${o===`json`?`active`:``}`,onClick:()=>s(`json`),children:`JSON`})]}),i&&(0,G.jsx)(`div`,{className:`error-message`,children:i}),n&&!e&&(0,G.jsx)(`p`,{children:`Collecting diagnostics…`}),e&&o===`json`&&(0,G.jsx)(`div`,{className:`diagnose-json`,children:(0,G.jsx)(ya,{code:g,language:`json`})}),e&&o===`summary`&&(0,G.jsxs)(G.Fragment,{children:[e.hints&&e.hints.length>0&&(0,G.jsxs)(`div`,{className:`card`,style:{borderLeft:`4px solid var(--color-warning-border)`},children:[(0,G.jsx)(`h3`,{style:{marginTop:0},children:`Hints`}),e.hints.map((e,t)=>(0,G.jsxs)(`div`,{style:{marginBottom:12},children:[(0,G.jsxs)(`p`,{style:{margin:0},children:[(0,G.jsxs)(`strong`,{style:{textTransform:`uppercase`},children:[`[`,e.severity,`]`]}),` `,e.message]}),e.remedy&&(0,G.jsx)(`pre`,{className:`code-block`,style:{marginTop:6,whiteSpace:`pre-wrap`},children:e.remedy})]},t))]}),(0,G.jsxs)(`div`,{className:`card`,children:[(0,G.jsx)(`h3`,{style:{marginTop:0},children:`Versions`}),(0,G.jsx)(`div`,{className:`table-container`,children:(0,G.jsx)(`table`,{children:(0,G.jsxs)(`tbody`,{children:[(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Kronk`}),(0,G.jsx)(`td`,{children:e.versions.kronk||`—`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`yzma`}),(0,G.jsx)(`td`,{children:e.versions.yzma||`—`})]})]})})})]}),(0,G.jsxs)(`div`,{className:`card`,children:[(0,G.jsx)(`h3`,{style:{marginTop:0},children:`System`}),(0,G.jsx)(`div`,{className:`table-container`,children:(0,G.jsx)(`table`,{children:(0,G.jsxs)(`tbody`,{children:[(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`OS`}),(0,G.jsx)(`td`,{children:e.system.os})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Arch`}),(0,G.jsx)(`td`,{children:e.system.arch})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`CPU`}),(0,G.jsx)(`td`,{children:e.system.cpuModel||`—`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`CPUs`}),(0,G.jsx)(`td`,{children:e.system.numCPU})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`RAM`}),(0,G.jsx)(`td`,{children:e.system.ramBytes?J(e.system.ramBytes):`—`})]})]})})}),(0,G.jsx)(zo,{commands:e.system.commands})]}),(0,G.jsxs)(`div`,{className:`card`,children:[(0,G.jsx)(`h3`,{style:{marginTop:0},children:`llama.cpp`}),e.llama.installed?(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(`p`,{style:{marginTop:0,color:`var(--color-text-secondary)`},children:[`Root: `,(0,G.jsx)(`code`,{children:e.llama.root})]}),(e.llama.backends??[]).map(e=>(0,G.jsxs)(`div`,{style:{marginBottom:24},children:[(0,G.jsx)(`h4`,{style:{marginBottom:8},children:e.processor}),(0,G.jsx)(`div`,{className:`table-container`,style:{marginBottom:12},children:(0,G.jsx)(`table`,{children:(0,G.jsxs)(`tbody`,{children:[(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`binDir`}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:e.binDir})})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`version`}),(0,G.jsx)(`td`,{children:e.version||`—`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`build`}),(0,G.jsx)(`td`,{children:e.build||`—`})]})]})})}),(e.devices??[]).length===0?(0,G.jsx)(`p`,{style:{color:`var(--color-text-secondary)`,margin:`4px 0`},children:`No devices detected.`}):(0,G.jsx)(`div`,{className:`table-container`,children:(0,G.jsxs)(`table`,{children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{children:`ID`}),(0,G.jsx)(`th`,{children:`Device`}),(0,G.jsx)(`th`,{style:{textAlign:`right`},children:`VRAM Total`}),(0,G.jsx)(`th`,{style:{textAlign:`right`},children:`VRAM Free`})]})}),(0,G.jsx)(`tbody`,{children:(e.devices??[]).map(e=>(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:e.id}),(0,G.jsx)(`td`,{children:e.name}),(0,G.jsx)(`td`,{style:{textAlign:`right`},children:Ro(e.vramTotalMiB)}),(0,G.jsx)(`td`,{style:{textAlign:`right`},children:Ro(e.vramFreeMiB)})]},e.id))})]})}),(0,G.jsx)(zo,{commands:e.commands})]},e.processor))]}):(0,G.jsx)(`p`,{style:{color:`var(--color-text-secondary)`},children:`No llama.cpp libraries installed for this machine.`})]}),e.engine?.probed&&(0,G.jsxs)(`div`,{className:`card`,style:e.engine.loaded?void 0:{borderLeft:`4px solid var(--color-error)`},children:[(0,G.jsx)(`h3`,{style:{marginTop:0},children:`Engine`}),e.engine.loaded?(0,G.jsx)(`p`,{style:{marginTop:0,color:`var(--color-text-secondary)`},children:`Loaded — Kronk can load models and run inference.`}):(0,G.jsx)(`p`,{style:{marginTop:0,color:`var(--color-error)`},children:(0,G.jsx)(`strong`,{children:`Degraded — Kronk could not load its llama.cpp libraries in-process, so model loading and inference are unavailable.`})}),(0,G.jsx)(`div`,{className:`table-container`,children:(0,G.jsx)(`table`,{children:(0,G.jsxs)(`tbody`,{children:[(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Loaded`}),(0,G.jsx)(`td`,{children:e.engine.loaded?`✓ true`:`✗ false`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Processor`}),(0,G.jsx)(`td`,{children:e.engine.processor||`—`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Library path`}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:e.engine.libPath})})]})]})})}),e.engine.error&&(0,G.jsx)(`pre`,{className:`code-block`,style:{marginTop:12,whiteSpace:`pre-wrap`},children:e.engine.error})]}),(0,G.jsxs)(`div`,{className:`card`,children:[(0,G.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,justifyContent:`space-between`,gap:12},children:[(0,G.jsx)(`h3`,{style:{margin:0},children:`Benchmark`}),(0,G.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:12},children:[(0,G.jsxs)(`span`,{className:`bench-processor`,children:[(0,G.jsx)(`label`,{htmlFor:`bench-processor`,children:`Processor:`}),(0,G.jsxs)(`select`,{id:`bench-processor`,value:f,onChange:e=>p(e.target.value),disabled:c||n,children:[(0,G.jsx)(`option`,{value:``,children:`Auto`}),_.map(e=>(0,G.jsx)(`option`,{value:e,children:e},e))]})]}),(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:h,disabled:c||n||!e.llama.installed,children:c?`Running benchmark…`:`Run benchmark`})]})]}),c?(0,G.jsx)(`p`,{style:{color:`var(--color-text-secondary)`},children:`Running benchmark — loading the model and measuring throughput…`}):e.bench.model?(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`div`,{className:`table-container`,children:(0,G.jsx)(`table`,{children:(0,G.jsxs)(`tbody`,{children:[(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Backend`}),(0,G.jsx)(`td`,{children:e.bench.processor||`—`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Model`}),(0,G.jsx)(`td`,{children:e.bench.model})]})]})})}),(0,G.jsx)(zo,{commands:e.bench.commands,open:!0})]}):u?(0,G.jsxs)(`div`,{style:{color:`var(--color-warning-text)`},children:[(0,G.jsxs)(`p`,{style:{marginTop:0},children:[`Benchmark skipped — the benchmark model `,(0,G.jsx)(`code`,{children:Lo}),` `,`is not installed, so there was nothing to run. Install it from the CLI, then click `,(0,G.jsx)(`strong`,{children:`Run benchmark`}),` again:`]}),(0,G.jsx)(`pre`,{className:`code-block`,style:{whiteSpace:`pre-wrap`},children:`kronk model pull ${Lo}`}),(0,G.jsxs)(`p`,{style:{marginBottom:0},children:[`Or fetch it automatically with `,(0,G.jsx)(`code`,{children:`kronk diagnose --install`}),`.`]})]}):(0,G.jsxs)(`p`,{style:{color:`var(--color-text-secondary)`},children:[`No benchmark run yet. Click `,(0,G.jsx)(`strong`,{children:`Run benchmark`}),` to measure inference throughput — prompt-processing and token-generation speed. Requires a benchmark model to be installed.`]})]})]})]})}function Vo(e){return e<1e6?`${(e/1e3).toFixed(0)} KB`:e<1e9?`${(e/1e6).toFixed(1)} MB`:`${(e/1e9).toFixed(2)} GB`}function Ho(e){if(e<60)return`${Math.round(e)}s`;let t=Math.floor(e/60),n=Math.round(e%60);return t<60?`${t}m ${n}s`:`${Math.floor(t/60)}h ${t%60}m`}function Uo({progress:e,meta:t}){let[,n]=(0,x.useState)(0);(0,x.useEffect)(()=>{let e=setInterval(()=>n(e=>e+1),1e3);return()=>clearInterval(e)},[]);let{currentBytes:r,totalBytes:i,mbPerSec:a,pct:o,startedAtMs:s}=e,c=(Date.now()-s)/1e3,l=``;c>=5&&i>0&&r0&&(l=` · ETA ${Ho((i-r)/(a*1e3*1e3))}`);let u=e.src.split(`/`).pop()||e.src,d=t&&t.fileTotal>1,f=i>0,p=[f?`${o.toFixed(1)}%`:``,f?`${Vo(r)} / ${Vo(i)}`:`${Vo(r)}`,a>0?`${a.toFixed(1)} MB/s`:``].filter(Boolean).join(` · `)+l,m=f?o:0,h=m>=45;return(0,G.jsxs)(`div`,{className:`download-progress`,children:[(0,G.jsx)(`div`,{className:`download-progress-text`,children:(0,G.jsxs)(`span`,{children:[`Downloading `,u,d?` (file ${t.fileIndex} of ${t.fileTotal})`:``]})}),(0,G.jsxs)(`div`,{className:`playground-autotest-progress-bar`,children:[(0,G.jsx)(`div`,{className:`playground-autotest-progress-fill`,style:{width:`${Math.max(m,1)}%`},children:h&&(0,G.jsx)(`span`,{className:`playground-autotest-progress-label`,children:p})}),!h&&(0,G.jsx)(`span`,{className:`playground-autotest-progress-label-outside`,children:p})]})]})}function Wo(e){return e.replace(/\.gguf$/i,``)}function Go(e){return Wo(e.split(`/`).pop()??e).replace(/-\d+-of-\d+$/,``)}var Ko=/^(UD-)?((IQ|Q)\d+(_[A-Z0-9]+)*|BF16|F16|F32)$/i;function qo(e){return Ko.test(e.trim())}function Jo(e){let t=(e.split(`/`).pop()??e).toLowerCase();return/(^|[-._])mmproj([-._]|$)/.test(t)}function Yo(e,t){if(/(^|[-_])mtp([-_]|$)/i.test(t))return!1;let n=(e.split(`/`).pop()??e).toLowerCase();return n.startsWith(`mtp-`)||n.startsWith(`mtp_`)}function Xo(e,t){let n=Wo(e.split(`/`).pop()??e).replace(/-\d+-of-\d+$/,``).toLowerCase(),r=t.trim().toLowerCase();return n.endsWith(`-`+r)||n.endsWith(`.`+r)||n===r}function Zo(e){let t=e.trim().split(`?`)[0];if(!t)return null;let n=t;for(let e of[`https://huggingface.co/`,`http://huggingface.co/`,`https://hf.co/`,`http://hf.co/`,`huggingface.co/`,`hf.co/`])if(n.toLowerCase().startsWith(e)){n=n.slice(e.length);break}let r=n.split(`/`).filter(e=>e!==``);if(r.length<2)return null;let i=r[0],a=r[1],o=``;return r.length>4&&(r[2]===`resolve`||r[2]===`blob`||r[2]===`tree`)?o=r.slice(4).join(`/`):r.length>2&&(o=r.slice(2).join(`/`)),{provider:i,family:a,model:o?Go(o):``}}function Qo(e){let t=1e9,n=1e6,r=1e3;return e>=t?`${(e/t).toFixed(1)} GB`:e>=n?`${(e/n).toFixed(1)} MB`:e>=r?`${(e/r).toFixed(1)} KB`:`${e} B`}function $o(e){let t=new Map;for(let n of e){let e=n.filename.replace(/-\d+-of-\d+(\.gguf)$/i,`$1`),r=t.get(e);r?r.push(n):t.set(e,[n])}let n=[];for(let[e,r]of t){if(r.length===1){let e=r[0];n.push({label:e.filename,filename:e.filename,sizeStr:e.size_str,parts:1});continue}r.sort((e,t)=>e.filename.localeCompare(t.filename));let t=r.reduce((e,t)=>e+t.size,0);n.push({label:e,filename:r[0].filename,sizeStr:Qo(t),parts:r.length})}return n}function es(e){return/-\d+-of-\d+\.gguf$/i.test(e)}function ts(e,t,n){let r=e.trim(),i=t.trim(),a=Wo(n.trim());return!r||!i?``:a?`${r}/${i}/${a}.gguf`:`${r}/${i}`}function ns(){let{download:e,isDownloading:t,startDownload:n,cancelDownload:r,clearDownload:i}=zn(),[a,o]=(0,x.useState)(``),[s,c]=(0,x.useState)(``),[l,u]=(0,x.useState)(``),[d,f]=(0,x.useState)(null),[p,m]=(0,x.useState)(null),[h,g]=(0,x.useState)(null),[_,v]=(0,x.useState)(!1),[y,b]=(0,x.useState)(!1),[S,C]=(0,x.useState)(``),[w,T]=(0,x.useState)(!1),[E,D]=(0,x.useState)(``),O=e?.status===`complete`,k=e?.status===`error`,A=a.trim().length>0&&s.trim().length>0,j=async e=>{if(_||t)return;let n=a.trim(),r=s.trim(),i=Wo((e??l).trim());if(!n||!r){g(`Provider and Family are required`);return}v(!0),g(null),f(null),m(null);try{if(!i){let e=await W.lookupHuggingFace(`${n}/${r}`);m(e.repo_files??[]);return}if(qo(i)){let e=((await W.lookupHuggingFace(`${n}/${r}`)).repo_files??[]).filter(e=>!Jo(e.filename)&&!Yo(e.filename,r)&&Xo(e.filename,i));if(e.length===0){g(`No GGUF file matching quant "${i}" found in ${n}/${r}`);return}let t=new Set(e.map(e=>Go(e.filename)));if(t.size>1){m(e);return}let a=[...t][0];u(a);let o=await W.resolveSource(`${n}/${r}/${a}.gguf`);f(o);return}let e=await W.resolveSource(`${n}/${r}/${i}.gguf`);f(e)}catch(e){g(e instanceof Error?e.message:String(e))}finally{v(!1)}},M=()=>void j(),N=e=>{let t=Go(e);u(t),m(null),j(t)},P=e=>{let t=Zo(e.clipboardData.getData(`text`));t&&(e.preventDefault(),o(t.provider),c(t.family),u(t.model))},F=e=>{e.key===`Enter`&&A&&(e.preventDefault(),M())},I=()=>{f(null),m(null),g(null),C(``),b(!1),D(``),T(!1)},L=()=>{if(!d||t||d.installed)return;let e=y?S.trim():``,r=w?E.trim():``,i=d.canonical_id||ts(a,s,l);n(i,e||void 0,r||void 0)},R=d?.from_local?`on disk`:d?.from_cache?`cached`:`fetched from network`;return(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{className:`page-header`,children:[(0,G.jsx)(`h2`,{children:`HF Pull GGUF Model`}),(0,G.jsx)(`p`,{children:`Identify the model with three fields. Each one maps to a segment of the HuggingFace file URL:`}),(0,G.jsxs)(`pre`,{style:{fontSize:`14px`,lineHeight:`1.4`,padding:`12px 14px`,background:`var(--color-gray-100)`,border:`1px solid var(--color-gray-300)`,borderRadius:`4px`,margin:`8px 0`,overflowX:`auto`,fontFamily:`ui-monospace, SFMono-Regular, Menlo, monospace`,color:`var(--color-gray-900)`},children:[(0,G.jsx)(`span`,{style:{opacity:.85},children:`https://huggingface.co/`}),(0,G.jsx)(`span`,{style:{color:`var(--color-primary)`,fontWeight:600},children:`unsloth`}),(0,G.jsx)(`span`,{style:{opacity:.85},children:`/`}),(0,G.jsx)(`span`,{style:{color:`var(--color-success-text)`,fontWeight:600},children:`Qwen3.6-27B-GGUF`}),(0,G.jsx)(`span`,{style:{opacity:.85},children:`/blob/main/`}),(0,G.jsx)(`span`,{style:{color:`var(--color-warning-text)`,fontWeight:600},children:`Qwen3.6-27B-Q4_K_M`}),(0,G.jsx)(`span`,{style:{opacity:.85},children:`.gguf`}),`
+`)}function Va({input:e,isMoE:t,gpuLayers:n,expertLayersOnGPU:r,kvCacheOnCPU:i,deviceCount:a,tensorSplit:o,configName:s,defaults:c}){let[l,u]=(0,x.useState)(!1),d=Ba(Ra(e,t,n,r,i,a,o,c?.flashAttention),s,c);return(0,G.jsxs)(`div`,{style:{marginTop:`0px`,padding:`0px 12px 25px 0px`,background:`var(--color-gray-50)`,borderRadius:`6px`},children:[(0,G.jsx)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`12px`},children:(0,G.jsxs)(`button`,{type:`button`,onClick:()=>u(!l),"aria-expanded":l,"aria-controls":`computed-catalog-config`,style:{background:`none`,border:`none`,padding:0,cursor:`pointer`,fontSize:`14px`,fontWeight:600,color:`var(--color-text)`,display:`flex`,alignItems:`center`,gap:`6px`},children:[(0,G.jsx)(`span`,{style:{display:`inline-block`,transition:`transform 0.2s`,transform:l?`rotate(90deg)`:`rotate(0deg)`,fontSize:`12px`},children:`▶`}),`Computed Catalog Configuration`]})}),l&&(0,G.jsx)(`pre`,{id:`computed-catalog-config`,style:{marginTop:`8px`,padding:`12px`,background:`var(--color-gray-100)`,borderRadius:`6px`,fontSize:`0.85em`,overflow:`auto`,whiteSpace:`pre`},children:d})]})}function Ha({controlsProps:e,resultsProps:t,variant:n=`compact`,contextInfo:r,hideControls:i,hideResults:a,modelUrl:o,catalogConfigName:s,catalogConfigDefaults:c}){return(0,G.jsxs)(G.Fragment,{children:[!i&&(0,G.jsx)(`div`,{style:n===`compact`?{marginBottom:`24px`}:void 0,children:(0,G.jsx)(ja,{...e,variant:n,contextInfo:r,modelSizeBytes:t?.isUnifiedMemory?void 0:t?.input.model_size_bytes,modelWeightsCPU:t?.vramResult.modelWeightsCPU,kvCpuBytes:t?.vramResult.kvCpuBytes,totalSystemRamEst:t?.vramResult.totalSystemRamEst,systemRAMBytes:t?.systemRAMBytes})}),t&&!a&&(0,G.jsx)(Fa,{totalVram:t.vramResult.totalVram,slotMemory:t.vramResult.slotMemory,kvPerSlot:t.vramResult.kvPerSlot,kvPerTokenPerLayer:t.vramResult.kvPerTokenPerLayer,input:t.input,moe:t.moe,weights:t.weights,modelWeightsGPU:t.vramResult.modelWeightsGPU,modelWeightsCPU:t.vramResult.modelWeightsCPU,computeBufferEst:t.vramResult.computeBufferEst,alwaysActiveGPUBytes:t.vramResult.alwaysActiveGPUBytes,alwaysActiveCPUBytes:t.vramResult.alwaysActiveCPUBytes,expertGPUBytes:t.vramResult.expertGPUBytes,expertCPUBytes:t.vramResult.expertCPUBytes,gpuLayers:t.gpuLayers,expertLayersOnGPU:t.expertLayersOnGPU,kvCacheOnCPU:t.kvCacheOnCPU,totalSystemRamEst:t.vramResult.totalSystemRamEst,unifiedFootprint:t.vramResult.unifiedFootprint,perDevice:t.perDevice,deviceCount:t.deviceCount,tensorSplit:t.tensorSplit,isHardwareOverridden:t.isHardwareOverridden,isUnifiedMemory:t.isUnifiedMemory,fitAssessment:t.fitAssessment,modelUrl:o,catalogConfigName:s,catalogConfigDefaults:c,recomputing:t.recomputing})]})}function Ua(e){return e.filter(e=>e.type.startsWith(`gpu_`))}function Wa(e){return e.replace(`gpu_`,``).replace(`cuda`,`CUDA`).replace(`metal`,`Metal`).replace(`rocm`,`ROCm`).replace(`vulkan`,`Vulkan`)}function Ga(e){let t=Ua(e.devices),n=t.length>0?Wa(t[0].type):``;return{gpuCount:e.gpu_count,gpuType:n,gpuVramBytes:e.gpu_total_bytes,ramBytes:e.system_ram_bytes,gpuDevices:t,unifiedMemory:e.unified_memory}}function Ka(){let[e,t]=(0,x.useState)(null);return(0,x.useEffect)(()=>{let e=!1;return W.getDevices().then(n=>{e||t(Ga(n))}).catch(()=>{}),()=>{e=!0}},[]),e}var qa=150;function Ja(e){let t=e.trim();if(!t)return;let n=parseFloat(t);if(!(isNaN(n)||n<=0))return Math.round(n*1024*1024*1024)}function Ya(e){let t=e.trim();if(!t)return!1;let n=parseFloat(t);return isNaN(n)||n<=0}function Xa(e,t){return e===-1?0:e===0?t:e}function Za(e){return{totalVram:e.total_vram,slotMemory:e.slot_memory,kvPerSlot:e.kv_per_slot,kvPerTokenPerLayer:e.kv_per_token_per_layer,modelWeightsGPU:e.model_weights_gpu??0,modelWeightsCPU:e.model_weights_cpu??0,computeBufferEst:e.compute_buffer_est??0,alwaysActiveGPUBytes:e.always_active_gpu_bytes??0,alwaysActiveCPUBytes:e.always_active_cpu_bytes??0,expertGPUBytes:e.expert_gpu_bytes??0,expertCPUBytes:e.expert_cpu_bytes??0,kvVramBytes:e.kv_vram_bytes??0,kvCpuBytes:e.kv_cpu_bytes??0,totalSystemRamEst:e.total_system_ram_est??0,unifiedFootprint:e.unified_footprint}}function Qa(e={}){let{initialContextWindow:t=131072,initialBytesPerElement:n=2,initialSlots:r=1,serverResponse:i,enableHardwareOverrides:a=!1,modelUrl:o,modelUrls:s,modelId:c}=e,[l,u]=(0,x.useState)(t),[d,f]=(0,x.useState)(n),[p,m]=(0,x.useState)(r),[h,g]=(0,x.useState)(0),[_,v]=(0,x.useState)(Ca),[y,b]=(0,x.useState)(!1),[S,C]=(0,x.useState)(!0),[w,T]=(0,x.useState)(1),[E,D]=(0,x.useState)(``),[O,k]=(0,x.useState)(``),[A,j]=(0,x.useState)(``),[M,N]=(0,x.useState)(null),P=Ka(),F=P?.gpuCount,I=P?.gpuVramBytes??0,L=P?.ramBytes,R=P?.gpuDevices??[],z=a?Ja(O):void 0,ee=a?Ja(A):void 0,B=a&&M!=null?M:w,V=a&&(z!=null||M!=null),te=V||a&&ee!=null,H=z??I,ne=ee??L,re=(0,x.useMemo)(()=>z==null?R.slice(0,B):[],[z,R,B]),ie=!V&&P?.unifiedMemory===!0,ae=(0,x.useRef)(!1),oe=(0,x.useCallback)(e=>{ae.current=!0,T(e)},[]);(0,x.useEffect)(()=>{!P||P.gpuCount<=0||a&&M!=null||T(e=>ae.current?Math.min(Math.max(1,e),P.gpuCount):P.gpuCount)},[P,a,M]);let se=(0,x.useRef)(null);(0,x.useEffect)(()=>{if(!i||i===se.current)return;se.current=i,ge(null);let e=i.input;e&&(u(e.context_window),f(e.bytes_per_element),m(e.slots),g(Xa(e.gpu_layers,e.block_count)),v(e.expert_layers_on_gpu),C(e.swa_full??!0))},[i]);let ce=(0,x.useMemo)(()=>E?E.split(`,`).map(e=>parseFloat(e.trim())).filter(e=>!isNaN(e)):[],[E]),[le,ue]=(0,x.useState)(i??null),[de,fe]=(0,x.useState)(!1),[pe,me]=(0,x.useState)(!1),[he,ge]=(0,x.useState)(null);(0,x.useEffect)(()=>{i&&ue(i)},[i]);let _e=(0,x.useRef)(0),ve=(0,x.useRef)(!1);(0,x.useEffect)(()=>{if(!o&&!c&&!s?.length||!le&&!i||!ve.current&&(ve.current=!0,i?.fit_assessment))return;ge(null);let e=++_e.current;fe(!0);let t=setTimeout(async()=>{let t=re.slice(0,B),n=t.length===B&&t.length>0,r={model_url:o,model_urls:s,model_id:c,context_window:l,bytes_per_element:d,slots:p,gpu_layers:h===0?-1:h,expert_layers_on_gpu:_,kv_cache_on_cpu:y,swa_full:S,device_count:B,tensor_split:ce.length>0?ce:void 0,gpu_free_bytes:n?t.map(e=>e.free_bytes):void 0,gpu_capacity_bytes:H,system_ram_bytes:ne,unified_memory:ie};try{let t=await W.calculateVRAM(r);_e.current===e&&(ue(t),fe(!1))}catch{_e.current===e&&fe(!1)}},qa);return()=>clearTimeout(t)},[o,s,c,l,d,p,h,_,y,S,B,ce,re,H,ne,ie]);let ye=(0,x.useCallback)(async()=>{let e=le??i;if(de||!e||!o&&!c&&!s?.length)return;let t=e.input.block_count;if(!t||t<=0)return;ge(null);let n=Math.max(1,B),r=re.slice(0,n),a=r.length===n&&r.length>0,u=++_e.current;me(!0);let f={model_url:o,model_urls:s,model_id:c,context_window:l,bytes_per_element:d,slots:p,kv_cache_on_cpu:y,swa_full:S,device_count:n,tensor_split:ce.length>0?ce:void 0,auto_fit:!0,gpu_free_bytes:a?r.map(e=>e.free_bytes):void 0,gpu_capacity_bytes:H,system_ram_bytes:ne,unified_memory:ie};try{let e=await W.calculateVRAM(f);if(_e.current!==u)return;if(e.auto_fit_succeeded!==!0){ge(ie?`No placement fits in the available unified memory. The current placement was preserved.`:`No placement fits in the selected GPU and system memory. The current placement was preserved.`);return}ue(e),g(Xa(e.input.gpu_layers,t)),v(e.input.expert_layers_on_gpu)}catch(e){_e.current===u&&ge(e instanceof Error?e.message:`Unable to find a fitting placement.`)}finally{me(!1)}},[le,i,o,s,c,de,ie,ne,B,re,H,l,d,p,y,S,ce]),be=le??i??null,xe=be?.input,Se=(xe?.sliding_window??0)>0&&(xe?.sliding_window_layers??0)>0,Ce=be?.moe?.is_moe===!0&&be?.weights!=null,we=(0,x.useMemo)(()=>be?Za(be):null,[be]),Te=be?.per_device;return{controlsProps:{contextWindow:l,onContextWindowChange:u,bytesPerElement:d,onBytesPerElementChange:f,slots:p,onSlotsChange:m,maxDeviceCount:F,isMoE:Ce,blockCount:xe?.block_count,gpuLayers:h,onGpuLayersChange:g,expertLayersOnGPU:_,onExpertLayersOnGPUChange:v,kvCacheOnCPU:y,onKvCacheOnCPUChange:b,hasSWA:Se,swaFull:S,onSwaFullChange:C,deviceCount:B,onDeviceCountChange:oe,tensorSplit:E,onTensorSplitChange:D,showHardwareOverrides:a,gpuMemoryOverrideGB:O,onGpuMemoryOverrideGBChange:k,gpuMemoryOverrideInvalid:Ya(O),systemMemoryOverrideGB:A,onSystemMemoryOverrideGBChange:j,systemMemoryOverrideInvalid:Ya(A),deviceCountOverride:M,onDeviceCountOverrideChange:N,detectedGpuTotalBytes:I,detectedSystemRAMBytes:L,detectedDeviceCount:F,canAutoFit:!!(be&&(o||c||s?.length)),autoFitDisabled:de,autoFitting:pe,autoFitError:he,onAutoFit:()=>{ye()}},resultsProps:we&&xe?{vramResult:we,input:xe,moe:be?.moe,weights:be?.weights,gpuLayers:h,expertLayersOnGPU:_,kvCacheOnCPU:y,swaFull:S,perDevice:Te,deviceCount:B,systemRAMBytes:ne,gpuTotalBytes:H,gpuDevices:re,tensorSplit:E,isHardwareOverridden:te,isUnifiedMemory:ie,fitAssessment:be?.fit_assessment,recomputing:de}:null,isMoE:Ce,maxGpuCount:F,gpuTotalBytes:H,systemRAM:ne,gpuDevices:re}}function $a(e,t){return e?.moe?.is_moe===!0||!!t&&Object.keys(t).some(e=>e.endsWith(`.expert_count`))}var eo=[{value:``,label:`🟢 Recommended`},{value:`experts_cpu`,label:`💾 Save GPU Memory — experts on CPU`},{value:`keep_top_n`,label:`⚖️ Balanced — keep some experts on GPU`},{value:`experts_gpu`,label:`⚡ Maximum Speed — all on GPU`},{value:`custom`,label:`🔧 Advanced`}],to={experts_cpu:`💾 Save GPU Memory`,keep_top_n:`⚖️ Balanced`,experts_gpu:`⚡ Maximum Speed`},no={"model-card":`Model Card`,"draft-card":`Draft Model Card`,config:`Model Configuration`,sampling:`Sampling Parameters`,template:`Template`,vram:`VRAM Calculator`};function ro(e,t){switch(t){case`id`:return e.id.toLowerCase();case`owner`:return(e.owned_by||``).toLowerCase();case`family`:return(e.model_family||``).toLowerCase();case`projection`:return+!!e.has_projection;case`size`:return e.size;case`modified`:return new Date(e.modified).getTime();default:return``}}function io(e){return new Date(e).toLocaleString()}function ao(){let{models:e,loading:t,error:n,loadModels:r,invalidate:i}=In(),[a,o]=(0,x.useState)(null),[s,c]=(0,x.useState)(null),[l,u]=(0,x.useState)(!1),[d,f]=(0,x.useState)(null),[p,m]=(0,x.useState)(`model-card`),[h,g]=(0,x.useState)(null),[_,v]=(0,x.useState)(!1),[y,b]=(0,x.useState)(!1),[S,C]=(0,x.useState)(null),[w,T]=(0,x.useState)(!1),[E,D]=(0,x.useState)(!1),[O,k]=(0,x.useState)(!1),[A,j]=(0,x.useState)(null),[M,N]=(0,x.useState)(null),[P,F]=(0,x.useState)(`id`),[I,L]=(0,x.useState)(!0),R=s?.vram??null,[z,ee]=(0,x.useState)(),B=La(z),{controlsProps:V,resultsProps:te}=Qa({initialContextWindow:131072,initialBytesPerElement:2,serverResponse:R,modelId:a??void 0}),H=sa(s?.metadata),[ne,re]=(0,x.useState)(!1),ie=(0,x.useRef)(null),ae=(0,x.useRef)(null);(0,x.useEffect)(()=>()=>{ie.current&&clearTimeout(ie.current),ae.current&&clearTimeout(ae.current)},[]),(0,x.useEffect)(()=>{r()},[r]),(0,x.useEffect)(()=>{if(!a){c(null),f(null),ee(void 0);return}let e=!1;return u(!0),f(null),c(null),W.showModel(a).then(t=>{e||c(t)}).catch(t=>{e||f(t?.message??`Failed to load model info`)}).finally(()=>{e||u(!1)}),ee(void 0),W.autoTuneModel({model_id:a}).then(t=>{e||ee(t.recommended)}).catch(()=>{}),()=>{e=!0}},[a]);let oe=e?.data??[],se=s?.model_config?.[`draft-model`],ce=se?.[`model-id`]??null,le=!!ce;(0,x.useEffect)(()=>{if(p!==`draft-card`||!ce){g(null);return}let e=!1;return v(!0),g(null),W.showModel(ce).then(t=>{e||g(t)}).catch(()=>{}).finally(()=>{e||v(!1)}),()=>{e=!0}},[p,ce]);let ue=e=>{P===e?L(!I):(F(e),L(!0))},de=e=>{if(a===e){o(null),c(null),D(!1);return}o(e),m(`model-card`),D(!1),j(null),N(null)},fe=async()=>{b(!0),C(null),T(!1);try{await W.rebuildModelIndex(),i(),r(),o(null),c(null),T(!0),ie.current=setTimeout(()=>T(!1),3e3)}catch(e){C(e instanceof Error?e.message:`Failed to rebuild index`)}finally{b(!1)}},pe=()=>{a&&D(!0)},me=async()=>{if(a){k(!0),D(!1),j(null),N(null);try{await W.removeModel(a),N(`Model "${a}" removed successfully`),o(null),c(null),i(),await r(),ae.current=setTimeout(()=>N(null),3e3)}catch(e){j(e instanceof Error?e.message:`Failed to remove model`)}finally{k(!1)}}},he=()=>{D(!1)},ge=oe.filter(e=>e.id.split(`/`).length===2),_e=oe.filter(e=>e.id.split(`/`).length===3),ve=[...ge].sort((e,t)=>{let n=ro(e,P),r=ro(t,P),i=I?1:-1,a;return a=typeof n==`number`&&typeof r==`number`?(n-r)*i:String(n).localeCompare(String(r))*i,a!==0||P===`size`?a:e.size-t.size});return(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{className:`page-header-with-action`,children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`h2`,{children:`GGUF Models`}),(0,G.jsx)(`p`,{className:`page-description`,children:`List of all models available in the system. Click a model to view details.`})]}),(0,G.jsxs)(`div`,{style:{display:`flex`,gap:`8px`},children:[(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:()=>{i(),r(),o(null),c(null),D(!1),j(null),N(null),f(null),C(null),T(!1)},disabled:t,children:`Refresh`}),(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:fe,disabled:y||t,children:y?`Rebuilding...`:`Rebuild Index`}),a&&!E&&(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:pe,disabled:O,children:`Remove Model`}),a&&E&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:me,disabled:O,children:O?`Removing...`:`Yes, Remove`}),(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:he,disabled:O,children:`Cancel`})]})]})]}),n&&(0,G.jsx)(`div`,{className:`alert alert-error`,children:n}),A&&(0,G.jsx)(`div`,{className:`alert alert-error`,children:A}),M&&(0,G.jsx)(`div`,{className:`alert alert-success`,children:M}),S&&(0,G.jsx)(`div`,{className:`alert alert-error`,children:S}),w&&(0,G.jsx)(`div`,{className:`alert alert-success`,children:`Index rebuilt successfully`}),(0,G.jsxs)(`div`,{className:`catalog-main-content`,children:[t&&(0,G.jsx)(`div`,{className:`loading`,children:`Loading models`}),!t&&!n&&e&&(0,G.jsx)(`div`,{className:`catalog-table-wrap`,children:oe.length>0?(0,G.jsxs)(`table`,{className:`catalog-table`,children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{style:{width:`40px`,textAlign:`center`},title:`Configuration and template confirmed working with the Kronk catalog`,children:`VAL`}),[[`id`,`Model ID`],[`owner`,`Provider`],[`family`,`Family`]].map(([e,t])=>(0,G.jsxs)(`th`,{onClick:()=>ue(e),className:`catalog-table-sortable`,children:[t,(0,G.jsx)(`span`,{className:`catalog-table-sort-indicator`,children:P===e?I?` ▲`:` ▼`:``})]},e)),(0,G.jsxs)(`th`,{style:{textAlign:`center`},onClick:()=>ue(`projection`),className:`catalog-table-sortable`,title:`Multimodal projection file present`,children:[`MTMD`,(0,G.jsx)(`span`,{className:`catalog-table-sort-indicator`,children:P===`projection`?I?` ▲`:` ▼`:``})]}),[[`size`,`Size`],[`modified`,`Modified`]].map(([e,t])=>(0,G.jsxs)(`th`,{onClick:()=>ue(e),className:`catalog-table-sortable`,children:[t,(0,G.jsx)(`span`,{className:`catalog-table-sort-indicator`,children:P===e?I?` ▲`:` ▼`:``})]},e))]})}),(0,G.jsx)(`tbody`,{children:ve.map(e=>{let t=_e.filter(t=>t.id.startsWith(e.id+`/`)),n=a===e.id,r=a?.startsWith(e.id+`/`),i=n||r;return(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(`tr`,{className:a===e.id?`active`:``,onClick:()=>de(e.id),children:[(0,G.jsx)(`td`,{style:{textAlign:`center`,color:e.validated?`inherit`:`var(--color-error)`},children:e.validated?`✓`:`✗`}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`span`,{className:`catalog-table-cell-ellipsis`,children:e.id})}),(0,G.jsx)(`td`,{children:e.owned_by||`-`}),(0,G.jsx)(`td`,{children:e.model_family||`-`}),(0,G.jsx)(`td`,{style:{textAlign:`center`},children:e.has_projection?`✓`:``}),(0,G.jsx)(`td`,{children:J(e.size)}),(0,G.jsx)(`td`,{children:io(e.modified)})]},e.id),i&&t.map(e=>(0,G.jsxs)(`tr`,{className:a===e.id?`active`:``,onClick:()=>de(e.id),children:[(0,G.jsx)(`td`,{}),(0,G.jsx)(`td`,{style:{paddingLeft:`24px`},children:(0,G.jsxs)(`span`,{className:`catalog-table-cell-ellipsis`,children:[`↳ `,e.id]})}),(0,G.jsx)(`td`,{}),(0,G.jsx)(`td`,{children:`Configuration Profile`}),(0,G.jsx)(`td`,{}),(0,G.jsx)(`td`,{}),(0,G.jsx)(`td`,{})]},e.id))]})})})]}):(0,G.jsxs)(`div`,{className:`empty-state`,children:[(0,G.jsx)(`h3`,{children:`No models found`}),(0,G.jsx)(`p`,{children:`Pull a model to get started`})]})}),d&&(0,G.jsx)(`div`,{className:`alert alert-error`,style:{marginTop:`16px`},children:d}),l&&(0,G.jsx)(`div`,{style:{marginTop:`16px`},children:(0,G.jsx)(`div`,{className:`loading`,children:`Loading model details`})}),a&&s&&!l&&(0,G.jsxs)(`div`,{style:{marginTop:`16px`,borderTop:`1px solid var(--color-gray-200)`,paddingTop:`16px`},children:[(0,G.jsx)(`div`,{className:`tabs`,children:Object.keys(no).filter(e=>e!==`draft-card`||le).map(e=>(0,G.jsx)(`button`,{className:`tab ${p===e?`active`:``}`,onClick:()=>m(e),children:no[e]},e))}),p===`config`&&(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`h3`,{style:{marginBottom:`16px`},children:a}),s.desc&&(0,G.jsx)(`div`,{style:{marginBottom:`16px`},children:(0,G.jsx)(`p`,{children:s.desc})}),(0,G.jsx)(la,{rows:[{key:`owner`,label:`Provider`,value:s.owned_by},{key:`size`,label:`Size`,value:J(s.size)},...s.quantization?[{key:`quantization`,label:Y(`Quantization`,`quantization`),value:s.quantization}]:[],{key:`created`,label:`Created`,value:new Date(s.created).toLocaleString()},{key:`projection`,label:Y(`Has Projection`,`hasProjection`),value:(0,G.jsx)(`span`,{className:`badge ${s.has_projection?`badge-yes`:`badge-no`}`,children:s.has_projection?`Yes`:`No`})},{key:`validated`,label:Y(`Validated`,`validated`),value:(()=>{let e=oe.find(e=>e.id===a);return e?(0,G.jsx)(`span`,{style:{color:e.validated?`inherit`:`var(--color-error)`},children:e.validated?`✓`:`✗`}):`-`})()}]}),s.model_config&&(0,G.jsxs)(`div`,{style:{marginTop:`24px`},children:[(0,G.jsx)(`h4`,{className:`meta-section-title`,style:{marginBottom:`8px`},children:`Configuration`}),(0,G.jsx)(la,{rows:(()=>{let e=s.model_config,t=e=>(0,G.jsx)(`span`,{className:`badge ${e?`badge-yes`:`badge-no`}`,children:e?`Yes`:`No`});return[{key:`cache-min-tokens`,label:Y(`cache-min-tokens`,`cacheMinTokens`),value:na(e[`cache-min-tokens`])},{key:`cache-type-k`,label:Y(`cache-type-k`,`cacheTypeK`),value:e[`cache-type-k`]||`default`},{key:`cache-type-v`,label:Y(`cache-type-v`,`cacheTypeV`),value:e[`cache-type-v`]||`default`},{key:`context-window`,label:Y(`context-window`,`contextWindow`),value:na(e[`context-window`])},{key:`devices`,label:Y(`devices`,`devices`),value:e.devices?.join(`, `)||`—`},{key:`draft-model.devices`,label:Y(`draft-model.devices`,`draftDevice`),value:e[`draft-model`]?.devices?.join(`, `)||`—`},{key:`draft-model.main-gpu`,label:Y(`draft-model.main-gpu`,`draftMainGpu`),value:na(e[`draft-model`]?.[`main-gpu`])},{key:`draft-model.model-id`,label:Y(`draft-model.model-id`,`draftModel`),value:e[`draft-model`]?.[`model-id`]||`—`},{key:`draft-model.ndraft`,label:Y(`draft-model.ndraft`,`draftTokens`),value:na(e[`draft-model`]?.ndraft)},{key:`draft-model.ngpu-layers`,label:Y(`draft-model.ngpu-layers`,`draftGpuLayers`),value:na(e[`draft-model`]?.[`ngpu-layers`])},{key:`draft-model.tensor-split`,label:Y(`draft-model.tensor-split`,`draftTensorSplit`),value:e[`draft-model`]?.[`tensor-split`]?.join(`, `)||`—`},{key:`flash-attention`,label:Y(`flash-attention`,`flashAttention`),value:e[`flash-attention`]||`default`},{key:`imc-session-capacity`,label:Y(`imc-session-capacity`,`imcSessionCapacity`),value:na(e[`imc-session-capacity`])},{key:`incremental-cache`,label:Y(`incremental-cache`,`incrementalCache`),value:t(e[`incremental-cache`])},{key:`load-mode`,label:Y(`load-mode`,`loadMode`),value:e[`load-mode`]||`auto`},{key:`main-gpu`,label:Y(`main-gpu`,`mainGpu`),value:na(e[`main-gpu`])},{key:`moe.keep-experts-top-n`,label:Y(`moe.keep-experts-top-n`,`moeKeepExpertsTopN`),value:na(e.moe?.[`keep-experts-top-n`])},{key:`moe.mode`,label:Y(`moe.mode`,`moeMode`),value:e.moe?.mode||`—`},{key:`prefill-batch-size`,label:Y(`Prefill Batch Size`,`prefillBatchSize`),value:na(e[`prefill-batch-size`])},{key:`ngpu-layers`,label:Y(`ngpu-layers`,`ngpuLayers`),value:na(e[`ngpu-layers`]??`auto`)},{key:`nseq-max`,label:Y(`nseq-max`,`nSeqMax`),value:na(e[`nseq-max`])},{key:`nthreads`,label:Y(`nthreads`,`nthreads`),value:na(e.nthreads)},{key:`nthreads-batch`,label:Y(`nthreads-batch`,`nthreadsBatch`),value:na(e[`nthreads-batch`])},{key:`numa`,label:Y(`numa`,`numa`),value:e.numa||`—`},{key:`offload-kqv`,label:Y(`offload-kqv`,`offloadKQV`),value:na(e[`offload-kqv`])},{key:`op-offload`,label:Y(`op-offload`,`opOffload`),value:na(e[`op-offload`])},{key:`proj-on-cpu`,label:Y(`proj-on-cpu`,`projOnCpu`),value:na(e[`proj-on-cpu`])},{key:`proj-device`,label:Y(`proj-device`,`projDevice`),value:e[`proj-device`]||`automatic`},{key:`rope-freq-base`,label:Y(`rope-freq-base`,`ropeFreqBase`),value:na(e[`rope-freq-base`])},{key:`rope-freq-scale`,label:Y(`rope-freq-scale`,`ropeFreqScale`),value:na(e[`rope-freq-scale`])},{key:`rope-scaling-type`,label:Y(`rope-scaling-type`,`ropeScaling`),value:e[`rope-scaling-type`]||`—`},{key:`split-mode`,label:Y(`split-mode`,`splitMode`),value:e[`split-mode`]||`default`},{key:`swa-full`,label:Y(`swa-full`,`swaFull`),value:e[`swa-full`]==null?(0,G.jsx)(`span`,{className:`badge badge-yes`,children:`Yes (default)`}):t(e[`swa-full`])},{key:`tensor-buft-overrides`,label:Y(`tensor-buft-overrides`,`tensorBuftOverrides`),value:e[`tensor-buft-overrides`]?.join(`, `)||`—`},{key:`tensor-split`,label:Y(`tensor-split`,`tensorSplit`),value:e[`tensor-split`]?.join(`, `)||`—`},{key:`yarn-attn-factor`,label:Y(`yarn-attn-factor`,`yarnAttnFactor`),value:na(e[`yarn-attn-factor`])},{key:`yarn-beta-fast`,label:Y(`yarn-beta-fast`,`yarnBetaFast`),value:na(e[`yarn-beta-fast`])},{key:`yarn-beta-slow`,label:Y(`yarn-beta-slow`,`yarnBetaSlow`),value:na(e[`yarn-beta-slow`])},{key:`yarn-ext-factor`,label:Y(`yarn-ext-factor`,`yarnExtFactor`),value:na(e[`yarn-ext-factor`])},{key:`yarn-orig-ctx`,label:Y(`yarn-orig-ctx`,`yarnOrigCtx`),value:na(e[`yarn-orig-ctx`])}]})()})]})]}),p===`sampling`&&(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`h3`,{style:{marginBottom:`16px`},children:`Sampling Parameters`}),s.model_config?.[`sampling-parameters`]?(()=>{let e=s.model_config[`sampling-parameters`];return(0,G.jsx)(la,{rows:[{key:`dry_allowed_length`,label:Y(`dry_allowed_length`,`dry_allowed_length`),value:na(e.dry_allowed_length)},{key:`dry_base`,label:Y(`dry_base`,`dry_base`),value:na(e.dry_base)},{key:`dry_multiplier`,label:Y(`dry_multiplier`,`dry_multiplier`),value:na(e.dry_multiplier)},{key:`dry_penalty_last_n`,label:Y(`dry_penalty_last_n`,`dry_penalty_last_n`),value:na(e.dry_penalty_last_n)},{key:`enable_thinking`,label:Y(`enable_thinking`,`enable_thinking`),value:na(e.enable_thinking??`—`)},{key:`frequency_penalty`,label:Y(`frequency_penalty`,`frequency_penalty`),value:ta(e.frequency_penalty)},{key:`grammar`,label:Y(`grammar`,`grammar`),value:na(e.grammar||`—`)},{key:`max_tokens`,label:Y(`max_tokens`,`max_tokens`),value:na(e.max_tokens)},{key:`min_p`,label:Y(`min_p`,`min_p`),value:ta(e.min_p)},{key:`presence_penalty`,label:Y(`presence_penalty`,`presence_penalty`),value:ta(e.presence_penalty)},{key:`reasoning_effort`,label:Y(`reasoning_effort`,`reasoning_effort`),value:na(e.reasoning_effort??`—`)},{key:`repeat_last_n`,label:Y(`repeat_last_n`,`repeat_last_n`),value:na(e.repeat_last_n)},{key:`repeat_penalty`,label:Y(`repeat_penalty`,`repeat_penalty`),value:ta(e.repeat_penalty)},{key:`temperature`,label:Y(`temperature`,`temperature`),value:ta(e.temperature)},{key:`top_k`,label:Y(`top_k`,`top_k`),value:na(e.top_k)},{key:`top_p`,label:Y(`top_p`,`top_p`),value:ta(e.top_p)},{key:`xtc_min_keep`,label:Y(`xtc_min_keep`,`xtc_min_keep`),value:na(e.xtc_min_keep)},{key:`xtc_probability`,label:Y(`xtc_probability`,`xtc_probability`),value:na(e.xtc_probability)},{key:`xtc_threshold`,label:Y(`xtc_threshold`,`xtc_threshold`),value:na(e.xtc_threshold)}]})})():(0,G.jsx)(`div`,{className:`empty-state`,children:(0,G.jsx)(`p`,{children:`No sampling parameters configured for this model.`})})]}),p===`model-card`&&(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`h3`,{style:{marginBottom:`16px`},children:`Model Card`}),(0,G.jsx)(va,{metadata:s.metadata??{},quantization:s.quantization,webPage:s.web_page})]}),p===`draft-card`&&le&&(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`h3`,{style:{marginBottom:`16px`},children:`Draft Model Card`}),(0,G.jsxs)(`div`,{style:{marginBottom:`24px`},children:[(0,G.jsx)(`h4`,{className:`meta-section-title`,style:{marginBottom:`8px`},children:`Draft Settings`}),(0,G.jsx)(la,{rows:[{key:`draft-id`,label:Y(`Model ID`,`draftModel`),value:ce??`-`},...se?[{key:`draft-ndraft`,label:Y(`Draft Tokens`,`draftTokens`),value:na(se.ndraft)},...se[`ngpu-layers`]==null?[]:[{key:`draft-ngpu`,label:Y(`GPU Layers`,`ngpuLayers`),value:na(se[`ngpu-layers`])}],...se.devices?.length?[{key:`draft-devices`,label:Y(`Devices`,`devices`),value:se.devices.join(`, `)}]:[]]:[]]})]}),_&&(0,G.jsx)(`div`,{className:`loading`,children:`Loading draft model details`}),h&&(0,G.jsxs)(`div`,{style:{marginBottom:`24px`},children:[(0,G.jsx)(`h4`,{className:`meta-section-title`,style:{marginBottom:`8px`},children:`Model Details`}),(0,G.jsx)(la,{rows:[{key:`draft-owner`,label:`Provider`,value:h.owned_by},{key:`draft-size`,label:`Size`,value:J(h.size)},...h.quantization?[{key:`draft-quantization`,label:Y(`Quantization`,`quantization`),value:h.quantization}]:[]]})]}),h?(0,G.jsx)(va,{metadata:h.metadata??{},quantization:h.quantization,webPage:h.web_page}):!_&&(0,G.jsx)(`div`,{className:`empty-state`,children:(0,G.jsx)(`p`,{children:`No metadata available for the draft model.`})})]}),p===`template`&&(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`h3`,{style:{marginBottom:`16px`},children:`Chat Template`}),s.metadata?.[`tokenizer.chat_template`]?(0,G.jsx)(ya,{code:s.metadata[`tokenizer.chat_template`],language:`django`}):(0,G.jsx)(`div`,{className:`empty-state`,children:(0,G.jsx)(`p`,{children:`No chat template found in metadata.`})})]}),p===`vram`&&(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{style:{display:`flex`,justifyContent:`space-between`,alignItems:`center`,marginBottom:`16px`},children:[(0,G.jsx)(`h3`,{children:`VRAM Calculator`}),(0,G.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:()=>re(!0),children:`Learn More`})]}),ne&&(0,G.jsx)(Ta,{onClose:()=>re(!1)}),te?(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`p`,{style:{fontSize:`13px`,color:`var(--color-text-secondary)`,marginBottom:`16px`},children:`Computed locally from GGUF header. Adjust parameters below to see how they affect VRAM.`}),(0,G.jsx)(Ha,{controlsProps:V,resultsProps:te,variant:`compact`,contextInfo:H,catalogConfigName:a??void 0,catalogConfigDefaults:B})]}):(0,G.jsx)(`div`,{className:`empty-state`,children:(0,G.jsx)(`p`,{children:`No VRAM data available for this model.`})})]})]})]})]})}function oo({label:e,sublabel:t,used:n,budget:r,total:i}){let a=Math.max(i,1),o=Math.max(r,0),s=Math.max(n,0),c=s/a*100,l=o/a*100,u=o>0?s/o*100:0,d=`usage-bar-fill usage-bar-fill-low`;return u>=85?d=`usage-bar-fill usage-bar-fill-high`:u>=60&&(d=`usage-bar-fill usage-bar-fill-mid`),(0,G.jsxs)(`div`,{className:`usage-bar-row`,children:[(0,G.jsxs)(`div`,{className:`usage-bar-label`,children:[(0,G.jsx)(`strong`,{children:e}),t&&(0,G.jsxs)(`span`,{className:`usage-bar-sublabel`,children:[` `,t]})]}),(0,G.jsxs)(`div`,{className:`usage-bar-track`,title:`Used ${J(s)} / Budget ${J(o)} / Total ${J(i)}`,children:[(0,G.jsx)(`div`,{className:d,style:{width:`${Math.min(c,100)}%`}}),l<100&&(0,G.jsx)(`div`,{className:`usage-bar-cap-marker`,style:{left:`${Math.min(l,100)}%`}})]}),(0,G.jsxs)(`div`,{className:`usage-bar-readout`,children:[(0,G.jsx)(`span`,{className:`usage-bar-used`,children:J(s)}),(0,G.jsx)(`span`,{className:`usage-bar-sep`,children:` / `}),(0,G.jsx)(`span`,{className:`usage-bar-budget`,children:J(o)}),(0,G.jsxs)(`span`,{className:`usage-bar-pct`,children:[` (`,u.toFixed(1),`%)`]}),` `,(0,G.jsx)(aa,{tooltipKey:`budgetUsageBar`})]})]})}function so(e){if(!e)return`—`;if(e.startsWith(`0001-01-01`))return`Never`;let t=new Date(e);return Number.isNaN(t.getTime())?`—`:t.toLocaleString()}function co(e,t){return t<=0?`0%`:`${(e/t*100).toFixed(1)}%`}function lo(){let[e,t]=(0,x.useState)(null),[n,r]=(0,x.useState)(null),[i,a]=(0,x.useState)(!0),[o,s]=(0,x.useState)(null),[c,l]=(0,x.useState)(null);(0,x.useEffect)(()=>{u();let e=window.setInterval(()=>{u(!0)},5e3);return()=>window.clearInterval(e)},[]);let u=async(e=!1)=>{e||a(!0),s(null);try{let[e,n]=await Promise.all([W.listRunningModels(),W.getPoolBudget()]);t(e),r(n)}catch(e){s(e instanceof Error?e.message:`Failed to load running models`)}finally{e||a(!1)}},d=async e=>{if(confirm(`Unload model "${e}"?`)){l(e),s(null);try{await W.unloadModel(e),await u()}catch(e){s(e instanceof Error?e.message:`Failed to unload model`)}finally{l(null)}}};return(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{className:`page-header-with-action`,children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`h2`,{children:`Running Models`}),(0,G.jsx)(`p`,{className:`page-description`,children:`Models currently loaded in cache and the pool's resource budget`})]}),(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:()=>u(),disabled:i,children:`Refresh`})]}),n&&(0,G.jsxs)(`div`,{className:`card`,children:[(0,G.jsxs)(`h3`,{style:{marginTop:0},children:[`Resource Budget — `,n.budget_percent,`% of detected hardware`,` `,(0,G.jsx)(aa,{tooltipKey:`budgetPercent`})]}),(0,G.jsxs)(`p`,{style:{marginTop:0,marginBottom:16,color:`var(--text-muted, #888)`},children:[`Headroom per GPU: `,J(n.headroom_bytes),` `,(0,G.jsx)(aa,{tooltipKey:`budgetHeadroom`})]}),n.unified_memory&&(0,G.jsx)(`p`,{style:{marginTop:0,marginBottom:16,color:`var(--text-muted, #888)`},children:(0,G.jsxs)(`em`,{children:[`Apple Silicon unified memory detected. The GPU (Metal) and CPU share a single physical pool, so the resman tracks just one budget under `,(0,G.jsx)(`strong`,{children:`Unified Memory`}),` below to avoid double-counting the same bytes against two budgets.`]})}),(0,G.jsxs)(`div`,{className:`usage-bar-list`,children:[n.devices.map(e=>(0,G.jsx)(oo,{label:e.name,sublabel:e.type,used:e.used_bytes,budget:e.budget_bytes,total:e.total_bytes},`bar-${e.index}-${e.name}`)),(n.ram_total>0||n.ram_budget>0)&&(0,G.jsx)(oo,{label:n.unified_memory?`Unified Memory`:`System RAM`,sublabel:n.unified_memory?`metal+ram`:`ram`,used:n.ram_used,budget:n.ram_budget,total:n.ram_total>0?n.ram_total:n.ram_budget})]}),(0,G.jsx)(`div`,{className:`table-container`,children:(0,G.jsxs)(`table`,{children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{children:`Device`}),(0,G.jsx)(`th`,{children:`Type`}),(0,G.jsx)(`th`,{style:{textAlign:`right`},children:Y(`Total`,`budgetDeviceTotal`)}),(0,G.jsx)(`th`,{style:{textAlign:`right`},children:Y(`Budget`,`budgetDeviceBudget`)}),(0,G.jsx)(`th`,{style:{textAlign:`right`},children:Y(`Used`,`budgetDeviceUsed`)}),(0,G.jsx)(`th`,{style:{textAlign:`right`},children:Y(`% of Budget`,`budgetDevicePctOfBudget`)}),(0,G.jsx)(`th`,{style:{textAlign:`right`},children:Y(`Free in Budget`,`budgetDeviceFree`)})]})}),(0,G.jsxs)(`tbody`,{children:[n.devices.map(e=>(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:e.name}),(0,G.jsx)(`td`,{children:e.type}),(0,G.jsx)(`td`,{style:{textAlign:`right`},children:J(e.total_bytes)}),(0,G.jsx)(`td`,{style:{textAlign:`right`},children:J(e.budget_bytes)}),(0,G.jsx)(`td`,{style:{textAlign:`right`},children:J(e.used_bytes)}),(0,G.jsx)(`td`,{style:{textAlign:`right`},children:co(e.used_bytes,e.budget_bytes)}),(0,G.jsx)(`td`,{style:{textAlign:`right`},children:J(Math.max(e.budget_bytes-e.used_bytes,0))})]},`${e.index}-${e.name}`)),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:n.unified_memory?`Unified Memory`:`System RAM`}),(0,G.jsx)(`td`,{children:n.unified_memory?`metal+ram`:`ram`}),(0,G.jsx)(`td`,{style:{textAlign:`right`},children:n.ram_total>0?J(n.ram_total):`—`}),(0,G.jsx)(`td`,{style:{textAlign:`right`},children:J(n.ram_budget)}),(0,G.jsx)(`td`,{style:{textAlign:`right`},children:J(n.ram_used)}),(0,G.jsx)(`td`,{style:{textAlign:`right`},children:co(n.ram_used,n.ram_budget)}),(0,G.jsx)(`td`,{style:{textAlign:`right`},children:J(Math.max(n.ram_budget-n.ram_used,0))})]})]})]})}),n.reservations.length>0&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(`h4`,{style:{marginTop:24,marginBottom:4},children:[`Active Reservations (`,n.reservations.length,`)`]}),(0,G.jsx)(`p`,{style:{marginTop:0,marginBottom:12,color:`var(--text-muted, #888)`},children:`Bytes currently charged against the resource budget by the resman. May briefly differ from Loaded Models during load or unload.`}),(0,G.jsx)(`div`,{className:`table-container`,children:(0,G.jsxs)(`table`,{children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{children:Y(`Key`,`budgetReservationKey`)}),(0,G.jsx)(`th`,{style:{textAlign:`right`},children:Y(`Total`,`budgetReservationTotal`)}),n.unified_memory?(0,G.jsx)(`th`,{style:{textAlign:`right`},children:Y(`Unified Memory`,`budgetReservationUnified`)}):(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`th`,{style:{textAlign:`right`},children:Y(`VRAM`,`budgetReservationVRAM`)}),(0,G.jsx)(`th`,{style:{textAlign:`right`},children:Y(`System`,`budgetReservationSystem`)})]}),(0,G.jsx)(`th`,{children:Y(`Per-Device`,`budgetReservationPerDevice`)})]})}),(0,G.jsx)(`tbody`,{children:n.reservations.map(e=>(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{style:{whiteSpace:`nowrap`},children:e.key}),(0,G.jsx)(`td`,{style:{textAlign:`right`,fontWeight:`bold`,whiteSpace:`nowrap`},children:J(e.vram_bytes+e.ram_bytes)}),n.unified_memory?(0,G.jsx)(`td`,{style:{textAlign:`right`,whiteSpace:`nowrap`},children:J(e.vram_bytes+e.ram_bytes)}):(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`td`,{style:{textAlign:`right`,whiteSpace:`nowrap`},children:J(e.vram_bytes)}),(0,G.jsx)(`td`,{style:{textAlign:`right`,whiteSpace:`nowrap`},children:J(e.ram_bytes)})]}),(0,G.jsx)(`td`,{children:e.per.length===0?`—`:e.per.map(e=>`${e.name}: ${J(e.bytes)}`).join(`, `)})]},e.key))})]})})]})]}),(0,G.jsxs)(`div`,{className:`card`,children:[(0,G.jsx)(`h3`,{style:{marginTop:0,marginBottom:4},children:`Loaded Models`}),(0,G.jsx)(`p`,{style:{marginTop:0,marginBottom:16,color:`var(--text-muted, #888)`},children:`Models currently in cache and serving traffic.`}),i&&(0,G.jsx)(`div`,{className:`loading`,children:`Loading running models`}),o&&(0,G.jsx)(`div`,{className:`alert alert-error`,children:o}),!i&&!o&&e&&(0,G.jsx)(`div`,{className:`table-container`,children:e.length>0?(0,G.jsxs)(`table`,{children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{children:Y(`ID`,`runningModelID`)}),(0,G.jsx)(`th`,{children:Y(`Backend`,`runningModelBackend`)}),(0,G.jsx)(`th`,{children:Y(`Status`,`runningModelStatus`)}),(0,G.jsx)(`th`,{children:Y(`Owner`,`runningModelOwner`)}),(0,G.jsx)(`th`,{children:Y(`Family`,`runningModelFamily`)}),(0,G.jsx)(`th`,{style:{textAlign:`right`},children:Y(`Size`,`runningModelSize`)}),(0,G.jsx)(`th`,{style:{textAlign:`right`},children:Y(`VRAM`,`runningModelVRAMTotal`)}),(0,G.jsx)(`th`,{style:{textAlign:`right`},children:Y(`KV`,`runningModelKVCache`)}),(0,G.jsx)(`th`,{style:{textAlign:`right`},children:Y(`Slots`,`runningModelSlots`)}),(0,G.jsx)(`th`,{children:Y(`Expires`,`runningModelExpiresAt`)}),(0,G.jsx)(`th`,{style:{textAlign:`right`},children:Y(`Streams`,`runningModelActiveStreams`)}),(0,G.jsx)(`th`,{})]})}),(0,G.jsx)(`tbody`,{children:e.map(e=>{let t=e.status===`loading`;return(0,G.jsxs)(`tr`,{style:t?{opacity:.7,fontStyle:`italic`}:void 0,children:[(0,G.jsx)(`td`,{children:e.id}),(0,G.jsx)(`td`,{style:{whiteSpace:`nowrap`},children:e.backend||`—`}),(0,G.jsx)(`td`,{style:{whiteSpace:`nowrap`},children:t?(0,G.jsx)(`span`,{style:{color:`var(--text-muted, #888)`},children:`Loading…`}):`loaded`}),(0,G.jsx)(`td`,{children:e.owned_by||`—`}),(0,G.jsx)(`td`,{children:e.model_family||`—`}),(0,G.jsx)(`td`,{style:{textAlign:`right`,whiteSpace:`nowrap`},children:e.size>0?J(e.size):`—`}),(0,G.jsx)(`td`,{style:{textAlign:`right`,whiteSpace:`nowrap`},children:J(e.vram_total)}),(0,G.jsx)(`td`,{style:{textAlign:`right`,whiteSpace:`nowrap`},children:t||e.kv_cache===0?`—`:J(e.kv_cache)}),(0,G.jsx)(`td`,{style:{textAlign:`right`},children:t?`—`:e.slots}),(0,G.jsx)(`td`,{style:{whiteSpace:`nowrap`},children:t?`—`:so(e.expires_at)}),(0,G.jsx)(`td`,{style:{textAlign:`right`},children:t?`—`:e.active_streams}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`button`,{className:`btn btn-primary btn-sm`,onClick:()=>d(e.id),disabled:c===e.id||e.active_streams>0||t,title:t?`Cannot unload while the model is still loading`:e.active_streams>0?`Cannot unload while streams are active`:`Unload model from cache`,children:c===e.id?`Unloading…`:`Unload`})})]},e.id)})}),e.length>1&&(0,G.jsx)(`tfoot`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{colSpan:6,style:{textAlign:`right`,fontWeight:`bold`},children:`Total:`}),(0,G.jsx)(`td`,{style:{textAlign:`right`,fontWeight:`bold`,whiteSpace:`nowrap`},children:J(e.reduce((e,t)=>e+t.vram_total,0))}),(0,G.jsx)(`td`,{style:{textAlign:`right`,fontWeight:`bold`,whiteSpace:`nowrap`},children:J(e.reduce((e,t)=>e+(t.status===`loading`?0:t.kv_cache),0))}),(0,G.jsx)(`td`,{style:{textAlign:`right`,fontWeight:`bold`,whiteSpace:`nowrap`},children:e.reduce((e,t)=>e+(t.status===`loading`?0:t.slots),0)}),(0,G.jsx)(`td`,{colSpan:3})]})})]}):(0,G.jsxs)(`div`,{className:`empty-state`,children:[(0,G.jsx)(`h3`,{children:`No running models`}),(0,G.jsx)(`p`,{children:`Models will appear here when loaded into cache`})]})})]})]})}var uo=``,fo={active:0,idle:1,empty:2},po=[[`Model`,`imcModelID`],[`Cache Entry`,`imcSessionID`],[`State`,`imcState`],[`Current Messages`,`imcMessages`],[`Current Tokens`,`imcContext`],[`Current Allocated`,`imcAllocated`],[`Latest Request Input`,`imcInputTokens`],[`Latest Request Output`,`imcOutputTokens`],[`Latest Request Context`,`imcRequestTotal`],[`Peak Context`,`imcPeakContext`],[`Peak Memory`,`imcSnapshotBytes`],[`Peak Used`,`imcUtilization`],[`Media`,`imcMedia`],[`Last Used`,`imcLastUsed`]],mo=[[`Model`,`imcModelID`],[`Cache Entry`,`imcSystemCacheID`],[`System Tokens`,`imcSystemContext`],[`Allocated`,`imcSystemAllocated`],[`Snapshot Memory`,`imcSystemSnapshotBytes`],[`Restores`,`imcSystemRestores`],[`Active Restores`,`imcSystemActiveRestores`],[`Last Used`,`imcLastUsed`]],ho=`kronk-imc-view`,go=`kronk-imc-model`;function _o(){try{return sessionStorage.getItem(ho)===`system`?`system`:`current`}catch{return`current`}}function vo(){try{return sessionStorage.getItem(go)??uo}catch{return uo}}function yo(e){if(!e||e.startsWith(`0001-01-01`))return`—`;let t=new Date(e);return Number.isNaN(t.getTime())?`—`:t.toLocaleString()}function bo(e,t){return t>0?`${(e/t*100).toFixed(1)}%`:`0%`}function xo(){let[e,t]=(0,x.useState)(null),[n,r]=(0,x.useState)(null),[i,a]=(0,x.useState)(_o),[o,s]=(0,x.useState)(vo),[c,l]=(0,x.useState)(`last_used`),[u,d]=(0,x.useState)(!1),[f,p]=(0,x.useState)(`last_used`),[m,h]=(0,x.useState)(!1),[g,_]=(0,x.useState)(!0),[v,y]=(0,x.useState)(null),[b,S]=(0,x.useState)(!1),C=async(e=!1)=>{e||_(!0),y(null);try{let[e,n]=await Promise.all([W.listIMCSessions(),W.listIMCSystemCaches()]);t(e),r(n);let i=new Set([...e,...n].map(e=>e.model_id));s(e=>e===uo||i.has(e)?e:uo)}catch(e){y(e instanceof Error?e.message:`Failed to load IMC caches`)}finally{e||_(!1)}};(0,x.useEffect)(()=>{C();let e=window.setInterval(()=>C(!0),5e3);return()=>window.clearInterval(e)},[]),(0,x.useEffect)(()=>{try{sessionStorage.setItem(ho,i)}catch{}},[i]),(0,x.useEffect)(()=>{try{sessionStorage.setItem(go,o)}catch{}},[o]),(0,x.useEffect)(()=>{if(!b)return;let e=e=>e.key===`Escape`&&S(!1);return document.addEventListener(`keydown`,e),()=>document.removeEventListener(`keydown`,e)},[b]);let w=e=>{e===c?d(e=>!e):(l(e),d(!0))},T=e=>{e===f?h(e=>!e):(p(e),h(!0))},E=e=>c===e?u?` ▲`:` ▼`:``,D=e=>f===e?m?` ▲`:` ▼`:``,O=[...new Set([...e??[],...n??[]].map(e=>e.model_id))].sort((e,t)=>e.localeCompare(t)),k=(e??[]).filter(e=>o===uo||e.model_id===o),A=(n??[]).filter(e=>o===uo||e.model_id===o),j=k.sort((e,t)=>{let n;switch(c){case`model_id`:n=e.model_id.localeCompare(t.model_id);break;case`id`:n=e.id-t.id;break;case`state`:n=fo[e.state]-fo[t.state];break;case`messages`:n=e.messages-t.messages;break;case`context`:n=e.context-t.context;break;case`allocated`:n=e.allocated-t.allocated;break;case`snapshot_bytes`:n=e.snapshot_bytes-t.snapshot_bytes;break;case`input_tokens`:n=e.input_tokens-t.input_tokens;break;case`output_tokens`:n=e.output_tokens-t.output_tokens;break;case`request_context`:n=e.input_tokens+e.output_tokens-t.input_tokens-t.output_tokens;break;case`peak_context`:n=e.peak_context-t.peak_context;break;case`utilization`:n=So(e)-So(t);break;case`has_media`:n=Number(e.has_media)-Number(t.has_media);break;case`last_used`:n=Date.parse(e.last_used)-Date.parse(t.last_used)}return n||=e.model_id.localeCompare(t.model_id)||e.id-t.id,u?n:-n}),M=A.sort((e,t)=>{let n;switch(f){case`model_id`:n=e.model_id.localeCompare(t.model_id);break;case`id`:n=e.id-t.id;break;case`tokens`:n=e.tokens-t.tokens;break;case`allocated`:n=e.allocated-t.allocated;break;case`snapshot_bytes`:n=e.snapshot_bytes-t.snapshot_bytes;break;case`restore_count`:n=e.restore_count-t.restore_count;break;case`active_restores`:n=e.active_restores-t.active_restores;break;case`last_used`:n=Date.parse(e.last_used)-Date.parse(t.last_used)}return n||=e.model_id.localeCompare(t.model_id)||e.id-t.id,m?n:-n});return(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{className:`page-header-with-action`,children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`h2`,{children:`IMC Sessions`}),(0,G.jsx)(`p`,{className:`page-description`,children:`Working sessions and reusable System prompt caches for loaded models`})]}),(0,G.jsxs)(`div`,{style:{display:`flex`,gap:`8px`},children:[(0,G.jsx)(`button`,{className:`btn btn-secondary`,onClick:()=>S(!0),children:`Field Guide`}),(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:()=>C(),disabled:g,children:`Refresh`})]})]}),(0,G.jsxs)(`div`,{className:`tabs`,role:`tablist`,"aria-label":`IMC cache type`,children:[(0,G.jsx)(`button`,{type:`button`,role:`tab`,"aria-selected":i===`current`,className:`tab ${i===`current`?`active`:``}`,onClick:()=>a(`current`),children:`Working Sessions`}),(0,G.jsx)(`button`,{type:`button`,role:`tab`,"aria-selected":i===`system`,className:`tab ${i===`system`?`active`:``}`,onClick:()=>a(`system`),children:`System Caches`})]}),b&&(0,G.jsx)(`div`,{className:`modal-overlay`,role:`dialog`,"aria-modal":`true`,"aria-labelledby":`imc-field-guide-title`,onClick:()=>S(!1),children:(0,G.jsxs)(`div`,{className:`modal-content`,onClick:e=>e.stopPropagation(),children:[(0,G.jsxs)(`div`,{className:`modal-header`,children:[(0,G.jsxs)(`h3`,{id:`imc-field-guide-title`,children:[`IMC `,i===`current`?`Working Session`:`System Cache`,` Field Guide`]}),(0,G.jsx)(`button`,{className:`modal-close`,onClick:()=>S(!1),"aria-label":`Close field guide`,children:`×`})]}),(0,G.jsx)(`div`,{className:`modal-body`,children:(0,G.jsx)(`dl`,{style:{margin:0,display:`grid`,gap:`20px`},children:(i===`current`?po:mo).map(([e,t])=>(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`dt`,{children:(0,G.jsx)(`strong`,{children:e})}),(0,G.jsx)(`dd`,{style:{margin:`4px 0 0`},children:ia[t]})]},t))})})]})}),v&&(0,G.jsx)(`div`,{className:`alert alert-error`,children:v}),O.length>0&&(0,G.jsxs)(`div`,{className:`tabs imc-model-tabs`,role:`tablist`,"aria-label":`IMC caches by model`,children:[(0,G.jsx)(`button`,{type:`button`,role:`tab`,"aria-selected":o===uo,className:`tab ${o===uo?`active`:``}`,onClick:()=>s(uo),children:`All`}),O.map(e=>(0,G.jsx)(`button`,{type:`button`,role:`tab`,"aria-selected":o===e,className:`tab imc-model-tab ${o===e?`active`:``}`,title:e,onClick:()=>s(e),children:(0,G.jsx)(`span`,{className:`imc-model-tab-label`,children:ra(e)})},e))]}),(0,G.jsx)(`div`,{className:`card`,children:g&&!e?(0,G.jsx)(`div`,{className:`loading`,children:`Loading IMC caches...`}):i===`current`?(0,G.jsx)(Co,{data:j,sort:w,indicator:E}):(0,G.jsx)(wo,{data:M,sort:T,indicator:D})})]})}function So(e){return e.context_window>0?e.peak_context/e.context_window:0}function Co({data:e,sort:t,indicator:n}){if(e.length===0)return(0,G.jsxs)(`div`,{className:`empty-state`,children:[(0,G.jsx)(`h3`,{children:`No IMC working sessions`}),(0,G.jsx)(`p`,{children:`Entries appear when an IMC-enabled model is loaded`})]});let r=(e,r,i,a=!1)=>(0,G.jsxs)(`th`,{onClick:()=>t(i),className:`catalog-table-sortable`,style:a?{textAlign:`right`}:void 0,children:[Y(e,r),(0,G.jsx)(`span`,{className:`catalog-table-sort-indicator`,children:n(i)})]});return(0,G.jsx)(`div`,{style:{overflowX:`auto`},children:(0,G.jsxs)(`table`,{className:`imc-sessions-table`,children:[(0,G.jsxs)(`thead`,{children:[(0,G.jsxs)(`tr`,{className:`imc-table-groups`,children:[(0,G.jsx)(`th`,{colSpan:3,className:`imc-table-group imc-table-group-session`,children:`Session`}),(0,G.jsx)(`th`,{colSpan:3,className:`imc-table-group imc-table-group-request`,children:`Latest Request`}),(0,G.jsx)(`th`,{colSpan:3,className:`imc-table-group imc-table-group-current`,children:`Working Cache`}),(0,G.jsx)(`th`,{colSpan:3,className:`imc-table-group imc-table-group-capacity`,children:`Peak / Usage`}),(0,G.jsx)(`th`,{colSpan:2,className:`imc-table-group imc-table-group-details`,children:`Details`})]}),(0,G.jsxs)(`tr`,{className:`imc-table-columns`,children:[r(`Model`,`imcModelID`,`model_id`),r(`Cache Entry`,`imcSessionID`,`id`),r(`State`,`imcState`,`state`),r(`Input`,`imcInputTokens`,`input_tokens`,!0),r(`Output`,`imcOutputTokens`,`output_tokens`,!0),r(`Context`,`imcRequestTotal`,`request_context`,!0),r(`Messages`,`imcMessages`,`messages`,!0),r(`Tokens`,`imcContext`,`context`,!0),r(`Allocated`,`imcAllocated`,`allocated`,!0),r(`Peak Context`,`imcPeakContext`,`peak_context`,!0),r(`Peak Memory`,`imcSnapshotBytes`,`snapshot_bytes`,!0),r(`Peak Used`,`imcUtilization`,`utilization`,!0),r(`Media`,`imcMedia`,`has_media`),r(`Last Used`,`imcLastUsed`,`last_used`)]})]}),(0,G.jsx)(`tbody`,{children:e.map(e=>(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:e.model_id}),(0,G.jsx)(`td`,{children:e.id}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`span`,{className:`badge badge-${e.state}`,children:e.state})}),(0,G.jsx)(`td`,{className:`imc-request-cell`,style:{textAlign:`right`},children:e.input_tokens.toLocaleString()}),(0,G.jsx)(`td`,{className:`imc-request-cell`,style:{textAlign:`right`},children:e.output_tokens.toLocaleString()}),(0,G.jsx)(`td`,{className:`imc-request-cell`,style:{textAlign:`right`},children:(e.input_tokens+e.output_tokens).toLocaleString()}),(0,G.jsx)(`td`,{className:`imc-current-cell`,style:{textAlign:`right`},children:e.messages.toLocaleString()}),(0,G.jsx)(`td`,{className:`imc-current-cell`,style:{textAlign:`right`},children:e.context.toLocaleString()}),(0,G.jsx)(`td`,{className:`imc-current-cell`,style:{textAlign:`right`},children:e.allocated.toLocaleString()}),(0,G.jsx)(`td`,{className:`imc-capacity-cell`,style:{textAlign:`right`},children:e.peak_context.toLocaleString()}),(0,G.jsx)(`td`,{className:`imc-capacity-cell`,style:{textAlign:`right`},children:J(e.snapshot_bytes)}),(0,G.jsx)(`td`,{className:`imc-capacity-cell`,style:{textAlign:`right`},children:bo(e.peak_context,e.context_window)}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`span`,{className:`badge badge-${e.has_media?`yes`:`no`}`,children:e.has_media?`yes`:`no`})}),(0,G.jsx)(`td`,{style:{whiteSpace:`nowrap`},children:yo(e.last_used)})]},`${e.model_id}-${e.id}`))})]})})}function wo({data:e,sort:t,indicator:n}){if(e.length===0)return(0,G.jsxs)(`div`,{className:`empty-state`,children:[(0,G.jsx)(`h3`,{children:`No System caches`}),(0,G.jsx)(`p`,{children:`Entries appear after requests with System prompts`})]});let r=(e,r,i,a=!1)=>(0,G.jsxs)(`th`,{onClick:()=>t(i),className:`catalog-table-sortable`,style:a?{textAlign:`right`}:void 0,children:[Y(e,r),(0,G.jsx)(`span`,{className:`catalog-table-sort-indicator`,children:n(i)})]});return(0,G.jsx)(`div`,{style:{overflowX:`auto`},children:(0,G.jsxs)(`table`,{className:`imc-sessions-table`,children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[r(`Model`,`imcModelID`,`model_id`),r(`Cache Entry`,`imcSystemCacheID`,`id`),r(`System Tokens`,`imcSystemContext`,`tokens`,!0),r(`Allocated`,`imcSystemAllocated`,`allocated`,!0),r(`Snapshot Memory`,`imcSystemSnapshotBytes`,`snapshot_bytes`,!0),r(`Restores`,`imcSystemRestores`,`restore_count`,!0),r(`Active Restores`,`imcSystemActiveRestores`,`active_restores`,!0),r(`Last Used`,`imcLastUsed`,`last_used`)]})}),(0,G.jsx)(`tbody`,{children:e.map(e=>(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:e.model_id}),(0,G.jsx)(`td`,{children:e.id}),(0,G.jsx)(`td`,{className:`imc-system-cell`,style:{textAlign:`right`},children:e.tokens.toLocaleString()}),(0,G.jsx)(`td`,{className:`imc-system-cell`,style:{textAlign:`right`},children:e.allocated.toLocaleString()}),(0,G.jsx)(`td`,{className:`imc-system-cell`,style:{textAlign:`right`},children:J(e.snapshot_bytes)}),(0,G.jsx)(`td`,{style:{textAlign:`right`},children:e.restore_count.toLocaleString()}),(0,G.jsx)(`td`,{style:{textAlign:`right`},children:e.active_restores.toLocaleString()}),(0,G.jsx)(`td`,{style:{whiteSpace:`nowrap`},children:yo(e.last_used)})]},`${e.model_id}-${e.id}`))})]})})}function To(e){return e&&e.length>0?e.join(`, `):`None`}function Eo(e){return e>=0?`Slot ${e}`:`—`}function Do(e,t,n,r){if(e.slots.length===0)return`—`;for(let i=0;i=0?(n+1)%e.slots.length:r}`}function Oo(e){return e<=0?`—`:e<6e4?`${(e/1e3).toFixed(1)}s`:`${Math.floor(e/6e4)}m ${Math.floor(e%6e4/1e3)}s`}function ko(e){return e.phase===`imc-restore`?`Restoring session state`:`—`}function Ao(e){if(e.phase===`prefill-imc`)return`${e.imc_prepared_tokens.toLocaleString()} / ${e.imc_total_tokens.toLocaleString()} · IMC extension`;if(e.phase!==`prefill`)return`—`;let t=e.prefilled_tokens,n=t+e.prefill_remaining;return`${t.toLocaleString()} / ${n.toLocaleString()}${e.prefill_owner?` (owner)`:``}`}function jo(e){return e.request_id.replace(/^chatcmpl-/,``)||`—`}function Mo(e){return e.generation_mode?`${e.generated_tokens.toLocaleString()} tokens · ${e.generation_mode} · ${e.generation_rows} rows`:`—`}function No(e){return e===`imc-restore`?`prefill stage 1 · restore`:e===`prefill-imc`?`prefill stage 2 · IMC`:e===`prefill`?`prefill stage 2 · request`:e===`media-prefill`?`prefill stage 2 · media`:e}function Po(e){return e.mtp?`MTP · nDraft ${e.ndraft}`:e.ndraft>0?`Speculative · nDraft ${e.ndraft}`:`Non-MTP`}function Fo({model:e}){let t=Do(e,e.eligible_imc_slots,e.imc_selector_selected,e.imc_selector_next),n=Do(e,e.eligible_prefill_slots,e.prefill_selector_selected,e.prefill_selector_selected>=0?(e.prefill_selector_selected+1)%e.slots.length:e.prefill_selector_next);return(0,G.jsxs)(`div`,{className:`card slot-model-card`,children:[(0,G.jsxs)(`div`,{className:`slot-model-heading`,children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`h3`,{title:e.model_id,children:ra(e.model_id)}),(0,G.jsx)(`span`,{className:`slot-mode-badge`,children:Po(e)})]}),(0,G.jsxs)(`span`,{className:`slot-iteration`,children:[`Iteration `,e.iteration.toLocaleString()]})]}),(0,G.jsxs)(`div`,{className:`slot-summary-grid`,children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`span`,{children:Y(`Batch sizing`,`slotBatchSizing`)}),(0,G.jsxs)(`strong`,{children:[e.prefill_batch_size.toLocaleString(),` / `,e.nubatch.toLocaleString(),` / `,e.nbatch.toLocaleString()]}),(0,G.jsx)(`small`,{children:`Prefill batch / NUBatch / NBatch`})]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`span`,{children:Y(`Request queue`,`slotQueue`)}),(0,G.jsx)(`strong`,{children:e.queued_requests+e.pending_requests}),(0,G.jsxs)(`small`,{children:[e.queued_requests,` channel + `,e.pending_requests,` pending`]})]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`span`,{children:Y(`Prefill stage 1 · IMC extension`,`slotIMCSelector`)}),(0,G.jsx)(`strong`,{children:Eo(e.imc_selector_selected)}),(0,G.jsxs)(`small`,{children:[`Next: `,t,` · Waiting: `,To(e.eligible_imc_slots)]})]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`span`,{children:Y(`Prefill stage 2 · request`,`slotPrefillSelector`)}),(0,G.jsx)(`strong`,{children:Eo(e.prefill_selector_selected)}),(0,G.jsxs)(`small`,{children:[`Next: `,n,` · Waiting: `,To(e.eligible_prefill_slots)]})]})]}),(0,G.jsx)(`div`,{className:`table-container`,children:(0,G.jsxs)(`table`,{className:`slots-table`,children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{children:Y(`Slot`,`slotID`)}),(0,G.jsx)(`th`,{children:Y(`Phase`,`slotPhase`)}),(0,G.jsx)(`th`,{children:Y(`Request`,`slotRequest`)}),(0,G.jsx)(`th`,{children:Y(`Age`,`slotAge`)}),(0,G.jsx)(`th`,{children:Y(`Stage 1 · restore`,`slotIMCProgress`)}),(0,G.jsx)(`th`,{children:Y(`Stage 2 · decode`,`slotPrefillProgress`)}),(0,G.jsx)(`th`,{children:Y(`Generation`,`slotGeneration`)}),(0,G.jsx)(`th`,{style:{textAlign:`right`},children:Y(`Past`,`slotPastTokens`)})]})}),(0,G.jsx)(`tbody`,{children:e.slots.map(e=>(0,G.jsxs)(`tr`,{className:e.prefill_owner?`slot-prefill-owner`:void 0,children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`strong`,{children:e.id})}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`span`,{className:`slot-phase slot-phase-${e.phase}`,children:No(e.phase)})}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{className:`slot-request-id`,title:e.request_id||void 0,children:jo(e)})}),(0,G.jsx)(`td`,{className:`slot-request-age`,children:Oo(e.request_age_ms)}),(0,G.jsx)(`td`,{children:ko(e)}),(0,G.jsx)(`td`,{children:Ao(e)}),(0,G.jsx)(`td`,{children:Mo(e)}),(0,G.jsx)(`td`,{style:{textAlign:`right`},children:e.past_tokens.toLocaleString()})]},e.id))})]})})]})}function Io(){let[e,t]=(0,x.useState)(null),[n,r]=(0,x.useState)(!0),[i,a]=(0,x.useState)(null),o=async(e=!1)=>{e||r(!0),a(null);try{t(await W.listBatchEngineSlots())}catch(e){a(e instanceof Error?e.message:`Failed to load batch engine slots`)}finally{e||r(!1)}};return(0,x.useEffect)(()=>{o();let e=window.setInterval(()=>o(!0),1e3);return()=>window.clearInterval(e)},[]),(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{className:`page-header-with-action`,children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`h2`,{children:`Batch Engine Slots`}),(0,G.jsx)(`p`,{className:`page-description`,children:`Live scheduler, prefill, generation, and IMC preparation state for loaded generation models`})]}),(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:()=>o(),disabled:n,children:`Refresh`})]}),i&&(0,G.jsx)(`div`,{className:`alert alert-error`,children:i}),n&&!e&&(0,G.jsx)(`div`,{className:`loading`,children:`Loading slot state…`}),!n&&e?.length===0&&(0,G.jsx)(`div`,{className:`empty-state`,children:`No loaded generation models expose batch-engine slots.`}),e?.map(e=>(0,G.jsx)(Fo,{model:e},e.model_id))]})}var Lo=`unsloth/Qwen3-0.6B-Q8_0`;function Ro(e){return e?J(e*1024*1024):`—`}function zo({commands:e,open:t}){return!e||e.length===0?null:(0,G.jsx)(`div`,{style:{marginTop:12},children:e.map((e,n)=>(0,G.jsxs)(`details`,{open:t,style:{marginBottom:12},children:[(0,G.jsxs)(`summary`,{style:{cursor:`pointer`,fontFamily:`"SF Mono", "Monaco", "Inconsolata", "Fira Code", monospace`,fontSize:`14px`,color:`var(--color-gray-900)`,padding:`4px 0`},children:[`$ `,e.cmd]}),e.err&&(0,G.jsxs)(`p`,{style:{color:`var(--color-error)`,margin:`8px 0 0`,fontSize:`13px`},children:[`error: `,e.err]}),(0,G.jsx)(`pre`,{className:`code-block`,style:{marginTop:8,whiteSpace:`pre`},children:e.output||`(no output)`})]},`${e.cmd}-${n}`))})}function Bo(){let[e,t]=(0,x.useState)(null),[n,r]=(0,x.useState)(!0),[i,a]=(0,x.useState)(null),[o,s]=(0,x.useState)(`summary`),[c,l]=(0,x.useState)(!1),[u,d]=(0,x.useState)(!1),[f,p]=(0,x.useState)(``);(0,x.useEffect)(()=>{m()},[]);let m=async()=>{r(!0),a(null),d(!1);try{let e=await W.getDiagnose();t(e)}catch(e){a(e instanceof Error?e.message:`Failed to load diagnostics`)}finally{r(!1)}},h=async()=>{l(!0),a(null);try{let e=await W.getDiagnose(!0,f);t(e),d(!0),s(`summary`)}catch(e){a(e instanceof Error?e.message:`Failed to run benchmark`)}finally{l(!1)}},g=e?JSON.stringify(e,null,2):``,_=Array.from(new Set([...(e?.llama.backends??[]).map(e=>e.processor),`cpu`]));return(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{className:`page-header-with-action`,children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`h2`,{children:`Info`}),(0,G.jsxs)(`p`,{className:`page-description`,children:[`Host environment diagnostics — versions, system, and the llama.cpp backends and devices Kronk can see. Use `,(0,G.jsx)(`strong`,{children:`Run benchmark`}),` `,`to measure inference throughput; it loads a model and takes a few seconds.`]})]}),(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:m,disabled:n||c,children:`Refresh`})]}),e&&(0,G.jsxs)(`div`,{className:`tabs`,children:[(0,G.jsx)(`button`,{className:`tab ${o===`summary`?`active`:``}`,onClick:()=>s(`summary`),children:`Summary`}),(0,G.jsx)(`button`,{className:`tab ${o===`json`?`active`:``}`,onClick:()=>s(`json`),children:`JSON`})]}),i&&(0,G.jsx)(`div`,{className:`error-message`,children:i}),n&&!e&&(0,G.jsx)(`p`,{children:`Collecting diagnostics…`}),e&&o===`json`&&(0,G.jsx)(`div`,{className:`diagnose-json`,children:(0,G.jsx)(ya,{code:g,language:`json`})}),e&&o===`summary`&&(0,G.jsxs)(G.Fragment,{children:[e.hints&&e.hints.length>0&&(0,G.jsxs)(`div`,{className:`card`,style:{borderLeft:`4px solid var(--color-warning-border)`},children:[(0,G.jsx)(`h3`,{style:{marginTop:0},children:`Hints`}),e.hints.map((e,t)=>(0,G.jsxs)(`div`,{style:{marginBottom:12},children:[(0,G.jsxs)(`p`,{style:{margin:0},children:[(0,G.jsxs)(`strong`,{style:{textTransform:`uppercase`},children:[`[`,e.severity,`]`]}),` `,e.message]}),e.remedy&&(0,G.jsx)(`pre`,{className:`code-block`,style:{marginTop:6,whiteSpace:`pre-wrap`},children:e.remedy})]},t))]}),(0,G.jsxs)(`div`,{className:`card`,children:[(0,G.jsx)(`h3`,{style:{marginTop:0},children:`Versions`}),(0,G.jsx)(`div`,{className:`table-container`,children:(0,G.jsx)(`table`,{children:(0,G.jsxs)(`tbody`,{children:[(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Kronk`}),(0,G.jsx)(`td`,{children:e.versions.kronk||`—`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`yzma`}),(0,G.jsx)(`td`,{children:e.versions.yzma||`—`})]})]})})})]}),(0,G.jsxs)(`div`,{className:`card`,children:[(0,G.jsx)(`h3`,{style:{marginTop:0},children:`System`}),(0,G.jsx)(`div`,{className:`table-container`,children:(0,G.jsx)(`table`,{children:(0,G.jsxs)(`tbody`,{children:[(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`OS`}),(0,G.jsx)(`td`,{children:e.system.os})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Arch`}),(0,G.jsx)(`td`,{children:e.system.arch})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`CPU`}),(0,G.jsx)(`td`,{children:e.system.cpuModel||`—`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`CPUs`}),(0,G.jsx)(`td`,{children:e.system.numCPU})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`RAM`}),(0,G.jsx)(`td`,{children:e.system.ramBytes?J(e.system.ramBytes):`—`})]})]})})}),(0,G.jsx)(zo,{commands:e.system.commands})]}),(0,G.jsxs)(`div`,{className:`card`,children:[(0,G.jsx)(`h3`,{style:{marginTop:0},children:`llama.cpp`}),e.llama.installed?(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(`p`,{style:{marginTop:0,color:`var(--color-text-secondary)`},children:[`Root: `,(0,G.jsx)(`code`,{children:e.llama.root})]}),(e.llama.backends??[]).map(e=>(0,G.jsxs)(`div`,{style:{marginBottom:24},children:[(0,G.jsx)(`h4`,{style:{marginBottom:8},children:e.processor}),(0,G.jsx)(`div`,{className:`table-container`,style:{marginBottom:12},children:(0,G.jsx)(`table`,{children:(0,G.jsxs)(`tbody`,{children:[(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`binDir`}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:e.binDir})})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`version`}),(0,G.jsx)(`td`,{children:e.version||`—`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`build`}),(0,G.jsx)(`td`,{children:e.build||`—`})]})]})})}),(e.devices??[]).length===0?(0,G.jsx)(`p`,{style:{color:`var(--color-text-secondary)`,margin:`4px 0`},children:`No devices detected.`}):(0,G.jsx)(`div`,{className:`table-container`,children:(0,G.jsxs)(`table`,{children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{children:`ID`}),(0,G.jsx)(`th`,{children:`Device`}),(0,G.jsx)(`th`,{style:{textAlign:`right`},children:`VRAM Total`}),(0,G.jsx)(`th`,{style:{textAlign:`right`},children:`VRAM Free`})]})}),(0,G.jsx)(`tbody`,{children:(e.devices??[]).map(e=>(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:e.id}),(0,G.jsx)(`td`,{children:e.name}),(0,G.jsx)(`td`,{style:{textAlign:`right`},children:Ro(e.vramTotalMiB)}),(0,G.jsx)(`td`,{style:{textAlign:`right`},children:Ro(e.vramFreeMiB)})]},e.id))})]})}),(0,G.jsx)(zo,{commands:e.commands})]},e.processor))]}):(0,G.jsx)(`p`,{style:{color:`var(--color-text-secondary)`},children:`No llama.cpp libraries installed for this machine.`})]}),e.engine?.probed&&(0,G.jsxs)(`div`,{className:`card`,style:e.engine.loaded?void 0:{borderLeft:`4px solid var(--color-error)`},children:[(0,G.jsx)(`h3`,{style:{marginTop:0},children:`Engine`}),e.engine.loaded?(0,G.jsx)(`p`,{style:{marginTop:0,color:`var(--color-text-secondary)`},children:`Loaded — Kronk can load models and run inference.`}):(0,G.jsx)(`p`,{style:{marginTop:0,color:`var(--color-error)`},children:(0,G.jsx)(`strong`,{children:`Degraded — Kronk could not load its llama.cpp libraries in-process, so model loading and inference are unavailable.`})}),(0,G.jsx)(`div`,{className:`table-container`,children:(0,G.jsx)(`table`,{children:(0,G.jsxs)(`tbody`,{children:[(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Loaded`}),(0,G.jsx)(`td`,{children:e.engine.loaded?`✓ true`:`✗ false`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Processor`}),(0,G.jsx)(`td`,{children:e.engine.processor||`—`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Library path`}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:e.engine.libPath})})]})]})})}),e.engine.error&&(0,G.jsx)(`pre`,{className:`code-block`,style:{marginTop:12,whiteSpace:`pre-wrap`},children:e.engine.error})]}),(0,G.jsxs)(`div`,{className:`card`,children:[(0,G.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,justifyContent:`space-between`,gap:12},children:[(0,G.jsx)(`h3`,{style:{margin:0},children:`Benchmark`}),(0,G.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:12},children:[(0,G.jsxs)(`span`,{className:`bench-processor`,children:[(0,G.jsx)(`label`,{htmlFor:`bench-processor`,children:`Processor:`}),(0,G.jsxs)(`select`,{id:`bench-processor`,value:f,onChange:e=>p(e.target.value),disabled:c||n,children:[(0,G.jsx)(`option`,{value:``,children:`Auto`}),_.map(e=>(0,G.jsx)(`option`,{value:e,children:e},e))]})]}),(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:h,disabled:c||n||!e.llama.installed,children:c?`Running benchmark…`:`Run benchmark`})]})]}),c?(0,G.jsx)(`p`,{style:{color:`var(--color-text-secondary)`},children:`Running benchmark — loading the model and measuring throughput…`}):e.bench.model?(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`div`,{className:`table-container`,children:(0,G.jsx)(`table`,{children:(0,G.jsxs)(`tbody`,{children:[(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Backend`}),(0,G.jsx)(`td`,{children:e.bench.processor||`—`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Model`}),(0,G.jsx)(`td`,{children:e.bench.model})]})]})})}),(0,G.jsx)(zo,{commands:e.bench.commands,open:!0})]}):u?(0,G.jsxs)(`div`,{style:{color:`var(--color-warning-text)`},children:[(0,G.jsxs)(`p`,{style:{marginTop:0},children:[`Benchmark skipped — the benchmark model `,(0,G.jsx)(`code`,{children:Lo}),` `,`is not installed, so there was nothing to run. Install it from the CLI, then click `,(0,G.jsx)(`strong`,{children:`Run benchmark`}),` again:`]}),(0,G.jsx)(`pre`,{className:`code-block`,style:{whiteSpace:`pre-wrap`},children:`kronk model pull ${Lo}`}),(0,G.jsxs)(`p`,{style:{marginBottom:0},children:[`Or fetch it automatically with `,(0,G.jsx)(`code`,{children:`kronk diagnose --install`}),`.`]})]}):(0,G.jsxs)(`p`,{style:{color:`var(--color-text-secondary)`},children:[`No benchmark run yet. Click `,(0,G.jsx)(`strong`,{children:`Run benchmark`}),` to measure inference throughput — prompt-processing and token-generation speed. Requires a benchmark model to be installed.`]})]})]})]})}function Vo(e){return e<1e6?`${(e/1e3).toFixed(0)} KB`:e<1e9?`${(e/1e6).toFixed(1)} MB`:`${(e/1e9).toFixed(2)} GB`}function Ho(e){if(e<60)return`${Math.round(e)}s`;let t=Math.floor(e/60),n=Math.round(e%60);return t<60?`${t}m ${n}s`:`${Math.floor(t/60)}h ${t%60}m`}function Uo({progress:e,meta:t}){let[,n]=(0,x.useState)(0);(0,x.useEffect)(()=>{let e=setInterval(()=>n(e=>e+1),1e3);return()=>clearInterval(e)},[]);let{currentBytes:r,totalBytes:i,mbPerSec:a,pct:o,startedAtMs:s}=e,c=(Date.now()-s)/1e3,l=``;c>=5&&i>0&&r0&&(l=` · ETA ${Ho((i-r)/(a*1e3*1e3))}`);let u=e.src.split(`/`).pop()||e.src,d=t&&t.fileTotal>1,f=i>0,p=[f?`${o.toFixed(1)}%`:``,f?`${Vo(r)} / ${Vo(i)}`:`${Vo(r)}`,a>0?`${a.toFixed(1)} MB/s`:``].filter(Boolean).join(` · `)+l,m=f?o:0,h=m>=45;return(0,G.jsxs)(`div`,{className:`download-progress`,children:[(0,G.jsx)(`div`,{className:`download-progress-text`,children:(0,G.jsxs)(`span`,{children:[`Downloading `,u,d?` (file ${t.fileIndex} of ${t.fileTotal})`:``]})}),(0,G.jsxs)(`div`,{className:`playground-autotest-progress-bar`,children:[(0,G.jsx)(`div`,{className:`playground-autotest-progress-fill`,style:{width:`${Math.max(m,1)}%`},children:h&&(0,G.jsx)(`span`,{className:`playground-autotest-progress-label`,children:p})}),!h&&(0,G.jsx)(`span`,{className:`playground-autotest-progress-label-outside`,children:p})]})]})}function Wo(e){return e.replace(/\.gguf$/i,``)}function Go(e){return Wo(e.split(`/`).pop()??e).replace(/-\d+-of-\d+$/,``)}var Ko=/^(UD-)?((IQ|Q)\d+(_[A-Z0-9]+)*|BF16|F16|F32)$/i;function qo(e){return Ko.test(e.trim())}function Jo(e){let t=(e.split(`/`).pop()??e).toLowerCase();return/(^|[-._])mmproj([-._]|$)/.test(t)}function Yo(e,t){if(/(^|[-_])mtp([-_]|$)/i.test(t))return!1;let n=(e.split(`/`).pop()??e).toLowerCase();return n.startsWith(`mtp-`)||n.startsWith(`mtp_`)}function Xo(e,t){let n=Wo(e.split(`/`).pop()??e).replace(/-\d+-of-\d+$/,``).toLowerCase(),r=t.trim().toLowerCase();return n.endsWith(`-`+r)||n.endsWith(`.`+r)||n===r}function Zo(e){let t=e.trim().split(`?`)[0];if(!t)return null;let n=t;for(let e of[`https://huggingface.co/`,`http://huggingface.co/`,`https://hf.co/`,`http://hf.co/`,`huggingface.co/`,`hf.co/`])if(n.toLowerCase().startsWith(e)){n=n.slice(e.length);break}let r=n.split(`/`).filter(e=>e!==``);if(r.length<2)return null;let i=r[0],a=r[1],o=``;return r.length>4&&(r[2]===`resolve`||r[2]===`blob`||r[2]===`tree`)?o=r.slice(4).join(`/`):r.length>2&&(o=r.slice(2).join(`/`)),{provider:i,family:a,model:o?Go(o):``}}function Qo(e){let t=1e9,n=1e6,r=1e3;return e>=t?`${(e/t).toFixed(1)} GB`:e>=n?`${(e/n).toFixed(1)} MB`:e>=r?`${(e/r).toFixed(1)} KB`:`${e} B`}function $o(e){let t=new Map;for(let n of e){let e=n.filename.replace(/-\d+-of-\d+(\.gguf)$/i,`$1`),r=t.get(e);r?r.push(n):t.set(e,[n])}let n=[];for(let[e,r]of t){if(r.length===1){let e=r[0];n.push({label:e.filename,filename:e.filename,sizeStr:e.size_str,parts:1});continue}r.sort((e,t)=>e.filename.localeCompare(t.filename));let t=r.reduce((e,t)=>e+t.size,0);n.push({label:e,filename:r[0].filename,sizeStr:Qo(t),parts:r.length})}return n}function es(e){return/-\d+-of-\d+\.gguf$/i.test(e)}function ts(e,t,n){let r=e.trim(),i=t.trim(),a=Wo(n.trim());return!r||!i?``:a?`${r}/${i}/${a}.gguf`:`${r}/${i}`}function ns(){let{download:e,isDownloading:t,startDownload:n,cancelDownload:r,clearDownload:i}=zn(),[a,o]=(0,x.useState)(``),[s,c]=(0,x.useState)(``),[l,u]=(0,x.useState)(``),[d,f]=(0,x.useState)(null),[p,m]=(0,x.useState)(null),[h,g]=(0,x.useState)(null),[_,v]=(0,x.useState)(!1),[y,b]=(0,x.useState)(!1),[S,C]=(0,x.useState)(``),[w,T]=(0,x.useState)(!1),[E,D]=(0,x.useState)(``),O=e?.status===`complete`,k=e?.status===`error`,A=a.trim().length>0&&s.trim().length>0,j=async e=>{if(_||t)return;let n=a.trim(),r=s.trim(),i=Wo((e??l).trim());if(!n||!r){g(`Provider and Family are required`);return}v(!0),g(null),f(null),m(null);try{if(!i){let e=await W.lookupHuggingFace(`${n}/${r}`);m(e.repo_files??[]);return}if(qo(i)){let e=((await W.lookupHuggingFace(`${n}/${r}`)).repo_files??[]).filter(e=>!Jo(e.filename)&&!Yo(e.filename,r)&&Xo(e.filename,i));if(e.length===0){g(`No GGUF file matching quant "${i}" found in ${n}/${r}`);return}let t=new Set(e.map(e=>Go(e.filename)));if(t.size>1){m(e);return}let a=[...t][0];u(a);let o=await W.resolveSource(`${n}/${r}/${a}.gguf`);f(o);return}let e=await W.resolveSource(`${n}/${r}/${i}.gguf`);f(e)}catch(e){g(e instanceof Error?e.message:String(e))}finally{v(!1)}},M=()=>void j(),N=e=>{let t=Go(e);u(t),m(null),j(t)},P=e=>{let t=Zo(e.clipboardData.getData(`text`));t&&(e.preventDefault(),o(t.provider),c(t.family),u(t.model))},F=e=>{e.key===`Enter`&&A&&(e.preventDefault(),M())},I=()=>{f(null),m(null),g(null),C(``),b(!1),D(``),T(!1)},L=()=>{if(!d||t||d.installed)return;let e=y?S.trim():``,r=w?E.trim():``,i=d.canonical_id||ts(a,s,l);n(i,e||void 0,r||void 0)},R=d?.from_local?`on disk`:d?.from_cache?`cached`:`fetched from network`;return(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{className:`page-header`,children:[(0,G.jsx)(`h2`,{children:`HF Pull GGUF Model`}),(0,G.jsx)(`p`,{children:`Identify the model with three fields. Each one maps to a segment of the HuggingFace file URL:`}),(0,G.jsxs)(`pre`,{style:{fontSize:`14px`,lineHeight:`1.4`,padding:`12px 14px`,background:`var(--color-gray-100)`,border:`1px solid var(--color-gray-300)`,borderRadius:`4px`,margin:`8px 0`,overflowX:`auto`,fontFamily:`ui-monospace, SFMono-Regular, Menlo, monospace`,color:`var(--color-gray-900)`},children:[(0,G.jsx)(`span`,{style:{opacity:.85},children:`https://huggingface.co/`}),(0,G.jsx)(`span`,{style:{color:`var(--color-primary)`,fontWeight:600},children:`unsloth`}),(0,G.jsx)(`span`,{style:{opacity:.85},children:`/`}),(0,G.jsx)(`span`,{style:{color:`var(--color-success-text)`,fontWeight:600},children:`Qwen3.6-27B-GGUF`}),(0,G.jsx)(`span`,{style:{opacity:.85},children:`/blob/main/`}),(0,G.jsx)(`span`,{style:{color:`var(--color-warning-text)`,fontWeight:600},children:`Qwen3.6-27B-Q4_K_M`}),(0,G.jsx)(`span`,{style:{opacity:.85},children:`.gguf`}),`
`,` `,(0,G.jsx)(`span`,{style:{color:`var(--color-primary)`},children:`└─────┘`}),` `,(0,G.jsx)(`span`,{style:{color:`var(--color-success-text)`},children:`└──────────────┘`}),` `,(0,G.jsx)(`span`,{style:{color:`var(--color-warning-text)`},children:`└────────────────┘`}),`
`,` `,(0,G.jsx)(`span`,{style:{color:`var(--color-primary)`,fontWeight:600},children:`Provider`}),` `,(0,G.jsx)(`span`,{style:{color:`var(--color-success-text)`,fontWeight:600},children:`Family`}),` `,(0,G.jsx)(`span`,{style:{color:`var(--color-warning-text)`,fontWeight:600},children:`Model`})]}),(0,G.jsxs)(`ul`,{style:{margin:`4px 0 0 0`,paddingLeft:`20px`,fontSize:`13px`},children:[(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`strong`,{children:`Model is optional.`}),` Leave it blank and click `,(0,G.jsx)(`em`,{children:`Browse files`}),` to see every GGUF in the repo and pick one.`]}),(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`strong`,{children:`Quant shortcut.`}),` The Model field also accepts just a quant tag (e.g. `,(0,G.jsx)(`code`,{children:`Q4_K_M`}),`, `,(0,G.jsx)(`code`,{children:`Q8_0`}),`, `,(0,G.jsx)(`code`,{children:`BF16`}),`) — we'll find the matching file in the repo for you.`]}),(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`strong`,{children:`Paste anything.`}),` Pasting a full HuggingFace URL or`,` `,(0,G.jsx)(`code`,{children:`owner/repo[/file.gguf]`}),` shorthand into the Provider field auto-splits it across all three fields.`]})]})]}),(0,G.jsxs)(`div`,{className:`card`,children:[(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsxs)(`label`,{htmlFor:`provider`,children:[`Provider `,(0,G.jsx)(`span`,{style:{opacity:.6},children:`(required)`})]}),(0,G.jsx)(`input`,{type:`text`,id:`provider`,value:a,onChange:e=>o(e.target.value),onPaste:P,onKeyDown:F,placeholder:`unsloth`,disabled:_||t})]}),(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsxs)(`label`,{htmlFor:`family`,children:[`Family `,(0,G.jsx)(`span`,{style:{opacity:.6},children:`(required)`})]}),(0,G.jsx)(`input`,{type:`text`,id:`family`,value:s,onChange:e=>c(e.target.value),onKeyDown:F,placeholder:`Qwen3-0.6B-GGUF`,disabled:_||t})]}),(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsxs)(`label`,{htmlFor:`model`,children:[`Model `,(0,G.jsx)(`span`,{style:{opacity:.6},children:`(optional — full basename, just a quant tag, or blank)`})]}),(0,G.jsx)(`input`,{type:`text`,id:`model`,value:l,onChange:e=>u(e.target.value),onKeyDown:F,placeholder:`Qwen3-0.6B-Q8_0 · Q4_K_M · (blank)`,disabled:_||t})]}),(0,G.jsxs)(`div`,{style:{display:`flex`,gap:`8px`},children:[(0,G.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:M,disabled:_||t||!A,children:_?`Resolving…`:l.trim()?`Resolve`:`Browse files`}),(d||p||h)&&!t&&(0,G.jsx)(`button`,{type:`button`,className:`btn`,onClick:I,disabled:_,children:`Clear`})]}),h&&(0,G.jsx)(`div`,{className:`status-box`,children:(0,G.jsx)(`div`,{className:`status-line error`,children:h})}),p&&(()=>{let e=$o(p.filter(e=>!Jo(e.filename)&&!Yo(e.filename,s.trim())));return(0,G.jsxs)(`div`,{className:`card`,style:{background:`var(--color-gray-100)`,marginTop:`12px`},children:[(0,G.jsxs)(`div`,{style:{marginBottom:`12px`},children:[(0,G.jsx)(`strong`,{children:`Pick a file from `}),(0,G.jsxs)(`code`,{children:[a.trim(),`/`,s.trim()]}),(0,G.jsxs)(`span`,{style:{fontSize:`12px`,opacity:.7,marginLeft:`8px`},children:[`(`,e.length,` GGUF model`,e.length===1?``:`s`,`)`]})]}),e.length===0?(0,G.jsx)(`div`,{style:{opacity:.7},children:`No GGUF files found in this repository.`}):(0,G.jsxs)(`table`,{className:`kv-table`,children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{style:{textAlign:`left`},children:`Filename`}),(0,G.jsx)(`th`,{children:`Size`}),(0,G.jsx)(`th`,{})]})}),(0,G.jsx)(`tbody`,{children:e.map(e=>(0,G.jsxs)(`tr`,{children:[(0,G.jsxs)(`td`,{children:[(0,G.jsx)(`code`,{style:{wordBreak:`break-all`},children:e.label}),e.parts>1&&(0,G.jsxs)(`span`,{style:{fontSize:`11px`,opacity:.7,marginLeft:`8px`},children:[`(`,e.parts,` shards)`]})]}),(0,G.jsx)(`td`,{style:{whiteSpace:`nowrap`},children:e.sizeStr}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:()=>N(e.filename),disabled:_||t,children:`Select`})})]},e.label))})]})]})})(),d&&(0,G.jsxs)(`div`,{className:`card`,style:{background:`var(--color-gray-100)`,marginTop:`12px`},children:[(0,G.jsxs)(`div`,{style:{display:`flex`,alignItems:`baseline`,gap:`12px`,marginBottom:`12px`},children:[(0,G.jsx)(`strong`,{style:{fontSize:`16px`},children:d.canonical_id}),(0,G.jsxs)(`span`,{style:{fontSize:`12px`,opacity:.7},children:[`(`,R,`)`]}),d.installed&&(0,G.jsx)(`span`,{style:{fontSize:`12px`,color:`var(--color-success-text)`},children:`● already installed`})]}),(0,G.jsx)(`table`,{className:`kv-table`,children:(0,G.jsxs)(`tbody`,{children:[(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Provider`}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:d.provider})})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Family`}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:d.family})})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Revision`}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:d.revision||`main`})})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsxs)(`td`,{children:[`Files`,d.download_urls.length>1?` (${d.download_urls.length} shards)`:``]}),(0,G.jsx)(`td`,{children:d.download_urls.map((e,t)=>(0,G.jsx)(`div`,{children:(0,G.jsx)(`code`,{style:{wordBreak:`break-all`},children:e})},t))})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Projection`}),(0,G.jsx)(`td`,{children:d.download_proj?(0,G.jsx)(`code`,{style:{wordBreak:`break-all`},children:d.download_proj}):(0,G.jsx)(`span`,{style:{opacity:.6},children:`none`})})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`MTP drafter`}),(0,G.jsx)(`td`,{children:d.download_mtp?(0,G.jsx)(`code`,{style:{wordBreak:`break-all`},children:d.download_mtp}):(0,G.jsx)(`span`,{style:{opacity:.6},children:`none`})})]})]})}),(0,G.jsxs)(`details`,{style:{marginTop:`12px`},open:y,onToggle:e=>b(e.target.open),children:[(0,G.jsx)(`summary`,{style:{cursor:`pointer`,userSelect:`none`},children:`Override projection URL`}),(0,G.jsxs)(`div`,{className:`form-group`,style:{marginTop:`8px`},children:[(0,G.jsx)(`label`,{htmlFor:`projOverride`,children:`Projection URL (fully qualified HuggingFace URL)`}),(0,G.jsx)(`input`,{type:`text`,id:`projOverride`,value:S,onChange:e=>C(e.target.value),placeholder:`https://huggingface.co/org/repo/resolve/main/mmproj-model.gguf`,disabled:t}),(0,G.jsx)(`p`,{style:{fontSize:`12px`,opacity:.7,margin:`4px 0 0 0`},children:`When set, the explicit projection URL replaces the resolver's choice. Leave the field empty (or close this section) to use the projection above.`})]})]}),(0,G.jsxs)(`details`,{style:{marginTop:`12px`},open:w,onToggle:e=>T(e.target.open),children:[(0,G.jsx)(`summary`,{style:{cursor:`pointer`,userSelect:`none`},children:`Override MTP drafter URL`}),(0,G.jsxs)(`div`,{className:`form-group`,style:{marginTop:`8px`},children:[(0,G.jsx)(`label`,{htmlFor:`mtpOverride`,children:`MTP drafter URL (fully qualified HuggingFace URL)`}),(0,G.jsx)(`input`,{type:`text`,id:`mtpOverride`,value:E,onChange:e=>D(e.target.value),placeholder:`https://huggingface.co/org/repo/resolve/main/mtp-model.gguf`,disabled:t}),(0,G.jsx)(`p`,{style:{fontSize:`12px`,opacity:.7,margin:`4px 0 0 0`},children:`When set, the explicit MTP drafter URL replaces the resolver's choice. Leave the field empty (or close this section) to use the MTP drafter above.`})]})]}),(0,G.jsxs)(`div`,{style:{display:`flex`,gap:`12px`,marginTop:`16px`},children:[(0,G.jsx)(`button`,{type:`button`,className:`btn btn-primary`,onClick:L,disabled:t||d.installed,title:d.installed?`Model is already installed`:``,children:t?`Downloading…`:`Pull`}),t&&(0,G.jsx)(`button`,{className:`btn btn-danger`,type:`button`,onClick:r,children:`Cancel`}),(O||k)&&(0,G.jsx)(`button`,{className:`btn`,type:`button`,onClick:i,children:`Clear progress`})]})]}),e&&e.progress&&t&&(0,G.jsx)(Uo,{progress:e.progress,meta:e.meta}),e&&e.messages.length>0&&(0,G.jsx)(`div`,{className:`status-box`,children:e.messages.map((e,t)=>(0,G.jsx)(`div`,{className:`status-line ${e.type}`,children:e.text},t))})]})]})}function rs(e){try{return new URL(e).pathname.split(`/`).pop()||e}catch{return e.split(`/`).pop()||e}}function is({meta:e,urls:t}){let n=t&&t.length>0?t:e.model_urls,r=n.length,i=r>1;return(0,G.jsx)(`table`,{className:`flags-table`,children:(0,G.jsxs)(`tbody`,{children:[e.model_id&&(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{children:`Model ID`}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:e.model_id})})]}),!i&&n.length===1&&(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{children:`Model URL`}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`a`,{href:n[0],target:`_blank`,rel:`noopener noreferrer`,children:(0,G.jsx)(`code`,{children:rs(n[0])})})})]}),i&&Array.from({length:r},(e,t)=>{let i=n[t];return(0,G.jsxs)(`tr`,{children:[(0,G.jsxs)(`th`,{children:[`Split `,t+1,` of `,r]}),(0,G.jsx)(`td`,{children:i?(0,G.jsx)(`a`,{href:i,target:`_blank`,rel:`noopener noreferrer`,children:(0,G.jsx)(`code`,{children:rs(i)})}):(0,G.jsx)(`em`,{children:`pending…`})})]},i??`pending-${t}`)}),e.proj_url&&(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{children:`Projection URL`}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`a`,{href:e.proj_url,target:`_blank`,rel:`noopener noreferrer`,children:(0,G.jsx)(`code`,{children:rs(e.proj_url)})})})]})]})})}var as=`kronk_kms_peer_server`;function os(e,t){switch(t){case`id`:return e.id.toLowerCase();case`owned_by`:return(e.owned_by||``).toLowerCase();case`model_family`:return(e.model_family||``).toLowerCase();case`has_projection`:return+!!e.has_projection;case`validated`:return+!!e.validated;case`size`:return e.size;default:return``}}function ss(){let{download:e,isDownloading:t,startCatalogDownload:n,cancelDownload:r,clearDownload:i}=zn(),{models:a,loadModels:o,invalidate:s}=In(),[c,l]=(0,x.useState)(()=>localStorage.getItem(as)||``),[u,d]=(0,x.useState)(null),[f,p]=(0,x.useState)(!1),[m,h]=(0,x.useState)(null),[g,_]=(0,x.useState)(`id`),[v,y]=(0,x.useState)(!0),[b,S]=(0,x.useState)(new Set),[C,w]=(0,x.useState)([]),[T,E]=(0,x.useState)(0),[D,O]=(0,x.useState)({}),[k,A]=(0,x.useState)(null),j=(0,x.useRef)(!1),M=C.length>0&&T{l(e),e?localStorage.setItem(as,e):localStorage.removeItem(as)},P=e=>{g===e?y(!v):(_(e),y(!0))},F=async()=>{let e=c.trim();if(!e){h(`Peer server is required`);return}p(!0),h(null),d(null),S(new Set),O({}),w([]),E(0),A(null);try{let[t]=await Promise.all([W.listPeerModels(e),o()]);d(t.models??[])}catch(e){h(e instanceof Error?e.message:String(e))}finally{p(!1)}},I=new Set((a?.data??[]).map(e=>e.id)),L=u?[...u].sort((e,t)=>{let n=os(e,g),r=os(t,g),i=v?1:-1;return typeof n==`number`&&typeof r==`number`?(n-r)*i:String(n).localeCompare(String(r))*i}):[],R=L.filter(e=>!I.has(e.id)).map(e=>e.id),z=R.length>0&&R.every(e=>b.has(e)),ee=e=>{M||I.has(e)||S(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},B=()=>{M||S(z?new Set:new Set(R))},V=e=>{t||M||(A(e),O({[e]:`pulling`}),j.current=!1,w([e]),E(0),n(e,c.trim()||void 0))},te=()=>{if(t||M)return;let e=L.filter(e=>b.has(e.id)).map(e=>e.id);if(e.length===0)return;j.current=!1;let r={};e.forEach(e=>{r[e]=`queued`}),r[e[0]]=`pulling`,O(r),w(e),E(0),A(e[0]),n(e[0],c.trim()||void 0)},H=()=>{j.current=!0,r()};(0,x.useEffect)(()=>{if(M&&e&&e.kind===`catalog`&&e.catalogId===C[T]){if(e.status===`complete`){let e=C[T];O(t=>({...t,[e]:`done`})),s(),o();let t=T+1;if(j.current||t>=C.length){j.current&&O(e=>{let n={...e};for(let e=t;e({...e,[r]:`pulling`})),i(),setTimeout(()=>n(r,c.trim()||void 0),0)}if(e.status===`error`){let e=C[T];O(t=>({...t,[e]:`error`}));let t=T+1;if(j.current||t>=C.length){j.current&&O(e=>{let n={...e};for(let e=t;e({...e,[r]:`pulling`})),i(),setTimeout(()=>n(r,c.trim()||void 0),0)}}},[e?.status,e?.catalogId,e?.kind,C,T,M,c,n,i,s,o]);let ne=e?.kind===`catalog`&&k!==null&&e.catalogId===k,re=ne&&e?.status===`downloading`,ie=ne?e?.messages??[]:[],ae=C.length-T,oe=(e,n)=>{let r=D[e];return M?r===`pulling`?(0,G.jsx)(`span`,{className:`badge`,style:{background:`var(--color-info, #2563eb)`,color:`white`},children:`Pulling…`}):r===`queued`?(0,G.jsx)(`span`,{className:`badge badge-no`,children:`Queued`}):r===`done`?(0,G.jsx)(`span`,{className:`badge badge-yes`,children:`Downloaded`}):r===`error`?(0,G.jsx)(`span`,{className:`badge`,style:{background:`var(--color-error, #dc2626)`,color:`white`},children:`Failed`}):n?(0,G.jsx)(`span`,{className:`badge badge-yes`,children:`Downloaded`}):(0,G.jsx)(`span`,{style:{opacity:.5,fontSize:`12px`},children:`—`}):r===`done`?(0,G.jsx)(`span`,{className:`badge badge-yes`,children:`Downloaded`}):r===`error`?(0,G.jsx)(`button`,{type:`button`,className:`btn btn-primary`,onClick:()=>V(e),disabled:t,style:{padding:`4px 10px`,fontSize:`13px`},title:`Retry pull`,children:`Retry`}):n?(0,G.jsx)(`span`,{className:`badge badge-yes`,children:`Downloaded`}):(0,G.jsx)(`button`,{type:`button`,className:`btn btn-primary`,onClick:()=>V(e),disabled:t,style:{padding:`4px 10px`,fontSize:`13px`},children:`Pull`})};return(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{className:`page-header`,children:[(0,G.jsx)(`h2`,{children:`KMS Pull GGUF Model`}),(0,G.jsx)(`p`,{className:`page-description`,children:`Connect to another Kronk server on your local network to browse the models it has downloaded, and pull any of those models into this server. The peer must be running with the download endpoint enabled.`})]}),(0,G.jsxs)(`div`,{className:`card`,children:[(0,G.jsxs)(`div`,{style:{display:`flex`,gap:`12px`,alignItems:`flex-end`,flexWrap:`wrap`},children:[(0,G.jsxs)(`div`,{className:`form-group`,style:{marginBottom:0,flex:`0 0 280px`},children:[(0,G.jsx)(X,{tooltipKey:`peerKMSHost`,htmlFor:`kms-peer-host`,children:`Peer Server`}),(0,G.jsx)(`input`,{id:`kms-peer-host`,type:`text`,value:c,onChange:e=>N(e.target.value),placeholder:`192.168.0.246:11435`,disabled:f||M,onKeyDown:e=>{e.key===`Enter`&&!f&&!M&&(e.preventDefault(),F())}})]}),(0,G.jsx)(`button`,{className:`btn btn-primary`,type:`button`,onClick:F,disabled:f||M||!c.trim(),children:f?`Connecting…`:`Connect`}),u&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`button`,{className:`btn btn-primary`,type:`button`,onClick:te,disabled:M||t||b.size===0,title:b.size===0?`Select one or more models to pull`:``,children:M?`Pulling ${T+1} of ${C.length}…`:`Pull Selected (${b.size})`}),M&&(0,G.jsxs)(`button`,{className:`btn btn-danger`,type:`button`,onClick:H,children:[`Cancel `,ae>1?`(${ae} remaining)`:``]})]})]}),m&&(0,G.jsx)(`div`,{className:`alert alert-error`,style:{marginTop:`12px`},children:m})]}),u&&(0,G.jsxs)(`div`,{className:`card`,style:{marginTop:`16px`},children:[(0,G.jsxs)(`div`,{style:{marginBottom:`12px`,fontSize:`13px`,color:`var(--color-gray-600)`},children:[u.length,` model`,u.length===1?``:`s`,` available on`,` `,(0,G.jsx)(`code`,{children:c.trim()})]}),u.length===0?(0,G.jsxs)(`div`,{className:`empty-state`,children:[(0,G.jsx)(`h3`,{children:`No models on peer`}),(0,G.jsx)(`p`,{children:`The peer reported no installed models.`})]}):(0,G.jsx)(`div`,{className:`catalog-table-wrap`,children:(0,G.jsxs)(`table`,{className:`catalog-table`,children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{style:{width:`32px`,textAlign:`center`},children:(0,G.jsx)(`input`,{type:`checkbox`,"aria-label":`Select all eligible models`,checked:z,disabled:M||R.length===0,onChange:B})}),(0,G.jsxs)(`th`,{style:{width:`40px`,textAlign:`center`},onClick:()=>P(`validated`),className:`catalog-table-sortable`,title:`Configuration and template confirmed working with the Kronk catalog`,children:[`VAL`,(0,G.jsx)(`span`,{className:`catalog-table-sort-indicator`,children:g===`validated`?v?` ▲`:` ▼`:``})]}),[[`id`,`Model ID`],[`owned_by`,`Provider`],[`model_family`,`Family`]].map(([e,t])=>(0,G.jsxs)(`th`,{onClick:()=>P(e),className:`catalog-table-sortable`,children:[t,(0,G.jsx)(`span`,{className:`catalog-table-sort-indicator`,children:g===e?v?` ▲`:` ▼`:``})]},e)),(0,G.jsxs)(`th`,{style:{textAlign:`center`},onClick:()=>P(`has_projection`),className:`catalog-table-sortable`,title:`Multimodal projection file present`,children:[`MTMD`,(0,G.jsx)(`span`,{className:`catalog-table-sort-indicator`,children:g===`has_projection`?v?` ▲`:` ▼`:``})]}),(0,G.jsxs)(`th`,{onClick:()=>P(`size`),className:`catalog-table-sortable`,children:[`Size`,(0,G.jsx)(`span`,{className:`catalog-table-sort-indicator`,children:g===`size`?v?` ▲`:` ▼`:``})]}),(0,G.jsx)(`th`,{style:{width:`160px`,textAlign:`right`},children:`Status`})]})}),(0,G.jsx)(`tbody`,{children:L.map(e=>{let t=I.has(e.id),n=b.has(e.id),r=k===e.id;return(0,G.jsxs)(`tr`,{className:r||n?`active`:``,onClick:()=>ee(e.id),style:{cursor:M||t?`default`:`pointer`},children:[(0,G.jsx)(`td`,{style:{textAlign:`center`},onClick:e=>e.stopPropagation(),children:(0,G.jsx)(`input`,{type:`checkbox`,checked:n,disabled:M||t,onChange:()=>ee(e.id),"aria-label":`Select ${e.id}`})}),(0,G.jsx)(`td`,{style:{textAlign:`center`,color:e.validated?`inherit`:`var(--color-error)`},children:e.validated?`✓`:`✗`}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`span`,{className:`catalog-table-cell-ellipsis`,children:e.id})}),(0,G.jsx)(`td`,{children:e.owned_by||`-`}),(0,G.jsx)(`td`,{children:e.model_family||`-`}),(0,G.jsx)(`td`,{style:{textAlign:`center`},children:e.has_projection?`✓`:``}),(0,G.jsx)(`td`,{children:J(e.size)}),(0,G.jsx)(`td`,{style:{textAlign:`right`},onClick:e=>e.stopPropagation(),children:oe(e.id,t)})]},e.id)})})]})})]}),e&&e.kind===`catalog`&&(e.status===`downloading`||e.messages.length>0)&&(0,G.jsxs)(`div`,{className:`card`,style:{marginTop:`16px`},children:[(0,G.jsxs)(`h3`,{style:{marginTop:0,marginBottom:`12px`},children:[`Pull: `,e.catalogId]}),e.meta&&(0,G.jsx)(is,{meta:e.meta}),e.progress&&re&&(0,G.jsx)(Uo,{progress:e.progress,meta:e.meta}),ie.length>0&&(0,G.jsx)(`div`,{className:`status-box`,children:ie.map((e,t)=>(0,G.jsx)(`div`,{className:`status-line ${e.type}`,children:e.text},t))})]})]})}function cs({children:e,defaultWidth:t,minWidth:n=180,maxWidth:r=600,storageKey:i,className:a}){let[o,s]=(0,x.useState)(()=>{if(i){let e=localStorage.getItem(i);if(e){let t=parseInt(e,10);if(Number.isFinite(t))return Math.max(n,Math.min(r,t))}}return t}),c=(0,x.useRef)(!1),l=(0,x.useRef)(0),u=(0,x.useRef)(0),d=(0,x.useRef)(o);d.current=o;let f=(0,x.useCallback)(e=>{e.preventDefault(),c.current=!0,l.current=e.clientX,u.current=d.current,document.body.style.cursor=`col-resize`,document.body.style.userSelect=`none`},[]);return(0,x.useEffect)(()=>{let e=e=>{if(!c.current)return;let t=e.clientX-l.current,i=Math.max(n,Math.min(r,u.current+t));s(i)},t=()=>{c.current&&(c.current=!1,document.body.style.cursor=``,document.body.style.userSelect=``,i&&localStorage.setItem(i,String(Math.round(d.current))))};return document.addEventListener(`mousemove`,e),document.addEventListener(`mouseup`,t),()=>{document.removeEventListener(`mousemove`,e),document.removeEventListener(`mouseup`,t)}},[n,r,i]),(0,G.jsxs)(`div`,{className:`resizable-panel ${a||``}`,style:{width:o,flexShrink:0},children:[(0,G.jsx)(`div`,{className:`resizable-panel-content`,children:e}),(0,G.jsx)(`div`,{className:`resizable-panel-handle`,onMouseDown:f})]})}var ls={"model-card":`Model Card`,catalog:`Catalog`,template:`Template`,vram:`VRAM Calculator`,pull:`Pull`},us=1048576,ds=1073741824,fs=1099511627776,ps=4*fs,ms=1e3;function hs(e){if(e<=0)return 0;if(e>=ms)return ps;let t=Math.log(us),n=Math.log(ps);return Math.exp(t+e/ms*(n-t))}function gs(e){if(e<=0)return 0;if(e>=ps)return ms;let t=Math.log(us),n=Math.log(ps);return Math.round((Math.log(Math.max(e,us))-t)/(n-t)*ms)}var _s={MB:us,GB:ds,TB:fs};function vs(e){return e>=fs?{value:(e/fs).toFixed(1),unit:`TB`}:e>=ds?{value:(e/ds).toFixed(1),unit:`GB`}:{value:Math.round(e/us).toString(),unit:`MB`}}function ys(e,t){let n=new Set(e);return n.has(t)?n.delete(t):n.add(t),n}var bs=[`images`,`audio`,`video`,`streaming`,`reasoning`,`tooling`,`embedding`,`rerank`,`decision`,`mtp`],xs={images:`Images`,audio:`Audio`,video:`Video`,streaming:`Streaming`,reasoning:`Reasoning`,tooling:`Tooling`,embedding:`Embedding`,rerank:`Rerank`,decision:`Decision`,mtp:`MTP`};function Ss({title:e,expanded:t,onToggle:n,children:r}){return(0,G.jsxs)(`div`,{className:`catalog-filter-section`,children:[(0,G.jsxs)(`div`,{className:`catalog-filter-section-header`,onClick:n,children:[(0,G.jsx)(`h4`,{children:e}),(0,G.jsx)(`span`,{className:`chevron ${t?`expanded`:``}`,children:`▶`})]}),t&&r]})}function Cs(){let{download:e,startCatalogDownload:t,cancelDownload:n}=zn(),[r,i]=(0,x.useState)(null),[a,o]=(0,x.useState)(!0),[s,c]=(0,x.useState)(null),[l,u]=(0,x.useState)(null),[d,f]=(0,x.useState)(null),[p,m]=(0,x.useState)(!1),[h,g]=(0,x.useState)(null),[_,v]=(0,x.useState)(`model-card`),[y,b]=(0,x.useState)(`id`),[S,C]=(0,x.useState)(!0),w=e=>{y===e?C(!S):(b(e),C(!0))},[T,E]=(0,x.useState)(!1),[D,O]=(0,x.useState)(!1),[k,A]=(0,x.useState)(null),[j,M]=(0,x.useState)(null),N=(0,x.useRef)(null);(0,x.useEffect)(()=>()=>{N.current&&clearTimeout(N.current)},[]);let[P,F]=(0,x.useState)(!1),[I,L]=(0,x.useState)({}),[R,z]=(0,x.useState)(null),[ee,B]=(0,x.useState)(null),[V,te]=(0,x.useState)(),[H,ne]=(0,x.useState)(``),[re,ie]=(0,x.useState)(new Set),[ae,oe]=(0,x.useState)(new Set),[se,ce]=(0,x.useState)(new Set),[le,ue]=(0,x.useState)(new Set),[de,fe]=(0,x.useState)(`0`),[pe,me]=(0,x.useState)(`MB`),[he,ge]=(0,x.useState)(`4`),[_e,ve]=(0,x.useState)(`TB`),[ye,be]=(0,x.useState)(`all`),[xe,Se]=(0,x.useState)(`all`),[Ce,we]=(0,x.useState)(new Set([`architecture`,`capabilities`,`size`])),Te=e=>we(t=>ys(t,e)),Ee=parseFloat(de),De=parseFloat(he),Oe=Number.isFinite(Ee)?Ee*_s[pe]:0,ke=Number.isFinite(De)?De*_s[_e]:ps,Ae=Math.min(Oe,ke),je=Math.max(Oe,ke),Me=gs(Ae),Ne=gs(je),Pe=e=>{let t=vs(hs(Math.min(e,gs(je))));fe(t.value),me(t.unit)},Fe=e=>{let t=vs(hs(Math.max(e,gs(Ae))));ge(t.value),ve(t.unit)},Ie=(0,x.useMemo)(()=>{if(!r)return{owners:[],families:[]};let e=e=>!!e;return{owners:[...new Set(r.map(e=>e.owned_by).filter(e))].sort(),families:[...new Set(r.map(e=>e.model_family).filter(e))].sort()}},[r]),Le=(0,x.useMemo)(()=>r?r.filter(e=>{if(H&&!e.id.toLowerCase().includes(H.toLowerCase())||re.size>0&&!re.has(e.owned_by)||ae.size>0&&!ae.has(e.model_family)||se.size>0&&(!e.model_type||!se.has(e.model_type))||e.total_size_bytesje||ye===`yes`&&!e.downloaded||ye===`no`&&e.downloaded||xe===`yes`&&!e.validated||xe===`no`&&e.validated)return!1;for(let t of le){let n=e.capabilities;if(!n||!n[t])return!1}return!0}):[],[r,H,re,ae,se,Ae,je,ye,xe,le]),Re=(0,x.useMemo)(()=>{let e=[...Le];return e.sort((e,t)=>{let n=0;switch(y){case`id`:n=e.id.localeCompare(t.id);break;case`owned_by`:n=(e.owned_by||``).localeCompare(t.owned_by||``);break;case`model_family`:n=(e.model_family||``).localeCompare(t.model_family||``);break;case`model_type`:n=(e.model_type||``).localeCompare(t.model_type||``);break;case`has_projection`:n=+!!e.has_projection-!!t.has_projection;break;case`mtp_source`:n=(e.mtp_source||``).localeCompare(t.mtp_source||``);break;case`total_size_bytes`:n=(e.total_size_bytes||0)-(t.total_size_bytes||0);break;case`validated`:n=+!!e.validated-!!t.validated}return S?n:-n}),e},[Le,y,S]),ze=H!==``||re.size>0||ae.size>0||se.size>0||le.size>0||Ae>0||je{l&&!Le.some(e=>e.id===l)&&(u(null),f(null),g(null),v(`model-card`))},[Le,l]);let Be=()=>{ne(``),ie(new Set),oe(new Set),ce(new Set),ue(new Set),fe(`0`),me(`MB`),ge(`4`),ve(`TB`),be(`all`),Se(`all`)},Ve=e?.kind===`catalog`&&e.catalogId===l,He=Ve?e.status===`downloading`:!1,Ue=Ve?e.messages:[],We=e?.kind===`catalog`&&e.catalogId===l&&(e.status===`downloading`||e.messages.length>0);(0,x.useEffect)(()=>{Ge()},[]),(0,x.useEffect)(()=>{e?.kind===`catalog`&&e.catalogId&&e.status===`downloading`&&(u(e.catalogId),v(`pull`))},[e?.status]),(0,x.useEffect)(()=>{if(e?.kind===`catalog`&&e.status===`complete`&&e.catalogId){let t=e.catalogId;(async()=>{try{let e=await W.listCatalog();i(e),u(t);let n=await W.showCatalogModel(t);f(n)}catch{}})()}},[e?.status]);let Ge=async()=>{o(!0),c(null),u(null),f(null),g(null),v(`model-card`);try{try{await W.reconcileCatalog()}catch{}let t=await W.listCatalog();i(t),e?.kind===`catalog`&&e.catalogId&&(u(e.catalogId),v(`pull`))}catch(e){c(e instanceof Error?e.message:`Failed to load catalog`)}finally{o(!1)}},Ke=async e=>{if(E(!1),A(null),l===e){u(null),f(null),v(`model-card`);return}u(e),v(`model-card`),m(!0),g(null),f(null);try{let t=await W.showCatalogModel(e);f(t)}catch(e){g(e instanceof Error?e.message:`Failed to load model info`)}finally{m(!1)}},qe=(0,x.useCallback)(async(e,t,n)=>{z(e),B(null);try{let r=await W.calculateVRAM({model_url:t,context_window:8192,bytes_per_element:1,slots:2,expert_layers_on_gpu:Ca,swa_full:d?.swa_full_default});if(n?.cancelled)return;L(t=>({...t,[e]:r}))}catch(e){if(n?.cancelled)return;B(e instanceof Error?e.message:`Failed to calculate VRAM`)}finally{n?.cancelled||z(t=>t===e?null:t)}},[d?.swa_full_default]);(0,x.useEffect)(()=>{if(_!==`vram`||!d||d.vram||I[d.id])return;let e=d.files?.model?.[0]?.url;if(!e)return;let t={cancelled:!1};return qe(d.id,e,t),()=>{t.cancelled=!0}},[_,d?.id,qe]),(0,x.useEffect)(()=>{B(null)},[d?.id]),(0,x.useEffect)(()=>{if(!d?.id){te(void 0);return}let e=!1;return te(void 0),W.autoTuneModel({catalog_id:d.id}).then(t=>{e||te(t.recommended)}).catch(()=>{}),()=>{e=!0}},[d?.id]);let Je=d?.vram??(d?I[d.id]:void 0),Ye=La(V),Xe=(0,x.useMemo)(()=>d?.files?.model?.map(e=>e.url)??[],[d?.files?.model]),Ze=d?.downloaded===!0&&d.validated===!0,{controlsProps:Qe,resultsProps:$e}=Qa({initialContextWindow:131072,initialBytesPerElement:2,serverResponse:Je??null,modelId:Ze?d?.id:void 0,modelUrls:Ze?void 0:Xe}),et=sa(d?.model_metadata),tt=()=>{l&&(t(l),v(`pull`))},nt=()=>{n()},rt=()=>{l&&E(!0)},it=async()=>{if(!l)return;let e=l;O(!0),E(!1),A(null),M(null);try{await W.removeCatalogModel(e),M(`Catalog entry "${e}" removed successfully`),u(null),f(null),v(`model-card`),await Ge(),N.current=setTimeout(()=>M(null),3e3)}catch(e){A(e instanceof Error?e.message:`Failed to remove catalog entry`)}finally{O(!1)}},at=()=>{E(!1)},ot=r?.find(e=>e.id===l),st=(ot?.downloaded??!1)&&(ot?.validated??!1);return(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{className:`page-header-with-action`,children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`h2`,{children:`Catalog`}),(0,G.jsx)(`p`,{className:`page-description`,children:`Browse available models in the catalog. Click a model to view details.`})]}),(0,G.jsxs)(`div`,{style:{display:`flex`,gap:`8px`},children:[(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:()=>{Ge(),u(null),f(null),v(`model-card`),g(null),E(!1),A(null),M(null)},disabled:a,children:`Refresh`}),l&&!T&&(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:rt,disabled:D,children:`Remove Model`}),l&&T&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:it,disabled:D,children:D?`Removing...`:`Yes, Remove`}),(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:at,disabled:D,children:`Cancel`})]})]})]}),(0,G.jsxs)(`div`,{className:`playground-layout`,children:[(0,G.jsxs)(cs,{defaultWidth:280,minWidth:240,maxWidth:600,storageKey:`catalog-sidebar-width`,className:`catalog-filter-sidebar-panel`,children:[(0,G.jsx)(`div`,{className:`catalog-filter-section`,children:(0,G.jsx)(`input`,{type:`text`,placeholder:`Search models...`,value:H,onChange:e=>ne(e.target.value),style:{width:`100%`,padding:`8px 10px`,border:`1px solid var(--color-gray-300)`,borderRadius:`4px`,fontSize:`14px`,background:`var(--color-white)`}})}),Ie.owners.length>0&&(0,G.jsx)(Ss,{title:`Provider`,expanded:Ce.has(`owner`),onToggle:()=>Te(`owner`),children:(0,G.jsx)(`div`,{className:`catalog-filter-options`,children:Ie.owners.map(e=>(0,G.jsxs)(`label`,{children:[(0,G.jsx)(`input`,{type:`checkbox`,checked:re.has(e),onChange:()=>ie(t=>ys(t,e))}),e]},e))})}),Ie.families.length>0&&(0,G.jsx)(Ss,{title:`Family`,expanded:Ce.has(`family`),onToggle:()=>Te(`family`),children:(0,G.jsx)(`div`,{className:`catalog-filter-options`,children:Ie.families.map(e=>(0,G.jsxs)(`label`,{children:[(0,G.jsx)(`input`,{type:`checkbox`,checked:ae.has(e),onChange:()=>oe(t=>ys(t,e))}),e]},e))})}),(0,G.jsx)(Ss,{title:`Architecture`,expanded:Ce.has(`architecture`),onToggle:()=>Te(`architecture`),children:(0,G.jsx)(`div`,{className:`catalog-filter-options`,children:[`Dense`,`MoE`,`Hybrid`].map(e=>(0,G.jsxs)(`label`,{children:[(0,G.jsx)(`input`,{type:`checkbox`,checked:se.has(e),onChange:()=>ce(t=>ys(t,e))}),e]},e))})}),(0,G.jsx)(Ss,{title:`Capabilities`,expanded:Ce.has(`capabilities`),onToggle:()=>Te(`capabilities`),children:(0,G.jsx)(`div`,{className:`catalog-filter-options`,children:bs.map(e=>(0,G.jsxs)(`label`,{children:[(0,G.jsx)(`input`,{type:`checkbox`,checked:le.has(e),onChange:()=>ue(t=>ys(t,e))}),xs[e]]},e))})}),(0,G.jsxs)(Ss,{title:`Size`,expanded:Ce.has(`size`),onToggle:()=>Te(`size`),children:[(0,G.jsxs)(`div`,{className:`catalog-range-row`,children:[(0,G.jsx)(`label`,{children:`Min`}),(0,G.jsx)(`input`,{type:`number`,min:`0`,step:`any`,value:de,onChange:e=>fe(e.target.value)}),(0,G.jsxs)(`select`,{value:pe,onChange:e=>me(e.target.value),children:[(0,G.jsx)(`option`,{value:`MB`,children:`MB`}),(0,G.jsx)(`option`,{value:`GB`,children:`GB`}),(0,G.jsx)(`option`,{value:`TB`,children:`TB`})]})]}),(0,G.jsxs)(`div`,{className:`catalog-range-row`,children:[(0,G.jsx)(`label`,{children:`Max`}),(0,G.jsx)(`input`,{type:`number`,min:`0`,step:`any`,value:he,onChange:e=>ge(e.target.value)}),(0,G.jsxs)(`select`,{value:_e,onChange:e=>ve(e.target.value),children:[(0,G.jsx)(`option`,{value:`MB`,children:`MB`}),(0,G.jsx)(`option`,{value:`GB`,children:`GB`}),(0,G.jsx)(`option`,{value:`TB`,children:`TB`})]})]}),(0,G.jsxs)(`div`,{className:`catalog-dual-range`,children:[(0,G.jsx)(`div`,{className:`catalog-dual-range-track`,children:(0,G.jsx)(`div`,{className:`catalog-dual-range-fill`,style:{left:`${Me/ms*100}%`,right:`${100-Ne/ms*100}%`}})}),(0,G.jsx)(`input`,{type:`range`,min:0,max:ms,value:Me,onChange:e=>Pe(Number(e.target.value))}),(0,G.jsx)(`input`,{type:`range`,min:0,max:ms,value:Ne,onChange:e=>Fe(Number(e.target.value))})]})]}),(0,G.jsx)(Ss,{title:`Downloaded`,expanded:Ce.has(`downloaded`),onToggle:()=>Te(`downloaded`),children:(0,G.jsx)(`div`,{className:`catalog-filter-radio`,children:[`all`,`yes`,`no`].map(e=>(0,G.jsx)(`button`,{className:ye===e?`active`:``,onClick:()=>be(e),children:e===`all`?`All`:e===`yes`?`Yes`:`No`},e))})}),(0,G.jsx)(Ss,{title:`Validated`,expanded:Ce.has(`validated`),onToggle:()=>Te(`validated`),children:(0,G.jsx)(`div`,{className:`catalog-filter-radio`,children:[`all`,`yes`,`no`].map(e=>(0,G.jsx)(`button`,{className:xe===e?`active`:``,onClick:()=>Se(e),children:e===`all`?`All`:e===`yes`?`Yes`:`No`},e))})}),(0,G.jsxs)(`div`,{className:`catalog-filter-footer`,children:[(0,G.jsx)(`div`,{className:`catalog-match-count`,children:r?`${Le.length} / ${r.length} models`:``}),ze&&(0,G.jsx)(`button`,{className:`btn btn-secondary`,onClick:Be,style:{fontSize:`12px`,padding:`6px 10px`},children:`Clear Filters`})]})]}),(0,G.jsxs)(`div`,{className:`catalog-main-content`,children:[a&&(0,G.jsx)(`div`,{className:`loading`,children:`Loading catalog`}),s&&(0,G.jsx)(`div`,{className:`alert alert-error`,children:s}),!a&&!s&&r&&(0,G.jsxs)(`div`,{className:`catalog-table-wrap`,children:[(0,G.jsxs)(`table`,{className:`catalog-table`,children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsxs)(`th`,{style:{width:`40px`,textAlign:`center`},onClick:()=>w(`validated`),className:`catalog-table-sortable`,title:`Configuration and template confirmed working with the Kronk catalog`,children:[`VAL`,(0,G.jsx)(`span`,{className:`catalog-table-sort-indicator`,children:y===`validated`?S?` ▲`:` ▼`:``})]}),[[`id`,`Model ID`],[`owned_by`,`Provider`],[`model_family`,`Family`]].map(([e,t])=>(0,G.jsxs)(`th`,{onClick:()=>w(e),className:`catalog-table-sortable`,children:[t,(0,G.jsx)(`span`,{className:`catalog-table-sort-indicator`,children:y===e?S?` ▲`:` ▼`:``})]},e)),(0,G.jsxs)(`th`,{onClick:()=>w(`model_type`),className:`catalog-table-sortable`,title:`Architecture class (Dense, MoE, or Hybrid) derived from GGUF metadata`,children:[`Arch`,(0,G.jsx)(`span`,{className:`catalog-table-sort-indicator`,children:y===`model_type`?S?` ▲`:` ▼`:``})]}),(0,G.jsxs)(`th`,{style:{textAlign:`center`},onClick:()=>w(`has_projection`),className:`catalog-table-sortable`,title:`Multimodal projection file present`,children:[`MTMD`,(0,G.jsx)(`span`,{className:`catalog-table-sort-indicator`,children:y===`has_projection`?S?` ▲`:` ▼`:``})]}),(0,G.jsxs)(`th`,{onClick:()=>w(`mtp_source`),className:`catalog-table-sortable`,title:`MTP implementation supplied by the model GGUF or a companion drafter file`,children:[`MTP`,(0,G.jsx)(`span`,{className:`catalog-table-sort-indicator`,children:y===`mtp_source`?S?` ▲`:` ▼`:``})]}),(0,G.jsxs)(`th`,{onClick:()=>w(`total_size_bytes`),className:`catalog-table-sortable`,children:[`Size`,(0,G.jsx)(`span`,{className:`catalog-table-sort-indicator`,children:y===`total_size_bytes`?S?` ▲`:` ▼`:``})]})]})}),(0,G.jsx)(`tbody`,{children:Re.map(e=>(0,G.jsxs)(`tr`,{className:l===e.id?`active`:``,onClick:()=>Ke(e.id),children:[(0,G.jsx)(`td`,{style:{textAlign:`center`,color:e.validated?`inherit`:`var(--color-error)`},children:e.validated?`✓`:`✗`}),(0,G.jsx)(`td`,{children:e.id}),(0,G.jsx)(`td`,{children:e.owned_by||`-`}),(0,G.jsx)(`td`,{children:e.model_family||`-`}),(0,G.jsx)(`td`,{children:e.model_type||`-`}),(0,G.jsx)(`td`,{style:{textAlign:`center`},children:e.has_projection?`✓`:``}),(0,G.jsx)(`td`,{children:e.mtp_source||`-`}),(0,G.jsx)(`td`,{children:e.total_size||`-`})]},e.id))})]}),Le.length===0&&(0,G.jsxs)(`div`,{className:`empty-state`,children:[(0,G.jsx)(`h3`,{children:ze?`No matching models`:`No catalog entries`}),(0,G.jsx)(`p`,{children:ze?`Try adjusting your filters`:`The catalog is empty`})]})]}),k&&(0,G.jsx)(`div`,{className:`alert alert-error`,style:{marginTop:`16px`},children:k}),j&&(0,G.jsx)(`div`,{className:`alert alert-success`,style:{marginTop:`16px`},children:j}),h&&(0,G.jsx)(`div`,{className:`alert alert-error`,style:{marginTop:`16px`},children:h}),p&&(0,G.jsx)(`div`,{style:{marginTop:`16px`},children:(0,G.jsx)(`div`,{className:`loading`,children:`Loading model details`})}),l&&!p&&(d||We)&&(0,G.jsxs)(`div`,{style:{marginTop:`16px`,borderTop:`1px solid var(--color-gray-200)`,paddingTop:`16px`},children:[(0,G.jsx)(`div`,{className:`tabs`,children:Object.keys(ls).map(e=>(0,G.jsx)(`button`,{className:`tab ${_===e?`active`:``}`,onClick:()=>v(e),disabled:!1,children:ls[e]},e))}),_===`catalog`&&d&&(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`h3`,{style:{marginBottom:`16px`},children:d.id}),d.metadata?.description&&(0,G.jsx)(`div`,{style:{marginBottom:`16px`},children:(0,G.jsx)(`p`,{children:d.metadata.description})}),d.web_page&&(0,G.jsxs)(`div`,{style:{marginBottom:`16px`},children:[(0,G.jsx)(`h4`,{className:`meta-section-title`,style:{marginBottom:`8px`},children:`Web Page`}),(0,G.jsx)(`p`,{children:(0,G.jsx)(`a`,{href:d.web_page,target:`_blank`,rel:`noopener noreferrer`,children:d.web_page})})]}),(0,G.jsxs)(`div`,{style:{marginBottom:`16px`},children:[(0,G.jsx)(`h4`,{className:`meta-section-title`,style:{marginBottom:`8px`},children:`Files`}),(0,G.jsx)(la,{rows:[{key:`model-url`,label:`Model URL`,value:(d.files?.model?.length??0)>0?d.files.model.map((e,t)=>(0,G.jsxs)(`div`,{children:[e.url,` `,e.size?`(${J(e.size)})`:``]},t)):`-`},{key:`proj-url`,label:`Projection URL`,value:d.files?.proj?.url?(0,G.jsxs)(`div`,{children:[d.files.proj.url,` `,d.files.proj.size?`(${J(d.files.proj.size)})`:``]}):`-`},{key:`mtp-url`,label:`MTP Drafter URL`,value:d.files?.mtp?.url?(0,G.jsxs)(`div`,{children:[d.files.mtp.url,` `,d.files.mtp.size?`(${J(d.files.mtp.size)})`:``]}):`-`}]})]}),(0,G.jsx)(la,{rows:[{key:`owner`,label:`Provider`,value:d.owned_by},{key:`family`,label:`Family`,value:d.model_family},{key:`arch`,label:`Architecture`,value:d.model_type||`-`},{key:`gguf-arch`,label:`GGUF Arch`,value:d.gguf_arch||`-`},{key:`params`,label:`Parameters`,value:d.parameters||`-`},{key:`size`,label:`Size`,value:d.total_size||`-`},{key:`downloaded`,label:`Downloaded`,value:(0,G.jsx)(`span`,{className:`badge ${d.downloaded?`badge-yes`:`badge-no`}`,children:d.downloaded?`Yes`:`No`})},{key:`validated`,label:Y(`Validated`,`validated`),value:(0,G.jsx)(`span`,{style:{color:d.validated?`inherit`:`var(--color-error)`},children:d.validated?`✓`:`✗`})},{key:`endpoint`,label:`Endpoint`,value:d.capabilities?.endpoint||`-`},{key:`mtp-source`,label:Y(`MTP Source`,`mtpSource`),value:d.mtp_source||`-`},{key:`template`,label:`Template`,value:d.template||`-`}]}),(0,G.jsxs)(`div`,{style:{marginTop:`24px`},children:[(0,G.jsx)(`h4`,{className:`meta-section-title`,style:{marginBottom:`8px`},children:`Capabilities`}),(0,G.jsx)(la,{rows:bs.map(e=>{let t=!!d.capabilities?.[e];return{key:e,label:xs[e],value:(0,G.jsx)(`span`,{className:`badge ${t?`badge-yes`:`badge-no`}`,children:t?`Yes`:`No`})}})})]})]}),_===`model-card`&&d&&(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`h3`,{style:{marginBottom:`16px`},children:`Model Card`}),(0,G.jsx)(va,{metadata:d.model_metadata??{},webPage:d.web_page})]}),_===`template`&&d&&(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`h3`,{style:{marginBottom:`16px`},children:`Chat Template`}),d.model_metadata?.[`tokenizer.chat_template`]?(0,G.jsx)(ya,{code:d.model_metadata[`tokenizer.chat_template`],language:`django`}):(0,G.jsx)(`div`,{className:`empty-state`,children:(0,G.jsx)(`p`,{children:`No chat template found in metadata.`})})]}),_===`vram`&&d&&(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{style:{display:`flex`,justifyContent:`space-between`,alignItems:`center`,marginBottom:`16px`},children:[(0,G.jsx)(`h3`,{children:`VRAM Calculator`}),(0,G.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:()=>F(!0),children:`Learn More`})]}),P&&(0,G.jsx)(Ta,{onClose:()=>F(!1)}),R===d.id?(0,G.jsxs)(`div`,{className:`vram-loading-banner`,children:[(0,G.jsx)(`span`,{className:`vram-loading-spinner`}),(0,G.jsx)(`span`,{children:`Fetching model header (up to 16 MB)…`})]}):ee&&!$e?(0,G.jsxs)(`div`,{className:`empty-state`,children:[(0,G.jsx)(`p`,{children:ee}),(0,G.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,style:{marginTop:`8px`},onClick:()=>{let e=d.files?.model?.[0]?.url;e&&qe(d.id,e)},children:`Retry`})]}):$e?(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`p`,{style:{fontSize:`13px`,color:`var(--color-text-secondary)`,marginBottom:`16px`},children:d.vram?`Computed locally from GGUF header. Adjust parameters below to see how they affect VRAM.`:`Computed from remote GGUF header. Adjust parameters below to see how they affect VRAM.`}),(0,G.jsx)(Ha,{controlsProps:Qe,resultsProps:$e,variant:`compact`,contextInfo:et,catalogConfigName:d.id,catalogConfigDefaults:Ye})]}):(0,G.jsx)(`div`,{className:`empty-state`,children:(0,G.jsx)(`p`,{children:`No VRAM data available for this model.`})})]}),_===`pull`&&(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`h3`,{style:{marginBottom:`16px`},children:[`Pull: `,l]}),(0,G.jsxs)(`div`,{style:{display:`flex`,gap:`8px`,alignItems:`center`,flexWrap:`wrap`,marginBottom:`16px`},children:[(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:tt,disabled:He||st,children:He?`Pulling...`:st?`Already Downloaded`:`Pull Model`}),He&&(0,G.jsx)(`button`,{className:`btn btn-danger`,onClick:nt,children:`Cancel`})]}),Ve&&e.meta&&(0,G.jsx)(is,{meta:e.meta}),Ve&&e.progress&&He&&(0,G.jsx)(Uo,{progress:e.progress,meta:e.meta}),Ue.length>0&&(0,G.jsx)(`div`,{className:`status-box`,children:Ue.map((e,t)=>(0,G.jsx)(`div`,{className:`status-line ${e.type}`,children:e.text},t))})]})]})]})]})]})}function ws(){let[e,t]=(0,x.useState)(!1),[n,r]=(0,x.useState)([]),[i,a]=(0,x.useState)(null),[o,s]=(0,x.useState)(!0),[c,l]=(0,x.useState)(!1),[u,d]=(0,x.useState)(``),[f,p]=(0,x.useState)([]),m=(0,x.useRef)(null),h=(0,x.useCallback)(async()=>{try{let e=await W.listLibsInstalls();p(e.bundles??[])}catch{p([])}},[]);return(0,x.useEffect)(()=>{W.getLibsVersion().then(a).catch(()=>{}).finally(()=>s(!1)),h()},[h]),(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{className:`page-header`,children:[(0,G.jsx)(`h2`,{children:`Llama.cpp Libs`}),(0,G.jsx)(`p`,{children:`Download, update, and manage llama.cpp libraries`})]}),(0,G.jsxs)(`div`,{className:`card`,children:[o?(0,G.jsx)(`p`,{children:`Loading version info...`}):i?(0,G.jsxs)(`div`,{style:{marginBottom:`24px`},children:[(0,G.jsx)(`h4`,{style:{marginTop:0,marginBottom:`12px`},children:`Current Version`}),(0,G.jsxs)(`div`,{className:`model-meta`,children:[i.arch&&(0,G.jsxs)(`div`,{className:`model-meta-item`,children:[(0,G.jsx)(`label`,{children:`Architecture`}),(0,G.jsx)(`span`,{children:i.arch})]}),i.os&&(0,G.jsxs)(`div`,{className:`model-meta-item`,children:[(0,G.jsx)(`label`,{children:`OS`}),(0,G.jsx)(`span`,{children:i.os})]}),i.processor&&(0,G.jsxs)(`div`,{className:`model-meta-item`,children:[(0,G.jsx)(`label`,{children:`Processor`}),(0,G.jsx)(`span`,{children:i.processor})]}),i.current&&(0,G.jsxs)(`div`,{className:`model-meta-item`,children:[(0,G.jsx)(`label`,{children:`Installed Version`}),(0,G.jsx)(`span`,{children:i.current})]}),i.latest&&(0,G.jsxs)(`div`,{className:`model-meta-item`,children:[(0,G.jsx)(`label`,{children:`Latest Version`}),(0,G.jsx)(`span`,{children:i.latest})]})]})]}):(0,G.jsx)(`p`,{style:{marginBottom:`24px`,color:`var(--color-gray-600)`},children:`No libs installed yet.`}),i&&(0,G.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`,marginBottom:`16px`},children:[(0,G.jsx)(`input`,{type:`checkbox`,checked:i.allow_upgrade||c,disabled:i.allow_upgrade||e,onChange:e=>l(e.target.checked),id:`allow-upgrade`}),(0,G.jsx)(`label`,{htmlFor:`allow-upgrade`,style:{fontSize:`14px`,cursor:i.allow_upgrade?`default`:`pointer`},children:`Allow Upgrade`}),(0,G.jsx)(aa,{text:"Controls this server's library upgrade policy. When enabled, the server tracks the latest llama.cpp release; otherwise it stays on the version currently installed. Independent of the standalone `kronk libs` CLI, which has its own --upgrade flag."})]}),(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(`label`,{htmlFor:`version`,children:`Version (leave empty for latest)`}),(0,G.jsx)(`input`,{type:`text`,id:`version`,value:u,onChange:e=>d(e.target.value),disabled:e,placeholder:`e.g. b5540`,style:{maxWidth:`200px`}})]}),(0,G.jsxs)(`div`,{style:{display:`flex`,gap:`12px`},children:[(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:()=>{t(!0),r([]),a(null);let e=(e,t)=>{r(n=>[...n,{text:e,type:t}])},n=c?!0:void 0;m.current=W.pullLibs(t=>{t.status&&e(t.status,`info`),(t.current||t.latest)&&a(t)},n=>{e(n,`error`),t(!1)},()=>{e(`Libs update complete!`,`success`),t(!1)},{allowUpgrade:n,version:u||void 0})},disabled:e||i!==null&&!i.allow_upgrade&&!c,children:e?`Updating...`:`Pull/Update Libs`}),e&&(0,G.jsx)(`button`,{className:`btn btn-danger`,onClick:()=>{m.current&&=(m.current(),null),t(!1),r(e=>[...e,{text:`Cancelled`,type:`error`}])},children:`Cancel`})]}),n.length>0&&(0,G.jsx)(`div`,{className:`status-box`,children:n.map((e,t)=>(0,G.jsx)(`div`,{className:`status-line ${e.type}`,children:e.text},t))})]}),(0,G.jsx)(Ts,{bundles:f,onChanged:h}),(0,G.jsx)(Es,{onChanged:h}),(0,G.jsx)(As,{installed:f,onChanged:h})]})}function Ts({bundles:e,onChanged:t}){let[n,r]=(0,x.useState)(null),i=async e=>{if(confirm(`Remove install ${e.os}/${e.arch}/${e.processor}?`)){r(null);try{await W.removeLibsInstall(e.arch,e.os,e.processor),t()}catch(e){r(`Remove failed: ${e.message}`)}}};return(0,G.jsxs)(`div`,{className:`card`,style:{marginTop:24},children:[(0,G.jsx)(`h3`,{style:{marginTop:0,marginBottom:8},children:`Installed Bundles`}),(0,G.jsxs)(`p`,{style:{marginBottom:16,color:`var(--color-gray-600)`,fontSize:14},children:[`Library bundles currently installed on disk under the libraries root. To switch the active install, set `,(0,G.jsx)(`code`,{children:`KRONK_LIB_PATH`}),` to a bundle's folder and restart the server.`]}),n&&(0,G.jsx)(`div`,{className:`status-box`,style:{marginBottom:16},children:(0,G.jsx)(`div`,{className:`status-line error`,children:n})}),e.length===0?(0,G.jsx)(`p`,{style:{color:`var(--color-gray-600)`,fontSize:14},children:`No installs found.`}):(0,G.jsxs)(`table`,{style:{width:`100%`,borderCollapse:`collapse`},children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{style:{textAlign:`left`,padding:8},children:`OS`}),(0,G.jsx)(`th`,{style:{textAlign:`left`,padding:8},children:`Architecture`}),(0,G.jsx)(`th`,{style:{textAlign:`left`,padding:8},children:`Processor`}),(0,G.jsx)(`th`,{style:{textAlign:`left`,padding:8},children:`Version`}),(0,G.jsx)(`th`,{style:{textAlign:`right`,padding:8},children:`Actions`})]})}),(0,G.jsx)(`tbody`,{children:e.map(e=>(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{style:{padding:8},children:e.os}),(0,G.jsx)(`td`,{style:{padding:8},children:e.arch}),(0,G.jsx)(`td`,{style:{padding:8},children:e.processor}),(0,G.jsx)(`td`,{style:{padding:8},children:e.version}),(0,G.jsx)(`td`,{style:{padding:8,textAlign:`right`},children:(0,G.jsx)(`button`,{className:`btn btn-danger`,onClick:()=>i(e),children:`Remove`})})]},`${e.os}-${e.arch}-${e.processor}`))})]})]})}function Es({onChanged:e}){let[t,n]=(0,x.useState)([]),[r,i]=(0,x.useState)(``),[a,o]=(0,x.useState)(``),[s,c]=(0,x.useState)(``),[l,u]=(0,x.useState)(``),[d,f]=(0,x.useState)(!1),[p,m]=(0,x.useState)([]),[h,g]=(0,x.useState)(null),_=(0,x.useRef)(null);(0,x.useEffect)(()=>{W.getLibsCombinations().then(e=>n(e.combinations??[])).catch(()=>n([]))},[]);let v=(0,x.useMemo)(()=>Array.from(new Set(t.map(e=>e.os))).sort(),[t]),y=(0,x.useMemo)(()=>{let e=t.filter(e=>!a||e.os===a);return Array.from(new Set(e.map(e=>e.arch))).sort()},[t,a]),b=(0,x.useMemo)(()=>{let e=t.filter(e=>(!a||e.os===a)&&(!r||e.arch===r));return Array.from(new Set(e.map(e=>e.processor))).sort()},[t,a,r]),S=r&&a&&s,C=(e,t)=>{m(n=>[...n,{text:e,type:t}])};return(0,G.jsxs)(`div`,{className:`card`,style:{marginTop:24},children:[(0,G.jsx)(`h3`,{style:{marginTop:0,marginBottom:8},children:`Library Installs`}),(0,G.jsxs)(`p`,{style:{marginBottom:16,color:`var(--color-gray-600)`,fontSize:14},children:[`Install llama.cpp library bundles for any supported (arch, os, processor) combination. Each install lives in its own folder under the libraries root. To run Kronk against a non-default install, set `,(0,G.jsx)(`code`,{children:`KRONK_LIB_PATH`}),` to that folder and restart the server.`]}),(0,G.jsxs)(`div`,{style:{display:`flex`,gap:12,flexWrap:`wrap`,marginBottom:16},children:[(0,G.jsxs)(`div`,{className:`form-group`,style:{minWidth:160},children:[(0,G.jsx)(X,{tooltipKey:`bundleOS`,htmlFor:`bundle-os`,children:`OS`}),(0,G.jsxs)(`select`,{id:`bundle-os`,value:a,onChange:e=>{o(e.target.value),i(``),c(``)},disabled:d,children:[(0,G.jsx)(`option`,{value:``,children:`Select…`}),v.map(e=>(0,G.jsx)(`option`,{value:e,children:e},e))]})]}),(0,G.jsxs)(`div`,{className:`form-group`,style:{minWidth:160},children:[(0,G.jsx)(X,{tooltipKey:`bundleArch`,htmlFor:`bundle-arch`,children:`Architecture`}),(0,G.jsxs)(`select`,{id:`bundle-arch`,value:r,onChange:e=>{i(e.target.value),c(``)},disabled:d||!a,children:[(0,G.jsx)(`option`,{value:``,children:`Select…`}),y.map(e=>(0,G.jsx)(`option`,{value:e,children:e},e))]})]}),(0,G.jsxs)(`div`,{className:`form-group`,style:{minWidth:160},children:[(0,G.jsx)(X,{tooltipKey:`bundleProcessor`,htmlFor:`bundle-processor`,children:`Processor`}),(0,G.jsxs)(`select`,{id:`bundle-processor`,value:s,onChange:e=>c(e.target.value),disabled:d||!r,children:[(0,G.jsx)(`option`,{value:``,children:`Select…`}),b.map(e=>(0,G.jsx)(`option`,{value:e,children:e},e))]})]}),(0,G.jsxs)(`div`,{className:`form-group`,style:{minWidth:160},children:[(0,G.jsx)(`label`,{htmlFor:`bundle-version`,children:`Version (optional)`}),(0,G.jsx)(`input`,{type:`text`,id:`bundle-version`,value:l,onChange:e=>u(e.target.value),placeholder:`latest`,disabled:d})]})]}),(0,G.jsxs)(`div`,{style:{display:`flex`,gap:12,marginBottom:16},children:[(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:()=>{S&&(f(!0),m([]),g(null),_.current=W.pullLibs(e=>{e.status&&C(e.status,`info`)},e=>{C(e,`error`),f(!1)},()=>{C(`Bundle download complete!`,`success`),g({os:a,arch:r,processor:s}),f(!1),e()},{arch:r,os:a,processor:s,version:l||void 0}))},disabled:d||!S,children:d?`Downloading…`:`Download Bundle`}),d&&(0,G.jsx)(`button`,{className:`btn btn-danger`,onClick:()=>{_.current&&=(_.current(),null),f(!1),C(`Cancelled`,`error`)},children:`Cancel`})]}),p.length>0&&(0,G.jsx)(`div`,{className:`status-box`,style:{marginBottom:16},children:p.map((e,t)=>(0,G.jsx)(`div`,{className:`status-line ${e.type}`,children:e.text},t))}),h&&(0,G.jsxs)(`div`,{className:`status-box`,style:{marginTop:8},children:[(0,G.jsxs)(`div`,{className:`status-line info`,style:{marginBottom:8},children:[`To activate this bundle, set `,(0,G.jsx)(`code`,{children:`KRONK_LIB_PATH`}),` to its folder and restart the server. Libraries are not hot-reloaded.`]}),(0,G.jsx)(`pre`,{style:{margin:0,fontFamily:`"SF Mono", "Monaco", "Inconsolata", "Fira Code", monospace`,fontSize:13,whiteSpace:`pre`,overflowX:`auto`},children:`export KRONK_LIB_PATH=~/.kronk/libraries/${h.os}/${h.arch}/${h.processor}
kronk server start`})]})]})}var Ds=`kronk_lib_peer_server`;function Os(e){return`${e.os}|${e.arch}|${e.processor}`}function ks(e){if(!e||e<=0)return``;let t=e/1e6;return t<1024?`${t.toFixed(1)} MB`:`${(t/1024).toFixed(2)} GB`}function As({installed:e,onChanged:t}){let[n,r]=(0,x.useState)(()=>localStorage.getItem(Ds)||``),[i,a]=(0,x.useState)(!1),[o,s]=(0,x.useState)(null),[c,l]=(0,x.useState)(null),[u,d]=(0,x.useState)({}),f=(0,x.useRef)({}),p=(0,x.useMemo)(()=>{let t=new Set;for(let n of e)t.add(Os(n));return t},[e]),m=e=>{r(e),e?localStorage.setItem(Ds,e):localStorage.removeItem(Ds)},h=async()=>{let e=n.trim();if(e){a(!0),l(null),s(null);try{let t=await W.listPeerLibsBundles(e);s(t.bundles??[])}catch(e){l(`Connect failed: ${e.message}`)}finally{a(!1)}}},g=e=>{let r=n.trim();if(!r)return;let i=Os(e);d(e=>({...e,[i]:{status:`connecting`}})),f.current[i]=W.pullLibsFromPeer(r,e.arch,e.os,e.processor,e=>{d(t=>({...t,[i]:{status:e.status,bytes:e.bytes,bytesTotal:e.bytes_total,mbPerSecond:e.mb_per_second,size:e.size??t[i]?.size,sha256:e.sha256??t[i]?.sha256}}))},e=>{d(t=>({...t,[i]:{...t[i]||{status:`error`},status:`error`,error:e}})),f.current[i]=null},()=>{d(e=>({...e,[i]:{...e[i]||{status:`complete`},status:`complete`}})),f.current[i]=null,t()})},_=e=>{let t=Os(e),n=f.current[t];n&&(n(),f.current[t]=null),d(e=>({...e,[t]:{...e[t]||{status:`cancelled`},status:`cancelled`}}))};return(0,G.jsxs)(`div`,{className:`card`,style:{marginTop:24},children:[(0,G.jsx)(`h3`,{style:{marginTop:0,marginBottom:8},children:`Pull Bundles From Network Peer`}),(0,G.jsx)(`p`,{style:{marginBottom:16,color:`var(--color-gray-600)`,fontSize:14},children:`Download library bundles from another Kronk server on the local network instead of from the upstream llama.cpp release. The peer must be running with the download endpoint enabled. Useful in workshops where Internet access is slow or unreliable.`}),(0,G.jsxs)(`div`,{style:{display:`flex`,gap:12,alignItems:`flex-end`,flexWrap:`wrap`,marginBottom:16},children:[(0,G.jsxs)(`div`,{className:`form-group`,style:{marginBottom:0,minWidth:240},children:[(0,G.jsx)(X,{tooltipKey:`peerLibsHost`,htmlFor:`peer-libs-host`,children:`Peer Server`}),(0,G.jsx)(`input`,{id:`peer-libs-host`,type:`text`,value:n,onChange:e=>m(e.target.value),disabled:i,placeholder:`192.168.0.246:11435`})]}),(0,G.jsxs)(`button`,{className:`btn btn-primary`,onClick:h,disabled:i||!n.trim(),children:[i?`Connecting…`:`Connect`,(0,G.jsx)(aa,{tooltipKey:`peerLibsConnect`})]})]}),c&&(0,G.jsx)(`div`,{className:`status-box`,style:{marginBottom:16},children:(0,G.jsx)(`div`,{className:`status-line error`,children:c})}),o!==null&&o.length===0&&(0,G.jsx)(`p`,{style:{color:`var(--color-gray-600)`,fontSize:14},children:`The peer reported no installed bundles.`}),o!==null&&o.length>0&&(0,G.jsxs)(`table`,{style:{width:`100%`,borderCollapse:`collapse`},children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{style:{textAlign:`left`,padding:8},children:`OS`}),(0,G.jsx)(`th`,{style:{textAlign:`left`,padding:8},children:`Architecture`}),(0,G.jsx)(`th`,{style:{textAlign:`left`,padding:8},children:`Processor`}),(0,G.jsx)(`th`,{style:{textAlign:`left`,padding:8},children:`Version`}),(0,G.jsx)(`th`,{style:{textAlign:`left`,padding:8},children:`Size`}),(0,G.jsx)(`th`,{style:{textAlign:`left`,padding:8},children:`Status`}),(0,G.jsx)(`th`,{style:{textAlign:`right`,padding:8},children:`Actions`})]})}),(0,G.jsx)(`tbody`,{children:o.map(e=>{let t=Os(e),n=u[t],r=p.has(t),i=n&&n.status!==`complete`&&n.status!==`error`&&n.status!==`cancelled`,a=n?.bytesTotal||n?.size||e.size||0,o=n?.bytes||0,s=a>0?Math.min(100,Math.round(o/a*100)):0;return(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{style:{padding:8},children:e.os}),(0,G.jsx)(`td`,{style:{padding:8},children:e.arch}),(0,G.jsx)(`td`,{style:{padding:8},children:e.processor}),(0,G.jsx)(`td`,{style:{padding:8},children:e.version}),(0,G.jsx)(`td`,{style:{padding:8},children:ks(e.size||a)}),(0,G.jsx)(`td`,{style:{padding:8,fontSize:13},children:n?(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{children:[n.status,n.status===`downloading`&&a>0&&(0,G.jsxs)(G.Fragment,{children:[` — `,ks(o),` / `,ks(a),` (`,s,`%) `,n.mbPerSecond?`@ ${n.mbPerSecond.toFixed(1)} MB/s`:``]})]}),n.status===`downloading`&&a>0&&(0,G.jsx)(`div`,{style:{marginTop:4,height:6,background:`var(--color-gray-200)`,borderRadius:3,overflow:`hidden`},children:(0,G.jsx)(`div`,{style:{width:`${s}%`,height:`100%`,background:`var(--color-primary, #2563eb)`,transition:`width 200ms linear`}})}),n.error&&(0,G.jsx)(`div`,{className:`status-line error`,style:{marginTop:4},children:n.error})]}):r?(0,G.jsx)(`span`,{style:{color:`var(--color-gray-600)`},children:`installed`}):(0,G.jsx)(`span`,{style:{color:`var(--color-gray-600)`},children:`—`})}),(0,G.jsx)(`td`,{style:{padding:8,textAlign:`right`},children:i?(0,G.jsx)(`button`,{className:`btn btn-danger`,onClick:()=>_(e),children:`Cancel`}):(0,G.jsxs)(`button`,{className:`btn btn-primary`,onClick:()=>g(e),children:[r?`Re-download`:`Download`,(0,G.jsx)(aa,{tooltipKey:`peerLibsDownload`})]})})]},t)})})]})]})}var js={id:`bucky`,engine:`Whisper.cpp`,backend:`Bucky`,environmentVariable:`KRONK_BUCKY_LIB_PATH`,rootFolder:`bucky-libraries`,getVersion:()=>W.getBuckyLibsVersion(),getCombinations:()=>W.getBuckyLibsCombinations(),listInstalls:()=>W.listBuckyLibsInstalls(),removeInstall:(e,t,n)=>W.removeBuckyLibsInstall(e,t,n),pull:(e,t,n,r)=>W.pullBuckyLibs(e,t,n,r)};function Ms(){return(0,G.jsx)(Ns,{backend:js})}function Ns({backend:e}){let[t,n]=(0,x.useState)(!1),[r,i]=(0,x.useState)([]),[a,o]=(0,x.useState)(null),[s,c]=(0,x.useState)(!0),[l,u]=(0,x.useState)(``),[d,f]=(0,x.useState)([]),p=(0,x.useRef)(null),m=(0,x.useCallback)(async()=>{try{let t=await e.listInstalls();f(t.bundles??[])}catch{f([])}},[e]);return(0,x.useEffect)(()=>{e.getVersion().then(o).catch(()=>{}).finally(()=>c(!1)),m()},[e,m]),(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{className:`page-header`,children:[(0,G.jsxs)(`h2`,{children:[e.engine,` Libs`]}),(0,G.jsxs)(`p`,{children:[`Download, update, and manage `,e.engine,` libraries`]})]}),(0,G.jsxs)(`div`,{className:`card`,children:[s?(0,G.jsx)(`p`,{children:`Loading version info...`}):a&&a.current?(0,G.jsxs)(`div`,{style:{marginBottom:`24px`},children:[(0,G.jsx)(`h4`,{style:{marginTop:0,marginBottom:`12px`},children:`Current Version`}),(0,G.jsxs)(`div`,{className:`model-meta`,children:[a.arch&&(0,G.jsxs)(`div`,{className:`model-meta-item`,children:[(0,G.jsx)(`label`,{children:`Architecture`}),(0,G.jsx)(`span`,{children:a.arch})]}),a.os&&(0,G.jsxs)(`div`,{className:`model-meta-item`,children:[(0,G.jsx)(`label`,{children:`OS`}),(0,G.jsx)(`span`,{children:a.os})]}),a.processor&&(0,G.jsxs)(`div`,{className:`model-meta-item`,children:[(0,G.jsx)(`label`,{children:`Processor`}),(0,G.jsx)(`span`,{children:a.processor})]}),(0,G.jsxs)(`div`,{className:`model-meta-item`,children:[(0,G.jsx)(`label`,{children:`Installed Version`}),(0,G.jsx)(`span`,{children:a.current})]})]})]}):(0,G.jsxs)(`p`,{style:{marginBottom:`24px`,color:`var(--color-gray-600)`},children:[`No `,e.backend,` libs installed yet for the active triple.`]}),(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(X,{tooltipKey:`bundleVersion`,htmlFor:`${e.id}-version`,children:`Version (leave empty for default)`}),(0,G.jsx)(`input`,{type:`text`,id:`${e.id}-version`,value:l,onChange:e=>u(e.target.value),disabled:t,placeholder:`e.g. v1.7.6`,style:{maxWidth:`200px`}})]}),(0,G.jsxs)(`div`,{style:{display:`flex`,gap:`12px`},children:[(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:()=>{n(!0),i([]),o(null);let t=(e,t)=>{i(n=>[...n,{text:e,type:t}])};p.current=e.pull(e=>{e.status&&t(e.status,`info`),e.current&&o(e)},e=>{t(e,`error`),n(!1)},()=>{t(`Libs update complete!`,`success`),n(!1),m()},{version:l||void 0})},disabled:t,children:t?`Updating...`:`Pull/Update Libs`}),t&&(0,G.jsx)(`button`,{className:`btn btn-danger`,onClick:()=>{p.current&&=(p.current(),null),n(!1),i(e=>[...e,{text:`Cancelled`,type:`error`}])},children:`Cancel`})]}),r.length>0&&(0,G.jsx)(`div`,{className:`status-box`,children:r.map((e,t)=>(0,G.jsx)(`div`,{className:`status-line ${e.type}`,children:e.text},t))})]}),(0,G.jsx)(Ps,{backend:e,bundles:d,onChanged:m}),(0,G.jsx)(Fs,{backend:e,onChanged:m})]})}function Ps({backend:e,bundles:t,onChanged:n}){let[r,i]=(0,x.useState)(null),a=async t=>{if(confirm(`Remove install ${t.os}/${t.arch}/${t.processor}?`)){i(null);try{await e.removeInstall(t.arch,t.os,t.processor),n()}catch(e){i(`Remove failed: ${e.message}`)}}};return(0,G.jsxs)(`div`,{className:`card`,style:{marginTop:24},children:[(0,G.jsx)(`h3`,{style:{marginTop:0,marginBottom:8},children:`Installed Bundles`}),(0,G.jsxs)(`p`,{style:{marginBottom:16,color:`var(--color-gray-600)`,fontSize:14},children:[e.engine,` library bundles currently installed on disk under the `,e.backend,` libraries root. To switch the active install, set `,(0,G.jsx)(`code`,{children:e.environmentVariable}),` to a bundle's folder and restart the server.`]}),r&&(0,G.jsx)(`div`,{className:`status-box`,style:{marginBottom:16},children:(0,G.jsx)(`div`,{className:`status-line error`,children:r})}),t.length===0?(0,G.jsx)(`p`,{style:{color:`var(--color-gray-600)`,fontSize:14},children:`No installs found.`}):(0,G.jsxs)(`table`,{style:{width:`100%`,borderCollapse:`collapse`},children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{style:{textAlign:`left`,padding:8},children:`OS`}),(0,G.jsx)(`th`,{style:{textAlign:`left`,padding:8},children:`Architecture`}),(0,G.jsx)(`th`,{style:{textAlign:`left`,padding:8},children:`Processor`}),(0,G.jsx)(`th`,{style:{textAlign:`left`,padding:8},children:`Version`}),(0,G.jsx)(`th`,{style:{textAlign:`right`,padding:8},children:`Actions`})]})}),(0,G.jsx)(`tbody`,{children:t.map(e=>(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{style:{padding:8},children:e.os}),(0,G.jsx)(`td`,{style:{padding:8},children:e.arch}),(0,G.jsx)(`td`,{style:{padding:8},children:e.processor}),(0,G.jsx)(`td`,{style:{padding:8},children:e.version}),(0,G.jsx)(`td`,{style:{padding:8,textAlign:`right`},children:(0,G.jsx)(`button`,{className:`btn btn-danger`,onClick:()=>a(e),children:`Remove`})})]},`${e.os}-${e.arch}-${e.processor}`))})]})]})}function Fs({backend:e,onChanged:t}){let[n,r]=(0,x.useState)([]),[i,a]=(0,x.useState)(``),[o,s]=(0,x.useState)(``),[c,l]=(0,x.useState)(``),[u,d]=(0,x.useState)(``),[f,p]=(0,x.useState)(!1),[m,h]=(0,x.useState)([]),[g,_]=(0,x.useState)(null),v=(0,x.useRef)(null);(0,x.useEffect)(()=>{e.getCombinations().then(e=>r(e.combinations??[])).catch(()=>r([]))},[e]);let y=(0,x.useMemo)(()=>Array.from(new Set(n.map(e=>e.os))).sort(),[n]),b=(0,x.useMemo)(()=>{let e=n.filter(e=>!o||e.os===o);return Array.from(new Set(e.map(e=>e.arch))).sort()},[n,o]),S=(0,x.useMemo)(()=>{let e=n.filter(e=>(!o||e.os===o)&&(!i||e.arch===i));return Array.from(new Set(e.map(e=>e.processor))).sort()},[n,o,i]),C=i&&o&&c,w=(e,t)=>{h(n=>[...n,{text:e,type:t}])};return(0,G.jsxs)(`div`,{className:`card`,style:{marginTop:24},children:[(0,G.jsx)(`h3`,{style:{marginTop:0,marginBottom:8},children:`Library Installs`}),(0,G.jsxs)(`p`,{style:{marginBottom:16,color:`var(--color-gray-600)`,fontSize:14},children:[`Install `,e.engine,` library bundles for any supported (arch, os, processor) combination. Each install lives in its own folder under the `,e.backend,` libraries root. To run Kronk against a non-default install, set `,(0,G.jsx)(`code`,{children:e.environmentVariable}),` to that folder and restart the server.`]}),(0,G.jsxs)(`div`,{style:{display:`flex`,gap:12,flexWrap:`wrap`,marginBottom:16},children:[(0,G.jsxs)(`div`,{className:`form-group`,style:{minWidth:160},children:[(0,G.jsx)(X,{tooltipKey:`bundleOS`,htmlFor:`${e.id}-bundle-os`,children:`OS`}),(0,G.jsxs)(`select`,{id:`${e.id}-bundle-os`,value:o,onChange:e=>{s(e.target.value),a(``),l(``)},disabled:f,children:[(0,G.jsx)(`option`,{value:``,children:`Select…`}),y.map(e=>(0,G.jsx)(`option`,{value:e,children:e},e))]})]}),(0,G.jsxs)(`div`,{className:`form-group`,style:{minWidth:160},children:[(0,G.jsx)(X,{tooltipKey:`bundleArch`,htmlFor:`${e.id}-bundle-arch`,children:`Architecture`}),(0,G.jsxs)(`select`,{id:`${e.id}-bundle-arch`,value:i,onChange:e=>{a(e.target.value),l(``)},disabled:f||!o,children:[(0,G.jsx)(`option`,{value:``,children:`Select…`}),b.map(e=>(0,G.jsx)(`option`,{value:e,children:e},e))]})]}),(0,G.jsxs)(`div`,{className:`form-group`,style:{minWidth:160},children:[(0,G.jsx)(X,{tooltipKey:`bundleProcessor`,htmlFor:`${e.id}-bundle-processor`,children:`Processor`}),(0,G.jsxs)(`select`,{id:`${e.id}-bundle-processor`,value:c,onChange:e=>l(e.target.value),disabled:f||!i,children:[(0,G.jsx)(`option`,{value:``,children:`Select…`}),S.map(e=>(0,G.jsx)(`option`,{value:e,children:e},e))]})]}),(0,G.jsxs)(`div`,{className:`form-group`,style:{minWidth:160},children:[(0,G.jsx)(X,{tooltipKey:`bundleVersion`,htmlFor:`${e.id}-bundle-version`,children:`Version (optional)`}),(0,G.jsx)(`input`,{type:`text`,id:`${e.id}-bundle-version`,value:u,onChange:e=>d(e.target.value),placeholder:`default`,disabled:f})]})]}),(0,G.jsxs)(`div`,{style:{display:`flex`,gap:12,marginBottom:16},children:[(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:()=>{C&&(p(!0),h([]),_(null),v.current=e.pull(e=>{e.status&&w(e.status,`info`)},e=>{w(e,`error`),p(!1)},()=>{w(`Bundle download complete!`,`success`),_({os:o,arch:i,processor:c}),p(!1),t()},{arch:i,os:o,processor:c,version:u||void 0}))},disabled:f||!C,children:f?`Downloading…`:`Download Bundle`}),f&&(0,G.jsx)(`button`,{className:`btn btn-danger`,onClick:()=>{v.current&&=(v.current(),null),p(!1),w(`Cancelled`,`error`)},children:`Cancel`})]}),m.length>0&&(0,G.jsx)(`div`,{className:`status-box`,style:{marginBottom:16},children:m.map((e,t)=>(0,G.jsx)(`div`,{className:`status-line ${e.type}`,children:e.text},t))}),g&&(0,G.jsxs)(`div`,{className:`status-box`,style:{marginTop:8},children:[(0,G.jsxs)(`div`,{className:`status-line info`,style:{marginBottom:8},children:[`To activate this bundle, set `,(0,G.jsx)(`code`,{children:e.environmentVariable}),` to its folder and restart the server. Libraries are not hot-reloaded.`]}),(0,G.jsx)(`pre`,{style:{margin:0,fontFamily:`"SF Mono", "Monaco", "Inconsolata", "Fira Code", monospace`,fontSize:13,whiteSpace:`pre`,overflowX:`auto`},children:`export ${e.environmentVariable}=~/.kronk/${e.rootFolder}/${g.os}/${g.arch}/${g.processor}
@@ -209,7 +209,7 @@ kronk server start`})]})]})}function Is(e){let t=/^([\d.]+)\s*(MB|GB|KB|B)?$/i.e
`))}function c(e,t,n,r){let i=n.enter(`tableCell`),o=n.enter(`phrasing`),s=n.containerPhrasing(e,{...r,before:a,after:a});return o(),i(),s}function l(e,t){return og(e,{align:t,alignDelimiters:r,padding:n,stringLength:i})}function u(e,t,n){let r=e.children,i=-1,a=[],o=t.enter(`table`);for(;++i0&&!n&&(e[e.length-1][1]._gfmAutolinkLiteralWalkedInto=!0),n}var G_={tokenize:$_,partial:!0};function K_(){return{document:{91:{name:`gfmFootnoteDefinition`,tokenize:X_,continuation:{tokenize:Z_},exit:Q_}},text:{91:{name:`gfmFootnoteCall`,tokenize:Y_},93:{name:`gfmPotentialFootnoteCall`,add:`after`,tokenize:q_,resolveTo:J_}}}}function q_(e,t,n){let r=this,i=r.events.length,a=r.parser.gfmFootnotes||(r.parser.gfmFootnotes=[]),o;for(;i--;){let e=r.events[i][1];if(e.type===`labelImage`){o=e;break}if(e.type===`gfmFootnoteCall`||e.type===`labelLink`||e.type===`label`||e.type===`image`||e.type===`link`)break}return s;function s(i){if(!o||!o._balanced)return n(i);let s=_u(r.sliceSerialize({start:o.end,end:r.now()}));return s.codePointAt(0)!==94||!a.includes(s.slice(1))?n(i):(e.enter(`gfmFootnoteCallLabelMarker`),e.consume(i),e.exit(`gfmFootnoteCallLabelMarker`),t(i))}}function J_(e,t){let n=e.length;for(;n--;)if(e[n][1].type===`labelImage`&&e[n][0]===`enter`){e[n][1];break}e[n+1][1].type=`data`,e[n+3][1].type=`gfmFootnoteCallLabelMarker`;let r={type:`gfmFootnoteCall`,start:Object.assign({},e[n+3][1].start),end:Object.assign({},e[e.length-1][1].end)},i={type:`gfmFootnoteCallMarker`,start:Object.assign({},e[n+3][1].end),end:Object.assign({},e[n+3][1].end)};i.end.column++,i.end.offset++,i.end._bufferIndex++;let a={type:`gfmFootnoteCallString`,start:Object.assign({},i.end),end:Object.assign({},e[e.length-1][1].start)},o={type:`chunkString`,contentType:`string`,start:Object.assign({},a.start),end:Object.assign({},a.end)},s=[e[n+1],e[n+2],[`enter`,r,t],e[n+3],e[n+4],[`enter`,i,t],[`exit`,i,t],[`enter`,a,t],[`enter`,o,t],[`exit`,o,t],[`exit`,a,t],e[e.length-2],e[e.length-1],[`exit`,r,t]];return e.splice(n,e.length-n+1,...s),e}function Y_(e,t,n){let r=this,i=r.parser.gfmFootnotes||(r.parser.gfmFootnotes=[]),a=0,o;return s;function s(t){return e.enter(`gfmFootnoteCall`),e.enter(`gfmFootnoteCallLabelMarker`),e.consume(t),e.exit(`gfmFootnoteCallLabelMarker`),c}function c(t){return t===94?(e.enter(`gfmFootnoteCallMarker`),e.consume(t),e.exit(`gfmFootnoteCallMarker`),e.enter(`gfmFootnoteCallString`),e.enter(`chunkString`).contentType=`string`,l):n(t)}function l(s){if(a>999||s===93&&!o||s===null||s===91||Tu(s))return n(s);if(s===93){e.exit(`chunkString`);let a=e.exit(`gfmFootnoteCallString`);return i.includes(_u(r.sliceSerialize(a)))?(e.enter(`gfmFootnoteCallLabelMarker`),e.consume(s),e.exit(`gfmFootnoteCallLabelMarker`),e.exit(`gfmFootnoteCall`),t):n(s)}return Tu(s)||(o=!0),a++,e.consume(s),s===92?u:l}function u(t){return t===91||t===92||t===93?(e.consume(t),a++,l):l(t)}}function X_(e,t,n){let r=this,i=r.parser.gfmFootnotes||(r.parser.gfmFootnotes=[]),a,o=0,s;return c;function c(t){return e.enter(`gfmFootnoteDefinition`)._container=!0,e.enter(`gfmFootnoteDefinitionLabel`),e.enter(`gfmFootnoteDefinitionLabelMarker`),e.consume(t),e.exit(`gfmFootnoteDefinitionLabelMarker`),l}function l(t){return t===94?(e.enter(`gfmFootnoteDefinitionMarker`),e.consume(t),e.exit(`gfmFootnoteDefinitionMarker`),e.enter(`gfmFootnoteDefinitionLabelString`),e.enter(`chunkString`).contentType=`string`,u):n(t)}function u(t){if(o>999||t===93&&!s||t===null||t===91||Tu(t))return n(t);if(t===93){e.exit(`chunkString`);let n=e.exit(`gfmFootnoteDefinitionLabelString`);return a=_u(r.sliceSerialize(n)),e.enter(`gfmFootnoteDefinitionLabelMarker`),e.consume(t),e.exit(`gfmFootnoteDefinitionLabelMarker`),e.exit(`gfmFootnoteDefinitionLabel`),f}return Tu(t)||(s=!0),o++,e.consume(t),t===92?d:u}function d(t){return t===91||t===92||t===93?(e.consume(t),o++,u):u(t)}function f(t){return t===58?(e.enter(`definitionMarker`),e.consume(t),e.exit(`definitionMarker`),i.includes(a)||i.push(a),ju(e,p,`gfmFootnoteDefinitionWhitespace`)):n(t)}function p(e){return t(e)}}function Z_(e,t,n){return e.check(Yu,t,e.attempt(G_,t,n))}function Q_(e){e.exit(`gfmFootnoteDefinition`)}function $_(e,t,n){let r=this;return ju(e,i,`gfmFootnoteDefinitionIndent`,5);function i(e){let i=r.events[r.events.length-1];return i&&i[1].type===`gfmFootnoteDefinitionIndent`&&i[2].sliceSerialize(i[1],!0).length===4?t(e):n(e)}}function ev(e){let t=(e||{}).singleTilde,n={name:`strikethrough`,tokenize:i,resolveAll:r};return t??=!0,{text:{126:n},insideSpan:{null:[n]},attentionMarkers:{null:[126]}};function r(e,t){let n=-1;for(;++n1?r(a):(e.consume(a),o++,c);if(o<2&&!t)return r(a);let l=e.exit(`strikethroughSequenceTemporary`),u=Vu(a);return l._open=!u||u===2&&!!s,l._close=!s||s===2&&!!u,n(a)}}}var tv=class{constructor(){this.map=[],this.index=new Map}add(e,t,n){nv(this,e,t,n)}consume(e){if(this.map.sort(function(e,t){return e[0]-t[0]}),this.map.length===0)return;let t=this.map.length,n=[];for(;t>0;)--t,n.push(e.slice(this.map[t][0]+this.map[t][1]),this.map[t][2]),e.length=this.map[t][0];n.push(e.slice()),e.length=0;let r=n.pop();for(;r;){for(let t of r)e.push(t);r=n.pop()}this.map.length=0,this.index.clear()}};function nv(e,t,n,r){if(n===0&&r.length===0)return;let i=e.index.get(t);if(i){i[1]+=n,i[2].push(...r);return}let a=[t,n,r];e.map.push(a),e.index.set(t,a)}function rv(e,t){let n=!1,r=[];for(;t-1;){let{type:e}=r.events[t][1];if(e===`lineEnding`||e===`linePrefix`)t--;else break}let i=t>-1?r.events[t][1].type:null,a=i===`tableHead`||i===`tableRow`?S:c;return a===S&&r.parser.lazy[r.now().line]?n(e):a(e)}function c(t){return e.enter(`tableHead`),e.enter(`tableRow`),l(t)}function l(e){return e===124?u(e):(o=!0,a+=1,u(e))}function u(t){return t===null?n(t):$(t)?a>1?(a=0,r.interrupt=!0,e.exit(`tableRow`),e.enter(`lineEnding`),e.consume(t),e.exit(`lineEnding`),p):n(t):Eu(t)?ju(e,u,`whitespace`)(t):(a+=1,o&&(o=!1,i+=1),t===124?(e.enter(`tableCellDivider`),e.consume(t),e.exit(`tableCellDivider`),o=!0,u):(e.enter(`data`),d(t)))}function d(t){return t===null||t===124||Tu(t)?(e.exit(`data`),u(t)):(e.consume(t),t===92?f:d)}function f(t){return t===92||t===124?(e.consume(t),d):d(t)}function p(t){return r.interrupt=!1,r.parser.lazy[r.now().line]?n(t):(e.enter(`tableDelimiterRow`),o=!1,Eu(t)?ju(e,m,`linePrefix`,r.parser.constructs.disable.null.includes(`codeIndented`)?void 0:4)(t):m(t))}function m(t){return t===45||t===58?g(t):t===124?(o=!0,e.enter(`tableCellDivider`),e.consume(t),e.exit(`tableCellDivider`),h):x(t)}function h(t){return Eu(t)?ju(e,g,`whitespace`)(t):g(t)}function g(t){return t===58?(a+=1,o=!0,e.enter(`tableDelimiterMarker`),e.consume(t),e.exit(`tableDelimiterMarker`),_):t===45?(a+=1,_(t)):t===null||$(t)?b(t):x(t)}function _(t){return t===45?(e.enter(`tableDelimiterFiller`),v(t)):x(t)}function v(t){return t===45?(e.consume(t),v):t===58?(o=!0,e.exit(`tableDelimiterFiller`),e.enter(`tableDelimiterMarker`),e.consume(t),e.exit(`tableDelimiterMarker`),y):(e.exit(`tableDelimiterFiller`),y(t))}function y(t){return Eu(t)?ju(e,b,`whitespace`)(t):b(t)}function b(n){return n===124?m(n):n===null||$(n)?!o||i!==a?x(n):(e.exit(`tableDelimiterRow`),e.exit(`tableHead`),t(n)):x(n)}function x(e){return n(e)}function S(t){return e.enter(`tableRow`),C(t)}function C(n){return n===124?(e.enter(`tableCellDivider`),e.consume(n),e.exit(`tableCellDivider`),C):n===null||$(n)?(e.exit(`tableRow`),t(n)):Eu(n)?ju(e,C,`whitespace`)(n):(e.enter(`data`),w(n))}function w(t){return t===null||t===124||Tu(t)?(e.exit(`data`),C(t)):(e.consume(t),t===92?T:w)}function T(t){return t===92||t===124?(e.consume(t),w):w(t)}}function ov(e,t){let n=-1,r=!0,i=0,a=[0,0,0,0],o=[0,0,0,0],s=!1,c=0,l,u,d,f=new tv;for(;++nn[2]+1){let t=n[2]+1,r=n[3]-n[2]-1;e.add(t,r,[])}}e.add(n[3]+1,0,[[`exit`,o,t]])}return i!==void 0&&(a.end=Object.assign({},lv(t.events,i)),e.add(i,0,[[`exit`,a,t]]),a=void 0),a}function cv(e,t,n,r,i){let a=[],o=lv(t.events,n);i&&(i.end=Object.assign({},o),a.push([`exit`,i,t])),r.end=Object.assign({},o),a.push([`exit`,r,t]),e.add(n+1,0,a)}function lv(e,t){let n=e[t],r=n[0]===`enter`?`start`:`end`;return n[1][r]}var uv={name:`tasklistCheck`,tokenize:fv};function dv(){return{text:{91:uv}}}function fv(e,t,n){let r=this;return i;function i(t){return r.previous!==null||!r._gfmTasklistFirstContentOfListItem?n(t):(e.enter(`taskListCheck`),e.enter(`taskListCheckMarker`),e.consume(t),e.exit(`taskListCheckMarker`),a)}function a(t){return Tu(t)?(e.enter(`taskListCheckValueUnchecked`),e.consume(t),e.exit(`taskListCheckValueUnchecked`),o):t===88||t===120?(e.enter(`taskListCheckValueChecked`),e.consume(t),e.exit(`taskListCheckValueChecked`),o):n(t)}function o(t){return t===93?(e.enter(`taskListCheckMarker`),e.consume(t),e.exit(`taskListCheckMarker`),e.exit(`taskListCheck`),s):n(t)}function s(r){return $(r)?t(r):Eu(r)?e.check({tokenize:pv},t,n)(r):n(r)}}function pv(e,t,n){return ju(e,r,`whitespace`);function r(e){return e===null?n(e):t(e)}}function mv(e){return pu([A_(),K_(),ev(e),iv(),dv()])}var hv={};function gv(e){let t=this,n=e||hv,r=t.data(),i=r.micromarkExtensions||=[],a=r.fromMarkdownExtensions||=[],o=r.toMarkdownExtensions||=[];i.push(mv(n)),a.push(y_()),o.push(b_(n))}function _v({usage:e}){let t=e.completion_tokens_details?.reasoning_tokens??0,n=Math.max(0,e.completion_tokens-t),r=e.prompt_tokens_details?.cached_tokens??0,i=e.draft_tokens??0,a=e.draft_accepted_tokens??0,o=e.draft_acceptance_rate??(i>0?a/i:0),s=i>0||a>0||e.draft_acceptance_rate!==void 0||e.draft_coverage!==void 0||!!e.draft_disable_reason;return(0,G.jsxs)(`div`,{className:`chat-message-usage`,children:[(0,G.jsxs)(`span`,{title:`Tokens in the rendered prompt, including cached tokens`,children:[`Input: `,e.prompt_tokens]}),(0,G.jsxs)(`span`,{title:`Prompt tokens restored from the incremental message cache`,children:[`Cached: `,r]}),(0,G.jsxs)(`span`,{title:`All generated tokens, including reasoning and visible output`,children:[`Completion: `,e.completion_tokens]}),(0,G.jsxs)(`span`,{title:`Reasoning-token subset of completion tokens`,children:[`Reasoning: `,t]}),(0,G.jsxs)(`span`,{title:`Visible output tokens derived as completion minus reasoning`,children:[`Visible: `,n]}),(0,G.jsxs)(`span`,{title:`Input plus completion tokens`,children:[`Total: `,e.total_tokens]}),(0,G.jsxs)(`span`,{title:`Post-first-token decode throughput`,children:[`Decode TPS: `,e.tokens_per_second.toFixed(2)]}),e.time_to_first_token_ms!==void 0&&(0,G.jsxs)(`span`,{title:`Time from slot prefill start to the first sampled token`,children:[`Prefill TTFT: `,e.time_to_first_token_ms.toFixed(0),`ms`]}),s&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(`span`,{title:`Tokens proposed by the draft model`,children:[`MTP Drafted: `,i]}),(0,G.jsxs)(`span`,{title:`Draft-model tokens accepted by the target model`,children:[`MTP Accepted: `,a]}),(0,G.jsxs)(`span`,{title:`Accepted draft tokens divided by drafted tokens`,children:[`MTP Acceptance: `,(o*100).toFixed(2),`%`]}),(0,G.jsxs)(`span`,{title:`Fraction of output positions covered by speculative decoding`,children:[`MTP Coverage: `,((e.draft_coverage??0)*100).toFixed(2),`%`]}),(0,G.jsxs)(`span`,{title:`Whether MTP remained enabled for the request`,children:[`MTP Status: `,e.draft_disable_reason?`disabled (${e.draft_disable_reason})`:`enabled`]})]})]})}function vv(e){return(e.match(/```/g)||[]).length%2==0?e:e+"\n```"}var yv={code({node:e,className:t,children:n,...r}){let i=/language-(\w+)/.exec(t||``);if(!i&&!t)return(0,G.jsx)(`code`,{className:`inline-code`,...r,children:n});let a=i?i[1]:`text`,o=String(n).replace(/\n$/,``);return(0,G.jsx)(`div`,{className:`chat-code-block-wrapper`,children:(0,G.jsx)(ya,{code:o,language:a,collapsible:!0})})},h1:({children:e})=>(0,G.jsx)(`h1`,{className:`markdown-h1`,children:e}),h2:({children:e})=>(0,G.jsx)(`h2`,{className:`markdown-h2`,children:e}),h3:({children:e})=>(0,G.jsx)(`h3`,{className:`markdown-h3`,children:e}),ul:({children:e})=>(0,G.jsx)(`ul`,{className:`markdown-list`,children:e}),ol:({children:e})=>(0,G.jsx)(`ol`,{className:`markdown-list markdown-list-ordered`,children:e}),li:({children:e})=>(0,G.jsx)(`li`,{className:`markdown-list-item`,children:e}),p:({children:e})=>(0,G.jsx)(`p`,{className:`markdown-paragraph`,children:e}),strong:({children:e})=>(0,G.jsx)(`strong`,{className:`markdown-bold`,children:e}),em:({children:e})=>(0,G.jsx)(`em`,{className:`markdown-italic`,children:e}),blockquote:({children:e})=>(0,G.jsx)(`blockquote`,{className:`markdown-blockquote`,children:e}),a:({href:e,children:t})=>(0,G.jsx)(`a`,{href:e,className:`markdown-link`,target:`_blank`,rel:`noopener noreferrer`,children:t})};function bv(e){let t=vv(e);return(0,G.jsx)(uh,{remarkPlugins:[gv],components:yv,children:t})}function xv({messages:e,setMessages:t,onClear:n,sampling:r,setSampling:i,modelBaseline:a,transport:o,modelVRAM:s,isMoE:c,disabled:l=!1,disabledPlaceholder:u,headerLeft:d,headerRight:f}){let[p,m]=(0,x.useState)(``),[h,g]=(0,x.useState)(!1),[_,v]=(0,x.useState)(null),[y,b]=(0,x.useState)(!1),[S,C]=(0,x.useState)([]),[w,T]=(0,x.useState)(!1),[E,D]=(0,x.useState)(null),[O,k]=(0,x.useState)(``),[A,j]=(0,x.useState)(`none`),M=(0,x.useRef)(null),N=(0,x.useRef)(null),P=(0,x.useRef)(null),F=(0,x.useRef)(null),I=(0,x.useRef)(null),L=(0,x.useRef)(!0),R=(0,x.useRef)(!1),z=(0,x.useRef)(!1),[ee,B]=(0,x.useState)(!1),V=(0,x.useCallback)(e=>{if(e.deltaY<0){let e=N.current;if(!e)return;e.scrollHeight>e.clientHeight&&(z.current=!0,L.current=!1,B(!0))}},[]),te=(0,x.useCallback)(()=>{if(R.current||!z.current)return;let e=N.current;e&&e.scrollHeight-e.scrollTop-e.clientHeight<100&&(L.current=!0,B(!1))},[]),H=(0,x.useCallback)(()=>{let e=N.current;e&&(R.current=!0,e.scrollTop=e.scrollHeight,L.current=!0,B(!1),requestAnimationFrame(()=>{R.current=!1}))},[]);(0,x.useEffect)(()=>{if(L.current){let e=N.current;if(!e)return;R.current=!0,e.scrollTop=e.scrollHeight,requestAnimationFrame(()=>{R.current=!1})}},[e]),(0,x.useEffect)(()=>{!h&&!l&&P.current?.focus()},[h,l]),(0,x.useEffect)(()=>()=>{I.current?.()},[]),(0,x.useEffect)(()=>{l&&h&&(I.current?.(),I.current=null,g(!1))},[l,h]);let ne=(0,x.useCallback)((e,t)=>{if(t.length===0)return e;let n=[];e&&n.push({type:`text`,text:e});for(let e of t)if(e.type===`image`)n.push({type:`image_url`,image_url:{url:e.dataUrl}});else if(e.type===`audio`){let t=e.dataUrl.match(/^data:audio\/(\w+);base64,(.+)$/);t&&n.push({type:`input_audio`,input_audio:{data:t[2],format:t[1]}})}return n},[]),re=(0,x.useCallback)(e=>{v(null),g(!0);let n=``,i=``,a,s=[];t(e=>[...e,{role:`assistant`,content:``,reasoning:``}]),I.current=o({messages:e,sampling:r,onMessage:e=>{let r=e.choices?.[0];if(r?.delta?.content&&(n+=r.delta.content),r?.delta?.reasoning_content&&(i+=r.delta.reasoning_content),r?.delta?.tool_calls&&r.delta.tool_calls.length>0)for(let e of r.delta.tool_calls){let t=e.index??(s.length>0?s[s.length-1].index:0),n=s.find(e=>e.index===t);n?(e.id&&!n.id&&(n.id=e.id),e.function?.name&&!n.function.name&&(n.function.name=e.function.name),e.function?.arguments&&(n.function.arguments+=e.function.arguments)):s.push({id:e.id||``,index:t,type:e.type||`function`,function:{name:e.function?.name||``,arguments:e.function?.arguments||``}})}e.usage&&(a=e.usage),t(e=>{let t=[...e];return t[t.length-1]={role:`assistant`,content:n,reasoning:i,usage:a,toolCalls:s.length?s:void 0},t})},onError:e=>{v(e),g(!1)},onComplete:()=>{g(!1)}})},[r,t,o]),ie=n=>{if(n.preventDefault(),!p.trim()&&S.length===0||l||h)return;let i={role:`user`,content:p.trim(),attachments:S.length>0?[...S]:void 0};t(e=>[...e,i]),m(``),C([]);let a=[...r.systemPrompt?[{role:`system`,content:r.systemPrompt}]:[],...e.map(e=>({role:e.role,content:e.attachments?ne(e.content,e.attachments):e.content})),{role:`user`,content:ne(p.trim(),S)}];re(a)},ae=t=>{D(t),k(e[t].content)},oe=()=>{D(null),k(``)},se=e=>{t(t=>t.map((t,n)=>n===e?{...t,content:O,originalContent:t.originalContent??t.content}:t)),D(null),k(``)},ce=e=>{t(t=>t.map((t,n)=>n===e&&t.originalContent!=null?{...t,content:t.originalContent,originalContent:void 0}:t))},le=n=>{if(l||h)return;let i=e.slice(0,n+1).map((e,t)=>t===n?{...e,content:O}:e);t(i),D(null),k(``);let a=[...r.systemPrompt?[{role:`system`,content:r.systemPrompt}]:[],...i.map(e=>({role:e.role,content:e.attachments?ne(e.content,e.attachments):e.content}))];re(a)},ue=()=>{I.current&&(I.current(),I.current=null,g(!1))},de=()=>{I.current&&(I.current(),I.current=null,g(!1)),n(),v(null),C([])},fe=e=>{let t=e.target.files;t&&(Array.from(t).forEach(e=>{let t=new FileReader;t.onload=()=>{let n=t.result,r=e.type.startsWith(`image/`)?`image`:`audio`;C(t=>[...t,{type:r,name:e.name,dataUrl:n}])},t.readAsDataURL(e)}),e.target.value=``)},pe=e=>{C(t=>t.filter((t,n)=>n!==e))};return(0,G.jsxs)(`div`,{className:`chat-container`,children:[(0,G.jsxs)(`div`,{className:`chat-header`,children:[(0,G.jsx)(`div`,{className:`chat-header-left`,children:d}),(0,G.jsxs)(`div`,{className:`chat-header-right`,children:[f,(0,G.jsxs)(`button`,{className:`btn btn-secondary btn-sm`,onClick:()=>b(!y),children:[`Settings`,pc(r,a)&&(0,G.jsx)(`span`,{className:`chat-setting-default`,children:`●`})]}),(0,G.jsx)(`button`,{className:`btn btn-secondary btn-sm`,onClick:de,disabled:h||e.length===0,children:`Clear chat`})]})]}),y&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(`div`,{className:`chat-system-prompt`,children:[(0,G.jsx)(`label`,{children:`System Prompt`}),(0,G.jsx)(`textarea`,{value:r.systemPrompt,onChange:e=>i({systemPrompt:e.target.value}),placeholder:`Enter a system prompt to set the model's behavior...`,className:`chat-system-prompt-input`,rows:3})]}),(0,G.jsxs)(`div`,{className:`chat-settings`,children:[(0,G.jsxs)(`div`,{className:`chat-setting ${uc(`maxTokens`,r.maxTokens,a)?`chat-setting-changed`:``}`,children:[(0,G.jsx)(X,{tooltipKey:`max_tokens`,after:uc(`maxTokens`,r.maxTokens,a)&&(0,G.jsx)(`span`,{className:`chat-setting-default`,title:`Default: ${dc(`maxTokens`,a)}`,children:`●`}),children:`Max Tokens`}),(0,G.jsx)(`input`,{type:`number`,value:r.maxTokens,onChange:e=>i({maxTokens:Number(e.target.value)}),min:1,max:32768})]}),(0,G.jsxs)(`div`,{className:`chat-setting ${uc(`temperature`,r.temperature,a)?`chat-setting-changed`:``}`,children:[(0,G.jsx)(X,{tooltipKey:`temperature`,after:uc(`temperature`,r.temperature,a)&&(0,G.jsx)(`span`,{className:`chat-setting-default`,title:`Default: ${dc(`temperature`,a)}`,children:`●`}),children:`Temperature`}),(0,G.jsx)(`input`,{type:`number`,value:r.temperature,onChange:e=>i({temperature:Number(e.target.value)}),min:0,max:2,step:.1})]}),(0,G.jsxs)(`div`,{className:`chat-setting ${uc(`topP`,r.topP,a)?`chat-setting-changed`:``}`,children:[(0,G.jsx)(X,{tooltipKey:`top_p`,after:uc(`topP`,r.topP,a)&&(0,G.jsx)(`span`,{className:`chat-setting-default`,title:`Default: ${dc(`topP`,a)}`,children:`●`}),children:`Top P`}),(0,G.jsx)(`input`,{type:`number`,value:r.topP,onChange:e=>i({topP:Number(e.target.value)}),min:0,max:1,step:.05})]}),(0,G.jsxs)(`div`,{className:`chat-setting ${uc(`topK`,r.topK,a)?`chat-setting-changed`:``}`,children:[(0,G.jsx)(X,{tooltipKey:`top_k`,after:uc(`topK`,r.topK,a)&&(0,G.jsx)(`span`,{className:`chat-setting-default`,title:`Default: ${dc(`topK`,a)}`,children:`●`}),children:`Top K`}),(0,G.jsx)(`input`,{type:`number`,value:r.topK,onChange:e=>i({topK:Number(e.target.value)}),min:1,max:100})]}),(0,G.jsxs)(`div`,{className:`chat-setting chat-setting-grammar`,children:[(0,G.jsx)(`label`,{children:`Grammar`}),(0,G.jsxs)(`select`,{value:A,onChange:e=>{let t=e.target.value;j(t),i({grammar:``})},children:[(0,G.jsx)(`option`,{value:`none`,children:`None`}),(0,G.jsx)(`option`,{value:`custom`,children:`Custom`})]})]}),(0,G.jsx)(`div`,{className:`chat-setting chat-setting-button`,children:(0,G.jsxs)(`button`,{type:`button`,className:`chat-advanced-toggle`,onClick:()=>T(!w),children:[`Advanced `,w?`▲`:`▼`,mc(r,a)&&(0,G.jsx)(`span`,{className:`chat-setting-default`,children:`●`})]})}),(0,G.jsx)(`div`,{className:`chat-setting chat-setting-button`,children:pc(r,a)&&a&&(0,G.jsx)(`button`,{type:`button`,className:`chat-reset-defaults`,onClick:()=>i(a),title:`Reset all sampling values to model defaults`,children:`Reset to default`})})]}),A===`custom`&&(0,G.jsx)(`div`,{className:`chat-grammar-editor`,children:(0,G.jsx)(`textarea`,{value:r.grammar,onChange:e=>i({grammar:e.target.value}),rows:4,placeholder:`Enter GBNF grammar...`,className:`chat-system-prompt-input`,style:{fontFamily:`monospace`,fontSize:`12px`}})}),w&&(0,G.jsx)(`div`,{className:`chat-settings`,children:(0,G.jsxs)(`div`,{className:`chat-advanced-settings`,children:[(0,G.jsxs)(`div`,{className:`chat-setting ${uc(`minP`,r.minP,a)?`chat-setting-changed`:``}`,children:[(0,G.jsx)(X,{tooltipKey:`min_p`,after:uc(`minP`,r.minP,a)&&(0,G.jsx)(`span`,{className:`chat-setting-default`,title:`Default: ${dc(`minP`,a)}`,children:`●`}),children:`Min P`}),(0,G.jsx)(`input`,{type:`number`,value:r.minP,onChange:e=>i({minP:Number(e.target.value)}),min:0,max:1,step:.01})]}),(0,G.jsxs)(`div`,{className:`chat-setting ${uc(`repeatPenalty`,r.repeatPenalty,a)?`chat-setting-changed`:``}`,children:[(0,G.jsx)(X,{tooltipKey:`repeat_penalty`,after:uc(`repeatPenalty`,r.repeatPenalty,a)&&(0,G.jsx)(`span`,{className:`chat-setting-default`,title:`Default: ${dc(`repeatPenalty`,a)}`,children:`●`}),children:`Repeat Penalty`}),(0,G.jsx)(`input`,{type:`number`,value:r.repeatPenalty,onChange:e=>i({repeatPenalty:Number(e.target.value)}),min:0,max:2,step:.1})]}),(0,G.jsxs)(`div`,{className:`chat-setting ${uc(`repeatLastN`,r.repeatLastN,a)?`chat-setting-changed`:``}`,children:[(0,G.jsx)(X,{tooltipKey:`repeat_last_n`,after:uc(`repeatLastN`,r.repeatLastN,a)&&(0,G.jsx)(`span`,{className:`chat-setting-default`,title:`Default: ${dc(`repeatLastN`,a)}`,children:`●`}),children:`Repeat Last N`}),(0,G.jsx)(`input`,{type:`number`,value:r.repeatLastN,onChange:e=>i({repeatLastN:Number(e.target.value)}),min:-1,max:512})]}),(0,G.jsxs)(`div`,{className:`chat-setting ${uc(`frequencyPenalty`,r.frequencyPenalty,a)?`chat-setting-changed`:``}`,children:[(0,G.jsx)(X,{tooltipKey:`frequency_penalty`,after:uc(`frequencyPenalty`,r.frequencyPenalty,a)&&(0,G.jsx)(`span`,{className:`chat-setting-default`,title:`Default: ${dc(`frequencyPenalty`,a)}`,children:`●`}),children:`Frequency Penalty`}),(0,G.jsx)(`input`,{type:`number`,value:r.frequencyPenalty,onChange:e=>i({frequencyPenalty:Number(e.target.value)}),min:0,max:2,step:.1})]}),(0,G.jsxs)(`div`,{className:`chat-setting ${uc(`presencePenalty`,r.presencePenalty,a)?`chat-setting-changed`:``}`,children:[(0,G.jsx)(X,{tooltipKey:`presence_penalty`,after:uc(`presencePenalty`,r.presencePenalty,a)&&(0,G.jsx)(`span`,{className:`chat-setting-default`,title:`Default: ${dc(`presencePenalty`,a)}`,children:`●`}),children:`Presence Penalty`}),(0,G.jsx)(`input`,{type:`number`,value:r.presencePenalty,onChange:e=>i({presencePenalty:Number(e.target.value)}),min:0,max:2,step:.1})]}),(0,G.jsxs)(`div`,{className:`chat-setting ${uc(`dryMultiplier`,r.dryMultiplier,a)?`chat-setting-changed`:``}`,children:[(0,G.jsx)(X,{tooltipKey:`dry_multiplier`,after:uc(`dryMultiplier`,r.dryMultiplier,a)&&(0,G.jsx)(`span`,{className:`chat-setting-default`,title:`Default: ${dc(`dryMultiplier`,a)}`,children:`●`}),children:`DRY Multiplier`}),(0,G.jsx)(`input`,{type:`number`,value:r.dryMultiplier,onChange:e=>i({dryMultiplier:Number(e.target.value)}),min:0,step:.1})]}),(0,G.jsxs)(`div`,{className:`chat-setting ${uc(`dryBase`,r.dryBase,a)?`chat-setting-changed`:``}`,children:[(0,G.jsx)(X,{tooltipKey:`dry_base`,after:uc(`dryBase`,r.dryBase,a)&&(0,G.jsx)(`span`,{className:`chat-setting-default`,title:`Default: ${dc(`dryBase`,a)}`,children:`●`}),children:`DRY Base`}),(0,G.jsx)(`input`,{type:`number`,value:r.dryBase,onChange:e=>i({dryBase:Number(e.target.value)}),min:1,step:.05})]}),(0,G.jsxs)(`div`,{className:`chat-setting ${uc(`dryAllowedLen`,r.dryAllowedLen,a)?`chat-setting-changed`:``}`,children:[(0,G.jsx)(X,{tooltipKey:`dry_allowed_length`,after:uc(`dryAllowedLen`,r.dryAllowedLen,a)&&(0,G.jsx)(`span`,{className:`chat-setting-default`,title:`Default: ${dc(`dryAllowedLen`,a)}`,children:`●`}),children:`DRY Allowed Length`}),(0,G.jsx)(`input`,{type:`number`,value:r.dryAllowedLen,onChange:e=>i({dryAllowedLen:Number(e.target.value)}),min:0})]}),(0,G.jsxs)(`div`,{className:`chat-setting ${uc(`dryPenaltyLast`,r.dryPenaltyLast,a)?`chat-setting-changed`:``}`,children:[(0,G.jsx)(X,{tooltipKey:`dry_penalty_last_n`,after:uc(`dryPenaltyLast`,r.dryPenaltyLast,a)&&(0,G.jsx)(`span`,{className:`chat-setting-default`,title:`Default: ${dc(`dryPenaltyLast`,a)}`,children:`●`}),children:`DRY Penalty Last N`}),(0,G.jsx)(`input`,{type:`number`,value:r.dryPenaltyLast,onChange:e=>i({dryPenaltyLast:Number(e.target.value)}),min:-1})]}),(0,G.jsxs)(`div`,{className:`chat-setting ${uc(`xtcProbability`,r.xtcProbability,a)?`chat-setting-changed`:``}`,children:[(0,G.jsx)(X,{tooltipKey:`xtc_probability`,after:uc(`xtcProbability`,r.xtcProbability,a)&&(0,G.jsx)(`span`,{className:`chat-setting-default`,title:`Default: ${dc(`xtcProbability`,a)}`,children:`●`}),children:`XTC Probability`}),(0,G.jsx)(`input`,{type:`number`,value:r.xtcProbability,onChange:e=>i({xtcProbability:Number(e.target.value)}),min:0,max:1,step:.01})]}),(0,G.jsxs)(`div`,{className:`chat-setting ${uc(`xtcThreshold`,r.xtcThreshold,a)?`chat-setting-changed`:``}`,children:[(0,G.jsx)(X,{tooltipKey:`xtc_threshold`,after:uc(`xtcThreshold`,r.xtcThreshold,a)&&(0,G.jsx)(`span`,{className:`chat-setting-default`,title:`Default: ${dc(`xtcThreshold`,a)}`,children:`●`}),children:`XTC Threshold`}),(0,G.jsx)(`input`,{type:`number`,value:r.xtcThreshold,onChange:e=>i({xtcThreshold:Number(e.target.value)}),min:0,max:1,step:.01})]}),(0,G.jsxs)(`div`,{className:`chat-setting ${uc(`xtcMinKeep`,r.xtcMinKeep,a)?`chat-setting-changed`:``}`,children:[(0,G.jsx)(X,{tooltipKey:`xtc_min_keep`,after:uc(`xtcMinKeep`,r.xtcMinKeep,a)&&(0,G.jsx)(`span`,{className:`chat-setting-default`,title:`Default: ${dc(`xtcMinKeep`,a)}`,children:`●`}),children:`XTC Min Keep`}),(0,G.jsx)(`input`,{type:`number`,value:r.xtcMinKeep,onChange:e=>i({xtcMinKeep:Number(e.target.value)}),min:1})]}),(0,G.jsxs)(`div`,{className:`chat-setting ${uc(`enableThinking`,r.enableThinking,a)?`chat-setting-changed`:``}`,children:[(0,G.jsx)(X,{tooltipKey:`enable_thinking`,after:uc(`enableThinking`,r.enableThinking,a)&&(0,G.jsx)(`span`,{className:`chat-setting-default`,title:`Default: ${dc(`enableThinking`,a)}`,children:`●`}),children:`Enable Thinking`}),(0,G.jsxs)(`select`,{value:r.enableThinking,onChange:e=>i({enableThinking:e.target.value}),children:[(0,G.jsx)(`option`,{value:``,children:`Default`}),(0,G.jsx)(`option`,{value:`true`,children:`Enabled`}),(0,G.jsx)(`option`,{value:`false`,children:`Disabled`})]})]}),(0,G.jsxs)(`div`,{className:`chat-setting ${uc(`reasoningEffort`,r.reasoningEffort,a)?`chat-setting-changed`:``}`,children:[(0,G.jsx)(X,{tooltipKey:`reasoning_effort`,after:uc(`reasoningEffort`,r.reasoningEffort,a)&&(0,G.jsx)(`span`,{className:`chat-setting-default`,title:`Default: ${dc(`reasoningEffort`,a)}`,children:`●`}),children:`Reasoning Effort`}),(0,G.jsxs)(`select`,{value:r.reasoningEffort,onChange:e=>i({reasoningEffort:e.target.value}),children:[(0,G.jsx)(`option`,{value:``,children:`Default`}),(0,G.jsx)(`option`,{value:`low`,children:`Low`}),(0,G.jsx)(`option`,{value:`medium`,children:`Medium`}),(0,G.jsx)(`option`,{value:`high`,children:`High`})]})]}),(0,G.jsxs)(`div`,{className:`chat-setting ${uc(`topLogprobs`,r.topLogprobs,a)?`chat-setting-changed`:``}`,children:[(0,G.jsxs)(`label`,{children:[`Top Logprobs`,uc(`topLogprobs`,r.topLogprobs,a)&&(0,G.jsx)(`span`,{className:`chat-setting-default`,title:`Default: ${dc(`topLogprobs`,a)}`,children:`●`})]}),(0,G.jsx)(`input`,{type:`number`,value:r.topLogprobs,onChange:e=>i({topLogprobs:Number(e.target.value)}),min:0,max:20})]}),(0,G.jsx)(`div`,{className:`chat-setting chat-setting-checkbox ${uc(`includeUsage`,r.includeUsage,a)?`chat-setting-changed`:``}`,children:(0,G.jsxs)(`label`,{children:[(0,G.jsx)(`input`,{type:`checkbox`,checked:r.includeUsage,onChange:e=>i({includeUsage:e.target.checked})}),`Include Usage`,uc(`includeUsage`,r.includeUsage,a)&&(0,G.jsx)(`span`,{className:`chat-setting-default`,title:`Default: ${dc(`includeUsage`,a)}`,children:`●`})]})}),(0,G.jsx)(`div`,{className:`chat-setting chat-setting-checkbox ${uc(`logprobs`,r.logprobs,a)?`chat-setting-changed`:``}`,children:(0,G.jsxs)(`label`,{children:[(0,G.jsx)(`input`,{type:`checkbox`,checked:r.logprobs,onChange:e=>i({logprobs:e.target.checked})}),`Logprobs`,uc(`logprobs`,r.logprobs,a)&&(0,G.jsx)(`span`,{className:`chat-setting-default`,title:`Default: ${dc(`logprobs`,a)}`,children:`●`})]})})]})})]}),c&&s&&(0,G.jsxs)(`details`,{className:`chat-moe-info`,children:[(0,G.jsxs)(`summary`,{style:{fontWeight:600,fontSize:`13px`,cursor:`pointer`,padding:`6px 12px`,background:`var(--color-gray-50)`,borderRadius:`6px`,margin:`0 0 8px`,listStyle:`revert`},children:[`🧩 MoE Model`,s.moe&&(0,G.jsxs)(`span`,{style:{fontWeight:400,fontSize:`12px`,color:`var(--color-text-secondary)`,marginLeft:`6px`},children:[`(`,s.moe.expert_count,` experts, top-`,s.moe.expert_used_count,` active`,s.moe.has_shared_experts?`, shared experts`:``,`)`]})]}),(0,G.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,gap:`8px`,padding:`12px`,background:`var(--color-gray-50)`,borderRadius:`6px`,margin:`0 0 8px`},children:[s.weights&&(0,G.jsxs)(`div`,{style:{display:`grid`,gridTemplateColumns:`1fr 1fr`,gap:`4px 16px`,fontSize:`12px`,color:`var(--color-text-secondary)`},children:[(0,G.jsx)(`span`,{children:`Always-active weights (GPU):`}),(0,G.jsx)(`span`,{style:{fontWeight:500},children:J(s.always_active_gpu_bytes??0)}),(s.always_active_cpu_bytes??0)>0&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`span`,{children:`Always-active weights (CPU):`}),(0,G.jsx)(`span`,{style:{fontWeight:500},children:J(s.always_active_cpu_bytes??0)})]}),(s.expert_gpu_bytes??0)>0&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`span`,{children:`Expert weights (GPU):`}),(0,G.jsx)(`span`,{style:{fontWeight:500},children:J(s.expert_gpu_bytes??0)})]}),(s.expert_cpu_bytes??0)>0&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`span`,{children:`Expert weights (CPU):`}),(0,G.jsx)(`span`,{style:{fontWeight:500},children:J(s.expert_cpu_bytes??0)})]}),(0,G.jsx)(`span`,{children:`KV cache:`}),(0,G.jsx)(`span`,{style:{fontWeight:500},children:J(s.slot_memory)}),(s.compute_buffer_est??0)>0&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`span`,{children:`Compute buffer (est.):`}),(0,G.jsxs)(`span`,{style:{fontWeight:500},children:[`~`,J(s.compute_buffer_est??0)]})]}),(0,G.jsx)(`span`,{style:{fontWeight:600},children:`Total estimated VRAM:`}),(0,G.jsx)(`span`,{style:{fontWeight:600},children:J(s.total_vram)})]}),!s.weights&&s.total_vram>0&&(0,G.jsxs)(`div`,{style:{fontSize:`12px`,color:`var(--color-text-secondary)`},children:[`Total VRAM: `,J(s.total_vram)]}),(0,G.jsxs)(`div`,{style:{fontSize:`11px`,color:`var(--color-text-secondary)`,lineHeight:1.4,marginTop:`4px`},children:[`💡 `,ia.moeTipBatch,` `,ia.moeTipFlashAttention]})]})]}),_&&(0,G.jsx)(`div`,{className:`alert alert-error`,children:_}),(0,G.jsxs)(`div`,{className:`chat-messages-wrapper`,children:[(0,G.jsxs)(`div`,{className:`chat-messages`,ref:N,onScroll:te,onWheel:V,children:[e.length===0&&(0,G.jsxs)(`div`,{className:`chat-empty`,children:[(0,G.jsx)(`p`,{children:u||`Select a model and start chatting`}),(0,G.jsx)(`p`,{className:`chat-empty-hint`,children:`Type a message below to begin`})]}),e.map((t,n)=>(0,G.jsxs)(`div`,{className:`chat-message chat-message-${t.role}`,children:[(0,G.jsxs)(`div`,{className:`chat-message-header`,children:[(0,G.jsx)(`span`,{children:t.role===`user`?`USER`:`MODEL`}),!h&&E===null&&(0,G.jsxs)(`span`,{className:`chat-header-actions`,children:[t.originalContent!=null&&(0,G.jsx)(`button`,{className:`chat-edit-btn`,onClick:()=>ce(n),title:`Revert to original message`,children:`Undo`}),(0,G.jsx)(`button`,{className:`chat-edit-btn`,onClick:()=>ae(n),title:`Edit message`,children:`Edit`})]})]}),t.attachments&&t.attachments.length>0&&(0,G.jsx)(`div`,{className:`chat-message-attachments`,children:t.attachments.map((e,t)=>(0,G.jsx)(`div`,{className:`chat-attachment-preview`,children:e.type===`image`?(0,G.jsx)(`img`,{src:e.dataUrl,alt:e.name,className:`chat-attachment-image`}):(0,G.jsx)(`div`,{className:`chat-attachment-audio`,children:(0,G.jsxs)(`span`,{children:[`🔊 `,e.name]})})},t))}),t.reasoning&&(0,G.jsxs)(`details`,{className:`chat-message-reasoning`,open:h&&n===e.length-1,children:[(0,G.jsxs)(`summary`,{className:`chat-reasoning-summary`,children:[`Reasoning (`,t.reasoning.length.toLocaleString(),` chars)`]}),(0,G.jsx)(`div`,{className:`chat-reasoning-content`,children:bv(t.reasoning)})]}),(0,G.jsx)(`div`,{className:`chat-message-content`,children:E===n?(0,G.jsxs)(`div`,{className:`chat-edit-area`,children:[(0,G.jsx)(`textarea`,{className:`chat-edit-textarea`,value:O,onChange:e=>k(e.target.value),rows:Math.max(4,O.split(`
`).length),autoFocus:!0}),(0,G.jsxs)(`div`,{className:`chat-edit-actions`,children:[(0,G.jsx)(`button`,{className:`btn btn-primary btn-sm`,onClick:()=>t.role===`assistant`?se(n):le(n),disabled:!O.trim(),children:t.role===`assistant`?`Save`:`Send`}),(0,G.jsx)(`button`,{className:`btn btn-secondary btn-sm`,onClick:oe,children:`Cancel`})]})]}):t.content?bv(t.content):h&&n===e.length-1?`...`:``}),t.toolCalls&&t.toolCalls.length>0&&(0,G.jsx)(`div`,{className:`chat-message-tool-calls`,children:t.toolCalls.map(e=>(0,G.jsxs)(`div`,{className:`chat-tool-call`,children:[`Tool call `,e.id,`: `,e.function.name,`(`,e.function.arguments,`)`]},e.id))}),t.usage&&(0,G.jsx)(_v,{usage:t.usage})]},n)),(0,G.jsx)(`div`,{ref:M})]}),ee&&(0,G.jsx)(`button`,{className:`chat-scroll-bottom-btn`,onClick:H,title:`Scroll to bottom`,children:`↓`})]}),(0,G.jsx)(`form`,{onSubmit:ie,className:`chat-input-form`,children:(0,G.jsxs)(`div`,{className:`chat-input-row`,children:[S.length>0&&(0,G.jsx)(`div`,{className:`chat-attachments-bar`,children:S.map((e,t)=>(0,G.jsxs)(`div`,{className:`chat-attachment-chip`,children:[e.type===`image`?(0,G.jsx)(`img`,{src:e.dataUrl,alt:e.name,className:`chat-attachment-chip-image`}):(0,G.jsx)(`span`,{className:`chat-attachment-chip-audio`,children:`🔊`}),(0,G.jsx)(`span`,{className:`chat-attachment-chip-name`,children:e.name}),(0,G.jsx)(`button`,{type:`button`,className:`chat-attachment-chip-remove`,onClick:()=>pe(t),children:`×`})]},t))}),(0,G.jsx)(`textarea`,{ref:P,value:p,onChange:e=>m(e.target.value),onKeyDown:e=>{e.key===`Enter`&&!e.shiftKey&&(e.preventDefault(),ie(e))},placeholder:l?u||`Chat is disabled`:`Type your message... (Enter to send, Shift+Enter for new line)`,disabled:h||l,className:`chat-input`,rows:3}),(0,G.jsxs)(`div`,{className:`chat-input-buttons`,children:[(0,G.jsx)(`input`,{ref:F,type:`file`,accept:`image/*,audio/*`,multiple:!0,onChange:fe,style:{display:`none`}}),(0,G.jsx)(`button`,{type:`button`,className:`btn btn-secondary chat-attach-btn`,onClick:()=>F.current?.click(),disabled:h||l,children:`📎`}),h?(0,G.jsx)(`button`,{type:`button`,className:`btn btn-danger`,onClick:ue,children:`Stop`}):(0,G.jsx)(`button`,{type:`submit`,className:`btn btn-primary`,disabled:!p.trim()&&S.length===0||l,children:`Send`})]})]})})]})}var Sv=`kronk_chat_history_enabled`;function Cv(){let{models:e,loading:t,loadModels:n}=In(),{messages:r,setMessages:i,clearMessages:a}=ic(),{sampling:o,setSampling:s}=lc(),{saveChat:c}=bc(),[l,u]=(0,x.useState)(()=>localStorage.getItem(`kronk_chat_model`)||``),[d,f]=(0,x.useState)(!1),[p,m]=(0,x.useState)(()=>{let e=localStorage.getItem(Sv);return e===null||e===`true`}),[h,g]=(0,x.useState)(null),[_,v]=(0,x.useState)(null),[y,b]=(0,x.useState)(void 0),S=$a(h,y),[C,w]=(0,x.useState)(null),T=(0,x.useRef)(null),[E,D]=(0,x.useState)(void 0),O=(0,x.useCallback)(()=>{m(e=>{let t=!e;try{localStorage.setItem(Sv,String(t))}catch{}return t})},[]),k=(0,x.useCallback)(e=>({temperature:e.temperature??oc.temperature,topK:e.top_k??oc.topK,topP:e.top_p??oc.topP,minP:e.min_p??oc.minP,presencePenalty:e.presence_penalty??oc.presencePenalty,maxTokens:e.max_tokens??oc.maxTokens,repeatPenalty:e.repeat_penalty??oc.repeatPenalty,repeatLastN:e.repeat_last_n??oc.repeatLastN,dryMultiplier:e.dry_multiplier??oc.dryMultiplier,dryBase:e.dry_base??oc.dryBase,dryAllowedLen:e.dry_allowed_length??oc.dryAllowedLen,dryPenaltyLast:e.dry_penalty_last_n??oc.dryPenaltyLast,xtcProbability:e.xtc_probability??oc.xtcProbability,xtcThreshold:e.xtc_threshold??oc.xtcThreshold,xtcMinKeep:e.xtc_min_keep??oc.xtcMinKeep,frequencyPenalty:e.frequency_penalty??oc.frequencyPenalty,enableThinking:e.enable_thinking??oc.enableThinking,reasoningEffort:e.reasoning_effort??oc.reasoningEffort,includeUsage:oc.includeUsage,logprobs:oc.logprobs,topLogprobs:oc.topLogprobs,grammar:e.grammar??oc.grammar,systemPrompt:oc.systemPrompt}),[]),A=(0,x.useCallback)(e=>{if(e){let t=k(e),n=t.grammar?.endsWith(`.grm`)?{...t,grammar:``}:t;s(n),w(n)}else w(null)},[s,k]);(0,x.useEffect)(()=>{n()},[n]),(0,x.useEffect)(()=>{if(e?.data&&e.data.length>0){let t=e.data.filter(e=>{let t=e.id.toLowerCase();return!t.includes(`embed`)&&!t.includes(`rerank`)});!t.some(e=>e.id===l)&&t.length>0&&u(t[0].id)}},[e,l]),(0,x.useEffect)(()=>{if(!l){g(null),v(null),b(void 0),D(void 0);return}g(null),v(null),b(void 0),D(void 0);let e=!1;return W.showModel(l).then(t=>{e||(g(t.vram||null),v(t.template??``),b(t.metadata),D(t.model_config?.[`draft-model`]?.[`model-id`]),T.current!==l&&A(t.model_config?.[`sampling-parameters`]),T.current=l,localStorage.setItem(`kronk_chat_model`,l))}).catch(()=>{e||(g(null),v(null),b(void 0),D(void 0))}),()=>{e=!0}},[l,A]);let j=(0,x.useCallback)(({messages:e,sampling:t,onMessage:n,onError:r,onComplete:i})=>W.streamChat({model:l,messages:e,max_tokens:t.maxTokens,temperature:t.temperature,top_p:t.topP,top_k:t.topK,min_p:t.minP,presence_penalty:t.presencePenalty,repeat_penalty:t.repeatPenalty,repeat_last_n:t.repeatLastN,dry_multiplier:t.dryMultiplier,dry_base:t.dryBase,dry_allowed_length:t.dryAllowedLen,dry_penalty_last_n:t.dryPenaltyLast,xtc_probability:t.xtcProbability,xtc_threshold:t.xtcThreshold,xtc_min_keep:t.xtcMinKeep,frequency_penalty:t.frequencyPenalty,enable_thinking:t.enableThinking||void 0,reasoning_effort:t.reasoningEffort||void 0,stream_options:{include_usage:t.includeUsage},logprobs:t.logprobs,top_logprobs:t.topLogprobs,grammar:t.grammar||void 0},n,r,i),[l]),M=(0,x.useCallback)(()=>{p&&r.length>0&&c(l,r),a()},[p,r,l,c,a]),N=(0,x.useCallback)(e=>{let t=e.map(e=>({role:e.role,content:e.content,reasoning:e.reasoning}));i(t)},[i]),P=(0,x.useCallback)(e=>{let t=e.target.value;r.length>0&&(p&&c(l,r),a()),u(t)},[r,p,l,c,a]);return(0,G.jsxs)(`div`,{className:`chat-layout`,children:[(0,G.jsx)(wc,{isOpen:d,onClose:()=>f(!1),onLoadChat:N}),(0,G.jsx)(xv,{messages:r,setMessages:i,onClear:M,sampling:o,setSampling:s,modelBaseline:C,transport:j,modelVRAM:h,isMoE:S,disabled:!l,headerLeft:(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`h2`,{children:`Chat`}),(0,G.jsxs)(`div`,{className:`chat-model-selector-group`,children:[(0,G.jsxs)(`select`,{value:l,onChange:P,disabled:t,className:`chat-model-select`,children:[t&&(0,G.jsx)(`option`,{children:`Loading models...`}),!t&&e?.data?.length===0&&(0,G.jsx)(`option`,{children:`No models available`}),e?.data?.filter(e=>{let t=e.id.toLowerCase();return!t.includes(`embed`)&&!t.includes(`rerank`)}).map(e=>(0,G.jsx)(`option`,{value:e.id,children:e.id},e.id))]}),(E||_!==null)&&(0,G.jsxs)(`div`,{className:`chat-model-info`,children:[E&&(0,G.jsxs)(`span`,{className:`chat-draft-label`,title:`Draft model for speculative decoding`,children:[`⚡ `,E]}),_!==null&&(0,G.jsxs)(`span`,{className:`chat-template-label`,title:`Chat template`,children:[`Template: `,_===``?`builtin`:_]})]})]})]}),headerRight:(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(`button`,{type:`button`,className:`chat-history-toggle ${p?`chat-history-toggle-on`:`chat-history-toggle-off`}`,onClick:O,title:p?`Chat history auto-save is on`:`Chat history auto-save is off`,children:[`Chat History: `,p?`ON`:`OFF`]}),(0,G.jsx)(`button`,{className:`btn btn-secondary btn-sm`,onClick:()=>f(!d),children:`History`})]})})]})}var wv=`kronk_decision_model`,Tv={route:{type:`choice`,instructions:`Which team should handle this request?`,criteria:{billing:`Payments, invoices, refunds, and duplicate charges`,technical_support:`Product bugs and technical problems`,sales:`Plans, pricing, and new purchases`}},urgency:{type:`score`,instructions:`How urgent is this request?`,criteria:[`not urgent`,`normal`,`urgent`,`critical`]},requires_human:{type:`noul`,instructions:`Should a human review this request?`}},Ev={route:`Route`,urgency:`Urgency`,requires_human:`Human review`};function Dv(e=0){return`${(e*100).toFixed(1)}%`}function Ov({probabilities:e}){if(!e)return null;let t=Object.entries(e).sort((e,t)=>t[1]-e[1]);return(0,G.jsx)(`div`,{className:`decision-probabilities`,children:t.map(([e,t])=>(0,G.jsxs)(`div`,{className:`decision-probability`,children:[(0,G.jsxs)(`div`,{className:`decision-probability-label`,children:[(0,G.jsx)(`span`,{children:e.replaceAll(`_`,` `)}),(0,G.jsx)(`strong`,{children:Dv(t)})]}),(0,G.jsx)(`div`,{className:`decision-probability-track`,children:(0,G.jsx)(`span`,{style:{width:`${Math.max(0,Math.min(100,t*100))}%`}})})]},e))})}function kv({id:e,answer:t}){let n=``,r=``;switch(t.type){case`choice`:n=t.choice?.replaceAll(`_`,` `)??`No choice`,r=`${Dv(t.confidence)} confidence`;break;case`score`:{n=t.score?.toFixed(2)??`No score`;let e=t.legend?.[String(Math.round(t.score??0))];r=typeof e==`string`?e:`${Dv(t.confidence)} confidence`;break}case`noul`:n=Dv(t.noul),r=(t.noul??0)>=.5?`Human review recommended`:`Automation recommended`}return(0,G.jsxs)(`article`,{className:`decision-answer-card`,children:[(0,G.jsxs)(`div`,{className:`decision-answer-heading`,children:[(0,G.jsx)(`span`,{className:`decision-answer-type decision-answer-type-${t.type}`,children:t.type}),(0,G.jsx)(`h4`,{children:Ev[e]??e})]}),(0,G.jsx)(`div`,{className:`decision-answer-primary`,children:n}),(0,G.jsx)(`p`,{children:r}),(0,G.jsx)(Ov,{probabilities:t.probabilities})]})}function Av(){let[e,t]=(0,x.useState)(()=>localStorage.getItem(wv)||``),[n,r]=(0,x.useState)([]),[i,a]=(0,x.useState)(!0),[o,s]=(0,x.useState)(null),[c,l]=(0,x.useState)(`I was charged twice and need this fixed today.`),[u,d]=(0,x.useState)(`business`),[f,p]=(0,x.useState)(!1),[m,h]=(0,x.useState)(null),[g,_]=(0,x.useState)(null),v=(0,x.useMemo)(()=>Object.entries(Tv),[]),y=n.find(t=>t.id===e),b=y?.downloaded===!0&&y.validated===!0,S=b&&c.trim()!==``&&!f;(0,x.useEffect)(()=>{let e=!1;return W.listCatalog().then(n=>{if(e)return;let i=n.filter(e=>e.capabilities?.decision===!0||e.capabilities?.endpoint===`decision`);r(i),t(e=>i.some(t=>t.id===e)?e:i[0]?.id??``)}).catch(t=>{e||s(t.message)}).finally(()=>{e||a(!1)}),()=>{e=!0}},[]);let C=e=>{t(e),localStorage.setItem(wv,e),h(null),_(null)};return(0,G.jsxs)(`div`,{className:`decision-page`,children:[(0,G.jsxs)(`div`,{className:`page-header`,children:[(0,G.jsx)(`h2`,{children:`Decision`}),(0,G.jsx)(`p`,{children:`Evaluate structured questions against shared state with an installed decision model.`})]}),(0,G.jsxs)(`div`,{className:`decision-grid`,children:[(0,G.jsxs)(`form`,{className:`decision-card decision-form`,onSubmit:async t=>{if(t.preventDefault(),!S)return;let n=e.trim();localStorage.setItem(wv,n),p(!0),h(null),_(null);try{_(await W.decide({model:n,state:{customer_message:c.trim(),account_tier:u},questions:Tv}))}catch(e){h(e.message)}finally{p(!1)}},children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`span`,{className:`decision-eyebrow`,children:`Customer support example`}),(0,G.jsx)(`h3`,{children:`Request state`})]}),(0,G.jsx)(X,{htmlFor:`decision-model`,tooltipKey:`decisionModel`,children:`Model`}),(0,G.jsxs)(`select`,{id:`decision-model`,className:`form-select`,value:e,onChange:e=>C(e.target.value),disabled:i||f||n.length===0,children:[i&&(0,G.jsx)(`option`,{value:``,children:`Loading decision models…`}),!i&&n.length===0&&(0,G.jsx)(`option`,{value:``,children:`No decision models in catalog`}),n.map(e=>(0,G.jsxs)(`option`,{value:e.id,children:[e.id,e.downloaded?e.validated?` — ready`:` — validation failed`:` — download required`]},e.id))]}),(0,G.jsx)(`div`,{className:`decision-model-status`,"aria-live":`polite`,children:i?(0,G.jsx)(`span`,{children:`Checking model availability…`}):o?(0,G.jsxs)(`span`,{className:`decision-model-status-error`,children:[`Unable to verify model availability: `,o]}):y?b?(0,G.jsx)(`span`,{className:`decision-model-status-ready`,children:`● Downloaded and ready`}):y.downloaded?(0,G.jsxs)(`span`,{className:`decision-model-status-required`,children:[`This model did not pass integrity validation. Re-download it from `,(0,G.jsx)(`strong`,{children:`Kronk → Catalog`}),` before evaluating a decision.`]}):(0,G.jsxs)(`span`,{className:`decision-model-status-required`,children:[`Download this model from `,(0,G.jsx)(`strong`,{children:`Kronk → Catalog`}),` before evaluating a decision.`]}):(0,G.jsx)(`span`,{className:`decision-model-status-required`,children:`No decision models are available in the catalog.`})}),(0,G.jsx)(X,{htmlFor:`decision-message`,tooltipKey:`decisionState`,children:`Customer message`}),(0,G.jsx)(`textarea`,{id:`decision-message`,className:`decision-message`,rows:5,value:c,onChange:e=>l(e.target.value),disabled:f}),(0,G.jsx)(X,{htmlFor:`decision-account-tier`,tooltipKey:`decisionAccountTier`,children:`Account tier`}),(0,G.jsxs)(`select`,{id:`decision-account-tier`,className:`form-select`,value:u,onChange:e=>d(e.target.value),disabled:f,children:[(0,G.jsx)(`option`,{value:`free`,children:`Free`}),(0,G.jsx)(`option`,{value:`pro`,children:`Pro`}),(0,G.jsx)(`option`,{value:`business`,children:`Business`}),(0,G.jsx)(`option`,{value:`enterprise`,children:`Enterprise`})]}),(0,G.jsx)(`button`,{className:`btn btn-primary decision-submit`,type:`submit`,disabled:!S,children:f?`Evaluating…`:`Evaluate decision`})]}),(0,G.jsxs)(`section`,{className:`decision-card decision-questions`,"aria-labelledby":`decision-questions-title`,children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`span`,{className:`decision-eyebrow`,children:`Fixed for this example`}),(0,G.jsx)(`h3`,{id:`decision-questions-title`,children:`Questions`})]}),v.map(([e,t])=>(0,G.jsxs)(`div`,{className:`decision-question`,children:[(0,G.jsxs)(`div`,{className:`decision-question-heading`,children:[(0,G.jsx)(`strong`,{children:Ev[e]}),(0,G.jsx)(`span`,{children:t.type})]}),(0,G.jsx)(`p`,{children:t.instructions}),t.type===`choice`&&!Array.isArray(t.criteria)&&(0,G.jsx)(`div`,{className:`decision-option-list`,children:Object.keys(t.criteria??{}).map(e=>(0,G.jsx)(`span`,{children:e.replaceAll(`_`,` `)},e))}),t.type===`score`&&Array.isArray(t.criteria)&&(0,G.jsx)(`div`,{className:`decision-scale`,children:t.criteria.map((e,t)=>(0,G.jsxs)(`span`,{children:[(0,G.jsx)(`b`,{children:t}),String(e)]},String(e)))})]},e))]})]}),m&&(0,G.jsxs)(`div`,{className:`alert alert-error decision-alert`,children:[`Decision failed: `,m]}),(0,G.jsxs)(`section`,{className:`decision-results`,"aria-live":`polite`,children:[(0,G.jsxs)(`div`,{className:`decision-results-header`,children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`span`,{className:`decision-eyebrow`,children:`Model output`}),(0,G.jsx)(`h3`,{children:`Answers`})]}),g&&(0,G.jsxs)(`span`,{children:[g.usage.input_tokens,` input tokens`]})]}),g?(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`div`,{className:`decision-answer-grid`,children:v.map(([e])=>{let t=g.answers[e];return t?(0,G.jsx)(kv,{id:e,answer:t},e):null})}),(0,G.jsxs)(`details`,{className:`decision-raw`,children:[(0,G.jsx)(`summary`,{children:`Raw response`}),(0,G.jsx)(`pre`,{children:JSON.stringify(g,null,2)})]})]}):(0,G.jsxs)(`div`,{className:`decision-empty`,children:[(0,G.jsx)(`div`,{className:`decision-empty-icon`,children:`◇`}),(0,G.jsx)(`strong`,{children:`No decision yet`}),(0,G.jsx)(`span`,{children:`Run the example to see typed answers and calibrated probabilities.`})]})]})]})}var jv=[{code:``,label:`Auto-detect`},{code:`en`,label:`English`},{code:`es`,label:`Spanish`},{code:`fr`,label:`French`},{code:`de`,label:`German`},{code:`it`,label:`Italian`},{code:`pt`,label:`Portuguese`},{code:`nl`,label:`Dutch`},{code:`pl`,label:`Polish`},{code:`ru`,label:`Russian`},{code:`uk`,label:`Ukrainian`},{code:`tr`,label:`Turkish`},{code:`ar`,label:`Arabic`},{code:`he`,label:`Hebrew`},{code:`hi`,label:`Hindi`},{code:`ja`,label:`Japanese`},{code:`ko`,label:`Korean`},{code:`zh`,label:`Chinese`},{code:`vi`,label:`Vietnamese`},{code:`th`,label:`Thai`},{code:`id`,label:`Indonesian`},{code:`sv`,label:`Swedish`},{code:`no`,label:`Norwegian`},{code:`da`,label:`Danish`},{code:`fi`,label:`Finnish`},{code:`cs`,label:`Czech`},{code:`el`,label:`Greek`},{code:`ro`,label:`Romanian`},{code:`hu`,label:`Hungarian`}],Mv=30,Nv=`kronk_translator_model`;function Pv(e){return/\.en\b|-en\b/i.test(e)}function Fv(e){return e<1024?`${e} B`:e<1048576?`${(e/1024).toFixed(1)} KB`:e<1073741824?`${(e/1048576).toFixed(1)} MB`:`${(e/1073741824).toFixed(2)} GB`}function Iv(e){if(!isFinite(e)||e<0)return`0s`;let t=Math.floor(e/60),n=e-t*60;return t>0?`${t}m ${n.toFixed(1)}s`:`${n.toFixed(1)}s`}function Lv(e){let t=Math.max(0,Math.round(e*1e3)),n=Math.floor(t/36e5),r=Math.floor(t%36e5/6e4),i=Math.floor(t%6e4/1e3),a=t%1e3;return`${String(n).padStart(2,`0`)}:${String(r).padStart(2,`0`)}:${String(i).padStart(2,`0`)},${String(a).padStart(3,`0`)}`}function Rv(e){return Lv(e).replace(`,`,`.`)}function zv(e){return e.segments.map((e,t)=>`${t+1}\n${Lv(e.start)} --> ${Lv(e.end)}\n${e.text.trim()}\n`).join(`
`)}function Bv(e){return`WEBVTT\n\n${e.segments.map(e=>`${Rv(e.start)} --> ${Rv(e.end)}\n${e.text.trim()}\n`).join(`
-`)}`}function Vv(e,t,n){let r=new Blob([t],{type:n}),i=URL.createObjectURL(r),a=document.createElement(`a`);a.href=i,a.download=e,document.body.appendChild(a),a.click(),document.body.removeChild(a),URL.revokeObjectURL(i)}function Hv(){let[e,t]=(0,x.useState)([]),[n,r]=(0,x.useState)(!0),[i,a]=(0,x.useState)(null),[o,s]=(0,x.useState)(()=>localStorage.getItem(Nv)||``),[c,l]=(0,x.useState)(null),[u,d]=(0,x.useState)(``),[f,p]=(0,x.useState)(!1),[m,h]=(0,x.useState)(``),[g,_]=(0,x.useState)(null),[v,y]=(0,x.useState)(!1),b=(0,x.useRef)(null),[S,C]=(0,x.useState)(!1),[w,T]=(0,x.useState)(0),E=(0,x.useRef)(null),D=(0,x.useRef)([]),O=(0,x.useRef)(null),k=(0,x.useRef)(0),[A,j]=(0,x.useState)(!1),[M,N]=(0,x.useState)(null),[P,F]=(0,x.useState)(null),[I,L]=(0,x.useState)(!1),R=(0,x.useCallback)(async()=>{r(!0),a(null);try{let e=await W.listBuckyModels();t(e.models??[])}catch(e){a(e.message),t([])}finally{r(!1)}},[]);(0,x.useEffect)(()=>{R()},[R]),(0,x.useEffect)(()=>{e.length!==0&&(e.some(e=>e.id===o)||s(e[0].id))},[e,o]),(0,x.useEffect)(()=>{if(!o){l(null);return}localStorage.setItem(Nv,o);let e=!1;return W.getBuckyModelDetails(o).then(t=>{e||l(t)}).catch(()=>{e||l(null)}),()=>{e=!0}},[o]);let z=(0,x.useMemo)(()=>c?c.is_multilingual:!Pv(o),[c,o]);(0,x.useEffect)(()=>{z||(f&&p(!1),u&&u!==`en`&&d(``))},[z,f,u]);let ee=(0,x.useCallback)(e=>{_(t=>(t&&URL.revokeObjectURL(t.objectURL),e))},[]);(0,x.useEffect)(()=>()=>{g&&URL.revokeObjectURL(g.objectURL)},[]);let B=(0,x.useCallback)(e=>{ee({blob:e,filename:e.name,size:e.size,source:`file`,objectURL:URL.createObjectURL(e)}),F(null),N(null)},[ee]),V=(0,x.useCallback)(e=>{let t=e.target.files?.[0];t&&B(t),e.target.value=``},[B]),te=(0,x.useCallback)(e=>{e.preventDefault(),y(!1);let t=e.dataTransfer.files?.[0];t&&B(t)},[B]),H=(0,x.useCallback)(()=>{let e=E.current;e&&e.state!==`inactive`&&e.stop(),O.current!==null&&(window.clearInterval(O.current),O.current=null)},[]),ne=(0,x.useCallback)(async()=>{N(null);try{let e=await navigator.mediaDevices.getUserMedia({audio:!0}),t=new MediaRecorder(e);E.current=t,D.current=[],t.ondataavailable=e=>{e.data.size>0&&D.current.push(e.data)},t.onstop=()=>{e.getTracks().forEach(e=>e.stop());let n=new Blob(D.current,{type:t.mimeType||`audio/webm`}),r=(t.mimeType||`audio/webm`).includes(`ogg`)?`ogg`:`webm`;ee({blob:n,filename:`mic-${new Date().toISOString().replace(/[:.]/g,`-`)}.${r}`,size:n.size,source:`mic`,objectURL:URL.createObjectURL(n)}),C(!1),T(0),E.current=null},k.current=Date.now(),t.start(),C(!0),F(null),T(0),O.current=window.setInterval(()=>{let e=(Date.now()-k.current)/1e3;T(e),e>=Mv&&H()},100)}catch(e){N(`Microphone error: ${e.message}`)}},[ee,H]);(0,x.useEffect)(()=>()=>{H()},[H]);let re=!!o&&!!g&&!A&&!S,ie=(0,x.useCallback)(async()=>{if(!g||!o)return;j(!0),N(null),F(null);let e=performance.now();try{let t=await W.transcribe(o,g.blob,{filename:g.filename,language:u||void 0,translate:f||void 0,prompt:m||void 0}),n=performance.now()-e;F({response:t,wallMs:n,model:o,multilingual:z,translated:!!f,sourceHint:u,inputName:g.filename,inputSize:g.size,inputSource:g.source})}catch(e){N(e.message)}finally{j(!1)}},[g,o,u,f,m,z]),ae=(0,x.useCallback)(()=>{ee(null),F(null),N(null)},[ee]),oe=P?P.response.text.trim().split(/\s+/).filter(Boolean).length:0,se=P?P.response.text.length:0,ce=P&&P.wallMs>0?P.response.duration*1e3/P.wallMs:0;return(0,G.jsxs)(`div`,{className:`translator-page`,children:[(0,G.jsxs)(`div`,{className:`page-header`,children:[(0,G.jsx)(`h2`,{children:`Translator`}),(0,G.jsxs)(`p`,{children:[`Transcribe speech to text or translate non-English speech into English using whisper.cpp. Upload an audio file or record up to `,Mv,` seconds from your microphone.`]})]}),i&&(0,G.jsxs)(`div`,{className:`alert alert-error`,children:[`Failed to load whisper models: `,i]}),!n&&e.length===0&&(0,G.jsxs)(`div`,{className:`alert alert-error`,children:[`No whisper models installed. Go to `,(0,G.jsx)(`strong`,{children:`Bucky → Models → List`}),` to download one.`]}),(0,G.jsxs)(`div`,{className:`translator-grid`,children:[(0,G.jsxs)(`section`,{className:`translator-card`,children:[(0,G.jsx)(`h3`,{children:`Settings`}),(0,G.jsx)(X,{htmlFor:`translator-model`,tooltipKey:`translatorModel`,children:`Model`}),(0,G.jsxs)(`select`,{id:`translator-model`,className:`form-select`,value:o,onChange:e=>s(e.target.value),disabled:n||e.length===0,children:[n&&(0,G.jsx)(`option`,{children:`Loading…`}),!n&&e.length===0&&(0,G.jsx)(`option`,{children:`No models available`}),e.map(e=>(0,G.jsxs)(`option`,{value:e.id,children:[e.id,Pv(e.id)?` (English-only)`:``]},e.id))]}),(0,G.jsx)(X,{htmlFor:`translator-language`,tooltipKey:`translatorSourceLanguage`,children:`Source language`}),(0,G.jsx)(`select`,{id:`translator-language`,className:`form-select`,value:u,onChange:e=>d(e.target.value),disabled:!z,children:jv.map(e=>(0,G.jsx)(`option`,{value:e.code,children:e.label},e.code))}),(0,G.jsxs)(X,{tooltipKey:`translatorTranslate`,children:[(0,G.jsx)(`input`,{type:`checkbox`,checked:f,onChange:e=>p(e.target.checked),disabled:!z}),` `,`Translate to English`]}),(0,G.jsx)(X,{htmlFor:`translator-prompt`,tooltipKey:`translatorPrompt`,children:`Decoder prompt (optional)`}),(0,G.jsx)(`textarea`,{id:`translator-prompt`,className:`translator-textarea`,rows:3,value:m,onChange:e=>h(e.target.value),placeholder:`e.g. proper nouns or technical terms to bias spelling`})]}),(0,G.jsxs)(`section`,{className:`translator-card`,children:[(0,G.jsx)(`h3`,{children:`Audio input`}),(0,G.jsxs)(`div`,{className:`translator-drop ${v?`translator-drop-over`:``}`,onDragOver:e=>{e.preventDefault(),y(!0)},onDragLeave:()=>y(!1),onDrop:te,onClick:()=>b.current?.click(),children:[(0,G.jsx)(`div`,{className:`translator-drop-icon`,children:`🎵`}),(0,G.jsx)(`div`,{children:`Drop audio file here or click to choose`}),(0,G.jsx)(`input`,{ref:b,type:`file`,accept:`audio/*`,style:{display:`none`},onChange:V})]}),(0,G.jsx)(`div`,{className:`translator-mic-row`,children:S?(0,G.jsxs)(`button`,{type:`button`,className:`btn btn-primary`,onClick:H,children:[`■ Stop recording (`,w.toFixed(1),`s / `,Mv,`s)`]}):(0,G.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:ne,disabled:A,children:`● Record from microphone`})}),g&&(0,G.jsxs)(`div`,{className:`translator-input-preview`,children:[(0,G.jsxs)(`div`,{className:`translator-input-meta`,children:[(0,G.jsx)(`strong`,{children:g.filename}),(0,G.jsx)(`span`,{className:`translator-input-source`,children:g.source===`mic`?`microphone`:`file`}),(0,G.jsx)(`span`,{children:Fv(g.size)}),(0,G.jsx)(`button`,{type:`button`,className:`btn-link`,onClick:ae,children:`remove`})]}),(0,G.jsx)(`audio`,{src:g.objectURL,controls:!0,className:`translator-audio`})]}),(0,G.jsx)(`div`,{className:`translator-submit-row`,children:(0,G.jsx)(`button`,{type:`button`,className:`btn btn-primary`,onClick:ie,disabled:!re,children:A?`Working…`:f?`Translate`:`Transcribe`})}),M&&(0,G.jsx)(`div`,{className:`alert alert-error`,children:M})]})]}),P&&(0,G.jsxs)(`section`,{className:`translator-card translator-result`,children:[(0,G.jsxs)(`div`,{className:`translator-result-header`,children:[(0,G.jsx)(`h3`,{children:P.translated?`Translation`:`Transcription`}),(0,G.jsxs)(`div`,{className:`translator-result-actions`,children:[(0,G.jsx)(`button`,{type:`button`,className:`btn btn-secondary btn-sm`,onClick:()=>navigator.clipboard.writeText(P.response.text),children:`Copy`}),(0,G.jsx)(`button`,{type:`button`,className:`btn btn-secondary btn-sm`,onClick:()=>Vv(`transcript.txt`,P.response.text,`text/plain`),children:`.txt`}),(0,G.jsx)(`button`,{type:`button`,className:`btn btn-secondary btn-sm`,onClick:()=>Vv(`transcript.srt`,zv(P.response),`application/x-subrip`),children:`.srt`}),(0,G.jsx)(`button`,{type:`button`,className:`btn btn-secondary btn-sm`,onClick:()=>Vv(`transcript.vtt`,Bv(P.response),`text/vtt`),children:`.vtt`})]})]}),(0,G.jsx)(`pre`,{className:`translator-text`,children:P.response.text||`(empty)`}),(0,G.jsx)(`table`,{className:`translator-meta`,children:(0,G.jsxs)(`tbody`,{children:[(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Model`}),(0,G.jsxs)(`td`,{children:[P.model,P.multilingual?` (multilingual)`:` (English-only)`]})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Mode`}),(0,G.jsx)(`td`,{children:P.translated?`translate → English`:`transcribe (source language)`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Source hint`}),(0,G.jsx)(`td`,{children:P.sourceHint||`auto-detect`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Detected language`}),(0,G.jsx)(`td`,{children:P.response.language||`(unknown)`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Audio duration`}),(0,G.jsx)(`td`,{children:Iv(P.response.duration)})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Wall time`}),(0,G.jsx)(`td`,{children:Iv(P.wallMs/1e3)})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:Y(`Realtime factor`,`translatorRealtimeFactor`)}),(0,G.jsx)(`td`,{children:ce>0?`${ce.toFixed(2)}×`:`—`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Segments`}),(0,G.jsx)(`td`,{children:P.response.segments.length})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Words / chars`}),(0,G.jsxs)(`td`,{children:[oe,` / `,se]})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Input`}),(0,G.jsxs)(`td`,{children:[P.inputName,` · `,Fv(P.inputSize),` · `,P.inputSource]})]})]})}),(0,G.jsxs)(`button`,{type:`button`,className:`btn-link`,onClick:()=>L(e=>!e),children:[I?`▼`:`▶`,` Segments (`,P.response.segments.length,`)`]}),I&&(0,G.jsxs)(`table`,{className:`translator-segments`,children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{children:`#`}),(0,G.jsx)(`th`,{children:`Start`}),(0,G.jsx)(`th`,{children:`End`}),(0,G.jsx)(`th`,{children:`Text`}),(0,G.jsx)(`th`,{children:Y(`No-speech`,`translatorNoSpeechProb`)})]})}),(0,G.jsx)(`tbody`,{children:P.response.segments.map(e=>(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:e.id}),(0,G.jsx)(`td`,{children:Iv(e.start)}),(0,G.jsx)(`td`,{children:Iv(e.end)}),(0,G.jsx)(`td`,{children:e.text.trim()}),(0,G.jsx)(`td`,{children:e.no_speech_prob.toFixed(3)})]},e.id))})]})]})]})}var Uv=`kronk_image_generator_model`,Wv=26214400;function Gv(e){return e<1048576?`${Math.ceil(e/1024)} KB`:e<1073741824?`${(e/1048576).toFixed(0)} MB`:`${(e/1073741824).toFixed(2)} GB`}function Kv(){let[e,t]=(0,x.useState)([]),[n,r]=(0,x.useState)(!0),[i,a]=(0,x.useState)(null),[o,s]=(0,x.useState)(()=>localStorage.getItem(Uv)||``),[c,l]=(0,x.useState)(``),[u,d]=(0,x.useState)(`text`),[f,p]=(0,x.useState)(null),[m,h]=(0,x.useState)(!1),[g,_]=(0,x.useState)(``),[v,y]=(0,x.useState)(``),[b,S]=(0,x.useState)(20),[C,w]=(0,x.useState)(7),[T,E]=(0,x.useState)(0),[D,O]=(0,x.useState)(.75),[k,A]=(0,x.useState)(!1),[j,M]=(0,x.useState)(null),[N,P]=(0,x.useState)(null),[F,I]=(0,x.useState)(null),[L,R]=(0,x.useState)(!1),[z,ee]=(0,x.useState)(null),B=(0,x.useRef)(null),V=(0,x.useCallback)(async()=>{r(!0),a(null);try{let e=await W.listMalinaModels();t((e.models??[]).filter(e=>e.basic_text_to_image))}catch(e){a(e.message),t([])}finally{r(!1)}},[]);(0,x.useEffect)(()=>{V()},[V]),(0,x.useEffect)(()=>W.streamImageProgress(e=>{R(!0),ee(null),e.status===`progress`&&I(e)},e=>{R(!1),ee(e)}),[]),(0,x.useEffect)(()=>{e.length!==0&&(e.some(e=>e.id===o)||s(e[0].id))},[e,o]),(0,x.useEffect)(()=>{o&&localStorage.setItem(Uv,o)},[o]),(0,x.useEffect)(()=>()=>{f&&URL.revokeObjectURL(f.objectURL)},[f]);let te=(0,x.useMemo)(()=>e.find(e=>e.id===o),[e,o]),H=N?.data[0],ne=!!o&&!!c.trim()&&(u===`text`||!!f)&&!k,re=(0,x.useCallback)(e=>{if(e.type!==`image/png`&&e.type!==`image/jpeg`){M(`Source image must be a PNG or JPEG.`);return}if(e.size>Wv){M(`Source image exceeds the 25 MB limit.`);return}p({file:e,objectURL:URL.createObjectURL(e)}),M(null),P(null)},[]),ie=(0,x.useCallback)(()=>{p(null),P(null)},[]),ae=(0,x.useCallback)(async e=>{if(e.preventDefault(),ne){A(!0),M(null),P(null),I(null);try{let e={model:o,prompt:c.trim(),negative_prompt:g.trim()||void 0,size:v||void 0,steps:b,cfg_scale:C,seed:T<=0?-1:T};u===`image`&&f?(e.strength=D,P(await W.editImage(e,f.file))):P(await W.generateImage(e))}catch(e){M(e.message)}finally{A(!1)}}},[ne,C,u,g,c,T,o,v,f,b,D]),oe=(0,x.useCallback)(()=>{if(!H)return;let e=document.createElement(`a`);e.href=`data:image/png;base64,${H.b64_json}`,e.download=`${o}-${H.seed}.png`,document.body.appendChild(e),e.click(),document.body.removeChild(e)},[H,o]);return(0,G.jsxs)(`div`,{className:`image-generator-page`,children:[(0,G.jsxs)(`div`,{className:`page-header`,children:[(0,G.jsx)(`h2`,{children:`Image Generator`}),(0,G.jsx)(`p`,{children:`Generate a PNG from a text prompt using an installed Malina model.`})]}),i&&(0,G.jsxs)(`div`,{className:`alert alert-error`,children:[`Failed to load Malina models: `,i]}),!n&&e.length===0&&!i&&(0,G.jsxs)(`div`,{className:`alert alert-error`,children:[`No Malina models installed. Install one with `,(0,G.jsx)(`code`,{children:`kronk malina model pull --local sd-1.5`}),`.`]}),(0,G.jsxs)(`div`,{className:`image-generator-grid`,children:[(0,G.jsxs)(`form`,{className:`image-generator-card`,onSubmit:ae,children:[(0,G.jsx)(`h3`,{children:`Generate`}),(0,G.jsx)(X,{tooltipKey:`imageGeneratorMode`,children:`Mode`}),(0,G.jsxs)(`div`,{className:`image-generator-mode`,role:`group`,"aria-label":`Generation mode`,children:[(0,G.jsx)(`button`,{className:`btn ${u===`text`?`btn-primary`:`btn-secondary`}`,type:`button`,onClick:()=>d(`text`),disabled:k,children:`Text to image`}),(0,G.jsx)(`button`,{className:`btn ${u===`image`?`btn-primary`:`btn-secondary`}`,type:`button`,onClick:()=>d(`image`),disabled:k,children:`Image to image`})]}),(0,G.jsx)(X,{htmlFor:`image-generator-model`,tooltipKey:`imageGeneratorModel`,children:`Model`}),(0,G.jsxs)(`select`,{id:`image-generator-model`,className:`form-select`,value:o,onChange:e=>s(e.target.value),disabled:n||e.length===0||k,children:[n&&(0,G.jsx)(`option`,{children:`Loading…`}),!n&&e.length===0&&(0,G.jsx)(`option`,{children:`No models available`}),e.map(e=>(0,G.jsx)(`option`,{value:e.id,children:e.id},e.id))]}),te&&(0,G.jsxs)(`p`,{className:`image-generator-model-info`,children:[te.description,` (`,Gv(te.size),`)`]}),u===`image`&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(X,{tooltipKey:`imageGeneratorSource`,children:`Source image`}),f?(0,G.jsxs)(`div`,{className:`image-generator-source-preview`,children:[(0,G.jsx)(`img`,{src:f.objectURL,alt:`Source`}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:f.file.name}),(0,G.jsx)(`span`,{children:Gv(f.file.size)}),(0,G.jsx)(`button`,{className:`btn-link`,type:`button`,onClick:ie,children:`remove`})]})]}):(0,G.jsxs)(`div`,{className:`image-generator-drop ${m?`image-generator-drop-over`:``}`,onDragOver:e=>{e.preventDefault(),h(!0)},onDragLeave:()=>h(!1),onDrop:e=>{e.preventDefault(),h(!1);let t=e.dataTransfer.files?.[0];t&&re(t)},onClick:()=>B.current?.click(),children:[(0,G.jsx)(`strong`,{children:`Drop a PNG or JPEG here`}),(0,G.jsx)(`span`,{children:`or click to choose an image`})]}),(0,G.jsx)(`input`,{ref:B,type:`file`,accept:`image/png,image/jpeg`,hidden:!0,onChange:e=>{let t=e.target.files?.[0];t&&re(t),e.target.value=``}})]}),(0,G.jsx)(X,{htmlFor:`image-generator-prompt`,tooltipKey:`imageGeneratorPrompt`,children:`Prompt`}),(0,G.jsx)(`textarea`,{id:`image-generator-prompt`,className:`image-generator-prompt`,rows:7,value:c,onChange:e=>l(e.target.value),placeholder:`A lighthouse on a rocky coast at sunset`,disabled:k}),(0,G.jsxs)(`details`,{className:`image-generator-settings`,children:[(0,G.jsx)(`summary`,{children:`Generation settings`}),(0,G.jsx)(X,{htmlFor:`image-generator-negative-prompt`,tooltipKey:`imageGeneratorNegativePrompt`,children:`Negative prompt`}),(0,G.jsx)(`textarea`,{id:`image-generator-negative-prompt`,className:`image-generator-prompt`,rows:3,value:g,onChange:e=>_(e.target.value),placeholder:`blurry, distorted, artifacts`,disabled:k}),(0,G.jsx)(X,{htmlFor:`image-generator-size`,tooltipKey:`imageGeneratorSize`,children:`Size`}),(0,G.jsxs)(`select`,{id:`image-generator-size`,className:`form-select`,value:v,onChange:e=>y(e.target.value),disabled:k,children:[(0,G.jsx)(`option`,{value:``,children:`Automatic`}),(0,G.jsx)(`option`,{value:`512x512`,children:`512×512`}),(0,G.jsx)(`option`,{value:`768x512`,children:`768×512`}),(0,G.jsx)(`option`,{value:`512x768`,children:`512×768`}),(0,G.jsx)(`option`,{value:`1024x1024`,children:`1024×1024`})]}),(0,G.jsxs)(`div`,{className:`image-generator-settings-grid`,children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(X,{htmlFor:`image-generator-steps`,tooltipKey:`imageGeneratorSteps`,children:`Steps`}),(0,G.jsx)(`input`,{id:`image-generator-steps`,className:`form-input`,type:`number`,min:1,max:1e3,value:b,onChange:e=>S(Number(e.target.value)),disabled:k})]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(X,{htmlFor:`image-generator-cfg`,tooltipKey:`imageGeneratorCFGScale`,children:`CFG scale`}),(0,G.jsx)(`input`,{id:`image-generator-cfg`,className:`form-input`,type:`number`,min:.1,step:.1,value:C,onChange:e=>w(Number(e.target.value)),disabled:k})]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(X,{htmlFor:`image-generator-seed`,tooltipKey:`imageGeneratorSeed`,children:`Seed (≤ 0 = random)`}),(0,G.jsx)(`input`,{id:`image-generator-seed`,className:`form-input`,type:`number`,step:1,value:T,onChange:e=>E(Number(e.target.value)),disabled:k})]}),u===`image`&&(0,G.jsxs)(`div`,{children:[(0,G.jsx)(X,{htmlFor:`image-generator-strength`,tooltipKey:`imageGeneratorStrength`,children:`Strength`}),(0,G.jsx)(`input`,{id:`image-generator-strength`,className:`form-input`,type:`number`,min:.01,max:1,step:.01,value:D,onChange:e=>O(Number(e.target.value)),disabled:k})]})]})]}),(0,G.jsx)(`button`,{className:`btn btn-primary`,type:`submit`,disabled:!ne,children:k?`Generating…`:u===`image`?`Transform Image`:`Generate Image`}),j&&(0,G.jsx)(`div`,{className:`alert alert-error`,children:j})]}),(0,G.jsxs)(`section`,{className:`image-generator-card image-generator-preview`,children:[(0,G.jsxs)(`div`,{className:`image-generator-preview-header`,children:[(0,G.jsx)(`h3`,{children:`Result`}),H&&(0,G.jsx)(`button`,{className:`btn btn-secondary`,type:`button`,onClick:oe,children:`Download PNG`})]}),(0,G.jsxs)(`div`,{className:`image-generator-progress`,role:`status`,"aria-live":`polite`,children:[(0,G.jsxs)(`div`,{className:`image-generator-progress-header`,children:[(0,G.jsx)(`strong`,{children:`Global Malina activity`}),(0,G.jsx)(`span`,{children:F?.percent===void 0?L?`Listening`:`Unavailable`:`${F.percent.toFixed(+(F.percent<10))}%`})]}),(0,G.jsx)(`progress`,{max:100,value:F?.percent??0}),(0,G.jsxs)(`small`,{children:[F&&F.step!==void 0&&F.steps!==void 0?`Latest update: ${F.step} / ${F.steps}${F.seconds_per_step?` · ${F.seconds_per_step.toFixed(2)} s/step`:``}. `:z?`${z}. `:`Waiting for model loading or generation progress. `,`This server-wide feed is not tied to this request.`]})]}),k&&(0,G.jsx)(`div`,{className:`image-generator-empty`,children:`Generating image…`}),!k&&!H&&(0,G.jsx)(`div`,{className:`image-generator-empty`,children:`Your generated image will appear here.`}),H&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`img`,{className:`image-generator-image`,src:`data:image/png;base64,${H.b64_json}`,alt:c.trim()||`Generated image`}),(0,G.jsxs)(`div`,{className:`image-generator-meta`,children:[(0,G.jsxs)(`span`,{children:[H.width,`×`,H.height]}),H.seed>=0&&(0,G.jsxs)(`span`,{children:[`Seed `,H.seed]})]})]})]})]})]})}function qv(){return(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{className:`page-header`,children:[(0,G.jsx)(`h2`,{children:`SDK Documentation`}),(0,G.jsx)(`p`,{children:`Documentation for the Kronk SDK`})]}),(0,G.jsx)(`div`,{className:`card`,children:(0,G.jsxs)(`div`,{className:`empty-state`,children:[(0,G.jsx)(`h3`,{children:`🚧 Under Construction`}),(0,G.jsx)(`p`,{children:`SDK documentation is coming soon.`})]})})]})}function Jv(){let e=at();return(0,x.useEffect)(()=>{let t=document.querySelector(`.main-content`);if(!t)return;if(!e.hash){t.scrollTo({top:0});return}let n=e.hash.slice(1);requestAnimationFrame(()=>{let e=document.getElementById(n);if(!e)return;let r=t.getBoundingClientRect(),i=e.getBoundingClientRect().top-r.top+t.scrollTop;t.scrollTo({top:i-20,behavior:`smooth`})})},[e.key,e.hash]),(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{className:`page-header`,children:[(0,G.jsx)(`h2`,{children:`Kronk Package`}),(0,G.jsx)(`p`,{children:`Package kronk provides support for working with models using llama.cpp via yzma.`})]}),(0,G.jsxs)(`div`,{className:`doc-layout`,children:[(0,G.jsxs)(`div`,{className:`doc-content`,children:[(0,G.jsxs)(`div`,{className:`card`,children:[(0,G.jsx)(`h3`,{children:`Import`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`import "github.com/ardanlabs/kronk/sdk/kronk"`})})]}),(0,G.jsxs)(`div`,{className:`card`,id:`functions`,children:[(0,G.jsx)(`h3`,{children:`Functions`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-autotuneconfig`,children:[(0,G.jsx)(`h4`,{children:`AutoTuneConfig`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func AutoTuneConfig(ctx context.Context, cfg model.Config) model.Config`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`AutoTuneConfig seeds unset settings from a hardware-aware analysis of the model and returns the resulting Config. It uses the same shared models.AutoTune logic as the model pool so the SDK and pool seed defaults identically; the only SDK-specific part is preserving all settings outside AutoTune's ownership. On any failure the original cfg is returned unchanged so auto-tune never blocks a load.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-init`,children:[(0,G.jsx)(`h4`,{children:`Init`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func Init(opts ...InitOption) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Init initializes the Kronk backend support. If initialization fails, subsequent calls will retry, allowing libraries to be downloaded and loaded without restarting the server.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-initialized`,children:[(0,G.jsx)(`h4`,{children:`Initialized`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func Initialized() bool`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Initialized reports whether the Kronk backend has been successfully initialized. This can be used to determine if the server is running in a degraded state due to missing libraries.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-setfmtloggertraceid`,children:[(0,G.jsx)(`h4`,{children:`SetFmtLoggerTraceID`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func SetFmtLoggerTraceID(ctx context.Context, traceID string) context.Context`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`SetFmtLoggerTraceID allows you to set a trace id in the content that can be part of the output of the FmtLogger.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-new`,children:[(0,G.jsx)(`h4`,{children:`New`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func New(opts ...model.Option) (*Kronk, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`New provides the ability to use models in a concurrently safe way.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-newwithcontext`,children:[(0,G.jsx)(`h4`,{children:`NewWithContext`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func NewWithContext(ctx context.Context, opts ...model.Option) (*Kronk, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`NewWithContext provides the ability to use models in a concurrently safe way. The context is used to support logging trace ids during model loading.`})]})]}),(0,G.jsxs)(`div`,{className:`card`,id:`types`,children:[(0,G.jsx)(`h3`,{children:`Types`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-incompletedetail`,children:[(0,G.jsx)(`h4`,{children:`IncompleteDetail`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`type IncompleteDetail struct {
+`)}`}function Vv(e,t,n){let r=new Blob([t],{type:n}),i=URL.createObjectURL(r),a=document.createElement(`a`);a.href=i,a.download=e,document.body.appendChild(a),a.click(),document.body.removeChild(a),URL.revokeObjectURL(i)}function Hv(){let[e,t]=(0,x.useState)([]),[n,r]=(0,x.useState)(!0),[i,a]=(0,x.useState)(null),[o,s]=(0,x.useState)(()=>localStorage.getItem(Nv)||``),[c,l]=(0,x.useState)(null),[u,d]=(0,x.useState)(``),[f,p]=(0,x.useState)(!1),[m,h]=(0,x.useState)(``),[g,_]=(0,x.useState)(null),[v,y]=(0,x.useState)(!1),b=(0,x.useRef)(null),[S,C]=(0,x.useState)(!1),[w,T]=(0,x.useState)(0),E=(0,x.useRef)(null),D=(0,x.useRef)([]),O=(0,x.useRef)(null),k=(0,x.useRef)(0),[A,j]=(0,x.useState)(!1),[M,N]=(0,x.useState)(null),[P,F]=(0,x.useState)(null),[I,L]=(0,x.useState)(!1),R=(0,x.useCallback)(async()=>{r(!0),a(null);try{let e=await W.listBuckyModels();t(e.models??[])}catch(e){a(e.message),t([])}finally{r(!1)}},[]);(0,x.useEffect)(()=>{R()},[R]),(0,x.useEffect)(()=>{e.length!==0&&(e.some(e=>e.id===o)||s(e[0].id))},[e,o]),(0,x.useEffect)(()=>{if(!o){l(null);return}localStorage.setItem(Nv,o);let e=!1;return W.getBuckyModelDetails(o).then(t=>{e||l(t)}).catch(()=>{e||l(null)}),()=>{e=!0}},[o]);let z=(0,x.useMemo)(()=>c?c.is_multilingual:!Pv(o),[c,o]);(0,x.useEffect)(()=>{z||(f&&p(!1),u&&u!==`en`&&d(``))},[z,f,u]);let ee=(0,x.useCallback)(e=>{_(t=>(t&&URL.revokeObjectURL(t.objectURL),e))},[]);(0,x.useEffect)(()=>()=>{g&&URL.revokeObjectURL(g.objectURL)},[]);let B=(0,x.useCallback)(e=>{ee({blob:e,filename:e.name,size:e.size,source:`file`,objectURL:URL.createObjectURL(e)}),F(null),N(null)},[ee]),V=(0,x.useCallback)(e=>{let t=e.target.files?.[0];t&&B(t),e.target.value=``},[B]),te=(0,x.useCallback)(e=>{e.preventDefault(),y(!1);let t=e.dataTransfer.files?.[0];t&&B(t)},[B]),H=(0,x.useCallback)(()=>{let e=E.current;e&&e.state!==`inactive`&&e.stop(),O.current!==null&&(window.clearInterval(O.current),O.current=null)},[]),ne=(0,x.useCallback)(async()=>{N(null);try{let e=await navigator.mediaDevices.getUserMedia({audio:!0}),t=new MediaRecorder(e);E.current=t,D.current=[],t.ondataavailable=e=>{e.data.size>0&&D.current.push(e.data)},t.onstop=()=>{e.getTracks().forEach(e=>e.stop());let n=new Blob(D.current,{type:t.mimeType||`audio/webm`}),r=(t.mimeType||`audio/webm`).includes(`ogg`)?`ogg`:`webm`;ee({blob:n,filename:`mic-${new Date().toISOString().replace(/[:.]/g,`-`)}.${r}`,size:n.size,source:`mic`,objectURL:URL.createObjectURL(n)}),C(!1),T(0),E.current=null},k.current=Date.now(),t.start(),C(!0),F(null),T(0),O.current=window.setInterval(()=>{let e=(Date.now()-k.current)/1e3;T(e),e>=Mv&&H()},100)}catch(e){N(`Microphone error: ${e.message}`)}},[ee,H]);(0,x.useEffect)(()=>()=>{H()},[H]);let re=!!o&&!!g&&!A&&!S,ie=(0,x.useCallback)(async()=>{if(!g||!o)return;j(!0),N(null),F(null);let e=performance.now();try{let t=await W.transcribe(o,g.blob,{filename:g.filename,language:u||void 0,translate:f||void 0,prompt:m||void 0}),n=performance.now()-e;F({response:t,wallMs:n,model:o,multilingual:z,translated:!!f,sourceHint:u,inputName:g.filename,inputSize:g.size,inputSource:g.source})}catch(e){N(e.message)}finally{j(!1)}},[g,o,u,f,m,z]),ae=(0,x.useCallback)(()=>{ee(null),F(null),N(null)},[ee]),oe=P?P.response.text.trim().split(/\s+/).filter(Boolean).length:0,se=P?P.response.text.length:0,ce=P&&P.wallMs>0?P.response.duration*1e3/P.wallMs:0;return(0,G.jsxs)(`div`,{className:`translator-page`,children:[(0,G.jsxs)(`div`,{className:`page-header`,children:[(0,G.jsx)(`h2`,{children:`Translator`}),(0,G.jsxs)(`p`,{children:[`Transcribe speech to text or translate non-English speech into English using whisper.cpp. Upload an audio file or record up to `,Mv,` seconds from your microphone.`]})]}),i&&(0,G.jsxs)(`div`,{className:`alert alert-error`,children:[`Failed to load whisper models: `,i]}),!n&&e.length===0&&(0,G.jsxs)(`div`,{className:`alert alert-error`,children:[`No whisper models installed. Go to `,(0,G.jsx)(`strong`,{children:`Bucky → Models → List`}),` to download one.`]}),(0,G.jsxs)(`div`,{className:`translator-grid`,children:[(0,G.jsxs)(`section`,{className:`translator-card`,children:[(0,G.jsx)(`h3`,{children:`Settings`}),(0,G.jsx)(X,{htmlFor:`translator-model`,tooltipKey:`translatorModel`,children:`Model`}),(0,G.jsxs)(`select`,{id:`translator-model`,className:`form-select`,value:o,onChange:e=>s(e.target.value),disabled:n||e.length===0,children:[n&&(0,G.jsx)(`option`,{children:`Loading…`}),!n&&e.length===0&&(0,G.jsx)(`option`,{children:`No models available`}),e.map(e=>(0,G.jsxs)(`option`,{value:e.id,children:[e.id,Pv(e.id)?` (English-only)`:``]},e.id))]}),(0,G.jsx)(X,{htmlFor:`translator-language`,tooltipKey:`translatorSourceLanguage`,children:`Source language`}),(0,G.jsx)(`select`,{id:`translator-language`,className:`form-select`,value:u,onChange:e=>d(e.target.value),disabled:!z,children:jv.map(e=>(0,G.jsx)(`option`,{value:e.code,children:e.label},e.code))}),(0,G.jsxs)(X,{tooltipKey:`translatorTranslate`,children:[(0,G.jsx)(`input`,{type:`checkbox`,checked:f,onChange:e=>p(e.target.checked),disabled:!z}),` `,`Translate to English`]}),(0,G.jsx)(X,{htmlFor:`translator-prompt`,tooltipKey:`translatorPrompt`,children:`Decoder prompt (optional)`}),(0,G.jsx)(`textarea`,{id:`translator-prompt`,className:`translator-textarea`,rows:3,value:m,onChange:e=>h(e.target.value),placeholder:`e.g. proper nouns or technical terms to bias spelling`})]}),(0,G.jsxs)(`section`,{className:`translator-card`,children:[(0,G.jsx)(`h3`,{children:`Audio input`}),(0,G.jsxs)(`div`,{className:`translator-drop ${v?`translator-drop-over`:``}`,onDragOver:e=>{e.preventDefault(),y(!0)},onDragLeave:()=>y(!1),onDrop:te,onClick:()=>b.current?.click(),children:[(0,G.jsx)(`div`,{className:`translator-drop-icon`,children:`🎵`}),(0,G.jsx)(`div`,{children:`Drop audio file here or click to choose`}),(0,G.jsx)(`input`,{ref:b,type:`file`,accept:`audio/*`,style:{display:`none`},onChange:V})]}),(0,G.jsx)(`div`,{className:`translator-mic-row`,children:S?(0,G.jsxs)(`button`,{type:`button`,className:`btn btn-primary`,onClick:H,children:[`■ Stop recording (`,w.toFixed(1),`s / `,Mv,`s)`]}):(0,G.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:ne,disabled:A,children:`● Record from microphone`})}),g&&(0,G.jsxs)(`div`,{className:`translator-input-preview`,children:[(0,G.jsxs)(`div`,{className:`translator-input-meta`,children:[(0,G.jsx)(`strong`,{children:g.filename}),(0,G.jsx)(`span`,{className:`translator-input-source`,children:g.source===`mic`?`microphone`:`file`}),(0,G.jsx)(`span`,{children:Fv(g.size)}),(0,G.jsx)(`button`,{type:`button`,className:`btn-link`,onClick:ae,children:`remove`})]}),(0,G.jsx)(`audio`,{src:g.objectURL,controls:!0,className:`translator-audio`})]}),(0,G.jsx)(`div`,{className:`translator-submit-row`,children:(0,G.jsx)(`button`,{type:`button`,className:`btn btn-primary`,onClick:ie,disabled:!re,children:A?`Working…`:f?`Translate`:`Transcribe`})}),M&&(0,G.jsx)(`div`,{className:`alert alert-error`,children:M})]})]}),P&&(0,G.jsxs)(`section`,{className:`translator-card translator-result`,children:[(0,G.jsxs)(`div`,{className:`translator-result-header`,children:[(0,G.jsx)(`h3`,{children:P.translated?`Translation`:`Transcription`}),(0,G.jsxs)(`div`,{className:`translator-result-actions`,children:[(0,G.jsx)(`button`,{type:`button`,className:`btn btn-secondary btn-sm`,onClick:()=>navigator.clipboard.writeText(P.response.text),children:`Copy`}),(0,G.jsx)(`button`,{type:`button`,className:`btn btn-secondary btn-sm`,onClick:()=>Vv(`transcript.txt`,P.response.text,`text/plain`),children:`.txt`}),(0,G.jsx)(`button`,{type:`button`,className:`btn btn-secondary btn-sm`,onClick:()=>Vv(`transcript.srt`,zv(P.response),`application/x-subrip`),children:`.srt`}),(0,G.jsx)(`button`,{type:`button`,className:`btn btn-secondary btn-sm`,onClick:()=>Vv(`transcript.vtt`,Bv(P.response),`text/vtt`),children:`.vtt`})]})]}),(0,G.jsx)(`pre`,{className:`translator-text`,children:P.response.text||`(empty)`}),(0,G.jsx)(`table`,{className:`translator-meta`,children:(0,G.jsxs)(`tbody`,{children:[(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Model`}),(0,G.jsxs)(`td`,{children:[P.model,P.multilingual?` (multilingual)`:` (English-only)`]})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Mode`}),(0,G.jsx)(`td`,{children:P.translated?`translate → English`:`transcribe (source language)`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Source hint`}),(0,G.jsx)(`td`,{children:P.sourceHint||`auto-detect`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Detected language`}),(0,G.jsx)(`td`,{children:P.response.language||`(unknown)`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Audio duration`}),(0,G.jsx)(`td`,{children:Iv(P.response.duration)})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Wall time`}),(0,G.jsx)(`td`,{children:Iv(P.wallMs/1e3)})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:Y(`Realtime factor`,`translatorRealtimeFactor`)}),(0,G.jsx)(`td`,{children:ce>0?`${ce.toFixed(2)}×`:`—`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Segments`}),(0,G.jsx)(`td`,{children:P.response.segments.length})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Words / chars`}),(0,G.jsxs)(`td`,{children:[oe,` / `,se]})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Input`}),(0,G.jsxs)(`td`,{children:[P.inputName,` · `,Fv(P.inputSize),` · `,P.inputSource]})]})]})}),(0,G.jsxs)(`button`,{type:`button`,className:`btn-link`,onClick:()=>L(e=>!e),children:[I?`▼`:`▶`,` Segments (`,P.response.segments.length,`)`]}),I&&(0,G.jsxs)(`table`,{className:`translator-segments`,children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{children:`#`}),(0,G.jsx)(`th`,{children:`Start`}),(0,G.jsx)(`th`,{children:`End`}),(0,G.jsx)(`th`,{children:`Text`}),(0,G.jsx)(`th`,{children:Y(`No-speech`,`translatorNoSpeechProb`)})]})}),(0,G.jsx)(`tbody`,{children:P.response.segments.map(e=>(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:e.id}),(0,G.jsx)(`td`,{children:Iv(e.start)}),(0,G.jsx)(`td`,{children:Iv(e.end)}),(0,G.jsx)(`td`,{children:e.text.trim()}),(0,G.jsx)(`td`,{children:e.no_speech_prob.toFixed(3)})]},e.id))})]})]})]})}var Uv=`kronk_image_generator_model`,Wv=26214400;function Gv(e){return e<1048576?`${Math.ceil(e/1024)} KB`:e<1073741824?`${(e/1048576).toFixed(0)} MB`:`${(e/1073741824).toFixed(2)} GB`}function Kv(){let[e,t]=(0,x.useState)([]),[n,r]=(0,x.useState)(!0),[i,a]=(0,x.useState)(null),[o,s]=(0,x.useState)(()=>localStorage.getItem(Uv)||``),[c,l]=(0,x.useState)(``),[u,d]=(0,x.useState)(`text`),[f,p]=(0,x.useState)(null),[m,h]=(0,x.useState)(!1),[g,_]=(0,x.useState)(``),[v,y]=(0,x.useState)(``),[b,S]=(0,x.useState)(20),[C,w]=(0,x.useState)(7),[T,E]=(0,x.useState)(0),[D,O]=(0,x.useState)(.75),[k,A]=(0,x.useState)(!1),[j,M]=(0,x.useState)(null),[N,P]=(0,x.useState)(null),[F,I]=(0,x.useState)(null),[L,R]=(0,x.useState)(!1),[z,ee]=(0,x.useState)(null),B=(0,x.useRef)(null),V=(0,x.useCallback)(async()=>{r(!0),a(null);try{let e=await W.listMalinaModels();t((e.models??[]).filter(e=>e.basic_text_to_image))}catch(e){a(e.message),t([])}finally{r(!1)}},[]);(0,x.useEffect)(()=>{V()},[V]),(0,x.useEffect)(()=>W.streamImageProgress(e=>{R(!0),ee(null),e.status===`progress`&&I(e)},e=>{R(!1),ee(e)}),[]),(0,x.useEffect)(()=>{e.length!==0&&(e.some(e=>e.id===o)||s(e[0].id))},[e,o]),(0,x.useEffect)(()=>{o&&localStorage.setItem(Uv,o)},[o]),(0,x.useEffect)(()=>()=>{f&&URL.revokeObjectURL(f.objectURL)},[f]);let te=(0,x.useMemo)(()=>e.find(e=>e.id===o),[e,o]),H=N?.data[0],ne=!!o&&!!c.trim()&&(u===`text`||!!f)&&!k,re=(0,x.useCallback)(e=>{if(e.type!==`image/png`&&e.type!==`image/jpeg`){M(`Source image must be a PNG or JPEG.`);return}if(e.size>Wv){M(`Source image exceeds the 25 MB limit.`);return}p({file:e,objectURL:URL.createObjectURL(e)}),M(null),P(null)},[]),ie=(0,x.useCallback)(()=>{p(null),P(null)},[]),ae=(0,x.useCallback)(async e=>{if(e.preventDefault(),ne){A(!0),M(null),P(null),I(null);try{let e={model:o,prompt:c.trim(),negative_prompt:g.trim()||void 0,size:v||void 0,steps:b,cfg_scale:C,seed:T<=0?-1:T};u===`image`&&f?(e.strength=D,P(await W.editImage(e,f.file))):P(await W.generateImage(e))}catch(e){M(e.message)}finally{A(!1)}}},[ne,C,u,g,c,T,o,v,f,b,D]),oe=(0,x.useCallback)(()=>{if(!H)return;let e=document.createElement(`a`);e.href=`data:image/png;base64,${H.b64_json}`,e.download=`${o}-${H.seed}.png`,document.body.appendChild(e),e.click(),document.body.removeChild(e)},[H,o]);return(0,G.jsxs)(`div`,{className:`image-generator-page`,children:[(0,G.jsxs)(`div`,{className:`page-header`,children:[(0,G.jsx)(`h2`,{children:`Image Generator`}),(0,G.jsx)(`p`,{children:`Generate a PNG from a text prompt using an installed Malina model.`})]}),i&&(0,G.jsxs)(`div`,{className:`alert alert-error`,children:[`Failed to load Malina models: `,i]}),!n&&e.length===0&&!i&&(0,G.jsxs)(`div`,{className:`alert alert-error`,children:[`No Malina models installed. Install one with `,(0,G.jsx)(`code`,{children:`kronk malina model pull --local sd-1.5`}),`.`]}),(0,G.jsxs)(`div`,{className:`image-generator-grid`,children:[(0,G.jsxs)(`form`,{className:`image-generator-card`,onSubmit:ae,children:[(0,G.jsx)(`h3`,{children:`Generate`}),(0,G.jsx)(X,{tooltipKey:`imageGeneratorMode`,children:`Mode`}),(0,G.jsxs)(`div`,{className:`image-generator-mode`,role:`group`,"aria-label":`Generation mode`,children:[(0,G.jsx)(`button`,{className:`btn ${u===`text`?`btn-primary`:`btn-secondary`}`,type:`button`,onClick:()=>d(`text`),disabled:k,children:`Text to image`}),(0,G.jsx)(`button`,{className:`btn ${u===`image`?`btn-primary`:`btn-secondary`}`,type:`button`,onClick:()=>d(`image`),disabled:k,children:`Image to image`})]}),(0,G.jsx)(X,{htmlFor:`image-generator-model`,tooltipKey:`imageGeneratorModel`,children:`Model`}),(0,G.jsxs)(`select`,{id:`image-generator-model`,className:`form-select`,value:o,onChange:e=>s(e.target.value),disabled:n||e.length===0||k,children:[n&&(0,G.jsx)(`option`,{children:`Loading…`}),!n&&e.length===0&&(0,G.jsx)(`option`,{children:`No models available`}),e.map(e=>(0,G.jsx)(`option`,{value:e.id,children:e.id},e.id))]}),te&&(0,G.jsxs)(`p`,{className:`image-generator-model-info`,children:[te.description,` (`,Gv(te.size),`)`]}),u===`image`&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(X,{tooltipKey:`imageGeneratorSource`,children:`Source image`}),f?(0,G.jsxs)(`div`,{className:`image-generator-source-preview`,children:[(0,G.jsx)(`img`,{src:f.objectURL,alt:`Source`}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:f.file.name}),(0,G.jsx)(`span`,{children:Gv(f.file.size)}),(0,G.jsx)(`button`,{className:`btn-link`,type:`button`,onClick:ie,children:`remove`})]})]}):(0,G.jsxs)(`div`,{className:`image-generator-drop ${m?`image-generator-drop-over`:``}`,onDragOver:e=>{e.preventDefault(),h(!0)},onDragLeave:()=>h(!1),onDrop:e=>{e.preventDefault(),h(!1);let t=e.dataTransfer.files?.[0];t&&re(t)},onClick:()=>B.current?.click(),children:[(0,G.jsx)(`strong`,{children:`Drop a PNG or JPEG here`}),(0,G.jsx)(`span`,{children:`or click to choose an image`})]}),(0,G.jsx)(`input`,{ref:B,type:`file`,accept:`image/png,image/jpeg`,hidden:!0,onChange:e=>{let t=e.target.files?.[0];t&&re(t),e.target.value=``}})]}),(0,G.jsx)(X,{htmlFor:`image-generator-prompt`,tooltipKey:`imageGeneratorPrompt`,children:`Prompt`}),(0,G.jsx)(`textarea`,{id:`image-generator-prompt`,className:`image-generator-prompt`,rows:7,value:c,onChange:e=>l(e.target.value),placeholder:`A lighthouse on a rocky coast at sunset`,disabled:k}),(0,G.jsxs)(`details`,{className:`image-generator-settings`,children:[(0,G.jsx)(`summary`,{children:`Generation settings`}),(0,G.jsx)(X,{htmlFor:`image-generator-negative-prompt`,tooltipKey:`imageGeneratorNegativePrompt`,children:`Negative prompt`}),(0,G.jsx)(`textarea`,{id:`image-generator-negative-prompt`,className:`image-generator-prompt`,rows:3,value:g,onChange:e=>_(e.target.value),placeholder:`blurry, distorted, artifacts`,disabled:k}),(0,G.jsx)(X,{htmlFor:`image-generator-size`,tooltipKey:`imageGeneratorSize`,children:`Size`}),(0,G.jsxs)(`select`,{id:`image-generator-size`,className:`form-select`,value:v,onChange:e=>y(e.target.value),disabled:k,children:[(0,G.jsx)(`option`,{value:``,children:`Automatic`}),(0,G.jsx)(`option`,{value:`512x512`,children:`512×512`}),(0,G.jsx)(`option`,{value:`768x512`,children:`768×512`}),(0,G.jsx)(`option`,{value:`512x768`,children:`512×768`}),(0,G.jsx)(`option`,{value:`1024x1024`,children:`1024×1024`})]}),(0,G.jsxs)(`div`,{className:`image-generator-settings-grid`,children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(X,{htmlFor:`image-generator-steps`,tooltipKey:`imageGeneratorSteps`,children:`Steps`}),(0,G.jsx)(`input`,{id:`image-generator-steps`,className:`form-input`,type:`number`,min:1,max:1e3,value:b,onChange:e=>S(Number(e.target.value)),disabled:k})]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(X,{htmlFor:`image-generator-cfg`,tooltipKey:`imageGeneratorCFGScale`,children:`CFG scale`}),(0,G.jsx)(`input`,{id:`image-generator-cfg`,className:`form-input`,type:`number`,min:.1,step:.1,value:C,onChange:e=>w(Number(e.target.value)),disabled:k})]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(X,{htmlFor:`image-generator-seed`,tooltipKey:`imageGeneratorSeed`,children:`Seed (≤ 0 = random)`}),(0,G.jsx)(`input`,{id:`image-generator-seed`,className:`form-input`,type:`number`,step:1,value:T,onChange:e=>E(Number(e.target.value)),disabled:k})]}),u===`image`&&(0,G.jsxs)(`div`,{children:[(0,G.jsx)(X,{htmlFor:`image-generator-strength`,tooltipKey:`imageGeneratorStrength`,children:`Strength`}),(0,G.jsx)(`input`,{id:`image-generator-strength`,className:`form-input`,type:`number`,min:.01,max:1,step:.01,value:D,onChange:e=>O(Number(e.target.value)),disabled:k})]})]})]}),(0,G.jsx)(`button`,{className:`btn btn-primary`,type:`submit`,disabled:!ne,children:k?`Generating…`:u===`image`?`Transform Image`:`Generate Image`}),j&&(0,G.jsx)(`div`,{className:`alert alert-error`,children:j})]}),(0,G.jsxs)(`section`,{className:`image-generator-card image-generator-preview`,children:[(0,G.jsxs)(`div`,{className:`image-generator-preview-header`,children:[(0,G.jsx)(`h3`,{children:`Result`}),H&&(0,G.jsx)(`button`,{className:`btn btn-secondary`,type:`button`,onClick:oe,children:`Download PNG`})]}),(0,G.jsxs)(`div`,{className:`image-generator-progress`,role:`status`,"aria-live":`polite`,children:[(0,G.jsxs)(`div`,{className:`image-generator-progress-header`,children:[(0,G.jsx)(`strong`,{children:`Global Malina activity`}),(0,G.jsx)(`span`,{children:F?.percent===void 0?L?`Listening`:`Unavailable`:`${F.percent.toFixed(+(F.percent<10))}%`})]}),(0,G.jsx)(`progress`,{max:100,value:F?.percent??0}),(0,G.jsxs)(`small`,{children:[F&&F.step!==void 0&&F.steps!==void 0?`Latest update: ${F.step} / ${F.steps}${F.seconds_per_step?` · ${F.seconds_per_step.toFixed(2)} s/step`:``}. `:z?`${z}. `:`Waiting for model loading or generation progress. `,`This server-wide feed is not tied to this request.`]})]}),k&&(0,G.jsx)(`div`,{className:`image-generator-empty`,children:`Generating image…`}),!k&&!H&&(0,G.jsx)(`div`,{className:`image-generator-empty`,children:`Your generated image will appear here.`}),H&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`img`,{className:`image-generator-image`,src:`data:image/png;base64,${H.b64_json}`,alt:c.trim()||`Generated image`}),(0,G.jsxs)(`div`,{className:`image-generator-meta`,children:[(0,G.jsxs)(`span`,{children:[H.width,`×`,H.height]}),H.seed>=0&&(0,G.jsxs)(`span`,{children:[`Seed `,H.seed]})]})]})]})]})]})}function qv(){return(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{className:`page-header`,children:[(0,G.jsx)(`h2`,{children:`SDK Documentation`}),(0,G.jsx)(`p`,{children:`Documentation for the Kronk SDK`})]}),(0,G.jsx)(`div`,{className:`card`,children:(0,G.jsxs)(`div`,{className:`empty-state`,children:[(0,G.jsx)(`h3`,{children:`🚧 Under Construction`}),(0,G.jsx)(`p`,{children:`SDK documentation is coming soon.`})]})})]})}function Jv(){let e=at();return(0,x.useEffect)(()=>{let t=document.querySelector(`.main-content`);if(!t)return;if(!e.hash){t.scrollTo({top:0});return}let n=e.hash.slice(1);requestAnimationFrame(()=>{let e=document.getElementById(n);if(!e)return;let r=t.getBoundingClientRect(),i=e.getBoundingClientRect().top-r.top+t.scrollTop;t.scrollTo({top:i-20,behavior:`smooth`})})},[e.key,e.hash]),(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{className:`page-header`,children:[(0,G.jsx)(`h2`,{children:`Kronk Package`}),(0,G.jsx)(`p`,{children:`Package kronk provides support for working with models using llama.cpp via yzma.`})]}),(0,G.jsxs)(`div`,{className:`doc-layout`,children:[(0,G.jsxs)(`div`,{className:`doc-content`,children:[(0,G.jsxs)(`div`,{className:`card`,children:[(0,G.jsx)(`h3`,{children:`Import`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`import "github.com/ardanlabs/kronk/sdk/kronk"`})})]}),(0,G.jsxs)(`div`,{className:`card`,id:`functions`,children:[(0,G.jsx)(`h3`,{children:`Functions`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-autotuneconfig`,children:[(0,G.jsx)(`h4`,{children:`AutoTuneConfig`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func AutoTuneConfig(ctx context.Context, cfg model.Config) model.Config`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`AutoTuneConfig seeds unset settings from a hardware-aware analysis of the model and returns the resulting Config. It uses the same shared models.AutoTune logic as the model pool so the SDK and pool seed defaults identically; the only SDK-specific part is preserving all settings outside AutoTune's ownership. On any failure the original cfg is returned unchanged so auto-tune never blocks a load.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-autotuneconfigwithbudget`,children:[(0,G.jsx)(`h4`,{children:`AutoTuneConfigWithBudget`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func AutoTuneConfigWithBudget(ctx context.Context, cfg model.Config, budget models.AutoTuneBudget) model.Config`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`AutoTuneConfigWithBudget seeds unset settings using a stable memory budget. Pool callers use this so custom loads honor the same resource-manager limits as catalog-driven loads.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-init`,children:[(0,G.jsx)(`h4`,{children:`Init`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func Init(opts ...InitOption) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Init initializes the Kronk backend support. If initialization fails, subsequent calls will retry, allowing libraries to be downloaded and loaded without restarting the server.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-initialized`,children:[(0,G.jsx)(`h4`,{children:`Initialized`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func Initialized() bool`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Initialized reports whether the Kronk backend has been successfully initialized. This can be used to determine if the server is running in a degraded state due to missing libraries.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-setfmtloggertraceid`,children:[(0,G.jsx)(`h4`,{children:`SetFmtLoggerTraceID`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func SetFmtLoggerTraceID(ctx context.Context, traceID string) context.Context`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`SetFmtLoggerTraceID allows you to set a trace id in the content that can be part of the output of the FmtLogger.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-new`,children:[(0,G.jsx)(`h4`,{children:`New`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func New(opts ...model.Option) (*Kronk, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`New provides the ability to use models in a concurrently safe way.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-newwithcontext`,children:[(0,G.jsx)(`h4`,{children:`NewWithContext`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func NewWithContext(ctx context.Context, opts ...model.Option) (*Kronk, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`NewWithContext provides the ability to use models in a concurrently safe way. The context is used to support logging trace ids during model loading.`})]})]}),(0,G.jsxs)(`div`,{className:`card`,id:`types`,children:[(0,G.jsx)(`h3`,{children:`Types`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-incompletedetail`,children:[(0,G.jsx)(`h4`,{children:`IncompleteDetail`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`type IncompleteDetail struct {
Reason string \`json:"reason"\`
}`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`IncompleteDetail provides details about why a response is incomplete.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-initoption`,children:[(0,G.jsx)(`h4`,{children:`InitOption`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`type InitOption func(*initOptions)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`InitOption represents options for configuring Init.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-inputtokensdetails`,children:[(0,G.jsx)(`h4`,{children:`InputTokensDetails`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`type InputTokensDetails struct {
CachedTokens int \`json:"cached_tokens"\`
@@ -224,7 +224,7 @@ kronk server start`})]})]})}function Is(e){let t=/^([\d.]+)\s*(MB|GB|KB|B)?$/i.e
}`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ResponseTextFormat specifies the text format configuration.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-responseusage`,children:[(0,G.jsx)(`h4`,{children:`ResponseUsage`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:'type ResponseUsage struct {\n InputTokens int `json:"input_tokens"`\n InputTokensDetails InputTokensDetails `json:"input_tokens_details"`\n OutputTokens int `json:"output_tokens"`\n OutputTokenDetail OutputTokensDetails `json:"output_tokens_details"`\n TotalTokens int `json:"total_tokens"`\n}'})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ResponseUsage contains token usage information.`})]})]}),(0,G.jsxs)(`div`,{className:`card`,id:`methods`,children:[(0,G.jsx)(`h3`,{children:`Methods`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-kronk-activestreams`,children:[(0,G.jsx)(`h4`,{children:`Kronk.ActiveStreams`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (krn *Kronk) ActiveStreams() int`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ActiveStreams returns the number of active streams.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-kronk-batchenginesnapshot`,children:[(0,G.jsx)(`h4`,{children:`Kronk.BatchEngineSnapshot`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (krn *Kronk) BatchEngineSnapshot() (model.BatchEngineSnapshot, bool)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`BatchEngineSnapshot returns the latest generation scheduler state. Models used only for embeddings or reranking do not expose a batch engine.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-kronk-chat`,children:[(0,G.jsx)(`h4`,{children:`Kronk.Chat`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (krn *Kronk) Chat(ctx context.Context, d model.D) (model.ChatResponse, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Chat provides support to interact with an inference model. For text models, NSeqMax controls parallel sequence processing within a single model instance. For vision/audio models, NSeqMax creates multiple model instances in a pool for concurrent request handling.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-kronk-chatstreaming`,children:[(0,G.jsx)(`h4`,{children:`Kronk.ChatStreaming`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (krn *Kronk) ChatStreaming(ctx context.Context, d model.D) (<-chan model.ChatResponse, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ChatStreaming provides support to interact with an inference model. For text models, NSeqMax controls parallel sequence processing within a single model instance. For vision/audio models, NSeqMax creates multiple model instances in a pool for concurrent request handling. When stream_options.include_usage is true, the terminal choice is followed by a usage response with an empty Choices slice.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-kronk-chatstreaminghttp`,children:[(0,G.jsx)(`h4`,{children:`Kronk.ChatStreamingHTTP`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (krn *Kronk) ChatStreamingHTTP(ctx context.Context, w http.ResponseWriter, d model.D) (model.ChatResponse, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ChatStreamingHTTP provides http handler support for a chat/completions call. For text models, NSeqMax controls parallel sequence processing within a single model instance. For vision/audio models, NSeqMax creates multiple model instances in a pool for concurrent request handling.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-kronk-decision`,children:[(0,G.jsx)(`h4`,{children:`Kronk.Decision`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (krn *Kronk) Decision(ctx context.Context, req model.DecisionRequest) (model.DecisionResponse, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Decision evaluates typed questions against shared state using a supported decision model.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-kronk-decisionhttp`,children:[(0,G.jsx)(`h4`,{children:`Kronk.DecisionHTTP`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (krn *Kronk) DecisionHTTP(ctx context.Context, log Logger, w http.ResponseWriter, req model.DecisionRequest) (model.DecisionResponse, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`DecisionHTTP provides HTTP handler support for a decision call.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-kronk-embeddings`,children:[(0,G.jsx)(`h4`,{children:`Kronk.Embeddings`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (krn *Kronk) Embeddings(ctx context.Context, d model.D) (model.EmbedReponse, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Embeddings provides support to interact with an embedding model.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Supported options in d: - input (string): the text to embed (required) - truncate (bool): if true, truncate input to fit context window (default: false) - truncate_direction (string): "right" (default) or "left" - dimensions (int): reduce output to first N dimensions (for Matryoshka models)`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Each model instance processes calls sequentially (llama.cpp only supports sequence 0 for embedding extraction). Use NSeqMax > 1 to create multiple model instances for concurrent request handling. Batch multiple texts in the input parameter for better performance within a single request.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-kronk-embeddingshttp`,children:[(0,G.jsx)(`h4`,{children:`Kronk.EmbeddingsHTTP`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (krn *Kronk) EmbeddingsHTTP(ctx context.Context, log Logger, w http.ResponseWriter, d model.D) (model.EmbedReponse, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`EmbeddingsHTTP provides http handler support for an embeddings call.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-kronk-imcsessions`,children:[(0,G.jsx)(`h4`,{children:`Kronk.IMCSessions`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (krn *Kronk) IMCSessions() []model.IMCSessionDetail`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`IMCSessions returns the current state of the model's allocated IMC cache entries. An unloaded model has no sessions.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-kronk-imcsystemcaches`,children:[(0,G.jsx)(`h4`,{children:`Kronk.IMCSystemCaches`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (krn *Kronk) IMCSystemCaches() []model.IMCSystemCacheDetail`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`IMCSystemCaches returns the model's immutable System cache pool entries.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-kronk-modelconfig`,children:[(0,G.jsx)(`h4`,{children:`Kronk.ModelConfig`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (krn *Kronk) ModelConfig() model.Config`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ModelConfig returns a copy of the configuration being used. This may be different from the configuration passed to New() if the model has overridden any of the settings.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-kronk-modelid`,children:[(0,G.jsx)(`h4`,{children:`Kronk.ModelID`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (krn *Kronk) ModelID() string`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ModelID returns the identifier emitted by public inference responses.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-kronk-modelinfo`,children:[(0,G.jsx)(`h4`,{children:`Kronk.ModelInfo`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (krn *Kronk) ModelInfo() model.ModelInfo`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ModelInfo returns the model information.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-kronk-rerank`,children:[(0,G.jsx)(`h4`,{children:`Kronk.Rerank`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (krn *Kronk) Rerank(ctx context.Context, d model.D) (model.RerankResponse, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Rerank provides support to interact with a reranker model.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Supported options in d: - query (string): the query to rank documents against (required) - documents ([]string): the documents to rank (required) - top_n (int): return only the top N results (optional, default: all) - return_documents (bool): include document text in results (default: false)`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Each model instance processes calls sequentially (llama.cpp only supports sequence 0 for rerank extraction). Use NSeqMax > 1 to create multiple model instances for concurrent request handling. Batch multiple texts in the input parameter for better performance within a single request.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-kronk-rerankhttp`,children:[(0,G.jsx)(`h4`,{children:`Kronk.RerankHTTP`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (krn *Kronk) RerankHTTP(ctx context.Context, log Logger, w http.ResponseWriter, d model.D) (model.RerankResponse, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`RerankHTTP provides http handler support for a rerank call.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-kronk-response`,children:[(0,G.jsx)(`h4`,{children:`Kronk.Response`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (krn *Kronk) Response(ctx context.Context, d model.D) (ResponseResponse, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Response provides support to interact with an inference model. For text models, NSeqMax controls parallel sequence processing within a single model instance. For vision/audio models, NSeqMax creates multiple model instances in a pool for concurrent request handling.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-kronk-responsestreaming`,children:[(0,G.jsx)(`h4`,{children:`Kronk.ResponseStreaming`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (krn *Kronk) ResponseStreaming(ctx context.Context, d model.D) (<-chan ResponseStreamEvent, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ResponseStreaming provides streaming support for the Responses API. For text models, NSeqMax controls parallel sequence processing within a single model instance. For vision/audio models, NSeqMax creates multiple model instances in a pool for concurrent request handling.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-kronk-responsestreaminghttp`,children:[(0,G.jsx)(`h4`,{children:`Kronk.ResponseStreamingHTTP`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (krn *Kronk) ResponseStreamingHTTP(ctx context.Context, w http.ResponseWriter, d model.D) (ResponseResponse, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ResponseStreamingHTTP provides http handler support for a responses call. For text models, NSeqMax controls parallel sequence processing within a single model instance. For vision/audio models, NSeqMax creates multiple model instances in a pool for concurrent request handling.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-kronk-systeminfo`,children:[(0,G.jsx)(`h4`,{children:`Kronk.SystemInfo`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (krn *Kronk) SystemInfo() map[string]string`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`SystemInfo returns system information.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-kronk-tokenize`,children:[(0,G.jsx)(`h4`,{children:`Kronk.Tokenize`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (krn *Kronk) Tokenize(ctx context.Context, d model.D) (model.TokenizeResponse, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Tokenize returns the token count for a text input.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Supported options in d: - input (string): the text to tokenize (required) - apply_template (bool): if true, wrap input as a user message and apply the model's chat template before tokenizing (default: false) - add_generation_prompt (bool): when apply_template is true, controls whether the assistant role prefix is appended to the prompt (default: true)`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`When apply_template is true, the returned count includes all template overhead (role markers, separators, generation prompt). This reflects the actual number of tokens that would be fed to the model.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-kronk-tokenizehttp`,children:[(0,G.jsx)(`h4`,{children:`Kronk.TokenizeHTTP`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (krn *Kronk) TokenizeHTTP(ctx context.Context, log Logger, w http.ResponseWriter, d model.D) (model.TokenizeResponse, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`TokenizeHTTP provides http handler support for a tokenize call.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-kronk-unload`,children:[(0,G.jsx)(`h4`,{children:`Kronk.Unload`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (krn *Kronk) Unload(ctx context.Context) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Unload will close down the loaded model. You should call this only when you are completely done using Kronk.`})]})]}),(0,G.jsxs)(`div`,{className:`card`,id:`constants`,children:[(0,G.jsx)(`h3`,{children:`Constants`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`const-logsilent`,children:[(0,G.jsx)(`h4`,{children:`LogSilent`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`const (
LogSilent = applog.LogSilent
LogNormal = applog.LogNormal
-)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Set of logging levels supported by llama.cpp.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`const-version`,children:[(0,G.jsx)(`h4`,{children:`Version`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`const Version = "1.32.8-rc1"`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:"Version contains the current version of the kronk package. Bump this in the same commit that prepares a `v` release tag — CI guards the release pipeline (.github/workflows/release.yaml and docker.yml, via .github/scripts/check-version.sh) and refuses to publish a tag whose value does not match this constant."})]})]}),(0,G.jsxs)(`div`,{className:`card`,id:`variables`,children:[(0,G.jsx)(`h3`,{children:`Variables`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`var-discardlogger`,children:[(0,G.jsx)(`h4`,{children:`DiscardLogger`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`var DiscardLogger = applog.DiscardLogger`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`DiscardLogger discards logging.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`var-erradmissiontimeout`,children:[(0,G.jsx)(`h4`,{children:`ErrAdmissionTimeout`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`var ErrAdmissionTimeout = errors.New("admission timeout")`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ErrAdmissionTimeout indicates that a request could not obtain an admission permit within the configured admission timeout.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`var-errresponsecommitted`,children:[(0,G.jsx)(`h4`,{children:`ErrResponseCommitted`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`var ErrResponseCommitted = errors.New("response already committed")`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ErrResponseCommitted indicates that an HTTP streaming response was already committed before the operation failed.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`var-fmtlogger`,children:[(0,G.jsx)(`h4`,{children:`FmtLogger`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`var FmtLogger = applog.FmtLogger`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`FmtLogger provides a basic logger that writes to stdout.`})]})]})]}),(0,G.jsx)(`nav`,{className:`doc-sidebar`,children:(0,G.jsxs)(`div`,{className:`doc-sidebar-content`,children:[(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#functions`,className:`doc-index-header`,children:`Functions`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-autotuneconfig`,children:`AutoTuneConfig`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-init`,children:`Init`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-initialized`,children:`Initialized`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-setfmtloggertraceid`,children:`SetFmtLoggerTraceID`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-new`,children:`New`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-newwithcontext`,children:`NewWithContext`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#types`,className:`doc-index-header`,children:`Types`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-incompletedetail`,children:`IncompleteDetail`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-initoption`,children:`InitOption`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-inputtokensdetails`,children:`InputTokensDetails`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-kronk`,children:`Kronk`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-loglevel`,children:`LogLevel`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-logger`,children:`Logger`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-outputtokensdetails`,children:`OutputTokensDetails`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-responsecontentitem`,children:`ResponseContentItem`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-responseerror`,children:`ResponseError`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-responseformattype`,children:`ResponseFormatType`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-responseoutputitem`,children:`ResponseOutputItem`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-responsereasoning`,children:`ResponseReasoning`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-responseresponse`,children:`ResponseResponse`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-responsestreamevent`,children:`ResponseStreamEvent`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-responsetextformat`,children:`ResponseTextFormat`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-responseusage`,children:`ResponseUsage`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#methods`,className:`doc-index-header`,children:`Methods`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-activestreams`,children:`Kronk.ActiveStreams`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-batchenginesnapshot`,children:`Kronk.BatchEngineSnapshot`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-chat`,children:`Kronk.Chat`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-chatstreaming`,children:`Kronk.ChatStreaming`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-chatstreaminghttp`,children:`Kronk.ChatStreamingHTTP`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-decision`,children:`Kronk.Decision`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-decisionhttp`,children:`Kronk.DecisionHTTP`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-embeddings`,children:`Kronk.Embeddings`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-embeddingshttp`,children:`Kronk.EmbeddingsHTTP`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-imcsessions`,children:`Kronk.IMCSessions`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-imcsystemcaches`,children:`Kronk.IMCSystemCaches`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-modelconfig`,children:`Kronk.ModelConfig`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-modelid`,children:`Kronk.ModelID`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-modelinfo`,children:`Kronk.ModelInfo`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-rerank`,children:`Kronk.Rerank`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-rerankhttp`,children:`Kronk.RerankHTTP`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-response`,children:`Kronk.Response`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-responsestreaming`,children:`Kronk.ResponseStreaming`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-responsestreaminghttp`,children:`Kronk.ResponseStreamingHTTP`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-systeminfo`,children:`Kronk.SystemInfo`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-tokenize`,children:`Kronk.Tokenize`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-tokenizehttp`,children:`Kronk.TokenizeHTTP`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-unload`,children:`Kronk.Unload`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#constants`,className:`doc-index-header`,children:`Constants`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#const-logsilent`,children:`LogSilent`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#const-version`,children:`Version`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#variables`,className:`doc-index-header`,children:`Variables`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#var-discardlogger`,children:`DiscardLogger`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#var-erradmissiontimeout`,children:`ErrAdmissionTimeout`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#var-errresponsecommitted`,children:`ErrResponseCommitted`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#var-fmtlogger`,children:`FmtLogger`})})]})]})]})})]})]})}function Yv(){let e=at();return(0,x.useEffect)(()=>{let t=document.querySelector(`.main-content`);if(!t)return;if(!e.hash){t.scrollTo({top:0});return}let n=e.hash.slice(1);requestAnimationFrame(()=>{let e=document.getElementById(n);if(!e)return;let r=t.getBoundingClientRect(),i=e.getBoundingClientRect().top-r.top+t.scrollTop;t.scrollTo({top:i-20,behavior:`smooth`})})},[e.key,e.hash]),(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{className:`page-header`,children:[(0,G.jsx)(`h2`,{children:`Model Package`}),(0,G.jsx)(`p`,{children:`Package model provides the low-level api for working with models. This is an internal package and should not be used directly. If you use this package directly you are on your own. The project reserves the right to break this API.`})]}),(0,G.jsxs)(`div`,{className:`doc-layout`,children:[(0,G.jsxs)(`div`,{className:`doc-content`,children:[(0,G.jsxs)(`div`,{className:`card`,children:[(0,G.jsx)(`h3`,{children:`Import`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`import "github.com/ardanlabs/kronk/sdk/kronk/model"`})})]}),(0,G.jsxs)(`div`,{className:`card`,id:`functions`,children:[(0,G.jsx)(`h3`,{children:`Functions`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-addparams`,children:[(0,G.jsx)(`h4`,{children:`AddParams`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func AddParams(params Params, d D)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`AddParams adds the values from the Params struct into the provided D map. Only non-zero values are added.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-inityzmaworkarounds`,children:[(0,G.jsx)(`h4`,{children:`InitYzmaWorkarounds`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func InitYzmaWorkarounds(_ string) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`InitYzmaWorkarounds initializes Kronk-specific Yzma compatibility code.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-recurrentstatecopies`,children:[(0,G.jsx)(`h4`,{children:`RecurrentStateCopies`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func RecurrentStateCopies(cfg Config, embeddedMTP bool) int64`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`RecurrentStateCopies returns the number of current and rollback recurrent state planes allocated for the configured speculative-decoding mode. embeddedMTP selects the auto-detected MTP path; false selects an explicit separate drafter or companion MTP file.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-registerparser`,children:[(0,G.jsx)(`h4`,{children:`RegisterParser`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func RegisterParser(f ParserFactory)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`RegisterParser appends a parser factory to the registry. Call once per parser at server bootstrap, before any models are loaded. Order matters: the catch-all parser (fallback) must be registered last so the more specific parsers get first chance to claim.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-speculativecontextcount`,children:[(0,G.jsx)(`h4`,{children:`SpeculativeContextCount`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func SpeculativeContextCount(cfg Config) int64`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`SpeculativeContextCount returns the native contexts known from configuration before the target GGUF metadata is inspected. A companion MTP model creates a second target-shaped context. A separate classic drafter is estimated from its own GGUF, while embedded MTP is detected from the target's NextN metadata.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-validatechatrequest`,children:[(0,G.jsx)(`h4`,{children:`ValidateChatRequest`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func ValidateChatRequest(d D) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ValidateChatRequest validates the fields in a chat request document.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-validatemessages`,children:[(0,G.jsx)(`h4`,{children:`ValidateMessages`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func ValidateMessages(d D) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ValidateMessages validates the messages field of a chat document.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-newgrammarsampler`,children:[(0,G.jsx)(`h4`,{children:`NewGrammarSampler`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func NewGrammarSampler(vocab llama.Vocab, grammar string) *grammarSampler`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`NewGrammarSampler creates a grammar sampler that will be managed separately from the main sampler chain.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-verifyartifact`,children:[(0,G.jsx)(`h4`,{children:`VerifyArtifact`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func VerifyArtifact(modelFile string, digest ArtifactDigest, previous *ArtifactVerification, checkSHA bool) (ArtifactVerification, bool, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`VerifyArtifact checks modelFile against parsed integrity values. It reads the artifact itself but performs no sidecar I/O. The returned bool reports whether a new verification was produced and should be persisted by the caller.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-parsedecisionprotocol`,children:[(0,G.jsx)(`h4`,{children:`ParseDecisionProtocol`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func ParseDecisionProtocol(value string) (DecisionProtocol, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ParseDecisionProtocol parses value and returns the corresponding DecisionProtocol when it exists.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-parseggmltype`,children:[(0,G.jsx)(`h4`,{children:`ParseGGMLType`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func ParseGGMLType(s string) (GGMLType, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ParseGGMLType parses a string into a GGMLType. Supported values: "f32", "f16", "q4_0", "q4_1", "q5_0", "q5_1", "q8_0", "bf16", "auto".`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-parseloadmode`,children:[(0,G.jsx)(`h4`,{children:`ParseLoadMode`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func ParseLoadMode(s string) (LoadMode, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ParseLoadMode parses a string into a LoadMode.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-parsemoemode`,children:[(0,G.jsx)(`h4`,{children:`ParseMoEMode`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func ParseMoEMode(value string) (MoEMode, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ParseMoEMode parses value and returns the corresponding MoEMode when it exists.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-newmodel`,children:[(0,G.jsx)(`h4`,{children:`NewModel`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func NewModel(ctx context.Context, cfg Config) (*Model, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`NewModel loads a model from the GGUF files specified in cfg and returns a *Model ready to serve requests. It validates the configuration, builds llama.cpp model parameters, applies NUMA settings, performs the actual GGUF load (serialized via a process-wide mutex to guard the GGML_OP_OFFLOAD_MIN_BATCH env var), computes VRAM/KV diagnostics, retrieves the chat template, and initializes the per-model runtime — either the sequence-batch runtime or context-pool fallback for embed/rerank models, or a batch engine plus parser plugin and optional draft model for generation models.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`The returned *Model owns the underlying llama.Model, llama.Context, KV memory, batch engine, and (when configured) draft model; release them via Model.Unload when finished.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-detectmodeltypefromfiles`,children:[(0,G.jsx)(`h4`,{children:`DetectModelTypeFromFiles`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func DetectModelTypeFromFiles(modelFiles []string) (ModelType, string, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`DetectModelTypeFromFiles loads a model from the given GGUF files, determines the architecture type, and immediately frees the model. It returns the ModelType, the raw general.architecture string from the GGUF metadata, and any error encountered during loading.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-parseropescalingtype`,children:[(0,G.jsx)(`h4`,{children:`ParseRopeScalingType`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func ParseRopeScalingType(s string) (RopeScalingType, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ParseRopeScalingType parses a string into a RopeScalingType. Supported values: "none", "linear", "yarn".`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-parsesplitmode`,children:[(0,G.jsx)(`h4`,{children:`ParseSplitMode`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func ParseSplitMode(s string) (SplitMode, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ParseSplitMode parses a string into a SplitMode. Supported values are "none", "layer", "row", and "tensor".`})]})]}),(0,G.jsxs)(`div`,{className:`card`,id:`types`,children:[(0,G.jsx)(`h3`,{children:`Types`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-adapterconfig`,children:[(0,G.jsx)(`h4`,{children:`AdapterConfig`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`type AdapterConfig struct {
+)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Set of logging levels supported by llama.cpp.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`const-version`,children:[(0,G.jsx)(`h4`,{children:`Version`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`const Version = "1.32.8-rc1"`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:"Version contains the current version of the kronk package. Bump this in the same commit that prepares a `v` release tag — CI guards the release pipeline (.github/workflows/release.yaml and docker.yml, via .github/scripts/check-version.sh) and refuses to publish a tag whose value does not match this constant."})]})]}),(0,G.jsxs)(`div`,{className:`card`,id:`variables`,children:[(0,G.jsx)(`h3`,{children:`Variables`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`var-discardlogger`,children:[(0,G.jsx)(`h4`,{children:`DiscardLogger`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`var DiscardLogger = applog.DiscardLogger`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`DiscardLogger discards logging.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`var-erradmissiontimeout`,children:[(0,G.jsx)(`h4`,{children:`ErrAdmissionTimeout`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`var ErrAdmissionTimeout = errors.New("admission timeout")`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ErrAdmissionTimeout indicates that a request could not obtain an admission permit within the configured admission timeout.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`var-errresponsecommitted`,children:[(0,G.jsx)(`h4`,{children:`ErrResponseCommitted`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`var ErrResponseCommitted = errors.New("response already committed")`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ErrResponseCommitted indicates that an HTTP streaming response was already committed before the operation failed.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`var-fmtlogger`,children:[(0,G.jsx)(`h4`,{children:`FmtLogger`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`var FmtLogger = applog.FmtLogger`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`FmtLogger provides a basic logger that writes to stdout.`})]})]})]}),(0,G.jsx)(`nav`,{className:`doc-sidebar`,children:(0,G.jsxs)(`div`,{className:`doc-sidebar-content`,children:[(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#functions`,className:`doc-index-header`,children:`Functions`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-autotuneconfig`,children:`AutoTuneConfig`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-autotuneconfigwithbudget`,children:`AutoTuneConfigWithBudget`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-init`,children:`Init`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-initialized`,children:`Initialized`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-setfmtloggertraceid`,children:`SetFmtLoggerTraceID`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-new`,children:`New`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-newwithcontext`,children:`NewWithContext`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#types`,className:`doc-index-header`,children:`Types`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-incompletedetail`,children:`IncompleteDetail`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-initoption`,children:`InitOption`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-inputtokensdetails`,children:`InputTokensDetails`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-kronk`,children:`Kronk`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-loglevel`,children:`LogLevel`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-logger`,children:`Logger`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-outputtokensdetails`,children:`OutputTokensDetails`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-responsecontentitem`,children:`ResponseContentItem`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-responseerror`,children:`ResponseError`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-responseformattype`,children:`ResponseFormatType`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-responseoutputitem`,children:`ResponseOutputItem`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-responsereasoning`,children:`ResponseReasoning`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-responseresponse`,children:`ResponseResponse`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-responsestreamevent`,children:`ResponseStreamEvent`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-responsetextformat`,children:`ResponseTextFormat`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-responseusage`,children:`ResponseUsage`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#methods`,className:`doc-index-header`,children:`Methods`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-activestreams`,children:`Kronk.ActiveStreams`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-batchenginesnapshot`,children:`Kronk.BatchEngineSnapshot`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-chat`,children:`Kronk.Chat`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-chatstreaming`,children:`Kronk.ChatStreaming`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-chatstreaminghttp`,children:`Kronk.ChatStreamingHTTP`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-decision`,children:`Kronk.Decision`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-decisionhttp`,children:`Kronk.DecisionHTTP`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-embeddings`,children:`Kronk.Embeddings`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-embeddingshttp`,children:`Kronk.EmbeddingsHTTP`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-imcsessions`,children:`Kronk.IMCSessions`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-imcsystemcaches`,children:`Kronk.IMCSystemCaches`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-modelconfig`,children:`Kronk.ModelConfig`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-modelid`,children:`Kronk.ModelID`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-modelinfo`,children:`Kronk.ModelInfo`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-rerank`,children:`Kronk.Rerank`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-rerankhttp`,children:`Kronk.RerankHTTP`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-response`,children:`Kronk.Response`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-responsestreaming`,children:`Kronk.ResponseStreaming`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-responsestreaminghttp`,children:`Kronk.ResponseStreamingHTTP`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-systeminfo`,children:`Kronk.SystemInfo`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-tokenize`,children:`Kronk.Tokenize`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-tokenizehttp`,children:`Kronk.TokenizeHTTP`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-kronk-unload`,children:`Kronk.Unload`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#constants`,className:`doc-index-header`,children:`Constants`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#const-logsilent`,children:`LogSilent`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#const-version`,children:`Version`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#variables`,className:`doc-index-header`,children:`Variables`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#var-discardlogger`,children:`DiscardLogger`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#var-erradmissiontimeout`,children:`ErrAdmissionTimeout`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#var-errresponsecommitted`,children:`ErrResponseCommitted`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#var-fmtlogger`,children:`FmtLogger`})})]})]})]})})]})]})}function Yv(){let e=at();return(0,x.useEffect)(()=>{let t=document.querySelector(`.main-content`);if(!t)return;if(!e.hash){t.scrollTo({top:0});return}let n=e.hash.slice(1);requestAnimationFrame(()=>{let e=document.getElementById(n);if(!e)return;let r=t.getBoundingClientRect(),i=e.getBoundingClientRect().top-r.top+t.scrollTop;t.scrollTo({top:i-20,behavior:`smooth`})})},[e.key,e.hash]),(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{className:`page-header`,children:[(0,G.jsx)(`h2`,{children:`Model Package`}),(0,G.jsx)(`p`,{children:`Package model provides the low-level api for working with models. This is an internal package and should not be used directly. If you use this package directly you are on your own. The project reserves the right to break this API.`})]}),(0,G.jsxs)(`div`,{className:`doc-layout`,children:[(0,G.jsxs)(`div`,{className:`doc-content`,children:[(0,G.jsxs)(`div`,{className:`card`,children:[(0,G.jsx)(`h3`,{children:`Import`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`import "github.com/ardanlabs/kronk/sdk/kronk/model"`})})]}),(0,G.jsxs)(`div`,{className:`card`,id:`functions`,children:[(0,G.jsx)(`h3`,{children:`Functions`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-addparams`,children:[(0,G.jsx)(`h4`,{children:`AddParams`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func AddParams(params Params, d D)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`AddParams adds the values from the Params struct into the provided D map. Only non-zero values are added.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-inityzmaworkarounds`,children:[(0,G.jsx)(`h4`,{children:`InitYzmaWorkarounds`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func InitYzmaWorkarounds(_ string) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`InitYzmaWorkarounds initializes Kronk-specific Yzma compatibility code.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-recurrentstatecopies`,children:[(0,G.jsx)(`h4`,{children:`RecurrentStateCopies`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func RecurrentStateCopies(cfg Config, embeddedMTP bool) int64`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`RecurrentStateCopies returns the number of current and rollback recurrent state planes allocated for the configured speculative-decoding mode. embeddedMTP selects the auto-detected MTP path; false selects an explicit separate drafter or companion MTP file.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-registerparser`,children:[(0,G.jsx)(`h4`,{children:`RegisterParser`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func RegisterParser(f ParserFactory)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`RegisterParser appends a parser factory to the registry. Call once per parser at server bootstrap, before any models are loaded. Order matters: the catch-all parser (fallback) must be registered last so the more specific parsers get first chance to claim.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-speculativecontextcount`,children:[(0,G.jsx)(`h4`,{children:`SpeculativeContextCount`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func SpeculativeContextCount(cfg Config) int64`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`SpeculativeContextCount returns the native contexts known from configuration before the target GGUF metadata is inspected. A companion MTP model creates a second target-shaped context. A separate classic drafter is estimated from its own GGUF, while embedded MTP is detected from the target's NextN metadata.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-validatechatrequest`,children:[(0,G.jsx)(`h4`,{children:`ValidateChatRequest`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func ValidateChatRequest(d D) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ValidateChatRequest validates the fields in a chat request document.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-validatemessages`,children:[(0,G.jsx)(`h4`,{children:`ValidateMessages`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func ValidateMessages(d D) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ValidateMessages validates the messages field of a chat document.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-newgrammarsampler`,children:[(0,G.jsx)(`h4`,{children:`NewGrammarSampler`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func NewGrammarSampler(vocab llama.Vocab, grammar string) *grammarSampler`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`NewGrammarSampler creates a grammar sampler that will be managed separately from the main sampler chain.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-verifyartifact`,children:[(0,G.jsx)(`h4`,{children:`VerifyArtifact`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func VerifyArtifact(modelFile string, digest ArtifactDigest, previous *ArtifactVerification, checkSHA bool) (ArtifactVerification, bool, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`VerifyArtifact checks modelFile against parsed integrity values. It reads the artifact itself but performs no sidecar I/O. The returned bool reports whether a new verification was produced and should be persisted by the caller.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-parsedecisionprotocol`,children:[(0,G.jsx)(`h4`,{children:`ParseDecisionProtocol`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func ParseDecisionProtocol(value string) (DecisionProtocol, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ParseDecisionProtocol parses value and returns the corresponding DecisionProtocol when it exists.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-parseggmltype`,children:[(0,G.jsx)(`h4`,{children:`ParseGGMLType`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func ParseGGMLType(s string) (GGMLType, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ParseGGMLType parses a string into a GGMLType. Supported values: "f32", "f16", "q4_0", "q4_1", "q5_0", "q5_1", "q8_0", "bf16", "auto".`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-parseloadmode`,children:[(0,G.jsx)(`h4`,{children:`ParseLoadMode`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func ParseLoadMode(s string) (LoadMode, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ParseLoadMode parses a string into a LoadMode.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-parsemoemode`,children:[(0,G.jsx)(`h4`,{children:`ParseMoEMode`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func ParseMoEMode(value string) (MoEMode, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ParseMoEMode parses value and returns the corresponding MoEMode when it exists.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-newmodel`,children:[(0,G.jsx)(`h4`,{children:`NewModel`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func NewModel(ctx context.Context, cfg Config) (*Model, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`NewModel loads a model from the GGUF files specified in cfg and returns a *Model ready to serve requests. It validates the configuration, builds llama.cpp model parameters, applies NUMA settings, performs the actual GGUF load, computes VRAM/KV diagnostics, retrieves the chat template, and initializes the per-model runtime — either the sequence-batch runtime or context-pool fallback for embed/rerank models, or a batch engine plus parser plugin and optional draft model for generation models.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`The returned *Model owns the underlying llama.Model, llama.Context, KV memory, batch engine, and (when configured) draft model; release them via Model.Unload when finished.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-detectmodeltypefromfiles`,children:[(0,G.jsx)(`h4`,{children:`DetectModelTypeFromFiles`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func DetectModelTypeFromFiles(modelFiles []string) (ModelType, string, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`DetectModelTypeFromFiles loads a model from the given GGUF files, determines the architecture type, and immediately frees the model. It returns the ModelType, the raw general.architecture string from the GGUF metadata, and any error encountered during loading.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-parseropescalingtype`,children:[(0,G.jsx)(`h4`,{children:`ParseRopeScalingType`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func ParseRopeScalingType(s string) (RopeScalingType, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ParseRopeScalingType parses a string into a RopeScalingType. Supported values: "none", "linear", "yarn".`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-parsesplitmode`,children:[(0,G.jsx)(`h4`,{children:`ParseSplitMode`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func ParseSplitMode(s string) (SplitMode, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ParseSplitMode parses a string into a SplitMode. Supported values are "none", "layer", "row", and "tensor".`})]})]}),(0,G.jsxs)(`div`,{className:`card`,id:`types`,children:[(0,G.jsx)(`h3`,{children:`Types`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-adapterconfig`,children:[(0,G.jsx)(`h4`,{children:`AdapterConfig`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`type AdapterConfig struct {
Path string
Scale float32
}`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`AdapterConfig configures a local llama.cpp-compatible LoRA adapter GGUF. Scale is fixed for the lifetime of the loaded model.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-artifactdigest`,children:[(0,G.jsx)(`h4`,{children:`ArtifactDigest`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`type ArtifactDigest struct {
@@ -303,6 +303,7 @@ kronk server start`})]})]})}function Is(e){let t=/^([\d.]+)\s*(MB|GB|KB|B)?$/i.e
PtrIncrementalCache *bool
PtrInsecureLogging *bool
JinjaFile string
+ JinjaScript string
LoadMode LoadMode
Log applog.Logger
PtrMainGPU *int
@@ -316,7 +317,6 @@ kronk server start`})]})]})}function Is(e){let t=/^([\d.]+)\s*(MB|GB|KB|B)?$/i.e
NUMA string
PtrOffloadKQV *bool
PtrOpOffload *bool
- PtrOpOffloadMinBatch *int
ProjFile string
MTPDrafterFile string
PtrProjOnCPU *bool
@@ -340,7 +340,7 @@ kronk server start`})]})]})}function Is(e){let t=/^([\d.]+)\s*(MB|GB|KB|B)?$/i.e
PtrYarnOrigCtx *int
// Has unexported fields.
-}`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Config represents model level configuration. These values if configured incorrectly can cause the system to panic. The defaults are used when these values are set to 0.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Adapters contains local llama.cpp-compatible LoRA adapter GGUF files to load with the model. Adapter scales are fixed for the lifetime of the model.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ArtifactIntegrity contains expected artifact verification state keyed by model file path. It is used to avoid repeating completed verification work.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`AdmissionTimeout limits how long a request waits for an admission permit. The timeout applies only to admission, not request processing after a permit is acquired. When unset or set to 0, the default is 3 minutes.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`AutoTune, when true, asks kronk.New to run a hardware-aware analysis of the model (architecture, size, and available devices) and seed unset settings (context window, KV cache type, slots, flash attention, split mode, etc.) before loading. It is off by default for backwards compatibility, and any option the caller sets explicitly always wins over the analysis. It has no effect when using the low-level model package directly (only kronk.New applies it).`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`AutoTuned records that an upstream owner such as the Kronk Model Server has already applied AutoTune. When AutoTune and AutoTuned are both true, kronk.New preserves the enabled state for diagnostics without repeating the hardware analysis.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`CacheMinTokens sets the minimum token count required before caching. Messages shorter than this threshold are not cached, as the overhead of cache management may outweigh the prefill savings. When set to 0, defaults to 100 tokens.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`CacheTypeK is the data type for the K (key) cache. This controls the precision of the key vectors in the KV cache. Lower precision types (like Q8_0 or Q4_0) reduce memory usage but may slightly affect quality. When left as the zero value (GGMLTypeAuto), the default llama.cpp value is used.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`CacheTypeV is the data type for the V (value) cache. This controls the precision of the value vectors in the KV cache. When left as the zero value (GGMLTypeAuto), the default llama.cpp value is used.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ContextWindow (often referred to as context length) is the maximum number of tokens that a large language model can process and consider at one time when generating a response. It defines the model's effective "memory" for a single conversation or text generation task. When set to 0, the default value is 4096.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`DefaultParams contains the default sampling parameters for requests.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`DecisionProtocol optionally overrides automatic decision-protocol detection. It is useful when a decision model has been renamed and its GGUF metadata does not identify the protocol.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ChatTemplateKwargs contains model-level defaults passed only to the Jinja chat template. Request-level chat_template_kwargs override matching keys. Resolved first-class request parameters remain top-level template values.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`PtrDraftModel configures a separate speculative-decoding draft model or an nDraft override for an auto-detected MTP head.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Devices is a list of device names to use for model execution. When multiple devices are specified, the model is distributed across them according to the SplitMode and TensorSplit configuration. Device names can be obtained from the output of llama-bench --list-devices (e.g., "CUDA0", "CUDA1", "Metal"). When empty, the default device selection is used.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`PtrFlashAttention controls Flash Attention mode. Flash Attention reduces memory usage and speeds up attention computation, especially for large context windows. When nil, FlashAttentionAuto is used so llama.cpp can decide whether the active backend supports it. Set to FlashAttentionEnabled to force it on, or FlashAttentionDisabled to force it off.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`IMCSessionCapacity sets the number of reusable IMC session identities. When left unset or set to 0, generation models default to NSeqMax * QueueDepth. An explicit value must be at least that large so every admitted generation request can reserve a session.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`IncrementalCache enables Incremental Message Caching (IMC) for agentic workflows. It caches all messages except the last one (which triggers generation) and extends the cache incrementally on each turn. This is ideal for agents like Cline or OpenCode where conversations grow monotonically. The cache is rebuilt from scratch when the message prefix changes (new thread).`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`InsecureLogging enables logging of potentially sensitive data such as message content. This should only be enabled for debugging purposes in non-production environments.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`JinjaFile is the path to the jinja file. This is not required and can be used if you want to override the templated provided by the model metadata.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`LoadMode controls how model weights are loaded. The default is LoadModeAuto, which uses mmap when every selected device supports it and otherwise uses ordinary loading. LoadModeNone disables mmap, which can improve tensor placement on multi-socket NUMA systems running MoE models with CPU experts. LoadModeMLock requests resident pages without forcing mmap, LoadModeMMapMLock combines mmap and mlock, and LoadModeDirectIO bypasses the page cache where the platform and filesystem support it.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Log is the logger to use for model operations.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`MainGPU is the index of the GPU to use as the primary device when SplitMode is SplitModeNone. When nil, the default GPU (usually index 0) is used.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`PtrMoE controls expert-tensor placement for Mixture of Experts models.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ModelFiles is the path to the model files. This is mandatory to provide.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`PrefillBatchSize is the maximum number of prompt tokens one prefill owner can contribute to a decode iteration. The default is 2048. Larger values can reduce the number of decode calls needed to reach generation, but each call takes longer before already-generating slots can run again and requires larger compute buffers. Kronk derives llama.cpp's logical and physical batch capacities from this value, the configured slot count, and the generation mode. Multimodal models may require a complete media-token chunk to fit in this capacity.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`NGpuLayers is the number of model layers to offload to the GPU. When set to 0, all layers are offloaded (default). Set to -1 to keep all layers on CPU. Any positive value specifies the exact number of layers to offload.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`NSeqMax controls concurrency behavior based on model type. For text inference models (including vision/audio), it sets the maximum number of generation slots. For supported embedding and reranking architectures, it sets the maximum sequence width of the sequence-batch engine. Other embedding and reranking architectures use it as the context-pool size. For decision models, it sets the maximum number of work items evaluated together on one context. When set to 0, a default of 1 is used.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`NThreads is the number of threads to use for generation. When unset or set to 0, it defaults to the greater of 4 and runtime.NumCPU().`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`NThreadsBatch is the number of threads to use for batch processing. When unset or set to 0, it defaults to the greater of 4 and runtime.NumCPU().`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`NUMA controls the NUMA (Non-Uniform Memory Access) strategy. This matters most when expert tensors are on CPU and the system has multiple NUMA nodes. Valid values: "" (disabled), "distribute", "isolate", "numactl", "mirror". "distribute" is recommended for multi-socket MoE setups; without it, cross-socket memory access can cause significant bandwidth collapse.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`OffloadKQV controls whether the KV cache is offloaded to the GPU. When nil or true, the KV cache is stored on the GPU (default behavior). Set to false to keep the KV cache on the CPU, which reduces VRAM usage but may slow inference.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`OpOffload controls whether host tensor operations are offloaded to the device (GPU). When nil or true, operations are offloaded (default behavior). Set to false to keep operations on the CPU.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`OpOffloadMinBatch sets the minimum batch size at which host tensor operations are offloaded to the device. When unset or 0, llama.cpp's default is used.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ProjFile is the path to the projection files. This is mandatory for media based models like vision and audio.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`MTPDrafterFile is the path to a separate-file MTP drafter GGUF that ships alongside the main model. Supported files are Gemma assistant heads that share target KV and Qwen35 heads that own their draft KV. It is not the main model or a vocab-matched classic draft model. The catalog wires this field when it downloads a compatible companion from the model repository.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ProjOnCPU forces the multimodal projector (mmproj) to run on the CPU. When nil or false, the projector runs on whichever device llama.cpp picks by default (GPU when available). Set to true to keep the projector on the CPU — equivalent to llama-mtmd-cli's --no-mmproj-offload. The LLM itself is unaffected and still runs on whatever device WithNGpuLayers selects.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ProjDevice names the backend device used by the multimodal projector (mmproj), such as "CUDA1" or "MTL0". When empty, llama.cpp selects the projector device automatically. It cannot be combined with ProjOnCPU=true. The LLM device selection is unaffected.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`QueueDepth sets the number of admitted request layers for generation and decision models. The admission capacity is NSeqMax * QueueDepth. A depth of 1 admits only the requests that can occupy execution slots; the default depth of 2 admits one additional waiting layer. QueueDepth also determines the default IMC session capacity for text inference models.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`RopeFreqBase overrides the RoPE base frequency. When nil, uses model default. Common values: 10000 (Llama), 1000000 (Qwen3).`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`RopeFreqScale overrides the raw RoPE frequency multiplier. When nil, uses the value from model metadata. Kronk does not derive this value from ContextWindow; an N-times extension generally uses 1/N when the model's documentation requires explicit scaling.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`RecordArtifactVerification persists updated verification state after Kronk verifies a model artifact. When nil, verification state is not persisted.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`RopeScaling controls the RoPE scaling method for extended context support. Set to RopeScalingYaRN only when the model supports YaRN and configure the frequency scale required by that model.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`SessionStoreFactory constructs session stores for direct SDK use. Kronk invokes it separately for every working session store it needs and closes every successfully returned store. The factory must return a new, independent store on each call. The factory may capture shared, concurrency-safe resources such as a connection pool or process-wide quota. It receives the context for the operation that needs the store. Store read, prepare, commit, and reset operations also receive that context and return errors. System prompt preloads always remain in RAM. When nil, Kronk uses the built-in RAM factory. Backend-specific constructor parameters belong to the backend package and are captured by the injected factory.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`SplitMode controls how the model is split across multiple GPUs: - SplitModeNone (0): single GPU - SplitModeLayer (1): split layers and KV across GPUs - SplitModeRow (2): legacy row-split parallelism - SplitModeTensor (3): tensor parallelism`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`When nil (not set), the default is SplitModeLayer, matching llama.cpp. Layer mode distributes a single GGUF across multiple GPUs without requiring the backend-specific support used by row and tensor modes.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`SWAFull controls whether models with sliding window attention (SWA) use a full-size KV cache for SWA layers instead of the memory-efficient small cache. When nil (default), llama.cpp's default is used. When explicitly set to false, SWA layers only cache the last n_swa tokens, saving significant VRAM but limiting context caching and shifting. When true, SWA layers use the full context window for their KV cache, preserving accuracy at the cost of higher memory usage.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:'TensorBuftOverrides is a list of tensor buffer type override patterns that force matching tensors to execute on CPU instead of GPU. This is an expert-level configuration useful for MoE models where certain FFN expert tensors don\'t fit in VRAM. Supported values: - "all-ffn": offload all FFN expression tensors to CPU - "block:N": offload FFN tensors for block N to CPU (e.g., "block:12") - Any regex pattern matching tensor names (e.g., `blk\\.12\\.ffn_(up|down|gate)`)'}),(0,G.jsx)(`p`,{className:`doc-description`,children:`TensorSplit controls how model layers are proportionally distributed across multiple GPUs. Each element represents the fraction of the model assigned to the corresponding device. For example, [0.6, 0.4] splits 60%/40% across two GPUs. The length must match the number of devices. When empty, the split is determined automatically based on available VRAM.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`YarnAttnFactor sets the YaRN attention magnitude scaling factor. When nil, uses the model or llama.cpp default.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`YarnBetaFast sets the YaRN low correction dimension. When nil, uses the model or llama.cpp default.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`YarnBetaSlow sets the YaRN high correction dimension. When nil, uses the model or llama.cpp default.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`YarnExtFactor sets the YaRN extrapolation mix factor. When nil, uses the model or llama.cpp default. Set to 0 to disable extrapolation.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`YarnOrigCtx sets the original training context size for YaRN scaling. When nil or 0, uses the model's native training context length from metadata.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-contentlogprob`,children:[(0,G.jsx)(`h4`,{children:`ContentLogprob`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:'type ContentLogprob struct {\n Token string `json:"token"`\n Logprob float32 `json:"logprob"`\n Bytes []byte `json:"bytes,omitempty"`\n TopLogprobs []TopLogprob `json:"top_logprobs,omitempty"`\n}'})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ContentLogprob represents log probability information for a single token.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-d`,children:[(0,G.jsx)(`h4`,{children:`D`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`type D map[string]any`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`D represents a generic docment of fields and values.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-decisionanswer`,children:[(0,G.jsx)(`h4`,{children:`DecisionAnswer`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:'type DecisionAnswer struct {\n Type DecisionQuestionType `json:"type"`\n Choice string `json:"choice,omitempty"`\n Score float64 `json:"score,omitempty"`\n Noul float64 `json:"noul,omitempty"`\n Probabilities map[string]float64 `json:"probabilities,omitempty"`\n Legend map[string]any `json:"legend,omitempty"`\n Confidence float64 `json:"confidence,omitempty"`\n}'})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`DecisionAnswer contains the typed answer to one decision question. Choice is populated for Choice, Score and Legend for Score, Noul for Noul, and Probabilities and Confidence for Choice and Score.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-decisionnoulcriteria`,children:[(0,G.jsx)(`h4`,{children:`DecisionNoulCriteria`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`type DecisionNoulCriteria struct {
+}`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Config represents model level configuration. These values if configured incorrectly can cause the system to panic. The defaults are used when these values are set to 0.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Adapters contains local llama.cpp-compatible LoRA adapter GGUF files to load with the model. Adapter scales are fixed for the lifetime of the model.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ArtifactIntegrity contains expected artifact verification state keyed by model file path. It is used to avoid repeating completed verification work.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`AdmissionTimeout limits how long a request waits for an admission permit. The timeout applies only to admission, not request processing after a permit is acquired. When unset or set to 0, the default is 3 minutes.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`AutoTune, when true, asks kronk.New to run a hardware-aware analysis of the model (architecture, size, and available devices) and seed unset settings (context window, KV cache type, slots, flash attention, split mode, etc.) before loading. It is off by default for backwards compatibility, and any option the caller sets explicitly always wins over the analysis. It has no effect when using the low-level model package directly (only kronk.New applies it).`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`AutoTuned records that an upstream owner such as the Kronk Model Server has already applied AutoTune. When AutoTune and AutoTuned are both true, kronk.New preserves the enabled state for diagnostics without repeating the hardware analysis.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`CacheMinTokens sets the minimum token count required before caching. Messages shorter than this threshold are not cached, as the overhead of cache management may outweigh the prefill savings. When set to 0, defaults to 100 tokens.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`CacheTypeK is the data type for the K (key) cache. This controls the precision of the key vectors in the KV cache. Lower precision types (like Q8_0 or Q4_0) reduce memory usage but may slightly affect quality. When left as the zero value (GGMLTypeAuto), the default llama.cpp value is used.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`CacheTypeV is the data type for the V (value) cache. This controls the precision of the value vectors in the KV cache. When left as the zero value (GGMLTypeAuto), the default llama.cpp value is used.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ContextWindow (often referred to as context length) is the maximum number of tokens that a large language model can process and consider at one time when generating a response. It defines the model's effective "memory" for a single conversation or text generation task. When set to 0, the default value is 4096.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`DefaultParams contains the default sampling parameters for requests.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`DecisionProtocol optionally overrides automatic decision-protocol detection. It is useful when a decision model has been renamed and its GGUF metadata does not identify the protocol.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ChatTemplateKwargs contains model-level defaults passed only to the Jinja chat template. Request-level chat_template_kwargs override matching keys. Resolved first-class request parameters remain top-level template values.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`PtrDraftModel configures a separate speculative-decoding draft model or an nDraft override for an auto-detected MTP head.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Devices is a list of device names to use for model execution. When multiple devices are specified, the model is distributed across them according to the SplitMode and TensorSplit configuration. Device names can be obtained from the output of llama-bench --list-devices (e.g., "CUDA0", "CUDA1", "Metal"). When empty, the default device selection is used.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`PtrFlashAttention controls Flash Attention mode. Flash Attention reduces memory usage and speeds up attention computation, especially for large context windows. When nil, FlashAttentionAuto is used so llama.cpp can decide whether the active backend supports it. Set to FlashAttentionEnabled to force it on, or FlashAttentionDisabled to force it off.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`IMCSessionCapacity sets the number of reusable IMC session identities. When left unset or set to 0, generation models default to NSeqMax * QueueDepth. An explicit value must be at least that large so every admitted generation request can reserve a session.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`IncrementalCache enables Incremental Message Caching (IMC) for agentic workflows. It caches all messages except the last one (which triggers generation) and extends the cache incrementally on each turn. This is ideal for agents like Cline or OpenCode where conversations grow monotonically. The cache is rebuilt from scratch when the message prefix changes (new thread).`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`InsecureLogging enables logging of potentially sensitive data such as message content. This should only be enabled for debugging purposes in non-production environments.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`JinjaFile is the path to the jinja file. This is not required and can be used if you want to override the templated provided by the model metadata.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`JinjaScript is an in-memory jinja template override. It takes precedence over JinjaFile and is intended for request-scoped model configurations.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`LoadMode controls how model weights are loaded. The default is LoadModeAuto, which uses mmap when every selected device supports it and otherwise uses ordinary loading. LoadModeNone disables mmap, which can improve tensor placement on multi-socket NUMA systems running MoE models with CPU experts. LoadModeMLock requests resident pages without forcing mmap, LoadModeMMapMLock combines mmap and mlock, and LoadModeDirectIO bypasses the page cache where the platform and filesystem support it.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Log is the logger to use for model operations.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`MainGPU is the index of the GPU to use as the primary device when SplitMode is SplitModeNone. When nil, the default GPU (usually index 0) is used.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`PtrMoE controls expert-tensor placement for Mixture of Experts models.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ModelFiles is the path to the model files. This is mandatory to provide.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`PrefillBatchSize is the maximum number of prompt tokens one prefill owner can contribute to a decode iteration. The default is 2048. Larger values can reduce the number of decode calls needed to reach generation, but each call takes longer before already-generating slots can run again and requires larger compute buffers. Kronk derives llama.cpp's logical and physical batch capacities from this value, the configured slot count, and the generation mode. Multimodal models may require a complete media-token chunk to fit in this capacity.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`NGpuLayers is the number of model layers to offload to the GPU. When set to 0, all layers are offloaded (default). Set to -1 to keep all layers on CPU. Any positive value specifies the exact number of layers to offload.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`NSeqMax controls concurrency behavior based on model type. For text inference models (including vision/audio), it sets the maximum number of generation slots. For supported embedding and reranking architectures, it sets the maximum sequence width of the sequence-batch engine. Other embedding and reranking architectures use it as the context-pool size. For decision models, it sets the maximum number of work items evaluated together on one context. When set to 0, a default of 1 is used.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`NThreads is the number of threads to use for generation. When unset or set to 0, it defaults to the greater of 4 and runtime.NumCPU().`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`NThreadsBatch is the number of threads to use for batch processing. When unset or set to 0, it defaults to the greater of 4 and runtime.NumCPU().`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`NUMA controls the NUMA (Non-Uniform Memory Access) strategy. This matters most when expert tensors are on CPU and the system has multiple NUMA nodes. Valid values: "" (disabled), "distribute", "isolate", "numactl", "mirror". "distribute" is recommended for multi-socket MoE setups; without it, cross-socket memory access can cause significant bandwidth collapse.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`OffloadKQV controls whether the KV cache is offloaded to the GPU. When nil or true, the KV cache is stored on the GPU (default behavior). Set to false to keep the KV cache on the CPU, which reduces VRAM usage but may slow inference.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`OpOffload controls whether host tensor operations are offloaded to the device (GPU). When nil or true, operations are offloaded (default behavior). Set to false to keep operations on the CPU.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ProjFile is the path to the projection files. This is mandatory for media based models like vision and audio.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`MTPDrafterFile is the path to a separate-file MTP drafter GGUF that ships alongside the main model. Supported files are Gemma assistant heads that share target KV and Qwen35 heads that own their draft KV. It is not the main model or a vocab-matched classic draft model. The catalog wires this field when it downloads a compatible companion from the model repository.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ProjOnCPU forces the multimodal projector (mmproj) to run on the CPU. When nil or false, the projector runs on whichever device llama.cpp picks by default (GPU when available). Set to true to keep the projector on the CPU — equivalent to llama-mtmd-cli's --no-mmproj-offload. The LLM itself is unaffected and still runs on whatever device WithNGpuLayers selects.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ProjDevice names the backend device used by the multimodal projector (mmproj), such as "CUDA1" or "MTL0". When empty, llama.cpp selects the projector device automatically. It cannot be combined with ProjOnCPU=true. The LLM device selection is unaffected.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`QueueDepth sets the number of admitted request layers for generation and decision models. The admission capacity is NSeqMax * QueueDepth. A depth of 1 admits only the requests that can occupy execution slots; the default depth of 2 admits one additional waiting layer. QueueDepth also determines the default IMC session capacity for text inference models.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`RopeFreqBase overrides the RoPE base frequency. When nil, uses model default. Common values: 10000 (Llama), 1000000 (Qwen3).`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`RopeFreqScale overrides the raw RoPE frequency multiplier. When nil, uses the value from model metadata. Kronk does not derive this value from ContextWindow; an N-times extension generally uses 1/N when the model's documentation requires explicit scaling.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`RecordArtifactVerification persists updated verification state after Kronk verifies a model artifact. When nil, verification state is not persisted.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`RopeScaling controls the RoPE scaling method for extended context support. Set to RopeScalingYaRN only when the model supports YaRN and configure the frequency scale required by that model.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`SessionStoreFactory constructs session stores for direct SDK use. Kronk invokes it separately for every working session store it needs and closes every successfully returned store. The factory must return a new, independent store on each call. The factory may capture shared, concurrency-safe resources such as a connection pool or process-wide quota. It receives the context for the operation that needs the store. Store read, prepare, commit, and reset operations also receive that context and return errors. System prompt preloads always remain in RAM. When nil, Kronk uses the built-in RAM factory. Backend-specific constructor parameters belong to the backend package and are captured by the injected factory.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`SplitMode controls how the model is split across multiple GPUs: - SplitModeNone (0): single GPU - SplitModeLayer (1): split layers and KV across GPUs - SplitModeRow (2): legacy row-split parallelism - SplitModeTensor (3): tensor parallelism`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`When nil (not set), the default is SplitModeLayer, matching llama.cpp. Layer mode distributes a single GGUF across multiple GPUs without requiring the backend-specific support used by row and tensor modes.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`SWAFull controls whether models with sliding window attention (SWA) use a full-size KV cache for SWA layers instead of the memory-efficient small cache. When nil (default), llama.cpp's default is used. When explicitly set to false, SWA layers only cache the last n_swa tokens, saving significant VRAM but limiting context caching and shifting. When true, SWA layers use the full context window for their KV cache, preserving accuracy at the cost of higher memory usage.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:'TensorBuftOverrides is a list of tensor buffer type override patterns that force matching tensors to execute on CPU instead of GPU. This is an expert-level configuration useful for MoE models where certain FFN expert tensors don\'t fit in VRAM. Supported values: - "all-ffn": offload all FFN expression tensors to CPU - "block:N": offload FFN tensors for block N to CPU (e.g., "block:12") - Any regex pattern matching tensor names (e.g., `blk\\.12\\.ffn_(up|down|gate)`)'}),(0,G.jsx)(`p`,{className:`doc-description`,children:`TensorSplit controls how model layers are proportionally distributed across multiple GPUs. Each element represents the fraction of the model assigned to the corresponding device. For example, [0.6, 0.4] splits 60%/40% across two GPUs. The length must match the number of devices. When empty, the split is determined automatically based on available VRAM.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`YarnAttnFactor sets the YaRN attention magnitude scaling factor. When nil, uses the model or llama.cpp default.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`YarnBetaFast sets the YaRN low correction dimension. When nil, uses the model or llama.cpp default.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`YarnBetaSlow sets the YaRN high correction dimension. When nil, uses the model or llama.cpp default.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`YarnExtFactor sets the YaRN extrapolation mix factor. When nil, uses the model or llama.cpp default. Set to 0 to disable extrapolation.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`YarnOrigCtx sets the original training context size for YaRN scaling. When nil or 0, uses the model's native training context length from metadata.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-contentlogprob`,children:[(0,G.jsx)(`h4`,{children:`ContentLogprob`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:'type ContentLogprob struct {\n Token string `json:"token"`\n Logprob float32 `json:"logprob"`\n Bytes []byte `json:"bytes,omitempty"`\n TopLogprobs []TopLogprob `json:"top_logprobs,omitempty"`\n}'})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ContentLogprob represents log probability information for a single token.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-d`,children:[(0,G.jsx)(`h4`,{children:`D`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`type D map[string]any`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`D represents a generic docment of fields and values.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-decisionanswer`,children:[(0,G.jsx)(`h4`,{children:`DecisionAnswer`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:'type DecisionAnswer struct {\n Type DecisionQuestionType `json:"type"`\n Choice string `json:"choice,omitempty"`\n Score float64 `json:"score,omitempty"`\n Noul float64 `json:"noul,omitempty"`\n Probabilities map[string]float64 `json:"probabilities,omitempty"`\n Legend map[string]any `json:"legend,omitempty"`\n Confidence float64 `json:"confidence,omitempty"`\n}'})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`DecisionAnswer contains the typed answer to one decision question. Choice is populated for Choice, Score and Legend for Score, Noul for Noul, and Probabilities and Confidence for Choice and Score.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-decisionnoulcriteria`,children:[(0,G.jsx)(`h4`,{children:`DecisionNoulCriteria`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`type DecisionNoulCriteria struct {
False any
True any
}`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`DecisionNoulCriteria optionally describes the false and true boundaries of a Noul question.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-decisionoption`,children:[(0,G.jsx)(`h4`,{children:`DecisionOption`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`type DecisionOption struct {
@@ -578,7 +578,7 @@ kronk server start`})]})]})}function Is(e){let t=/^([\d.]+)\s*(MB|GB|KB|B)?$/i.e
// Reset returns the state machine to its initial state for reuse.
Reset()
-}`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`StateMachine is the per-request, per-slot streaming state machine. One instance is created per slot via Parser.NewStateMachine and reused across requests on that slot via Reset.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Behavior is undefined if Classify is called after a previous call returned eog=true. Callers must invoke Reset before reusing the state machine.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-statemachineflusher`,children:[(0,G.jsx)(`h4`,{children:`StateMachineFlusher`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`type StateMachineFlusher interface {
+}`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`StateMachine is the per-request, per-slot streaming state machine. One instance is created per slot via Parser.NewStateMachine and reused across requests on that slot via Reset.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Implementations may consume protocol framing. Once content has been recognized as answer, reasoning, or tool payload, unexpected non-whitespace continuations must be returned on an appropriate channel so final parsing can reject malformed output atomically.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Behavior is undefined if Classify is called after a previous call returned eog=true. Callers must invoke Reset before reusing the state machine.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-statemachineflusher`,children:[(0,G.jsx)(`h4`,{children:`StateMachineFlusher`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`type StateMachineFlusher interface {
Flush() Result
}`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`StateMachineFlusher is implemented by state machines that may retain model output not yet returned by Classify.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Flush drains that output at successful end-of-generation. It must not return content previously returned by Classify. Callers invoke Flush until it returns a zero Result so state machines can preserve multiple channel transitions retained from one decoded piece.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-streamingresponselogger`,children:[(0,G.jsx)(`h4`,{children:`StreamingResponseLogger`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`type StreamingResponseLogger struct {
// Has unexported fields.
@@ -599,7 +599,7 @@ kronk server start`})]})]})}function Is(e){let t=/^([\d.]+)\s*(MB|GB|KB|B)?$/i.e
// ConsumeVocabEOG consumes the textual representation of the sampled EOG
// token before the state machine is flushed.
ConsumeVocabEOG(content string)
-}`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`VocabEOGConsumer is optionally implemented by state machines whose native framing uses a token that the vocabulary also classifies as end-of-generation.`})]})]}),(0,G.jsxs)(`div`,{className:`card`,id:`methods`,children:[(0,G.jsx)(`h3`,{children:`Methods`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-choice-finishreason`,children:[(0,G.jsx)(`h4`,{children:`Choice.FinishReason`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (c Choice) FinishReason() string`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`FinishReason return the finish reason as an empty string if it is nil.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-admissiontimeout`,children:[(0,G.jsx)(`h4`,{children:`Config.AdmissionTimeout`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) AdmissionTimeout() time.Duration`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-cachemintokens`,children:[(0,G.jsx)(`h4`,{children:`Config.CacheMinTokens`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) CacheMinTokens() int`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-contextwindow`,children:[(0,G.jsx)(`h4`,{children:`Config.ContextWindow`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) ContextWindow() int`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-effectivenbatch`,children:[(0,G.jsx)(`h4`,{children:`Config.EffectiveNBatch`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) EffectiveNBatch() int`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`EffectiveNBatch returns the derived llama.cpp logical batch capacity.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-effectivenubatch`,children:[(0,G.jsx)(`h4`,{children:`Config.EffectiveNUBatch`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) EffectiveNUBatch() int`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`EffectiveNUBatch returns the derived llama.cpp physical batch capacity.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-expertlayersongpu`,children:[(0,G.jsx)(`h4`,{children:`Config.ExpertLayersOnGPU`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) ExpertLayersOnGPU() int64`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ExpertLayersOnGPU translates the model's MoE configuration into the value the vram calculator expects so every prediction site (resman planner, post-load model logging, BUI display) reflects what llama.cpp will actually do at runtime. With no MoE override we mirror llama.cpp's default behavior: experts follow the layer they belong to, and full GPU offload puts every expert on the GPU. Without this resolution the calculator defaults experts to CPU even when the runtime puts them on GPU, producing the inverse of the placement that's actually loaded and silently under-accounting expert weight memory in the BUI VRAM column.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-flashattention`,children:[(0,G.jsx)(`h4`,{children:`Config.FlashAttention`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) FlashAttention() FlashAttentionType`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`FlashAttention returns the configured flash attention mode. An unset value defaults to auto so llama.cpp can select the supported mode.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-imcsessioncapacity`,children:[(0,G.jsx)(`h4`,{children:`Config.IMCSessionCapacity`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) IMCSessionCapacity() int`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-incrementalcache`,children:[(0,G.jsx)(`h4`,{children:`Config.IncrementalCache`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) IncrementalCache() bool`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-insecurelogging`,children:[(0,G.jsx)(`h4`,{children:`Config.InsecureLogging`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) InsecureLogging() bool`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-maingpu`,children:[(0,G.jsx)(`h4`,{children:`Config.MainGPU`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) MainGPU() int`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-ngpulayers`,children:[(0,G.jsx)(`h4`,{children:`Config.NGpuLayers`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) NGpuLayers() int`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-nseqmax`,children:[(0,G.jsx)(`h4`,{children:`Config.NSeqMax`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) NSeqMax() int`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-nthreads`,children:[(0,G.jsx)(`h4`,{children:`Config.NThreads`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) NThreads() int`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-nthreadsbatch`,children:[(0,G.jsx)(`h4`,{children:`Config.NThreadsBatch`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) NThreadsBatch() int`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-opoffloadminbatch`,children:[(0,G.jsx)(`h4`,{children:`Config.OpOffloadMinBatch`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) OpOffloadMinBatch() int`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-prefillbatchsize`,children:[(0,G.jsx)(`h4`,{children:`Config.PrefillBatchSize`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) PrefillBatchSize() int`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-queuedepth`,children:[(0,G.jsx)(`h4`,{children:`Config.QueueDepth`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) QueueDepth() int`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-ropefreqbase`,children:[(0,G.jsx)(`h4`,{children:`Config.RopeFreqBase`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) RopeFreqBase() float32`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-ropefreqscale`,children:[(0,G.jsx)(`h4`,{children:`Config.RopeFreqScale`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) RopeFreqScale() float32`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-swafull`,children:[(0,G.jsx)(`h4`,{children:`Config.SWAFull`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) SWAFull() bool`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`SWAFull reports whether a full-size sliding-window attention cache was explicitly requested. Callers that need the effective value must check PtrSWAFull first because nil leaves the choice to llama.cpp.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-speculationmode`,children:[(0,G.jsx)(`h4`,{children:`Config.SpeculationMode`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) SpeculationMode() SpeculationMode`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`SpeculationMode returns the selected speculative-decoding implementation. The zero value preserves automatic selection.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-string`,children:[(0,G.jsx)(`h4`,{children:`Config.String`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) String() string`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-yarnattnfactor`,children:[(0,G.jsx)(`h4`,{children:`Config.YarnAttnFactor`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) YarnAttnFactor() float32`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-yarnbetafast`,children:[(0,G.jsx)(`h4`,{children:`Config.YarnBetaFast`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) YarnBetaFast() float32`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-yarnbetaslow`,children:[(0,G.jsx)(`h4`,{children:`Config.YarnBetaSlow`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) YarnBetaSlow() float32`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-yarnextfactor`,children:[(0,G.jsx)(`h4`,{children:`Config.YarnExtFactor`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) YarnExtFactor() float32`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-yarnorigctx`,children:[(0,G.jsx)(`h4`,{children:`Config.YarnOrigCtx`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) YarnOrigCtx() int`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-d-clone`,children:[(0,G.jsx)(`h4`,{children:`D.Clone`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (d D) Clone() D`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Clone creates a copy of the document. Mutable JSON maps and slices are cloned recursively so callers can reuse a request after submitting it. Byte slices are shared as immutable media payloads; scalar values are shared by value.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-d-messages`,children:[(0,G.jsx)(`h4`,{children:`D.Messages`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (d D) Messages() string`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-d-shallowclone`,children:[(0,G.jsx)(`h4`,{children:`D.ShallowClone`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (d D) ShallowClone() D`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ShallowClone creates a copy of the top-level map and the messages slice. Individual message maps are shared with the original. Use this when downstream code treats message maps as read-only or performs its own copy-on-write when mutation is needed.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-d-string`,children:[(0,G.jsx)(`h4`,{children:`D.String`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (d D) String() string`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`String returns a string representation of the document containing only fields that are safe to log. This excludes sensitive fields like messages and input which may contain private user data.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-decisionanswer-marshaljson`,children:[(0,G.jsx)(`h4`,{children:`DecisionAnswer.MarshalJSON`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (a DecisionAnswer) MarshalJSON() ([]byte, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`MarshalJSON emits the type-specific HTTP answer shape, including meaningful zero values and excluding fields owned by other question types.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-decisionprotocol-equal`,children:[(0,G.jsx)(`h4`,{children:`DecisionProtocol.Equal`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (dp DecisionProtocol) Equal(dp2 DecisionProtocol) bool`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Equal provides support for the go-cmp package and testing.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-decisionprotocol-iszero`,children:[(0,G.jsx)(`h4`,{children:`DecisionProtocol.IsZero`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (dp DecisionProtocol) IsZero() bool`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`IsZero reports whether the decision protocol is unset.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-decisionprotocol-marshaltext`,children:[(0,G.jsx)(`h4`,{children:`DecisionProtocol.MarshalText`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (dp DecisionProtocol) MarshalText() ([]byte, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`MarshalText provides support for logging and serialization.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-decisionprotocol-string`,children:[(0,G.jsx)(`h4`,{children:`DecisionProtocol.String`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (dp DecisionProtocol) String() string`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`String returns the name of the decision protocol.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-decisionprotocol-unmarshaltext`,children:[(0,G.jsx)(`h4`,{children:`DecisionProtocol.UnmarshalText`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (dp *DecisionProtocol) UnmarshalText(data []byte) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`UnmarshalText parses serialized text into a known DecisionProtocol.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-decisionstatevalue-marshaljson`,children:[(0,G.jsx)(`h4`,{children:`DecisionStateValue.MarshalJSON`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (o DecisionStateValue) MarshalJSON() ([]byte, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`MarshalJSON preserves the field order of a DecisionStateValue.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-draftmodelconfig-isseparate`,children:[(0,G.jsx)(`h4`,{children:`DraftModelConfig.IsSeparate`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (d DraftModelConfig) IsSeparate() bool`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`IsSeparate reports whether this config points at a separate draft GGUF. When false, the config is an MTP nDraft override that carries no model files and only applies when the target ships an auto-detected MTP head.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-draftmodelconfig-maingpu`,children:[(0,G.jsx)(`h4`,{children:`DraftModelConfig.MainGPU`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (d DraftModelConfig) MainGPU() int`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-draftmodelconfig-ngpulayers`,children:[(0,G.jsx)(`h4`,{children:`DraftModelConfig.NGpuLayers`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (d DraftModelConfig) NGpuLayers() int`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-flashattentiontype-marshaljson`,children:[(0,G.jsx)(`h4`,{children:`FlashAttentionType.MarshalJSON`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (t FlashAttentionType) MarshalJSON() ([]byte, error)`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-flashattentiontype-marshalyaml`,children:[(0,G.jsx)(`h4`,{children:`FlashAttentionType.MarshalYAML`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (t FlashAttentionType) MarshalYAML() (any, error)`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-flashattentiontype-string`,children:[(0,G.jsx)(`h4`,{children:`FlashAttentionType.String`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (t FlashAttentionType) String() string`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-flashattentiontype-unmarshaljson`,children:[(0,G.jsx)(`h4`,{children:`FlashAttentionType.UnmarshalJSON`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (t *FlashAttentionType) UnmarshalJSON(data []byte) error`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-flashattentiontype-unmarshalyaml`,children:[(0,G.jsx)(`h4`,{children:`FlashAttentionType.UnmarshalYAML`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (t *FlashAttentionType) UnmarshalYAML(unmarshal func(any) error) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`UnmarshalYAML implements yaml.Unmarshaler to parse string values.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-ggmltype-marshaljson`,children:[(0,G.jsx)(`h4`,{children:`GGMLType.MarshalJSON`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (t GGMLType) MarshalJSON() ([]byte, error)`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-ggmltype-marshalyaml`,children:[(0,G.jsx)(`h4`,{children:`GGMLType.MarshalYAML`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (t GGMLType) MarshalYAML() (any, error)`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-ggmltype-string`,children:[(0,G.jsx)(`h4`,{children:`GGMLType.String`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (t GGMLType) String() string`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`String returns the string representation of a GGMLType.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-ggmltype-toyzmatype`,children:[(0,G.jsx)(`h4`,{children:`GGMLType.ToYZMAType`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (t GGMLType) ToYZMAType() llama.GGMLType`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-ggmltype-unmarshaljson`,children:[(0,G.jsx)(`h4`,{children:`GGMLType.UnmarshalJSON`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (t *GGMLType) UnmarshalJSON(data []byte) error`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-ggmltype-unmarshalyaml`,children:[(0,G.jsx)(`h4`,{children:`GGMLType.UnmarshalYAML`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (t *GGMLType) UnmarshalYAML(unmarshal func(any) error) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`UnmarshalYAML implements yaml.Unmarshaler to parse string values like "f16".`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-loadmode-marshaljson`,children:[(0,G.jsx)(`h4`,{children:`LoadMode.MarshalJSON`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (lm LoadMode) MarshalJSON() ([]byte, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`MarshalJSON implements json.Marshaler.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-loadmode-marshalyaml`,children:[(0,G.jsx)(`h4`,{children:`LoadMode.MarshalYAML`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (lm LoadMode) MarshalYAML() (any, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`MarshalYAML implements yaml.Marshaler.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-loadmode-string`,children:[(0,G.jsx)(`h4`,{children:`LoadMode.String`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (lm LoadMode) String() string`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`String returns the string representation of a LoadMode.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-loadmode-toyzmatype`,children:[(0,G.jsx)(`h4`,{children:`LoadMode.ToYZMAType`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (lm LoadMode) ToYZMAType() llama.LoadMode`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ToYZMAType converts to the yzma/llama.cpp LoadMode type.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-loadmode-unmarshaljson`,children:[(0,G.jsx)(`h4`,{children:`LoadMode.UnmarshalJSON`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (lm *LoadMode) UnmarshalJSON(data []byte) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`UnmarshalJSON implements json.Unmarshaler.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-loadmode-unmarshalyaml`,children:[(0,G.jsx)(`h4`,{children:`LoadMode.UnmarshalYAML`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (lm *LoadMode) UnmarshalYAML(unmarshal func(any) error) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`UnmarshalYAML implements yaml.Unmarshaler.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-moeconfig-keepexpertsongpufortopnlayers`,children:[(0,G.jsx)(`h4`,{children:`MoEConfig.KeepExpertsOnGPUForTopNLayers`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m MoEConfig) KeepExpertsOnGPUForTopNLayers() int`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-moemode-equal`,children:[(0,G.jsx)(`h4`,{children:`MoEMode.Equal`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (mm MoEMode) Equal(mm2 MoEMode) bool`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Equal provides support for the go-cmp package and testing.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-moemode-iszero`,children:[(0,G.jsx)(`h4`,{children:`MoEMode.IsZero`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (mm MoEMode) IsZero() bool`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`IsZero reports whether the MoE mode is unset.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-moemode-marshaltext`,children:[(0,G.jsx)(`h4`,{children:`MoEMode.MarshalText`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (mm MoEMode) MarshalText() ([]byte, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`MarshalText provides support for logging and serialization.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-moemode-string`,children:[(0,G.jsx)(`h4`,{children:`MoEMode.String`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (mm MoEMode) String() string`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`String returns the name of the MoE mode.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-moemode-unmarshaltext`,children:[(0,G.jsx)(`h4`,{children:`MoEMode.UnmarshalText`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (mm *MoEMode) UnmarshalText(data []byte) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`UnmarshalText parses serialized text into a known MoEMode.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-batchenginesnapshot`,children:[(0,G.jsx)(`h4`,{children:`Model.BatchEngineSnapshot`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) BatchEngineSnapshot() (BatchEngineSnapshot, bool)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`BatchEngineSnapshot returns the latest generation scheduler snapshot. Models used only for embeddings or reranking do not have a generation batch engine.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-chat`,children:[(0,G.jsx)(`h4`,{children:`Model.Chat`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) Chat(ctx context.Context, d D) (ChatResponse, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Chat performs a chat request and returns the final response. All requests (including vision/audio) use batch processing and can run concurrently based on the NSeqMax config value, which controls parallel sequence processing.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-chatstreaming`,children:[(0,G.jsx)(`h4`,{children:`Model.ChatStreaming`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) ChatStreaming(ctx context.Context, d D) (<-chan ChatResponse, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ChatStreaming performs a chat request and streams the response. All requests (including vision/audio) use batch processing and can run concurrently based on the NSeqMax config value, which controls parallel sequence processing. When stream_options.include_usage is true, the terminal choice is followed by a usage response with an empty Choices slice. Validation failures are returned before a response channel is created.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-config`,children:[(0,G.jsx)(`h4`,{children:`Model.Config`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) Config() Config`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-decision`,children:[(0,G.jsx)(`h4`,{children:`Model.Decision`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) Decision(ctx context.Context, req DecisionRequest) (DecisionResponse, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Decision evaluates a set of decision questions against shared state.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-embeddings`,children:[(0,G.jsx)(`h4`,{children:`Model.Embeddings`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) Embeddings(ctx context.Context, d D) (response EmbedReponse, err error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Embeddings performs embedding for one or more inputs.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Supported options in d: - input ([]string): the texts to embed (required) - truncate (bool): if true, truncate inputs to fit context window (default: false) - truncate_direction (string): "right" (default) or "left" - dimensions (int): reduce output to first N dimensions (for Matryoshka models)`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Supported models process inputs together as a multi-sequence batch. Other models use the context-pool fallback.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-imcsessions`,children:[(0,G.jsx)(`h4`,{children:`Model.IMCSessions`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) IMCSessions() []IMCSessionDetail`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`IMCSessions returns the current state of the model's allocated IMC cache entries. It does not retain history or expose the cached content.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-imcsystemcaches`,children:[(0,G.jsx)(`h4`,{children:`Model.IMCSystemCaches`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) IMCSystemCaches() []IMCSystemCacheDetail`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`IMCSystemCaches returns every entry in the immutable System preload pool.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-modelinfo`,children:[(0,G.jsx)(`h4`,{children:`Model.ModelInfo`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) ModelInfo() ModelInfo`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-rerank`,children:[(0,G.jsx)(`h4`,{children:`Model.Rerank`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) Rerank(ctx context.Context, d D) (response RerankResponse, err error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Rerank performs reranking for a query against multiple documents. It scores each document's relevance to the query and returns results sorted by relevance score (highest first).`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Supported options in d: - query (string): the query to rank documents against (required) - documents ([]string): the documents to rank (required) - top_n (int): return only the top N results (optional, default: all) - return_documents (bool): include document text in results (default: false)`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Supported models process documents together as a multi-sequence batch. Other models use the context-pool fallback.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-tokenize`,children:[(0,G.jsx)(`h4`,{children:`Model.Tokenize`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) Tokenize(ctx context.Context, d D) (TokenizeResponse, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Tokenize returns the token count for a text input.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Supported options in d: - input (string): the text to tokenize (required) - apply_template (bool): if true, wrap input as a user message and apply the model's chat template before tokenizing (default: false) - add_generation_prompt (bool): when apply_template is true, controls whether the assistant role prefix is appended to the prompt (default: true)`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`When apply_template is true, the returned count includes all template overhead (role markers, separators, generation prompt). This reflects the actual number of tokens that would be fed to the model.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-unload`,children:[(0,G.jsx)(`h4`,{children:`Model.Unload`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) Unload(ctx context.Context) error`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-modelinfo-string`,children:[(0,G.jsx)(`h4`,{children:`ModelInfo.String`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (mi ModelInfo) String() string`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-modeltype-string`,children:[(0,G.jsx)(`h4`,{children:`ModelType.String`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (mt ModelType) String() string`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`String returns a human-readable name for the model type.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-params-string`,children:[(0,G.jsx)(`h4`,{children:`Params.String`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (p Params) String() string`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`String returns a string representation of all resolved Params values in the format key[value]\\nkey[value]\\n ... Grammar contents are intentionally redacted; only whether a grammar is active is reported.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-responsemessage-marshaljson`,children:[(0,G.jsx)(`h4`,{children:`ResponseMessage.MarshalJSON`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m ResponseMessage) MarshalJSON() ([]byte, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`MarshalJSON emits incremental and completed tool calls through the same OpenAI-compatible tool_calls wire field.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-ropescalingtype-marshaljson`,children:[(0,G.jsx)(`h4`,{children:`RopeScalingType.MarshalJSON`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (r RopeScalingType) MarshalJSON() ([]byte, error)`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-ropescalingtype-marshalyaml`,children:[(0,G.jsx)(`h4`,{children:`RopeScalingType.MarshalYAML`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (r RopeScalingType) MarshalYAML() (any, error)`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-ropescalingtype-string`,children:[(0,G.jsx)(`h4`,{children:`RopeScalingType.String`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (r RopeScalingType) String() string`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`String returns the string representation of a RopeScalingType.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-ropescalingtype-toyzmatype`,children:[(0,G.jsx)(`h4`,{children:`RopeScalingType.ToYZMAType`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (r RopeScalingType) ToYZMAType() llama.RopeScalingType`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ToYZMAType converts to the yzma/llama.cpp RopeScalingType.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-ropescalingtype-unmarshaljson`,children:[(0,G.jsx)(`h4`,{children:`RopeScalingType.UnmarshalJSON`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (r *RopeScalingType) UnmarshalJSON(data []byte) error`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-ropescalingtype-unmarshalyaml`,children:[(0,G.jsx)(`h4`,{children:`RopeScalingType.UnmarshalYAML`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (r *RopeScalingType) UnmarshalYAML(unmarshal func(any) error) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`UnmarshalYAML implements yaml.Unmarshaler to parse string values.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-splitmode-marshaljson`,children:[(0,G.jsx)(`h4`,{children:`SplitMode.MarshalJSON`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (s SplitMode) MarshalJSON() ([]byte, error)`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-splitmode-marshalyaml`,children:[(0,G.jsx)(`h4`,{children:`SplitMode.MarshalYAML`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (s SplitMode) MarshalYAML() (any, error)`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-splitmode-string`,children:[(0,G.jsx)(`h4`,{children:`SplitMode.String`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (s SplitMode) String() string`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`String returns the string representation of a SplitMode.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-splitmode-toyzmatype`,children:[(0,G.jsx)(`h4`,{children:`SplitMode.ToYZMAType`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (s SplitMode) ToYZMAType() llama.SplitMode`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ToYZMAType converts to the yzma/llama.cpp SplitMode type.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-splitmode-unmarshaljson`,children:[(0,G.jsx)(`h4`,{children:`SplitMode.UnmarshalJSON`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (s *SplitMode) UnmarshalJSON(data []byte) error`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-splitmode-unmarshalyaml`,children:[(0,G.jsx)(`h4`,{children:`SplitMode.UnmarshalYAML`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (s *SplitMode) UnmarshalYAML(unmarshal func(any) error) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`UnmarshalYAML implements yaml.Unmarshaler to parse string values.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-streamingresponselogger-capture`,children:[(0,G.jsx)(`h4`,{children:`StreamingResponseLogger.Capture`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (l *StreamingResponseLogger) Capture(resp ChatResponse)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Capture captures data from a streaming response. Call this for each response before forwarding it. It only captures from the final response (when FinishReason is set).`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-streamingresponselogger-string`,children:[(0,G.jsx)(`h4`,{children:`StreamingResponseLogger.String`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (l *StreamingResponseLogger) String() string`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`String returns a formatted string for logging.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-toolcallarguments-marshaljson`,children:[(0,G.jsx)(`h4`,{children:`ToolCallArguments.MarshalJSON`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (a ToolCallArguments) MarshalJSON() ([]byte, error)`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-toolcallarguments-unmarshaljson`,children:[(0,G.jsx)(`h4`,{children:`ToolCallArguments.UnmarshalJSON`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (a *ToolCallArguments) UnmarshalJSON(data []byte) error`})})]})]}),(0,G.jsxs)(`div`,{className:`card`,id:`constants`,children:[(0,G.jsx)(`h3`,{children:`Constants`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`const-numadisabled`,children:[(0,G.jsx)(`h4`,{children:`NUMADisabled`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`const (
+}`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`VocabEOGConsumer is optionally implemented by state machines whose native framing uses a token that the vocabulary also classifies as end-of-generation.`})]})]}),(0,G.jsxs)(`div`,{className:`card`,id:`methods`,children:[(0,G.jsx)(`h3`,{children:`Methods`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-choice-finishreason`,children:[(0,G.jsx)(`h4`,{children:`Choice.FinishReason`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (c Choice) FinishReason() string`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`FinishReason return the finish reason as an empty string if it is nil.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-admissiontimeout`,children:[(0,G.jsx)(`h4`,{children:`Config.AdmissionTimeout`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) AdmissionTimeout() time.Duration`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-cachemintokens`,children:[(0,G.jsx)(`h4`,{children:`Config.CacheMinTokens`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) CacheMinTokens() int`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-contextwindow`,children:[(0,G.jsx)(`h4`,{children:`Config.ContextWindow`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) ContextWindow() int`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-effectivenbatch`,children:[(0,G.jsx)(`h4`,{children:`Config.EffectiveNBatch`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) EffectiveNBatch() int`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`EffectiveNBatch returns the derived llama.cpp logical batch capacity.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-effectivenubatch`,children:[(0,G.jsx)(`h4`,{children:`Config.EffectiveNUBatch`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) EffectiveNUBatch() int`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`EffectiveNUBatch returns the derived llama.cpp physical batch capacity.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-expertlayersongpu`,children:[(0,G.jsx)(`h4`,{children:`Config.ExpertLayersOnGPU`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) ExpertLayersOnGPU() int64`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ExpertLayersOnGPU translates the model's MoE configuration into the value the vram calculator expects so every prediction site (resman planner, post-load model logging, BUI display) reflects what llama.cpp will actually do at runtime. With no MoE override we mirror llama.cpp's default behavior: experts follow the layer they belong to, and full GPU offload puts every expert on the GPU. Without this resolution the calculator defaults experts to CPU even when the runtime puts them on GPU, producing the inverse of the placement that's actually loaded and silently under-accounting expert weight memory in the BUI VRAM column.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-flashattention`,children:[(0,G.jsx)(`h4`,{children:`Config.FlashAttention`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) FlashAttention() FlashAttentionType`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`FlashAttention returns the configured flash attention mode. An unset value defaults to auto so llama.cpp can select the supported mode.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-imcsessioncapacity`,children:[(0,G.jsx)(`h4`,{children:`Config.IMCSessionCapacity`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) IMCSessionCapacity() int`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-incrementalcache`,children:[(0,G.jsx)(`h4`,{children:`Config.IncrementalCache`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) IncrementalCache() bool`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-insecurelogging`,children:[(0,G.jsx)(`h4`,{children:`Config.InsecureLogging`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) InsecureLogging() bool`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-maingpu`,children:[(0,G.jsx)(`h4`,{children:`Config.MainGPU`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) MainGPU() int`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-ngpulayers`,children:[(0,G.jsx)(`h4`,{children:`Config.NGpuLayers`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) NGpuLayers() int`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-nseqmax`,children:[(0,G.jsx)(`h4`,{children:`Config.NSeqMax`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) NSeqMax() int`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-nthreads`,children:[(0,G.jsx)(`h4`,{children:`Config.NThreads`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) NThreads() int`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-nthreadsbatch`,children:[(0,G.jsx)(`h4`,{children:`Config.NThreadsBatch`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) NThreadsBatch() int`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-prefillbatchsize`,children:[(0,G.jsx)(`h4`,{children:`Config.PrefillBatchSize`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) PrefillBatchSize() int`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-queuedepth`,children:[(0,G.jsx)(`h4`,{children:`Config.QueueDepth`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) QueueDepth() int`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-ropefreqbase`,children:[(0,G.jsx)(`h4`,{children:`Config.RopeFreqBase`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) RopeFreqBase() float32`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-ropefreqscale`,children:[(0,G.jsx)(`h4`,{children:`Config.RopeFreqScale`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) RopeFreqScale() float32`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-swafull`,children:[(0,G.jsx)(`h4`,{children:`Config.SWAFull`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) SWAFull() bool`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`SWAFull reports whether a full-size sliding-window attention cache was explicitly requested. Callers that need the effective value must check PtrSWAFull first because nil leaves the choice to llama.cpp.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-speculationmode`,children:[(0,G.jsx)(`h4`,{children:`Config.SpeculationMode`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) SpeculationMode() SpeculationMode`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`SpeculationMode returns the selected speculative-decoding implementation. The zero value preserves automatic selection.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-string`,children:[(0,G.jsx)(`h4`,{children:`Config.String`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) String() string`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-yarnattnfactor`,children:[(0,G.jsx)(`h4`,{children:`Config.YarnAttnFactor`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) YarnAttnFactor() float32`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-yarnbetafast`,children:[(0,G.jsx)(`h4`,{children:`Config.YarnBetaFast`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) YarnBetaFast() float32`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-yarnbetaslow`,children:[(0,G.jsx)(`h4`,{children:`Config.YarnBetaSlow`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) YarnBetaSlow() float32`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-yarnextfactor`,children:[(0,G.jsx)(`h4`,{children:`Config.YarnExtFactor`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) YarnExtFactor() float32`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-yarnorigctx`,children:[(0,G.jsx)(`h4`,{children:`Config.YarnOrigCtx`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) YarnOrigCtx() int`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-d-clone`,children:[(0,G.jsx)(`h4`,{children:`D.Clone`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (d D) Clone() D`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Clone creates a copy of the document. Mutable JSON maps and slices are cloned recursively so callers can reuse a request after submitting it. Byte slices are shared as immutable media payloads; scalar values are shared by value.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-d-messages`,children:[(0,G.jsx)(`h4`,{children:`D.Messages`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (d D) Messages() string`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-d-shallowclone`,children:[(0,G.jsx)(`h4`,{children:`D.ShallowClone`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (d D) ShallowClone() D`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ShallowClone creates a copy of the top-level map and the messages slice. Individual message maps are shared with the original. Use this when downstream code treats message maps as read-only or performs its own copy-on-write when mutation is needed.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-d-string`,children:[(0,G.jsx)(`h4`,{children:`D.String`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (d D) String() string`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`String returns a string representation of the document containing only fields that are safe to log. This excludes sensitive fields like messages and input which may contain private user data.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-decisionanswer-marshaljson`,children:[(0,G.jsx)(`h4`,{children:`DecisionAnswer.MarshalJSON`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (a DecisionAnswer) MarshalJSON() ([]byte, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`MarshalJSON emits the type-specific HTTP answer shape, including meaningful zero values and excluding fields owned by other question types.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-decisionprotocol-equal`,children:[(0,G.jsx)(`h4`,{children:`DecisionProtocol.Equal`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (dp DecisionProtocol) Equal(dp2 DecisionProtocol) bool`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Equal provides support for the go-cmp package and testing.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-decisionprotocol-iszero`,children:[(0,G.jsx)(`h4`,{children:`DecisionProtocol.IsZero`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (dp DecisionProtocol) IsZero() bool`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`IsZero reports whether the decision protocol is unset.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-decisionprotocol-marshaltext`,children:[(0,G.jsx)(`h4`,{children:`DecisionProtocol.MarshalText`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (dp DecisionProtocol) MarshalText() ([]byte, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`MarshalText provides support for logging and serialization.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-decisionprotocol-string`,children:[(0,G.jsx)(`h4`,{children:`DecisionProtocol.String`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (dp DecisionProtocol) String() string`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`String returns the name of the decision protocol.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-decisionprotocol-unmarshaltext`,children:[(0,G.jsx)(`h4`,{children:`DecisionProtocol.UnmarshalText`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (dp *DecisionProtocol) UnmarshalText(data []byte) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`UnmarshalText parses serialized text into a known DecisionProtocol.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-decisionstatevalue-marshaljson`,children:[(0,G.jsx)(`h4`,{children:`DecisionStateValue.MarshalJSON`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (o DecisionStateValue) MarshalJSON() ([]byte, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`MarshalJSON preserves the field order of a DecisionStateValue.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-draftmodelconfig-isseparate`,children:[(0,G.jsx)(`h4`,{children:`DraftModelConfig.IsSeparate`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (d DraftModelConfig) IsSeparate() bool`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`IsSeparate reports whether this config points at a separate draft GGUF. When false, the config is an MTP nDraft override that carries no model files and only applies when the target ships an auto-detected MTP head.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-draftmodelconfig-maingpu`,children:[(0,G.jsx)(`h4`,{children:`DraftModelConfig.MainGPU`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (d DraftModelConfig) MainGPU() int`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-draftmodelconfig-ngpulayers`,children:[(0,G.jsx)(`h4`,{children:`DraftModelConfig.NGpuLayers`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (d DraftModelConfig) NGpuLayers() int`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-flashattentiontype-marshaljson`,children:[(0,G.jsx)(`h4`,{children:`FlashAttentionType.MarshalJSON`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (t FlashAttentionType) MarshalJSON() ([]byte, error)`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-flashattentiontype-marshalyaml`,children:[(0,G.jsx)(`h4`,{children:`FlashAttentionType.MarshalYAML`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (t FlashAttentionType) MarshalYAML() (any, error)`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-flashattentiontype-string`,children:[(0,G.jsx)(`h4`,{children:`FlashAttentionType.String`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (t FlashAttentionType) String() string`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-flashattentiontype-unmarshaljson`,children:[(0,G.jsx)(`h4`,{children:`FlashAttentionType.UnmarshalJSON`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (t *FlashAttentionType) UnmarshalJSON(data []byte) error`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-flashattentiontype-unmarshalyaml`,children:[(0,G.jsx)(`h4`,{children:`FlashAttentionType.UnmarshalYAML`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (t *FlashAttentionType) UnmarshalYAML(unmarshal func(any) error) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`UnmarshalYAML implements yaml.Unmarshaler to parse string values.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-ggmltype-marshaljson`,children:[(0,G.jsx)(`h4`,{children:`GGMLType.MarshalJSON`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (t GGMLType) MarshalJSON() ([]byte, error)`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-ggmltype-marshalyaml`,children:[(0,G.jsx)(`h4`,{children:`GGMLType.MarshalYAML`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (t GGMLType) MarshalYAML() (any, error)`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-ggmltype-string`,children:[(0,G.jsx)(`h4`,{children:`GGMLType.String`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (t GGMLType) String() string`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`String returns the string representation of a GGMLType.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-ggmltype-toyzmatype`,children:[(0,G.jsx)(`h4`,{children:`GGMLType.ToYZMAType`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (t GGMLType) ToYZMAType() llama.GGMLType`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-ggmltype-unmarshaljson`,children:[(0,G.jsx)(`h4`,{children:`GGMLType.UnmarshalJSON`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (t *GGMLType) UnmarshalJSON(data []byte) error`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-ggmltype-unmarshalyaml`,children:[(0,G.jsx)(`h4`,{children:`GGMLType.UnmarshalYAML`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (t *GGMLType) UnmarshalYAML(unmarshal func(any) error) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`UnmarshalYAML implements yaml.Unmarshaler to parse string values like "f16".`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-loadmode-marshaljson`,children:[(0,G.jsx)(`h4`,{children:`LoadMode.MarshalJSON`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (lm LoadMode) MarshalJSON() ([]byte, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`MarshalJSON implements json.Marshaler.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-loadmode-marshalyaml`,children:[(0,G.jsx)(`h4`,{children:`LoadMode.MarshalYAML`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (lm LoadMode) MarshalYAML() (any, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`MarshalYAML implements yaml.Marshaler.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-loadmode-string`,children:[(0,G.jsx)(`h4`,{children:`LoadMode.String`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (lm LoadMode) String() string`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`String returns the string representation of a LoadMode.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-loadmode-toyzmatype`,children:[(0,G.jsx)(`h4`,{children:`LoadMode.ToYZMAType`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (lm LoadMode) ToYZMAType() llama.LoadMode`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ToYZMAType converts to the yzma/llama.cpp LoadMode type.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-loadmode-unmarshaljson`,children:[(0,G.jsx)(`h4`,{children:`LoadMode.UnmarshalJSON`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (lm *LoadMode) UnmarshalJSON(data []byte) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`UnmarshalJSON implements json.Unmarshaler.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-loadmode-unmarshalyaml`,children:[(0,G.jsx)(`h4`,{children:`LoadMode.UnmarshalYAML`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (lm *LoadMode) UnmarshalYAML(unmarshal func(any) error) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`UnmarshalYAML implements yaml.Unmarshaler.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-moeconfig-keepexpertsongpufortopnlayers`,children:[(0,G.jsx)(`h4`,{children:`MoEConfig.KeepExpertsOnGPUForTopNLayers`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m MoEConfig) KeepExpertsOnGPUForTopNLayers() int`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-moemode-equal`,children:[(0,G.jsx)(`h4`,{children:`MoEMode.Equal`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (mm MoEMode) Equal(mm2 MoEMode) bool`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Equal provides support for the go-cmp package and testing.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-moemode-iszero`,children:[(0,G.jsx)(`h4`,{children:`MoEMode.IsZero`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (mm MoEMode) IsZero() bool`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`IsZero reports whether the MoE mode is unset.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-moemode-marshaltext`,children:[(0,G.jsx)(`h4`,{children:`MoEMode.MarshalText`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (mm MoEMode) MarshalText() ([]byte, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`MarshalText provides support for logging and serialization.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-moemode-string`,children:[(0,G.jsx)(`h4`,{children:`MoEMode.String`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (mm MoEMode) String() string`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`String returns the name of the MoE mode.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-moemode-unmarshaltext`,children:[(0,G.jsx)(`h4`,{children:`MoEMode.UnmarshalText`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (mm *MoEMode) UnmarshalText(data []byte) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`UnmarshalText parses serialized text into a known MoEMode.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-batchenginesnapshot`,children:[(0,G.jsx)(`h4`,{children:`Model.BatchEngineSnapshot`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) BatchEngineSnapshot() (BatchEngineSnapshot, bool)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`BatchEngineSnapshot returns the latest generation scheduler snapshot. Models used only for embeddings or reranking do not have a generation batch engine.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-chat`,children:[(0,G.jsx)(`h4`,{children:`Model.Chat`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) Chat(ctx context.Context, d D) (ChatResponse, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Chat performs a chat request and returns the final response. All requests (including vision/audio) use batch processing and can run concurrently based on the NSeqMax config value, which controls parallel sequence processing.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-chatstreaming`,children:[(0,G.jsx)(`h4`,{children:`Model.ChatStreaming`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) ChatStreaming(ctx context.Context, d D) (<-chan ChatResponse, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ChatStreaming performs a chat request and streams the response. All requests (including vision/audio) use batch processing and can run concurrently based on the NSeqMax config value, which controls parallel sequence processing. When stream_options.include_usage is true, the terminal choice is followed by a usage response with an empty Choices slice. Validation failures are returned before a response channel is created.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-config`,children:[(0,G.jsx)(`h4`,{children:`Model.Config`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) Config() Config`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-decision`,children:[(0,G.jsx)(`h4`,{children:`Model.Decision`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) Decision(ctx context.Context, req DecisionRequest) (DecisionResponse, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Decision evaluates a set of decision questions against shared state.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-embeddings`,children:[(0,G.jsx)(`h4`,{children:`Model.Embeddings`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) Embeddings(ctx context.Context, d D) (response EmbedReponse, err error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Embeddings performs embedding for one or more inputs.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Supported options in d: - input ([]string): the texts to embed (required) - truncate (bool): if true, truncate inputs to fit context window (default: false) - truncate_direction (string): "right" (default) or "left" - dimensions (int): reduce output to first N dimensions (for Matryoshka models)`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Supported models process inputs together as a multi-sequence batch. Other models use the context-pool fallback.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-imcsessions`,children:[(0,G.jsx)(`h4`,{children:`Model.IMCSessions`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) IMCSessions() []IMCSessionDetail`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`IMCSessions returns the current state of the model's allocated IMC cache entries. It does not retain history or expose the cached content.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-imcsystemcaches`,children:[(0,G.jsx)(`h4`,{children:`Model.IMCSystemCaches`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) IMCSystemCaches() []IMCSystemCacheDetail`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`IMCSystemCaches returns every entry in the immutable System preload pool.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-modelinfo`,children:[(0,G.jsx)(`h4`,{children:`Model.ModelInfo`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) ModelInfo() ModelInfo`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-rerank`,children:[(0,G.jsx)(`h4`,{children:`Model.Rerank`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) Rerank(ctx context.Context, d D) (response RerankResponse, err error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Rerank performs reranking for a query against multiple documents. It scores each document's relevance to the query and returns results sorted by relevance score (highest first).`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Supported options in d: - query (string): the query to rank documents against (required) - documents ([]string): the documents to rank (required) - top_n (int): return only the top N results (optional, default: all) - return_documents (bool): include document text in results (default: false)`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Supported models process documents together as a multi-sequence batch. Other models use the context-pool fallback.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-tokenize`,children:[(0,G.jsx)(`h4`,{children:`Model.Tokenize`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) Tokenize(ctx context.Context, d D) (TokenizeResponse, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Tokenize returns the token count for a text input.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Supported options in d: - input (string): the text to tokenize (required) - apply_template (bool): if true, wrap input as a user message and apply the model's chat template before tokenizing (default: false) - add_generation_prompt (bool): when apply_template is true, controls whether the assistant role prefix is appended to the prompt (default: true)`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`When apply_template is true, the returned count includes all template overhead (role markers, separators, generation prompt). This reflects the actual number of tokens that would be fed to the model.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-unload`,children:[(0,G.jsx)(`h4`,{children:`Model.Unload`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) Unload(ctx context.Context) error`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-modelinfo-string`,children:[(0,G.jsx)(`h4`,{children:`ModelInfo.String`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (mi ModelInfo) String() string`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-modeltype-string`,children:[(0,G.jsx)(`h4`,{children:`ModelType.String`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (mt ModelType) String() string`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`String returns a human-readable name for the model type.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-params-string`,children:[(0,G.jsx)(`h4`,{children:`Params.String`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (p Params) String() string`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`String returns a string representation of all resolved Params values in the format key[value]\\nkey[value]\\n ... Grammar contents are intentionally redacted; only whether a grammar is active is reported.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-responsemessage-marshaljson`,children:[(0,G.jsx)(`h4`,{children:`ResponseMessage.MarshalJSON`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m ResponseMessage) MarshalJSON() ([]byte, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`MarshalJSON emits incremental and completed tool calls through the same OpenAI-compatible tool_calls wire field.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-ropescalingtype-marshaljson`,children:[(0,G.jsx)(`h4`,{children:`RopeScalingType.MarshalJSON`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (r RopeScalingType) MarshalJSON() ([]byte, error)`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-ropescalingtype-marshalyaml`,children:[(0,G.jsx)(`h4`,{children:`RopeScalingType.MarshalYAML`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (r RopeScalingType) MarshalYAML() (any, error)`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-ropescalingtype-string`,children:[(0,G.jsx)(`h4`,{children:`RopeScalingType.String`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (r RopeScalingType) String() string`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`String returns the string representation of a RopeScalingType.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-ropescalingtype-toyzmatype`,children:[(0,G.jsx)(`h4`,{children:`RopeScalingType.ToYZMAType`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (r RopeScalingType) ToYZMAType() llama.RopeScalingType`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ToYZMAType converts to the yzma/llama.cpp RopeScalingType.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-ropescalingtype-unmarshaljson`,children:[(0,G.jsx)(`h4`,{children:`RopeScalingType.UnmarshalJSON`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (r *RopeScalingType) UnmarshalJSON(data []byte) error`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-ropescalingtype-unmarshalyaml`,children:[(0,G.jsx)(`h4`,{children:`RopeScalingType.UnmarshalYAML`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (r *RopeScalingType) UnmarshalYAML(unmarshal func(any) error) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`UnmarshalYAML implements yaml.Unmarshaler to parse string values.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-splitmode-marshaljson`,children:[(0,G.jsx)(`h4`,{children:`SplitMode.MarshalJSON`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (s SplitMode) MarshalJSON() ([]byte, error)`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-splitmode-marshalyaml`,children:[(0,G.jsx)(`h4`,{children:`SplitMode.MarshalYAML`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (s SplitMode) MarshalYAML() (any, error)`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-splitmode-string`,children:[(0,G.jsx)(`h4`,{children:`SplitMode.String`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (s SplitMode) String() string`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`String returns the string representation of a SplitMode.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-splitmode-toyzmatype`,children:[(0,G.jsx)(`h4`,{children:`SplitMode.ToYZMAType`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (s SplitMode) ToYZMAType() llama.SplitMode`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ToYZMAType converts to the yzma/llama.cpp SplitMode type.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-splitmode-unmarshaljson`,children:[(0,G.jsx)(`h4`,{children:`SplitMode.UnmarshalJSON`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (s *SplitMode) UnmarshalJSON(data []byte) error`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-splitmode-unmarshalyaml`,children:[(0,G.jsx)(`h4`,{children:`SplitMode.UnmarshalYAML`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (s *SplitMode) UnmarshalYAML(unmarshal func(any) error) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`UnmarshalYAML implements yaml.Unmarshaler to parse string values.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-streamingresponselogger-capture`,children:[(0,G.jsx)(`h4`,{children:`StreamingResponseLogger.Capture`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (l *StreamingResponseLogger) Capture(resp ChatResponse)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Capture captures data from a streaming response. Call this for each response before forwarding it. It only captures from the final response (when FinishReason is set).`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-streamingresponselogger-string`,children:[(0,G.jsx)(`h4`,{children:`StreamingResponseLogger.String`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (l *StreamingResponseLogger) String() string`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`String returns a formatted string for logging.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-toolcallarguments-marshaljson`,children:[(0,G.jsx)(`h4`,{children:`ToolCallArguments.MarshalJSON`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (a ToolCallArguments) MarshalJSON() ([]byte, error)`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-toolcallarguments-unmarshaljson`,children:[(0,G.jsx)(`h4`,{children:`ToolCallArguments.UnmarshalJSON`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (a *ToolCallArguments) UnmarshalJSON(data []byte) error`})})]})]}),(0,G.jsxs)(`div`,{className:`card`,id:`constants`,children:[(0,G.jsx)(`h3`,{children:`Constants`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`const-numadisabled`,children:[(0,G.jsx)(`h4`,{children:`NUMADisabled`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`const (
NUMADisabled = ""
NUMADistribute = "distribute"
NUMAIsolate = "isolate"
@@ -754,7 +754,7 @@ kronk server start`})]})]})}function Is(e){let t=/^([\d.]+)\s*(MB|GB|KB|B)?$/i.e
SpeculationDisabled = internalspec.ModeDisabled
SpeculationClassic = internalspec.ModeClassic
SpeculationMTP = internalspec.ModeMTP
-)`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`const-defaultprefillbatchsize`,children:[(0,G.jsx)(`h4`,{children:`DefaultPrefillBatchSize`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`const DefaultPrefillBatchSize = int(vram.DefaultNUBatch)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`DefaultPrefillBatchSize is the prompt-token capacity used when prefill batch size is not explicitly configured.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`const-defaultqueuedepth`,children:[(0,G.jsx)(`h4`,{children:`DefaultQueueDepth`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`const DefaultQueueDepth = 2`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`DefaultQueueDepth is the number of admitted request layers used when queue depth is not explicitly configured.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`const-expertsallongpu`,children:[(0,G.jsx)(`h4`,{children:`ExpertsAllOnGPU`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`const ExpertsAllOnGPU = int64(math.MaxInt32)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ExpertsAllOnGPU is the sentinel value used for vram.Config.ExpertLayersOnGPU to request that every routed-expert layer be charged against GPU VRAM. The vram package treats any value greater than or equal to the model's block count as "all layers on GPU", so a large constant works regardless of model depth and avoids a metadata round-trip just to discover it.`})]})]}),(0,G.jsxs)(`div`,{className:`card`,id:`variables`,children:[(0,G.jsx)(`h3`,{children:`Variables`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`var-variable`,children:[(0,G.jsx)(`h4`,{children:`Variable`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`var (`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`// DecisionProtocolOpenJEV identifies the OpenJEV letter-readout protocol. DecisionProtocolOpenJEV = newDecisionProtocol("openjev")`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`// DecisionProtocolJevStyle identifies the macjev-render-v1 protocol. DecisionProtocolJevStyle = newDecisionProtocol("jev-style")`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`var-variable`,children:[(0,G.jsx)(`h4`,{children:`Variable`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`var (`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`// MoEModeAuto uses catalog defaults. MoEModeAuto = newMoEMode("auto")`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`// MoEModeExpertsCPU places all routed expert tensors on CPU. // Recommended for VRAM-constrained setups. MoEModeExpertsCPU = newMoEMode("experts_cpu")`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`// MoEModeExpertsGPU keeps all expert tensors on GPU. // Requires sufficient VRAM for the full model. MoEModeExpertsGPU = newMoEMode("experts_gpu")`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`// MoEModeKeepTopN keeps routed experts on GPU for the top N layers. // All other expert layers go to CPU. MoEModeKeepTopN = newMoEMode("keep_top_n")`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`// MoEModeCustom defers to TensorBuftOverrides for expert placement. MoEModeCustom = newMoEMode("custom")`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`var-errdecisionbudget`,children:[(0,G.jsx)(`h4`,{children:`ErrDecisionBudget`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`var ErrDecisionBudget = errors.New("decision input exceeds token budget")`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ErrDecisionBudget indicates that a rendered decision input exceeds the protocol's token budget. Inputs are never truncated.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`var-errdecisionrequest`,children:[(0,G.jsx)(`h4`,{children:`ErrDecisionRequest`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`var ErrDecisionRequest = errors.New("invalid decision request")`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ErrDecisionRequest indicates that a decision request is invalid.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`var-errfileinputsunsupported`,children:[(0,G.jsx)(`h4`,{children:`ErrFileInputsUnsupported`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`var ErrFileInputsUnsupported = errors.New("file inputs are not currently supported")`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ErrFileInputsUnsupported indicates file content parts are not supported.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`var-errinvalidrequest`,children:[(0,G.jsx)(`h4`,{children:`ErrInvalidRequest`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`var ErrInvalidRequest = errors.New("validate-document: invalid request")`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ErrInvalidRequest indicates that a model request contains an invalid or unsupported field value.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`var-errmessagesinvalid`,children:[(0,G.jsx)(`h4`,{children:`ErrMessagesInvalid`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`var ErrMessagesInvalid = errors.New("validate-document: messages is not a slice of documents")`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ErrMessagesInvalid indicates that a chat request's messages field has an invalid type.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`var-errmessagesmissing`,children:[(0,G.jsx)(`h4`,{children:`ErrMessagesMissing`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`var ErrMessagesMissing = errors.New("validate-document: no messages found in request")`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ErrMessagesMissing indicates that a chat request has no messages field.`})]})]})]}),(0,G.jsx)(`nav`,{className:`doc-sidebar`,children:(0,G.jsxs)(`div`,{className:`doc-sidebar-content`,children:[(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#functions`,className:`doc-index-header`,children:`Functions`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-addparams`,children:`AddParams`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-inityzmaworkarounds`,children:`InitYzmaWorkarounds`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-recurrentstatecopies`,children:`RecurrentStateCopies`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-registerparser`,children:`RegisterParser`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-speculativecontextcount`,children:`SpeculativeContextCount`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-validatechatrequest`,children:`ValidateChatRequest`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-validatemessages`,children:`ValidateMessages`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-newgrammarsampler`,children:`NewGrammarSampler`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-verifyartifact`,children:`VerifyArtifact`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-parsedecisionprotocol`,children:`ParseDecisionProtocol`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-parseggmltype`,children:`ParseGGMLType`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-parseloadmode`,children:`ParseLoadMode`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-parsemoemode`,children:`ParseMoEMode`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-newmodel`,children:`NewModel`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-detectmodeltypefromfiles`,children:`DetectModelTypeFromFiles`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-parseropescalingtype`,children:`ParseRopeScalingType`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-parsesplitmode`,children:`ParseSplitMode`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#types`,className:`doc-index-header`,children:`Types`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-adapterconfig`,children:`AdapterConfig`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-artifactdigest`,children:`ArtifactDigest`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-artifactintegrity`,children:`ArtifactIntegrity`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-artifactverification`,children:`ArtifactVerification`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-artifactverificationrecorder`,children:`ArtifactVerificationRecorder`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-batchenginesnapshot`,children:`BatchEngineSnapshot`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-batchgenerationcontribution`,children:`BatchGenerationContribution`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-batchslotsnapshot`,children:`BatchSlotSnapshot`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-channel`,children:`Channel`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-chatresponse`,children:`ChatResponse`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-choice`,children:`Choice`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-completiontokensdetails`,children:`CompletionTokensDetails`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-config`,children:`Config`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-contentlogprob`,children:`ContentLogprob`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-d`,children:`D`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-decisionanswer`,children:`DecisionAnswer`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-decisionnoulcriteria`,children:`DecisionNoulCriteria`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-decisionoption`,children:`DecisionOption`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-decisionprotocol`,children:`DecisionProtocol`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-decisionquestion`,children:`DecisionQuestion`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-decisionquestiontype`,children:`DecisionQuestionType`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-decisionrequest`,children:`DecisionRequest`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-decisionresponse`,children:`DecisionResponse`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-decisionstatefield`,children:`DecisionStateField`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-decisionstatevalue`,children:`DecisionStateValue`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-decisionusage`,children:`DecisionUsage`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-draftmodelconfig`,children:`DraftModelConfig`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-embeddata`,children:`EmbedData`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-embedreponse`,children:`EmbedReponse`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-embedusage`,children:`EmbedUsage`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-fingerprint`,children:`Fingerprint`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-flashattentiontype`,children:`FlashAttentionType`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-ggmltype`,children:`GGMLType`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-imcsessiondetail`,children:`IMCSessionDetail`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-imcsessionstate`,children:`IMCSessionState`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-imcsystemcachedetail`,children:`IMCSystemCacheDetail`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-loadmode`,children:`LoadMode`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-logger`,children:`Logger`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-logprobs`,children:`Logprobs`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-mediatype`,children:`MediaType`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-moeconfig`,children:`MoEConfig`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-moemode`,children:`MoEMode`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-model`,children:`Model`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-modelinfo`,children:`ModelInfo`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-modeltype`,children:`ModelType`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-option`,children:`Option`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-params`,children:`Params`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-paramsadjuster`,children:`ParamsAdjuster`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-parser`,children:`Parser`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-parserfactory`,children:`ParserFactory`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-prompttokensdetails`,children:`PromptTokensDetails`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-rerankresponse`,children:`RerankResponse`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-rerankresult`,children:`RerankResult`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-rerankusage`,children:`RerankUsage`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-responsemessage`,children:`ResponseMessage`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-responsetoolcall`,children:`ResponseToolCall`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-responsetoolcalldelta`,children:`ResponseToolCallDelta`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-responsetoolcalldeltafunction`,children:`ResponseToolCallDeltaFunction`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-responsetoolcallfunction`,children:`ResponseToolCallFunction`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-result`,children:`Result`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-ropescalingtype`,children:`RopeScalingType`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-sessionstore`,children:`SessionStore`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-sessionstorefactory`,children:`SessionStoreFactory`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-speculationmode`,children:`SpeculationMode`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-splitmode`,children:`SplitMode`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-statemachine`,children:`StateMachine`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-statemachineflusher`,children:`StateMachineFlusher`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-streamingresponselogger`,children:`StreamingResponseLogger`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-template`,children:`Template`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-tokenizeresponse`,children:`TokenizeResponse`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-toolawarestatemachine`,children:`ToolAwareStateMachine`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-toolcallarguments`,children:`ToolCallArguments`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-toolcalldeltastreamer`,children:`ToolCallDeltaStreamer`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-toolcallschemaparser`,children:`ToolCallSchemaParser`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-toplogprob`,children:`TopLogprob`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-usage`,children:`Usage`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-vocabeogconsumer`,children:`VocabEOGConsumer`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#methods`,className:`doc-index-header`,children:`Methods`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-choice-finishreason`,children:`Choice.FinishReason`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-admissiontimeout`,children:`Config.AdmissionTimeout`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-cachemintokens`,children:`Config.CacheMinTokens`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-contextwindow`,children:`Config.ContextWindow`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-effectivenbatch`,children:`Config.EffectiveNBatch`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-effectivenubatch`,children:`Config.EffectiveNUBatch`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-expertlayersongpu`,children:`Config.ExpertLayersOnGPU`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-flashattention`,children:`Config.FlashAttention`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-imcsessioncapacity`,children:`Config.IMCSessionCapacity`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-incrementalcache`,children:`Config.IncrementalCache`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-insecurelogging`,children:`Config.InsecureLogging`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-maingpu`,children:`Config.MainGPU`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-ngpulayers`,children:`Config.NGpuLayers`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-nseqmax`,children:`Config.NSeqMax`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-nthreads`,children:`Config.NThreads`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-nthreadsbatch`,children:`Config.NThreadsBatch`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-opoffloadminbatch`,children:`Config.OpOffloadMinBatch`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-prefillbatchsize`,children:`Config.PrefillBatchSize`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-queuedepth`,children:`Config.QueueDepth`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-ropefreqbase`,children:`Config.RopeFreqBase`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-ropefreqscale`,children:`Config.RopeFreqScale`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-swafull`,children:`Config.SWAFull`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-speculationmode`,children:`Config.SpeculationMode`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-string`,children:`Config.String`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-yarnattnfactor`,children:`Config.YarnAttnFactor`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-yarnbetafast`,children:`Config.YarnBetaFast`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-yarnbetaslow`,children:`Config.YarnBetaSlow`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-yarnextfactor`,children:`Config.YarnExtFactor`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-yarnorigctx`,children:`Config.YarnOrigCtx`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-d-clone`,children:`D.Clone`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-d-messages`,children:`D.Messages`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-d-shallowclone`,children:`D.ShallowClone`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-d-string`,children:`D.String`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-decisionanswer-marshaljson`,children:`DecisionAnswer.MarshalJSON`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-decisionprotocol-equal`,children:`DecisionProtocol.Equal`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-decisionprotocol-iszero`,children:`DecisionProtocol.IsZero`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-decisionprotocol-marshaltext`,children:`DecisionProtocol.MarshalText`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-decisionprotocol-string`,children:`DecisionProtocol.String`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-decisionprotocol-unmarshaltext`,children:`DecisionProtocol.UnmarshalText`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-decisionstatevalue-marshaljson`,children:`DecisionStateValue.MarshalJSON`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-draftmodelconfig-isseparate`,children:`DraftModelConfig.IsSeparate`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-draftmodelconfig-maingpu`,children:`DraftModelConfig.MainGPU`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-draftmodelconfig-ngpulayers`,children:`DraftModelConfig.NGpuLayers`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-flashattentiontype-marshaljson`,children:`FlashAttentionType.MarshalJSON`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-flashattentiontype-marshalyaml`,children:`FlashAttentionType.MarshalYAML`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-flashattentiontype-string`,children:`FlashAttentionType.String`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-flashattentiontype-unmarshaljson`,children:`FlashAttentionType.UnmarshalJSON`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-flashattentiontype-unmarshalyaml`,children:`FlashAttentionType.UnmarshalYAML`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-ggmltype-marshaljson`,children:`GGMLType.MarshalJSON`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-ggmltype-marshalyaml`,children:`GGMLType.MarshalYAML`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-ggmltype-string`,children:`GGMLType.String`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-ggmltype-toyzmatype`,children:`GGMLType.ToYZMAType`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-ggmltype-unmarshaljson`,children:`GGMLType.UnmarshalJSON`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-ggmltype-unmarshalyaml`,children:`GGMLType.UnmarshalYAML`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-loadmode-marshaljson`,children:`LoadMode.MarshalJSON`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-loadmode-marshalyaml`,children:`LoadMode.MarshalYAML`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-loadmode-string`,children:`LoadMode.String`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-loadmode-toyzmatype`,children:`LoadMode.ToYZMAType`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-loadmode-unmarshaljson`,children:`LoadMode.UnmarshalJSON`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-loadmode-unmarshalyaml`,children:`LoadMode.UnmarshalYAML`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-moeconfig-keepexpertsongpufortopnlayers`,children:`MoEConfig.KeepExpertsOnGPUForTopNLayers`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-moemode-equal`,children:`MoEMode.Equal`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-moemode-iszero`,children:`MoEMode.IsZero`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-moemode-marshaltext`,children:`MoEMode.MarshalText`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-moemode-string`,children:`MoEMode.String`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-moemode-unmarshaltext`,children:`MoEMode.UnmarshalText`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-batchenginesnapshot`,children:`Model.BatchEngineSnapshot`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-chat`,children:`Model.Chat`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-chatstreaming`,children:`Model.ChatStreaming`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-config`,children:`Model.Config`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-decision`,children:`Model.Decision`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-embeddings`,children:`Model.Embeddings`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-imcsessions`,children:`Model.IMCSessions`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-imcsystemcaches`,children:`Model.IMCSystemCaches`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-modelinfo`,children:`Model.ModelInfo`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-rerank`,children:`Model.Rerank`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-tokenize`,children:`Model.Tokenize`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-unload`,children:`Model.Unload`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-modelinfo-string`,children:`ModelInfo.String`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-modeltype-string`,children:`ModelType.String`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-params-string`,children:`Params.String`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-responsemessage-marshaljson`,children:`ResponseMessage.MarshalJSON`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-ropescalingtype-marshaljson`,children:`RopeScalingType.MarshalJSON`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-ropescalingtype-marshalyaml`,children:`RopeScalingType.MarshalYAML`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-ropescalingtype-string`,children:`RopeScalingType.String`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-ropescalingtype-toyzmatype`,children:`RopeScalingType.ToYZMAType`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-ropescalingtype-unmarshaljson`,children:`RopeScalingType.UnmarshalJSON`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-ropescalingtype-unmarshalyaml`,children:`RopeScalingType.UnmarshalYAML`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-splitmode-marshaljson`,children:`SplitMode.MarshalJSON`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-splitmode-marshalyaml`,children:`SplitMode.MarshalYAML`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-splitmode-string`,children:`SplitMode.String`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-splitmode-toyzmatype`,children:`SplitMode.ToYZMAType`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-splitmode-unmarshaljson`,children:`SplitMode.UnmarshalJSON`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-splitmode-unmarshalyaml`,children:`SplitMode.UnmarshalYAML`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-streamingresponselogger-capture`,children:`StreamingResponseLogger.Capture`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-streamingresponselogger-string`,children:`StreamingResponseLogger.String`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-toolcallarguments-marshaljson`,children:`ToolCallArguments.MarshalJSON`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-toolcallarguments-unmarshaljson`,children:`ToolCallArguments.UnmarshalJSON`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#constants`,className:`doc-index-header`,children:`Constants`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#const-numadisabled`,children:`NUMADisabled`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#const-objectchatunknown`,children:`ObjectChatUnknown`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#const-roleuser`,children:`RoleUser`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#const-finishreasonstop`,children:`FinishReasonStop`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#const-defadaptivepdecay`,children:`DefAdaptivePDecay`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#const-thinkingenabled`,children:`ThinkingEnabled`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#const-reasoningeffortnone`,children:`ReasoningEffortNone`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#const-speculationauto`,children:`SpeculationAuto`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#const-defaultprefillbatchsize`,children:`DefaultPrefillBatchSize`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#const-defaultqueuedepth`,children:`DefaultQueueDepth`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#const-expertsallongpu`,children:`ExpertsAllOnGPU`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#variables`,className:`doc-index-header`,children:`Variables`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#var-variable`,children:`Variable`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#var-variable`,children:`Variable`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#var-errdecisionbudget`,children:`ErrDecisionBudget`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#var-errdecisionrequest`,children:`ErrDecisionRequest`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#var-errfileinputsunsupported`,children:`ErrFileInputsUnsupported`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#var-errinvalidrequest`,children:`ErrInvalidRequest`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#var-errmessagesinvalid`,children:`ErrMessagesInvalid`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#var-errmessagesmissing`,children:`ErrMessagesMissing`})})]})]})]})})]})]})}function Xv(){let e=at();return(0,x.useEffect)(()=>{let t=document.querySelector(`.main-content`);if(!t)return;if(!e.hash){t.scrollTo({top:0});return}let n=e.hash.slice(1);requestAnimationFrame(()=>{let e=document.getElementById(n);if(!e)return;let r=t.getBoundingClientRect(),i=e.getBoundingClientRect().top-r.top+t.scrollTop;t.scrollTo({top:i-20,behavior:`smooth`})})},[e.key,e.hash]),(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{className:`page-header`,children:[(0,G.jsx)(`h2`,{children:`Pool Package`}),(0,G.jsx)(`p`,{children:`Package pool manages a pool of kronk APIs for specific llama models. Used by the model server to manage the number of models that are maintained in memory at any given time.`}),(0,G.jsx)(`p`,{children:`The pool is a thin, llama-typed wrapper around the generic engine in sdk/pool. The cache, eviction policy, budget reservations, and concurrent-load deduplication live in the core; the llama-specific planning, loading, and display logic lives in this package's llama.go (which implements loader.Loader[*kronk.Kronk]). Sibling wrappers in sdk/bucky/pool (whisper) follow the same shape and share the resman.Manager passed in via Config.Resman so VRAM/RAM budgeting is unified across every backend.`})]}),(0,G.jsxs)(`div`,{className:`doc-layout`,children:[(0,G.jsxs)(`div`,{className:`doc-content`,children:[(0,G.jsxs)(`div`,{className:`card`,children:[(0,G.jsx)(`h3`,{children:`Import`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`import "github.com/ardanlabs/kronk/sdk/kronk/pool"`})})]}),(0,G.jsxs)(`div`,{className:`card`,id:`functions`,children:[(0,G.jsx)(`h3`,{children:`Functions`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-humanbytes`,children:[(0,G.jsx)(`h4`,{children:`HumanBytes`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func HumanBytes(n int64) string`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`HumanBytes formats a byte count using decimal (SI) units. It aliases the core helper so existing callers of pool.HumanBytes keep working.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-new`,children:[(0,G.jsx)(`h4`,{children:`New`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func New(cfg Config) (*Pool, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`New constructs the pool for use.`})]})]}),(0,G.jsxs)(`div`,{className:`card`,id:`types`,children:[(0,G.jsx)(`h3`,{children:`Types`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-batchenginedetail`,children:[(0,G.jsx)(`h4`,{children:`BatchEngineDetail`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`type BatchEngineDetail struct {
+)`})})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`const-defaultprefillbatchsize`,children:[(0,G.jsx)(`h4`,{children:`DefaultPrefillBatchSize`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`const DefaultPrefillBatchSize = int(vram.DefaultNUBatch)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`DefaultPrefillBatchSize is the prompt-token capacity used when prefill batch size is not explicitly configured.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`const-defaultqueuedepth`,children:[(0,G.jsx)(`h4`,{children:`DefaultQueueDepth`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`const DefaultQueueDepth = 2`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`DefaultQueueDepth is the number of admitted request layers used when queue depth is not explicitly configured.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`const-expertsallongpu`,children:[(0,G.jsx)(`h4`,{children:`ExpertsAllOnGPU`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`const ExpertsAllOnGPU = int64(math.MaxInt32)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ExpertsAllOnGPU is the sentinel value used for vram.Config.ExpertLayersOnGPU to request that every routed-expert layer be charged against GPU VRAM. The vram package treats any value greater than or equal to the model's block count as "all layers on GPU", so a large constant works regardless of model depth and avoids a metadata round-trip just to discover it.`})]})]}),(0,G.jsxs)(`div`,{className:`card`,id:`variables`,children:[(0,G.jsx)(`h3`,{children:`Variables`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`var-variable`,children:[(0,G.jsx)(`h4`,{children:`Variable`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`var (`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`// DecisionProtocolOpenJEV identifies the OpenJEV letter-readout protocol. DecisionProtocolOpenJEV = newDecisionProtocol("openjev")`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`// DecisionProtocolJevStyle identifies the macjev-render-v1 protocol. DecisionProtocolJevStyle = newDecisionProtocol("jev-style")`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`var-variable`,children:[(0,G.jsx)(`h4`,{children:`Variable`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`var (`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`// MoEModeAuto uses catalog defaults. MoEModeAuto = newMoEMode("auto")`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`// MoEModeExpertsCPU places all routed expert tensors on CPU. // Recommended for VRAM-constrained setups. MoEModeExpertsCPU = newMoEMode("experts_cpu")`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`// MoEModeExpertsGPU keeps all expert tensors on GPU. // Requires sufficient VRAM for the full model. MoEModeExpertsGPU = newMoEMode("experts_gpu")`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`// MoEModeKeepTopN keeps routed experts on GPU for the top N layers. // All other expert layers go to CPU. MoEModeKeepTopN = newMoEMode("keep_top_n")`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`// MoEModeCustom defers to TensorBuftOverrides for expert placement. MoEModeCustom = newMoEMode("custom")`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`var-errdecisionbudget`,children:[(0,G.jsx)(`h4`,{children:`ErrDecisionBudget`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`var ErrDecisionBudget = errors.New("decision input exceeds token budget")`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ErrDecisionBudget indicates that a rendered decision input exceeds the protocol's token budget. Inputs are never truncated.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`var-errdecisionrequest`,children:[(0,G.jsx)(`h4`,{children:`ErrDecisionRequest`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`var ErrDecisionRequest = errors.New("invalid decision request")`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ErrDecisionRequest indicates that a decision request is invalid.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`var-errfileinputsunsupported`,children:[(0,G.jsx)(`h4`,{children:`ErrFileInputsUnsupported`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`var ErrFileInputsUnsupported = errors.New("file inputs are not currently supported")`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ErrFileInputsUnsupported indicates file content parts are not supported.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`var-errinvalidrequest`,children:[(0,G.jsx)(`h4`,{children:`ErrInvalidRequest`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`var ErrInvalidRequest = errors.New("validate-document: invalid request")`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ErrInvalidRequest indicates that a model request contains an invalid or unsupported field value.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`var-errmessagesinvalid`,children:[(0,G.jsx)(`h4`,{children:`ErrMessagesInvalid`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`var ErrMessagesInvalid = errors.New("validate-document: messages is not a slice of documents")`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ErrMessagesInvalid indicates that a chat request's messages field has an invalid type.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`var-errmessagesmissing`,children:[(0,G.jsx)(`h4`,{children:`ErrMessagesMissing`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`var ErrMessagesMissing = errors.New("validate-document: no messages found in request")`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ErrMessagesMissing indicates that a chat request has no messages field.`})]})]})]}),(0,G.jsx)(`nav`,{className:`doc-sidebar`,children:(0,G.jsxs)(`div`,{className:`doc-sidebar-content`,children:[(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#functions`,className:`doc-index-header`,children:`Functions`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-addparams`,children:`AddParams`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-inityzmaworkarounds`,children:`InitYzmaWorkarounds`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-recurrentstatecopies`,children:`RecurrentStateCopies`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-registerparser`,children:`RegisterParser`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-speculativecontextcount`,children:`SpeculativeContextCount`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-validatechatrequest`,children:`ValidateChatRequest`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-validatemessages`,children:`ValidateMessages`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-newgrammarsampler`,children:`NewGrammarSampler`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-verifyartifact`,children:`VerifyArtifact`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-parsedecisionprotocol`,children:`ParseDecisionProtocol`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-parseggmltype`,children:`ParseGGMLType`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-parseloadmode`,children:`ParseLoadMode`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-parsemoemode`,children:`ParseMoEMode`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-newmodel`,children:`NewModel`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-detectmodeltypefromfiles`,children:`DetectModelTypeFromFiles`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-parseropescalingtype`,children:`ParseRopeScalingType`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-parsesplitmode`,children:`ParseSplitMode`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#types`,className:`doc-index-header`,children:`Types`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-adapterconfig`,children:`AdapterConfig`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-artifactdigest`,children:`ArtifactDigest`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-artifactintegrity`,children:`ArtifactIntegrity`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-artifactverification`,children:`ArtifactVerification`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-artifactverificationrecorder`,children:`ArtifactVerificationRecorder`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-batchenginesnapshot`,children:`BatchEngineSnapshot`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-batchgenerationcontribution`,children:`BatchGenerationContribution`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-batchslotsnapshot`,children:`BatchSlotSnapshot`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-channel`,children:`Channel`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-chatresponse`,children:`ChatResponse`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-choice`,children:`Choice`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-completiontokensdetails`,children:`CompletionTokensDetails`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-config`,children:`Config`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-contentlogprob`,children:`ContentLogprob`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-d`,children:`D`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-decisionanswer`,children:`DecisionAnswer`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-decisionnoulcriteria`,children:`DecisionNoulCriteria`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-decisionoption`,children:`DecisionOption`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-decisionprotocol`,children:`DecisionProtocol`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-decisionquestion`,children:`DecisionQuestion`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-decisionquestiontype`,children:`DecisionQuestionType`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-decisionrequest`,children:`DecisionRequest`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-decisionresponse`,children:`DecisionResponse`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-decisionstatefield`,children:`DecisionStateField`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-decisionstatevalue`,children:`DecisionStateValue`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-decisionusage`,children:`DecisionUsage`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-draftmodelconfig`,children:`DraftModelConfig`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-embeddata`,children:`EmbedData`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-embedreponse`,children:`EmbedReponse`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-embedusage`,children:`EmbedUsage`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-fingerprint`,children:`Fingerprint`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-flashattentiontype`,children:`FlashAttentionType`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-ggmltype`,children:`GGMLType`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-imcsessiondetail`,children:`IMCSessionDetail`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-imcsessionstate`,children:`IMCSessionState`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-imcsystemcachedetail`,children:`IMCSystemCacheDetail`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-loadmode`,children:`LoadMode`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-logger`,children:`Logger`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-logprobs`,children:`Logprobs`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-mediatype`,children:`MediaType`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-moeconfig`,children:`MoEConfig`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-moemode`,children:`MoEMode`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-model`,children:`Model`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-modelinfo`,children:`ModelInfo`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-modeltype`,children:`ModelType`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-option`,children:`Option`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-params`,children:`Params`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-paramsadjuster`,children:`ParamsAdjuster`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-parser`,children:`Parser`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-parserfactory`,children:`ParserFactory`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-prompttokensdetails`,children:`PromptTokensDetails`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-rerankresponse`,children:`RerankResponse`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-rerankresult`,children:`RerankResult`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-rerankusage`,children:`RerankUsage`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-responsemessage`,children:`ResponseMessage`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-responsetoolcall`,children:`ResponseToolCall`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-responsetoolcalldelta`,children:`ResponseToolCallDelta`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-responsetoolcalldeltafunction`,children:`ResponseToolCallDeltaFunction`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-responsetoolcallfunction`,children:`ResponseToolCallFunction`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-result`,children:`Result`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-ropescalingtype`,children:`RopeScalingType`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-sessionstore`,children:`SessionStore`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-sessionstorefactory`,children:`SessionStoreFactory`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-speculationmode`,children:`SpeculationMode`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-splitmode`,children:`SplitMode`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-statemachine`,children:`StateMachine`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-statemachineflusher`,children:`StateMachineFlusher`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-streamingresponselogger`,children:`StreamingResponseLogger`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-template`,children:`Template`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-tokenizeresponse`,children:`TokenizeResponse`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-toolawarestatemachine`,children:`ToolAwareStateMachine`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-toolcallarguments`,children:`ToolCallArguments`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-toolcalldeltastreamer`,children:`ToolCallDeltaStreamer`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-toolcallschemaparser`,children:`ToolCallSchemaParser`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-toplogprob`,children:`TopLogprob`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-usage`,children:`Usage`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-vocabeogconsumer`,children:`VocabEOGConsumer`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#methods`,className:`doc-index-header`,children:`Methods`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-choice-finishreason`,children:`Choice.FinishReason`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-admissiontimeout`,children:`Config.AdmissionTimeout`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-cachemintokens`,children:`Config.CacheMinTokens`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-contextwindow`,children:`Config.ContextWindow`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-effectivenbatch`,children:`Config.EffectiveNBatch`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-effectivenubatch`,children:`Config.EffectiveNUBatch`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-expertlayersongpu`,children:`Config.ExpertLayersOnGPU`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-flashattention`,children:`Config.FlashAttention`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-imcsessioncapacity`,children:`Config.IMCSessionCapacity`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-incrementalcache`,children:`Config.IncrementalCache`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-insecurelogging`,children:`Config.InsecureLogging`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-maingpu`,children:`Config.MainGPU`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-ngpulayers`,children:`Config.NGpuLayers`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-nseqmax`,children:`Config.NSeqMax`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-nthreads`,children:`Config.NThreads`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-nthreadsbatch`,children:`Config.NThreadsBatch`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-prefillbatchsize`,children:`Config.PrefillBatchSize`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-queuedepth`,children:`Config.QueueDepth`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-ropefreqbase`,children:`Config.RopeFreqBase`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-ropefreqscale`,children:`Config.RopeFreqScale`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-swafull`,children:`Config.SWAFull`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-speculationmode`,children:`Config.SpeculationMode`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-string`,children:`Config.String`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-yarnattnfactor`,children:`Config.YarnAttnFactor`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-yarnbetafast`,children:`Config.YarnBetaFast`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-yarnbetaslow`,children:`Config.YarnBetaSlow`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-yarnextfactor`,children:`Config.YarnExtFactor`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-yarnorigctx`,children:`Config.YarnOrigCtx`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-d-clone`,children:`D.Clone`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-d-messages`,children:`D.Messages`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-d-shallowclone`,children:`D.ShallowClone`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-d-string`,children:`D.String`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-decisionanswer-marshaljson`,children:`DecisionAnswer.MarshalJSON`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-decisionprotocol-equal`,children:`DecisionProtocol.Equal`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-decisionprotocol-iszero`,children:`DecisionProtocol.IsZero`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-decisionprotocol-marshaltext`,children:`DecisionProtocol.MarshalText`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-decisionprotocol-string`,children:`DecisionProtocol.String`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-decisionprotocol-unmarshaltext`,children:`DecisionProtocol.UnmarshalText`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-decisionstatevalue-marshaljson`,children:`DecisionStateValue.MarshalJSON`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-draftmodelconfig-isseparate`,children:`DraftModelConfig.IsSeparate`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-draftmodelconfig-maingpu`,children:`DraftModelConfig.MainGPU`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-draftmodelconfig-ngpulayers`,children:`DraftModelConfig.NGpuLayers`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-flashattentiontype-marshaljson`,children:`FlashAttentionType.MarshalJSON`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-flashattentiontype-marshalyaml`,children:`FlashAttentionType.MarshalYAML`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-flashattentiontype-string`,children:`FlashAttentionType.String`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-flashattentiontype-unmarshaljson`,children:`FlashAttentionType.UnmarshalJSON`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-flashattentiontype-unmarshalyaml`,children:`FlashAttentionType.UnmarshalYAML`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-ggmltype-marshaljson`,children:`GGMLType.MarshalJSON`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-ggmltype-marshalyaml`,children:`GGMLType.MarshalYAML`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-ggmltype-string`,children:`GGMLType.String`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-ggmltype-toyzmatype`,children:`GGMLType.ToYZMAType`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-ggmltype-unmarshaljson`,children:`GGMLType.UnmarshalJSON`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-ggmltype-unmarshalyaml`,children:`GGMLType.UnmarshalYAML`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-loadmode-marshaljson`,children:`LoadMode.MarshalJSON`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-loadmode-marshalyaml`,children:`LoadMode.MarshalYAML`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-loadmode-string`,children:`LoadMode.String`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-loadmode-toyzmatype`,children:`LoadMode.ToYZMAType`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-loadmode-unmarshaljson`,children:`LoadMode.UnmarshalJSON`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-loadmode-unmarshalyaml`,children:`LoadMode.UnmarshalYAML`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-moeconfig-keepexpertsongpufortopnlayers`,children:`MoEConfig.KeepExpertsOnGPUForTopNLayers`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-moemode-equal`,children:`MoEMode.Equal`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-moemode-iszero`,children:`MoEMode.IsZero`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-moemode-marshaltext`,children:`MoEMode.MarshalText`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-moemode-string`,children:`MoEMode.String`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-moemode-unmarshaltext`,children:`MoEMode.UnmarshalText`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-batchenginesnapshot`,children:`Model.BatchEngineSnapshot`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-chat`,children:`Model.Chat`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-chatstreaming`,children:`Model.ChatStreaming`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-config`,children:`Model.Config`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-decision`,children:`Model.Decision`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-embeddings`,children:`Model.Embeddings`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-imcsessions`,children:`Model.IMCSessions`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-imcsystemcaches`,children:`Model.IMCSystemCaches`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-modelinfo`,children:`Model.ModelInfo`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-rerank`,children:`Model.Rerank`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-tokenize`,children:`Model.Tokenize`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-unload`,children:`Model.Unload`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-modelinfo-string`,children:`ModelInfo.String`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-modeltype-string`,children:`ModelType.String`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-params-string`,children:`Params.String`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-responsemessage-marshaljson`,children:`ResponseMessage.MarshalJSON`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-ropescalingtype-marshaljson`,children:`RopeScalingType.MarshalJSON`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-ropescalingtype-marshalyaml`,children:`RopeScalingType.MarshalYAML`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-ropescalingtype-string`,children:`RopeScalingType.String`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-ropescalingtype-toyzmatype`,children:`RopeScalingType.ToYZMAType`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-ropescalingtype-unmarshaljson`,children:`RopeScalingType.UnmarshalJSON`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-ropescalingtype-unmarshalyaml`,children:`RopeScalingType.UnmarshalYAML`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-splitmode-marshaljson`,children:`SplitMode.MarshalJSON`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-splitmode-marshalyaml`,children:`SplitMode.MarshalYAML`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-splitmode-string`,children:`SplitMode.String`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-splitmode-toyzmatype`,children:`SplitMode.ToYZMAType`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-splitmode-unmarshaljson`,children:`SplitMode.UnmarshalJSON`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-splitmode-unmarshalyaml`,children:`SplitMode.UnmarshalYAML`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-streamingresponselogger-capture`,children:`StreamingResponseLogger.Capture`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-streamingresponselogger-string`,children:`StreamingResponseLogger.String`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-toolcallarguments-marshaljson`,children:`ToolCallArguments.MarshalJSON`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-toolcallarguments-unmarshaljson`,children:`ToolCallArguments.UnmarshalJSON`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#constants`,className:`doc-index-header`,children:`Constants`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#const-numadisabled`,children:`NUMADisabled`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#const-objectchatunknown`,children:`ObjectChatUnknown`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#const-roleuser`,children:`RoleUser`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#const-finishreasonstop`,children:`FinishReasonStop`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#const-defadaptivepdecay`,children:`DefAdaptivePDecay`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#const-thinkingenabled`,children:`ThinkingEnabled`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#const-reasoningeffortnone`,children:`ReasoningEffortNone`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#const-speculationauto`,children:`SpeculationAuto`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#const-defaultprefillbatchsize`,children:`DefaultPrefillBatchSize`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#const-defaultqueuedepth`,children:`DefaultQueueDepth`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#const-expertsallongpu`,children:`ExpertsAllOnGPU`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#variables`,className:`doc-index-header`,children:`Variables`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#var-variable`,children:`Variable`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#var-variable`,children:`Variable`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#var-errdecisionbudget`,children:`ErrDecisionBudget`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#var-errdecisionrequest`,children:`ErrDecisionRequest`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#var-errfileinputsunsupported`,children:`ErrFileInputsUnsupported`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#var-errinvalidrequest`,children:`ErrInvalidRequest`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#var-errmessagesinvalid`,children:`ErrMessagesInvalid`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#var-errmessagesmissing`,children:`ErrMessagesMissing`})})]})]})]})})]})]})}function Xv(){let e=at();return(0,x.useEffect)(()=>{let t=document.querySelector(`.main-content`);if(!t)return;if(!e.hash){t.scrollTo({top:0});return}let n=e.hash.slice(1);requestAnimationFrame(()=>{let e=document.getElementById(n);if(!e)return;let r=t.getBoundingClientRect(),i=e.getBoundingClientRect().top-r.top+t.scrollTop;t.scrollTo({top:i-20,behavior:`smooth`})})},[e.key,e.hash]),(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{className:`page-header`,children:[(0,G.jsx)(`h2`,{children:`Pool Package`}),(0,G.jsx)(`p`,{children:`Package pool manages a pool of kronk APIs for specific llama models. Used by the model server to manage the number of models that are maintained in memory at any given time.`}),(0,G.jsx)(`p`,{children:`The pool is a thin, llama-typed wrapper around the generic engine in sdk/pool. The cache, eviction policy, budget reservations, and concurrent-load deduplication live in the core; the llama-specific planning, loading, and display logic lives in this package's llama.go (which implements loader.Loader[*kronk.Kronk]). Sibling wrappers in sdk/bucky/pool (whisper) follow the same shape and share the resman.Manager passed in via Config.Resman so VRAM/RAM budgeting is unified across every backend.`})]}),(0,G.jsxs)(`div`,{className:`doc-layout`,children:[(0,G.jsxs)(`div`,{className:`doc-content`,children:[(0,G.jsxs)(`div`,{className:`card`,children:[(0,G.jsx)(`h3`,{children:`Import`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`import "github.com/ardanlabs/kronk/sdk/kronk/pool"`})})]}),(0,G.jsxs)(`div`,{className:`card`,id:`functions`,children:[(0,G.jsx)(`h3`,{children:`Functions`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-humanbytes`,children:[(0,G.jsx)(`h4`,{children:`HumanBytes`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func HumanBytes(n int64) string`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`HumanBytes formats a byte count using decimal (SI) units. It aliases the core helper so existing callers of pool.HumanBytes keep working.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-new`,children:[(0,G.jsx)(`h4`,{children:`New`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func New(cfg Config) (*Pool, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`New constructs the pool for use.`})]})]}),(0,G.jsxs)(`div`,{className:`card`,id:`types`,children:[(0,G.jsx)(`h3`,{children:`Types`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-batchenginedetail`,children:[(0,G.jsx)(`h4`,{children:`BatchEngineDetail`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`type BatchEngineDetail struct {
ModelID string
model.BatchEngineSnapshot
}`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`BatchEngineDetail provides the current generation scheduler state for one loaded model.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-config`,children:[(0,G.jsx)(`h4`,{children:`Config`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`type Config struct {
@@ -790,7 +790,7 @@ kronk server start`})]})]})}function Is(e){let t=/^([\d.]+)\s*(MB|GB|KB|B)?$/i.e
Status string
}`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ModelDetail provides details for the models in the pool.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Backend identifies which pool produced the entry ("kronk" for llama.cpp models, "bucky" for whisper models). The BUI uses it to tag rows and tailor the unload path.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-pool`,children:[(0,G.jsx)(`h4`,{children:`Pool`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`type Pool struct {
// Has unexported fields.
-}`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Pool manages a set of Kronk APIs for use. It maintains a pool of these APIs and will unload them over time if not in use.`})]})]}),(0,G.jsxs)(`div`,{className:`card`,id:`methods`,children:[(0,G.jsx)(`h3`,{children:`Methods`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-llama-display`,children:[(0,G.jsx)(`h4`,{children:`Llama.Display`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (l *Llama) Display(krn *kronk.Kronk, modelID string) loader.Display`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Display implements loader.Loader.Display for the llama backend.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`It returns the KV cache and total VRAM values to surface in BUI/observability output for a loaded model. Both this path and the SDK-internal calculateVRAMDiag route through vram.FromFiles, so the two computations are byte-identical for any well-formed local model. The dedicated lookup is retained so a hypothetical resman-side failure (e.g. an index miss) cleanly falls back to the values the SDK stored at load time rather than zeroing out the BUI display.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-llama-load`,children:[(0,G.jsx)(`h4`,{children:`Llama.Load`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (l *Llama) Load(ctx context.Context, req loader.LoadRequest) (*kronk.Kronk, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Load implements loader.Loader.Load for the llama backend.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-llama-modelconfig`,children:[(0,G.jsx)(`h4`,{children:`Llama.ModelConfig`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (l *Llama) ModelConfig() map[string]models.ModelConfig`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ModelConfig returns the loaded per-model configuration overrides.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-llama-models`,children:[(0,G.jsx)(`h4`,{children:`Llama.Models`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (l *Llama) Models() *models.Models`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Models returns the underlying models system. Pool wrappers expose this for catalog-flavored APIs (ModelStatus, ModelConfig lookup).`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-llama-plan`,children:[(0,G.jsx)(`h4`,{children:`Llama.Plan`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (l *Llama) Plan(ctx context.Context, req loader.LoadRequest) (resman.PlanRequest, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Plan implements loader.Loader.Plan for the llama backend.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`It charges the predicted VRAM and system-RAM footprints to the resman independently so MoE models — whose routed experts can live on either side depending on the runtime placement — are accounted for accurately. Charging only the GPU side silently drops the CPU-resident expert weights, producing under-counts of the real resident footprint and exposing the pool to OOM on multi-load scenarios.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-llama-prepare`,children:[(0,G.jsx)(`h4`,{children:`Llama.Prepare`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (l *Llama) Prepare(_ context.Context, req loader.LoadRequest) (any, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Prepare resolves the model configuration once for both planning and loading.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-llama-resolvedmodelconfig`,children:[(0,G.jsx)(`h4`,{children:`Llama.ResolvedModelConfig`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (l *Llama) ResolvedModelConfig(modelID string) (models.ModelConfig, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ResolvedModelConfig returns the same budgeted configuration used to prepare a model for planning and loading.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-llama-validate`,children:[(0,G.jsx)(`h4`,{children:`Llama.Validate`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (l *Llama) Validate(ctx context.Context, req loader.LoadRequest, _ *kronk.Kronk) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Validate checks live backend headroom after every native context has been created but before the pool publishes the handle. CUDA and HIP report runtime device memory. Metal remains advisory because GGML reports recommendedMaxWorkingSetSize rather than physical unified-memory capacity. Vulkan also remains advisory because drivers without VK_EXT_memory_budget report the whole heap as free.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-pool-aquirecustom`,children:[(0,G.jsx)(`h4`,{children:`Pool.AquireCustom`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (p *Pool) AquireCustom(ctx context.Context, key string, cfg model.Config) (*kronk.Kronk, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`AquireCustom will provide a kronk API for a model using a pre-built config. This bypasses the normal catalog resolution path. The key includes the canonical model ID followed by the custom workload name.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-pool-aquiremodel`,children:[(0,G.jsx)(`h4`,{children:`Pool.AquireModel`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (p *Pool) AquireModel(ctx context.Context, modelID string) (*kronk.Kronk, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`AquireModel will provide a kronk API for the specified model. If the model is not in the pool, an API for the model will be created.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-pool-batchenginesnapshots`,children:[(0,G.jsx)(`h4`,{children:`Pool.BatchEngineSnapshots`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (p *Pool) BatchEngineSnapshots() []BatchEngineDetail`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`BatchEngineSnapshots returns the latest generation scheduler state for each loaded language model. Embedding and reranking models are omitted.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-pool-getexisting`,children:[(0,G.jsx)(`h4`,{children:`Pool.GetExisting`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (p *Pool) GetExisting(key string) (*kronk.Kronk, bool)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`GetExisting returns a pooled model if it exists, without creating one.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-pool-imcsessions`,children:[(0,G.jsx)(`h4`,{children:`Pool.IMCSessions`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (p *Pool) IMCSessions() []IMCSessionDetail`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`IMCSessions returns the current IMC cache entries for loaded models. It does not load models or retain session history.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-pool-imcsystemcaches`,children:[(0,G.jsx)(`h4`,{children:`Pool.IMCSystemCaches`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (p *Pool) IMCSystemCaches() []IMCSystemCacheDetail`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`IMCSystemCaches returns System cache pool entries for loaded models.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-pool-invalidate`,children:[(0,G.jsx)(`h4`,{children:`Pool.Invalidate`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (p *Pool) Invalidate(key string)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Invalidate removes a single entry from the pool, triggering unload.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`This is fire-and-forget: the eviction callback runs asynchronously, so the resource manager's reservation may not be released by the time this returns. Callers that need a consistent post-eviction view of the pool should use InvalidateSync instead.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-pool-invalidatesync`,children:[(0,G.jsx)(`h4`,{children:`Pool.InvalidateSync`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (p *Pool) InvalidateSync(ctx context.Context, key string) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`InvalidateSync invalidates a cache entry and waits for the eviction callback to release the underlying resource manager reservation.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-pool-modelconfig`,children:[(0,G.jsx)(`h4`,{children:`Pool.ModelConfig`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (p *Pool) ModelConfig() map[string]models.ModelConfig`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ModelConfig returns the loaded per-model configuration overrides.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-pool-modelstatus`,children:[(0,G.jsx)(`h4`,{children:`Pool.ModelStatus`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (p *Pool) ModelStatus() ([]ModelDetail, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ModelStatus returns information about the current models in the pool.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`The result includes both fully loaded models (entries currently in the cache) and in-flight loads (memory reservations that have not yet completed their GGUF read). The latter are returned with Status=ModelStatusLoading so BUI/observability can show them as occupying budget while still being unavailable to serve requests.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Cache keys use provider/modelID or provider/modelID/profile. The catalog resolver recovers the physical model metadata without discarding a profile.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-pool-resolvedmodelconfig`,children:[(0,G.jsx)(`h4`,{children:`Pool.ResolvedModelConfig`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (p *Pool) ResolvedModelConfig(modelID string) (models.ModelConfig, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ResolvedModelConfig returns the same budgeted configuration used to prepare a model for planning and loading.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-pool-resourcemanager`,children:[(0,G.jsx)(`h4`,{children:`Pool.ResourceManager`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (p *Pool) ResourceManager() *resman.Manager`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ResourceManager returns the pool's underlying resource manager.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-pool-shutdown`,children:[(0,G.jsx)(`h4`,{children:`Pool.Shutdown`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (p *Pool) Shutdown(ctx context.Context) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Shutdown releases all apis from the pool and performs a proper unloading.`})]})]}),(0,G.jsxs)(`div`,{className:`card`,id:`constants`,children:[(0,G.jsx)(`h3`,{children:`Constants`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`const-modelstatusloaded`,children:[(0,G.jsx)(`h4`,{children:`ModelStatusLoaded`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`const (
+}`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Pool manages a set of Kronk APIs for use. It maintains a pool of these APIs and will unload them over time if not in use.`})]})]}),(0,G.jsxs)(`div`,{className:`card`,id:`methods`,children:[(0,G.jsx)(`h3`,{children:`Methods`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-llama-display`,children:[(0,G.jsx)(`h4`,{children:`Llama.Display`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (l *Llama) Display(krn *kronk.Kronk, _ string) loader.Display`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Display implements loader.Loader.Display for the llama backend.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`It returns the KV cache and total VRAM values to surface in BUI/observability output for a loaded model. The SDK calculated and stored these values while loading the model, so status queries do not need to read and parse the GGUF header again.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-llama-load`,children:[(0,G.jsx)(`h4`,{children:`Llama.Load`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (l *Llama) Load(ctx context.Context, req loader.LoadRequest) (*kronk.Kronk, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Load implements loader.Loader.Load for the llama backend.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-llama-modelconfig`,children:[(0,G.jsx)(`h4`,{children:`Llama.ModelConfig`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (l *Llama) ModelConfig() map[string]models.ModelConfig`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ModelConfig returns the loaded per-model configuration overrides.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-llama-models`,children:[(0,G.jsx)(`h4`,{children:`Llama.Models`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (l *Llama) Models() *models.Models`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Models returns the underlying models system. Pool wrappers expose this for catalog-flavored APIs (ModelStatus, ModelConfig lookup).`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-llama-plan`,children:[(0,G.jsx)(`h4`,{children:`Llama.Plan`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (l *Llama) Plan(ctx context.Context, req loader.LoadRequest) (resman.PlanRequest, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Plan implements loader.Loader.Plan for the llama backend.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`It charges the predicted VRAM and system-RAM footprints to the resman independently so MoE models — whose routed experts can live on either side depending on the runtime placement — are accounted for accurately. Charging only the GPU side silently drops the CPU-resident expert weights, producing under-counts of the real resident footprint and exposing the pool to OOM on multi-load scenarios.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-llama-prepare`,children:[(0,G.jsx)(`h4`,{children:`Llama.Prepare`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (l *Llama) Prepare(_ context.Context, req loader.LoadRequest) (any, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Prepare resolves the model configuration once for both planning and loading.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-llama-resolvedkronkconfig`,children:[(0,G.jsx)(`h4`,{children:`Llama.ResolvedKronkConfig`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (l *Llama) ResolvedKronkConfig(modelID string) (model.Config, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ResolvedKronkConfig returns the same budgeted runtime configuration used to prepare a model for planning and loading.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-llama-resolvedmodelconfig`,children:[(0,G.jsx)(`h4`,{children:`Llama.ResolvedModelConfig`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (l *Llama) ResolvedModelConfig(modelID string) (models.ModelConfig, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ResolvedModelConfig returns the same budgeted configuration used to prepare a model for planning and loading.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-llama-validate`,children:[(0,G.jsx)(`h4`,{children:`Llama.Validate`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (l *Llama) Validate(ctx context.Context, req loader.LoadRequest, _ *kronk.Kronk) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Validate checks live backend headroom after every native context has been created but before the pool publishes the handle. CUDA and HIP report runtime device memory. Metal remains advisory because GGML reports recommendedMaxWorkingSetSize rather than physical unified-memory capacity. Vulkan also remains advisory because drivers without VK_EXT_memory_budget report the whole heap as free.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-pool-aquirecustom`,children:[(0,G.jsx)(`h4`,{children:`Pool.AquireCustom`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (p *Pool) AquireCustom(ctx context.Context, key string, cfg model.Config) (*kronk.Kronk, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`AquireCustom will provide a kronk API for a model using a pre-built config. This bypasses the normal catalog resolution path. The key includes the canonical model ID followed by the custom workload name.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-pool-aquiremodel`,children:[(0,G.jsx)(`h4`,{children:`Pool.AquireModel`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (p *Pool) AquireModel(ctx context.Context, modelID string) (*kronk.Kronk, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`AquireModel will provide a kronk API for the specified model. If the model is not in the pool, an API for the model will be created.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-pool-batchenginesnapshots`,children:[(0,G.jsx)(`h4`,{children:`Pool.BatchEngineSnapshots`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (p *Pool) BatchEngineSnapshots() []BatchEngineDetail`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`BatchEngineSnapshots returns the latest generation scheduler state for each loaded language model. Embedding and reranking models are omitted.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-pool-getexisting`,children:[(0,G.jsx)(`h4`,{children:`Pool.GetExisting`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (p *Pool) GetExisting(key string) (*kronk.Kronk, bool)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`GetExisting returns a pooled model if it exists, without creating one.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-pool-imcsessions`,children:[(0,G.jsx)(`h4`,{children:`Pool.IMCSessions`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (p *Pool) IMCSessions() []IMCSessionDetail`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`IMCSessions returns the current IMC cache entries for loaded models. It does not load models or retain session history.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-pool-imcsystemcaches`,children:[(0,G.jsx)(`h4`,{children:`Pool.IMCSystemCaches`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (p *Pool) IMCSystemCaches() []IMCSystemCacheDetail`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`IMCSystemCaches returns System cache pool entries for loaded models.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-pool-invalidate`,children:[(0,G.jsx)(`h4`,{children:`Pool.Invalidate`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (p *Pool) Invalidate(key string)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Invalidate removes a single entry from the pool, triggering unload.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`This is fire-and-forget: the eviction callback runs asynchronously, so the resource manager's reservation may not be released by the time this returns. Callers that need a consistent post-eviction view of the pool should use InvalidateSync instead.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-pool-invalidatesync`,children:[(0,G.jsx)(`h4`,{children:`Pool.InvalidateSync`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (p *Pool) InvalidateSync(ctx context.Context, key string) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`InvalidateSync invalidates a cache entry and waits for the eviction callback to release the underlying resource manager reservation. If unloading fails, the model and reservation remain in the pool and the error is returned.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-pool-modelconfig`,children:[(0,G.jsx)(`h4`,{children:`Pool.ModelConfig`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (p *Pool) ModelConfig() map[string]models.ModelConfig`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ModelConfig returns the loaded per-model configuration overrides.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-pool-modelstatus`,children:[(0,G.jsx)(`h4`,{children:`Pool.ModelStatus`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (p *Pool) ModelStatus() ([]ModelDetail, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ModelStatus returns information about the current models in the pool.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`The result includes both fully loaded models (entries currently in the cache) and in-flight loads (memory reservations that have not yet completed their GGUF read). The latter are returned with Status=ModelStatusLoading so BUI/observability can show them as occupying budget while still being unavailable to serve requests.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Cache keys use provider/modelID or provider/modelID/profile. The catalog resolver recovers the physical model metadata without discarding a profile.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-pool-resolvedkronkconfig`,children:[(0,G.jsx)(`h4`,{children:`Pool.ResolvedKronkConfig`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (p *Pool) ResolvedKronkConfig(modelID string) (model.Config, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ResolvedKronkConfig returns the same budgeted runtime configuration used to prepare a model for planning and loading.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-pool-resolvedmodelconfig`,children:[(0,G.jsx)(`h4`,{children:`Pool.ResolvedModelConfig`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (p *Pool) ResolvedModelConfig(modelID string) (models.ModelConfig, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ResolvedModelConfig returns the same budgeted configuration used to prepare a model for planning and loading.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-pool-resourcemanager`,children:[(0,G.jsx)(`h4`,{children:`Pool.ResourceManager`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (p *Pool) ResourceManager() *resman.Manager`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ResourceManager returns the pool's underlying resource manager.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-pool-shutdown`,children:[(0,G.jsx)(`h4`,{children:`Pool.Shutdown`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (p *Pool) Shutdown(ctx context.Context) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Shutdown releases all apis from the pool and performs a proper unloading.`})]})]}),(0,G.jsxs)(`div`,{className:`card`,id:`constants`,children:[(0,G.jsx)(`h3`,{children:`Constants`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`const-modelstatusloaded`,children:[(0,G.jsx)(`h4`,{children:`ModelStatusLoaded`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`const (
// ModelStatusLoaded means the model is fully loaded into the cache and
// ready to serve requests.
ModelStatusLoaded = "loaded"
@@ -799,7 +799,7 @@ kronk server start`})]})]})}function Is(e){let t=/^([\d.]+)\s*(MB|GB|KB|B)?$/i.e
// the model but the GGUF is still being read from disk and prepared by
// llama.cpp. It is not yet servable.
ModelStatusLoading = "loading"
-)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Model status values surfaced to BUI/observability.`})]})]}),(0,G.jsxs)(`div`,{className:`card`,id:`variables`,children:[(0,G.jsx)(`h3`,{children:`Variables`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`var-errnocapacity`,children:[(0,G.jsx)(`h4`,{children:`ErrNoCapacity`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`var ErrNoCapacity = errors.New("pool: insufficient memory budget")`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ErrNoCapacity is returned when a request's memory footprint can never fit in the configured budget on this hardware, even on an empty pool (e.g. an over-spec'd context window). It is the pool's public translation of the internal resman.ErrNoCapacity so callers can match on a pool-level sentinel without importing resman.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`var-errserverbusy`,children:[(0,G.jsx)(`h4`,{children:`ErrServerBusy`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`var ErrServerBusy = engine.ErrServerBusy`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ErrServerBusy is returned when the pool cannot make room for a new entry because no idle pool entry is available to evict. It aliases the core sentinel so errors.Is works across both packages.`})]})]})]}),(0,G.jsx)(`nav`,{className:`doc-sidebar`,children:(0,G.jsxs)(`div`,{className:`doc-sidebar-content`,children:[(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#functions`,className:`doc-index-header`,children:`Functions`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-humanbytes`,children:`HumanBytes`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-new`,children:`New`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#types`,className:`doc-index-header`,children:`Types`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-batchenginedetail`,children:`BatchEngineDetail`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-config`,children:`Config`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-imcsessiondetail`,children:`IMCSessionDetail`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-imcsystemcachedetail`,children:`IMCSystemCacheDetail`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-llama`,children:`Llama`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-modeldetail`,children:`ModelDetail`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-pool`,children:`Pool`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#methods`,className:`doc-index-header`,children:`Methods`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-llama-display`,children:`Llama.Display`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-llama-load`,children:`Llama.Load`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-llama-modelconfig`,children:`Llama.ModelConfig`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-llama-models`,children:`Llama.Models`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-llama-plan`,children:`Llama.Plan`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-llama-prepare`,children:`Llama.Prepare`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-llama-resolvedmodelconfig`,children:`Llama.ResolvedModelConfig`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-llama-validate`,children:`Llama.Validate`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-pool-aquirecustom`,children:`Pool.AquireCustom`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-pool-aquiremodel`,children:`Pool.AquireModel`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-pool-batchenginesnapshots`,children:`Pool.BatchEngineSnapshots`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-pool-getexisting`,children:`Pool.GetExisting`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-pool-imcsessions`,children:`Pool.IMCSessions`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-pool-imcsystemcaches`,children:`Pool.IMCSystemCaches`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-pool-invalidate`,children:`Pool.Invalidate`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-pool-invalidatesync`,children:`Pool.InvalidateSync`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-pool-modelconfig`,children:`Pool.ModelConfig`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-pool-modelstatus`,children:`Pool.ModelStatus`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-pool-resolvedmodelconfig`,children:`Pool.ResolvedModelConfig`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-pool-resourcemanager`,children:`Pool.ResourceManager`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-pool-shutdown`,children:`Pool.Shutdown`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#constants`,className:`doc-index-header`,children:`Constants`}),(0,G.jsx)(`ul`,{children:(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#const-modelstatusloaded`,children:`ModelStatusLoaded`})})})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#variables`,className:`doc-index-header`,children:`Variables`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#var-errnocapacity`,children:`ErrNoCapacity`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#var-errserverbusy`,children:`ErrServerBusy`})})]})]})]})})]})]})}function Zv(){let e=at();return(0,x.useEffect)(()=>{let t=document.querySelector(`.main-content`);if(!t)return;if(!e.hash){t.scrollTo({top:0});return}let n=e.hash.slice(1);requestAnimationFrame(()=>{let e=document.getElementById(n);if(!e)return;let r=t.getBoundingClientRect(),i=e.getBoundingClientRect().top-r.top+t.scrollTop;t.scrollTo({top:i-20,behavior:`smooth`})})},[e.key,e.hash]),(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{className:`page-header`,children:[(0,G.jsx)(`h2`,{children:`Bucky Package`}),(0,G.jsx)(`p`,{children:`Package bucky is the high-level whisper SDK entry point. It mirrors the role sdk/kronk plays for the llama backend: cross-cutting initialization, library loading, and the Acquire / Transcribe surface.`}),(0,G.jsx)(`p`,{children:`Init publishes the whisper backend's libraries + catalog factories to the cross-backend registry and loads the whisper.cpp shared library so subsequent New / NewWithContext calls can construct a model handle. Callers that do not use whisper simply skip the Init call and the backend is never registered.`})]}),(0,G.jsxs)(`div`,{className:`doc-layout`,children:[(0,G.jsxs)(`div`,{className:`doc-content`,children:[(0,G.jsxs)(`div`,{className:`card`,children:[(0,G.jsx)(`h3`,{children:`Import`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`import "github.com/ardanlabs/kronk/sdk/bucky"`})})]}),(0,G.jsxs)(`div`,{className:`card`,id:`functions`,children:[(0,G.jsx)(`h3`,{children:`Functions`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-init`,children:[(0,G.jsx)(`h4`,{children:`Init`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func Init(opts ...InitOption) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Init initializes the bucky / whisper backend. It registers the whisper backend with the cross-backend registry under backend.KindWhisper, then resolves the install path for the whisper.cpp shared library and loads it. If initialization fails, subsequent calls will retry — allowing libraries to be downloaded and loaded without restarting the server.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-initialized`,children:[(0,G.jsx)(`h4`,{children:`Initialized`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func Initialized() bool`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Initialized reports whether the bucky backend has been successfully initialized. This can be used to determine if the server is running in a degraded state due to missing whisper.cpp libraries.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-langid`,children:[(0,G.jsx)(`h4`,{children:`LangID`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func LangID(lang string) int32`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`LangID returns the whisper.cpp internal id for the supplied language code (e.g. "de" → 2). Returns -1 if the code is unknown.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Init must have been called before LangID, since the FFI symbol is resolved by whisper.Load.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-langmaxid`,children:[(0,G.jsx)(`h4`,{children:`LangMaxID`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func LangMaxID() int32`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`LangMaxID returns the largest language id whisper.cpp knows. The number of supported languages is LangMaxID()+1.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-langstr`,children:[(0,G.jsx)(`h4`,{children:`LangStr`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func LangStr(id int32) string`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`LangStr returns the short language code for the supplied id (e.g. 2 → "de"). Returns "" if the id is invalid.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-setfmtloggertraceid`,children:[(0,G.jsx)(`h4`,{children:`SetFmtLoggerTraceID`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func SetFmtLoggerTraceID(ctx context.Context, traceID string) context.Context`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`SetFmtLoggerTraceID allows you to set a trace id on the context that can be included in FmtLogger output.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-new`,children:[(0,G.jsx)(`h4`,{children:`New`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func New(opts ...model.Option) (*Bucky, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`New provides the ability to use a whisper model in a concurrently safe way.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-newwithcontext`,children:[(0,G.jsx)(`h4`,{children:`NewWithContext`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func NewWithContext(ctx context.Context, opts ...model.Option) (*Bucky, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`NewWithContext provides the ability to use a whisper model in a concurrently safe way. The context is used to support logging trace ids during model loading.`})]})]}),(0,G.jsxs)(`div`,{className:`card`,id:`types`,children:[(0,G.jsx)(`h3`,{children:`Types`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-bucky`,children:[(0,G.jsx)(`h4`,{children:`Bucky`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`type Bucky struct {
+)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Model status values surfaced to BUI/observability.`})]})]}),(0,G.jsxs)(`div`,{className:`card`,id:`variables`,children:[(0,G.jsx)(`h3`,{children:`Variables`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`var-errnocapacity`,children:[(0,G.jsx)(`h4`,{children:`ErrNoCapacity`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`var ErrNoCapacity = errors.New("pool: insufficient memory budget")`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ErrNoCapacity is returned when a request's memory footprint can never fit in the configured budget on this hardware, even on an empty pool (e.g. an over-spec'd context window). It is the pool's public translation of the internal resman.ErrNoCapacity so callers can match on a pool-level sentinel without importing resman.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`var-errserverbusy`,children:[(0,G.jsx)(`h4`,{children:`ErrServerBusy`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`var ErrServerBusy = engine.ErrServerBusy`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ErrServerBusy is returned when the pool cannot make room for a new entry because no idle pool entry is available to evict. It aliases the core sentinel so errors.Is works across both packages.`})]})]})]}),(0,G.jsx)(`nav`,{className:`doc-sidebar`,children:(0,G.jsxs)(`div`,{className:`doc-sidebar-content`,children:[(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#functions`,className:`doc-index-header`,children:`Functions`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-humanbytes`,children:`HumanBytes`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-new`,children:`New`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#types`,className:`doc-index-header`,children:`Types`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-batchenginedetail`,children:`BatchEngineDetail`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-config`,children:`Config`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-imcsessiondetail`,children:`IMCSessionDetail`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-imcsystemcachedetail`,children:`IMCSystemCacheDetail`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-llama`,children:`Llama`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-modeldetail`,children:`ModelDetail`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-pool`,children:`Pool`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#methods`,className:`doc-index-header`,children:`Methods`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-llama-display`,children:`Llama.Display`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-llama-load`,children:`Llama.Load`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-llama-modelconfig`,children:`Llama.ModelConfig`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-llama-models`,children:`Llama.Models`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-llama-plan`,children:`Llama.Plan`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-llama-prepare`,children:`Llama.Prepare`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-llama-resolvedkronkconfig`,children:`Llama.ResolvedKronkConfig`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-llama-resolvedmodelconfig`,children:`Llama.ResolvedModelConfig`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-llama-validate`,children:`Llama.Validate`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-pool-aquirecustom`,children:`Pool.AquireCustom`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-pool-aquiremodel`,children:`Pool.AquireModel`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-pool-batchenginesnapshots`,children:`Pool.BatchEngineSnapshots`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-pool-getexisting`,children:`Pool.GetExisting`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-pool-imcsessions`,children:`Pool.IMCSessions`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-pool-imcsystemcaches`,children:`Pool.IMCSystemCaches`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-pool-invalidate`,children:`Pool.Invalidate`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-pool-invalidatesync`,children:`Pool.InvalidateSync`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-pool-modelconfig`,children:`Pool.ModelConfig`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-pool-modelstatus`,children:`Pool.ModelStatus`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-pool-resolvedkronkconfig`,children:`Pool.ResolvedKronkConfig`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-pool-resolvedmodelconfig`,children:`Pool.ResolvedModelConfig`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-pool-resourcemanager`,children:`Pool.ResourceManager`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-pool-shutdown`,children:`Pool.Shutdown`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#constants`,className:`doc-index-header`,children:`Constants`}),(0,G.jsx)(`ul`,{children:(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#const-modelstatusloaded`,children:`ModelStatusLoaded`})})})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#variables`,className:`doc-index-header`,children:`Variables`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#var-errnocapacity`,children:`ErrNoCapacity`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#var-errserverbusy`,children:`ErrServerBusy`})})]})]})]})})]})]})}function Zv(){let e=at();return(0,x.useEffect)(()=>{let t=document.querySelector(`.main-content`);if(!t)return;if(!e.hash){t.scrollTo({top:0});return}let n=e.hash.slice(1);requestAnimationFrame(()=>{let e=document.getElementById(n);if(!e)return;let r=t.getBoundingClientRect(),i=e.getBoundingClientRect().top-r.top+t.scrollTop;t.scrollTo({top:i-20,behavior:`smooth`})})},[e.key,e.hash]),(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{className:`page-header`,children:[(0,G.jsx)(`h2`,{children:`Bucky Package`}),(0,G.jsx)(`p`,{children:`Package bucky is the high-level whisper SDK entry point. It mirrors the role sdk/kronk plays for the llama backend: cross-cutting initialization, library loading, and the Acquire / Transcribe surface.`}),(0,G.jsx)(`p`,{children:`Init publishes the whisper backend's libraries + catalog factories to the cross-backend registry and loads the whisper.cpp shared library so subsequent New / NewWithContext calls can construct a model handle. Callers that do not use whisper simply skip the Init call and the backend is never registered.`})]}),(0,G.jsxs)(`div`,{className:`doc-layout`,children:[(0,G.jsxs)(`div`,{className:`doc-content`,children:[(0,G.jsxs)(`div`,{className:`card`,children:[(0,G.jsx)(`h3`,{children:`Import`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`import "github.com/ardanlabs/kronk/sdk/bucky"`})})]}),(0,G.jsxs)(`div`,{className:`card`,id:`functions`,children:[(0,G.jsx)(`h3`,{children:`Functions`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-init`,children:[(0,G.jsx)(`h4`,{children:`Init`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func Init(opts ...InitOption) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Init initializes the bucky / whisper backend. It registers the whisper backend with the cross-backend registry under backend.KindWhisper, then resolves the install path for the whisper.cpp shared library and loads it. If initialization fails, subsequent calls will retry — allowing libraries to be downloaded and loaded without restarting the server.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-initialized`,children:[(0,G.jsx)(`h4`,{children:`Initialized`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func Initialized() bool`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Initialized reports whether the bucky backend has been successfully initialized. This can be used to determine if the server is running in a degraded state due to missing whisper.cpp libraries.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-langid`,children:[(0,G.jsx)(`h4`,{children:`LangID`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func LangID(lang string) int32`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`LangID returns the whisper.cpp internal id for the supplied language code (e.g. "de" → 2). Returns -1 if the code is unknown.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Init must have been called before LangID, since the FFI symbol is resolved by whisper.Load.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-langmaxid`,children:[(0,G.jsx)(`h4`,{children:`LangMaxID`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func LangMaxID() int32`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`LangMaxID returns the largest language id whisper.cpp knows. The number of supported languages is LangMaxID()+1.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-langstr`,children:[(0,G.jsx)(`h4`,{children:`LangStr`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func LangStr(id int32) string`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`LangStr returns the short language code for the supplied id (e.g. 2 → "de"). Returns "" if the id is invalid.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-setfmtloggertraceid`,children:[(0,G.jsx)(`h4`,{children:`SetFmtLoggerTraceID`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func SetFmtLoggerTraceID(ctx context.Context, traceID string) context.Context`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`SetFmtLoggerTraceID allows you to set a trace id on the context that can be included in FmtLogger output.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-new`,children:[(0,G.jsx)(`h4`,{children:`New`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func New(opts ...model.Option) (*Bucky, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`New provides the ability to use a whisper model in a concurrently safe way.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-newwithcontext`,children:[(0,G.jsx)(`h4`,{children:`NewWithContext`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func NewWithContext(ctx context.Context, opts ...model.Option) (*Bucky, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`NewWithContext provides the ability to use a whisper model in a concurrently safe way. The context is used to support logging trace ids during model loading.`})]})]}),(0,G.jsxs)(`div`,{className:`card`,id:`types`,children:[(0,G.jsx)(`h3`,{children:`Types`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-bucky`,children:[(0,G.jsx)(`h4`,{children:`Bucky`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`type Bucky struct {
// Has unexported fields.
}`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Bucky provides a concurrently safe API for using whisper.cpp. Each Bucky owns one model.Model and shared whisper.Context. The model maintains a pool of independent whisper.State values. The admission channel permits up to Config.NSeqMax concurrent operations plus Config.QueueDepth waiting calls.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-initoption`,children:[(0,G.jsx)(`h4`,{children:`InitOption`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`type InitOption func(*initOptions)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`InitOption represents options for configuring Init.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-loglevel`,children:[(0,G.jsx)(`h4`,{children:`LogLevel`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`type LogLevel = applog.LogLevel`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`LogLevel represents the logging level.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-logger`,children:[(0,G.jsx)(`h4`,{children:`Logger`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`type Logger = applog.Logger`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Logger provides a function for logging messages from different APIs.`})]})]}),(0,G.jsxs)(`div`,{className:`card`,id:`methods`,children:[(0,G.jsx)(`h3`,{children:`Methods`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-bucky-activestreams`,children:[(0,G.jsx)(`h4`,{children:`Bucky.ActiveStreams`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (b *Bucky) ActiveStreams() int`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ActiveStreams returns the number of in-flight transcribe calls.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-bucky-detectlanguage`,children:[(0,G.jsx)(`h4`,{children:`Bucky.DetectLanguage`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (b *Bucky) DetectLanguage(ctx context.Context, samples []float32, withProbs bool) (string, []float32, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`DetectLanguage runs a short whisper pass on the supplied 16 kHz mono float32 PCM samples and returns the detected language code along with the per-language probability vector (length LangMaxID()+1) when withProbs is true.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`DetectLanguage participates in the per-handle backpressure semaphore and blocks until a slot is available.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-bucky-modelconfig`,children:[(0,G.jsx)(`h4`,{children:`Bucky.ModelConfig`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (b *Bucky) ModelConfig() model.Config`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ModelConfig returns a copy of the resolved configuration being used.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-bucky-modelinfo`,children:[(0,G.jsx)(`h4`,{children:`Bucky.ModelInfo`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (b *Bucky) ModelInfo() model.ModelInfo`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ModelInfo returns the static information about the loaded model.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-bucky-newstream`,children:[(0,G.jsx)(`h4`,{children:`Bucky.NewStream`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (b *Bucky) NewStream(ctx context.Context, opts ...model.StreamOption) (*model.Stream, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`NewStream opens a streaming transcription session against the loaded model. The session reserves one whisper.State for its lifetime and counts against ActiveStreams, so an open stream blocks Unload exactly like an in-flight Transcribe. The backpressure slot and pool state are both released when the returned stream's Close completes. Caller must call Close exactly once.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-bucky-systeminfo`,children:[(0,G.jsx)(`h4`,{children:`Bucky.SystemInfo`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (b *Bucky) SystemInfo() map[string]string`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`SystemInfo returns the whisper.cpp system info string parsed into a key/value map for observability output.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-bucky-transcribe`,children:[(0,G.jsx)(`h4`,{children:`Bucky.Transcribe`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (b *Bucky) Transcribe(ctx context.Context, samples []float32, opts ...model.TranscribeOption) (model.Transcription, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Transcribe runs the whisper.cpp pipeline on the provided 16 kHz mono float32 PCM samples and returns the decoded text along with per-segment metadata. The call participates in the per-handle backpressure semaphore and blocks until a slot is available.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-bucky-transcribechannels`,children:[(0,G.jsx)(`h4`,{children:`Bucky.TranscribeChannels`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (b *Bucky) TranscribeChannels(ctx context.Context, channels [][]float32, opts ...model.TranscribeOption) (model.Diarization, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`TranscribeChannels transcribes each supplied channel of 16 kHz mono float32 PCM separately and merges the results into a single diarized transcript, treating one channel as one speaker. Pass the channels returned by model.DecodeChannels. The call participates in the per-handle backpressure semaphore and blocks until a slot is available.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-bucky-transcribechannelsfile`,children:[(0,G.jsx)(`h4`,{children:`Bucky.TranscribeChannelsFile`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (b *Bucky) TranscribeChannelsFile(ctx context.Context, r io.Reader, opts ...model.TranscribeOption) (model.Diarization, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`TranscribeChannelsFile decodes audio from r preserving its channel layout and runs TranscribeChannels to produce a diarized transcript. Native multi-channel formats (WAV, FLAC) yield true per-channel diarization; formats that require ffmpeg are downmixed to a single channel. The call participates in the per-handle backpressure semaphore and blocks until a slot is available.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-bucky-transcribefile`,children:[(0,G.jsx)(`h4`,{children:`Bucky.TranscribeFile`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (b *Bucky) TranscribeFile(ctx context.Context, r io.Reader, opts ...model.TranscribeOption) (model.Transcription, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`TranscribeFile decodes audio from r into 16 kHz mono float32 PCM (using ffmpeg when the input is a container the upstream pure-Go decoders do not handle) and then runs Transcribe on the resulting samples. The call participates in the per-handle backpressure semaphore and blocks until a slot is available.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-bucky-unload`,children:[(0,G.jsx)(`h4`,{children:`Bucky.Unload`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (b *Bucky) Unload(ctx context.Context) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Unload will close down the loaded model. You should call this only when you are completely done using Bucky.`})]})]}),(0,G.jsxs)(`div`,{className:`card`,id:`constants`,children:[(0,G.jsx)(`h3`,{children:`Constants`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`const-logsilent`,children:[(0,G.jsx)(`h4`,{children:`LogSilent`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`const (
LogSilent = applog.LogSilent
@@ -1115,7 +1115,7 @@ kronk server start`})]})]})}function Is(e){let t=/^([\d.]+)\s*(MB|GB|KB|B)?$/i.e
Text string
StartMs int64
EndMs int64
-}`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Word is one decoded word with its position in the source audio.`})]})]}),(0,G.jsxs)(`div`,{className:`card`,id:`methods`,children:[(0,G.jsx)(`h3`,{children:`Methods`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-withdefaults`,children:[(0,G.jsx)(`h4`,{children:`Config.WithDefaults`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) WithDefaults() Config`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`WithDefaults returns cfg with the zero-valued fields filled in.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-config`,children:[(0,G.jsx)(`h4`,{children:`Model.Config`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) Config() Config`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Config returns the resolved Config the Model was built with (defaults applied).`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-detectlanguage`,children:[(0,G.jsx)(`h4`,{children:`Model.DetectLanguage`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) DetectLanguage(ctx context.Context, samples []float32, withProbs bool) (string, []float32, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`DetectLanguage runs a short whisper pass on the supplied 16 kHz mono float32 PCM samples and returns the detected language code along with the per-language probability vector (length LangMaxID()+1) when withProbs is true.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`DetectLanguage acquires a whisper.State from the model's internal pool, so up to Config.NSeqMax goroutines may run DetectLanguage in parallel against the same Model.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-modelinfo`,children:[(0,G.jsx)(`h4`,{children:`Model.ModelInfo`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) ModelInfo() ModelInfo`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ModelInfo returns the static information about the loaded model.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-newstream`,children:[(0,G.jsx)(`h4`,{children:`Model.NewStream`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) NewStream(ctx context.Context, onClose func(), opts ...StreamOption) (*Stream, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`NewStream opens a streaming transcription session against the loaded model. It reserves one whisper.State from the pool for the lifetime of the stream; onClose, when non-nil, runs when the stream's worker exits (used by the bucky wrapper to release its backpressure slot). Caller must call Close exactly once.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-transcribe`,children:[(0,G.jsx)(`h4`,{children:`Model.Transcribe`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) Transcribe(ctx context.Context, samples []float32, opts ...TranscribeOption) (Transcription, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Transcribe runs the whisper.cpp pipeline on the provided 16 kHz mono float32 PCM samples and returns the decoded text along with per-segment metadata.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Transcribe acquires a whisper.State from the model's internal pool, so up to Config.NSeqMax goroutines may run Transcribe in parallel against the same Model. The acquired state is released back to the pool when Transcribe returns.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-transcribechannels`,children:[(0,G.jsx)(`h4`,{children:`Model.TranscribeChannels`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) TranscribeChannels(ctx context.Context, channels [][]float32, opts ...TranscribeOption) (Diarization, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`TranscribeChannels transcribes each supplied channel of 16 kHz mono float32 PCM separately and merges the results into a diarized transcript. Each channel is treated as one speaker, the common layout for call-center and meeting recordings where every participant has a dedicated channel. Pass the slices returned by DecodeChannels.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Channels are transcribed sequentially. Each channel acquires and releases a whisper.State from the model's internal pool, so other goroutines may still run Transcribe against the same Model between channels. Empty channels are skipped.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-transcribechannelsfile`,children:[(0,G.jsx)(`h4`,{children:`Model.TranscribeChannelsFile`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) TranscribeChannelsFile(ctx context.Context, r io.Reader, opts ...TranscribeOption) (Diarization, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`TranscribeChannelsFile decodes audio from r into one 16 kHz mono float32 channel per source channel (via DecodeChannels) and then runs TranscribeChannels. Native multi-channel formats (WAV, FLAC) yield true per-channel diarization; formats that require ffmpeg are downmixed to a single channel before transcription.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-transcribefile`,children:[(0,G.jsx)(`h4`,{children:`Model.TranscribeFile`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) TranscribeFile(ctx context.Context, r io.Reader, opts ...TranscribeOption) (Transcription, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`TranscribeFile is a convenience wrapper that decodes audio from r via Decode and then runs Transcribe on the resulting samples. It is intended for HTTP handlers and CLI callers that have an io.Reader (form upload, file on disk) rather than pre-decoded PCM.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-unload`,children:[(0,G.jsx)(`h4`,{children:`Model.Unload`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) Unload(ctx context.Context) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Unload releases the state pool followed by the underlying whisper context. Unload is single-use per Model; subsequent calls return an error.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`The supplied ctx is accepted for parity with sdk/kronk.Model.Unload — whisper has no in-flight requests to drain at this layer because concurrency is owned by the sdk/bucky wrapper.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-stream-close`,children:[(0,G.jsx)(`h4`,{children:`Stream.Close`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (s *Stream) Close() error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Close performs one final flush over remaining audio, emits the resulting Final event, closes Events, and returns the whisper.State to the pool. It is idempotent and blocks until the worker has exited.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-stream-events`,children:[(0,G.jsx)(`h4`,{children:`Stream.Events`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (s *Stream) Events() <-chan Event`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Events returns the channel of transcript events. It is closed after Close finishes its final flush, or after an EventError. Range over it.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-stream-feed`,children:[(0,G.jsx)(`h4`,{children:`Stream.Feed`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (s *Stream) Feed(ctx context.Context, samples []float32) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Feed pushes 16 kHz mono float32 PCM into the stream. It blocks, respecting ctx, when the internal buffer is full, back-pressuring a fast producer. Returns ctx.Err() on cancellation. The samples slice may be reused by the caller after Feed returns.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`This is the zero-conversion fast path: callers that already hold normalized 16 kHz mono float32 (browser Web Audio, CoreAudio) feed it directly. Callers with raw microphone PCM should use FeedPCM.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-stream-feedpcm`,children:[(0,G.jsx)(`h4`,{children:`Stream.FeedPCM`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (s *Stream) FeedPCM(ctx context.Context, raw []byte, f AudioFormat) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`FeedPCM is the raw-microphone adapter for Feed. A capture device never hands you 16 kHz mono float32; it hands you raw interleaved PCM at the hardware rate (commonly 48 kHz) as int16 or float32, in arbitrary-size blocks. FeedPCM interprets, downmixes, resamples, and normalizes raw into the 16 kHz mono float32 the engine consumes, then funnels it into the same buffer Feed writes to.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`All conversion is pure Go with NO ffmpeg or other subprocess, reusing the helpers already in github.com/ardanlabs/bucky/pkg/audio. The pipeline is:`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`1. interpret raw bytes -> []float32 per f.Sample (int16 -> v/32768, or reinterpret little-endian float32); 2. downmix f.Channels interleaved -> mono via audio.DownmixToMono; 3. resample f.SampleRate -> 16000 via a per-stream audio.Resampler, the stateful streaming resampler that carries fractional phase across calls so block seams introduce no discontinuity or drift (linear interpolation, no anti-alias filter — adequate for whisper, which is trained on 16 kHz); 4. normalize clamp to [-1, 1].`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`raw need not contain a whole number of frames; a partial trailing frame is buffered until the next call so block boundaries that fall mid-frame do not corrupt the stream.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-stream-reset`,children:[(0,G.jsx)(`h4`,{children:`Stream.Reset`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (s *Stream) Reset(ctx context.Context, opts ...ResetOption) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Reset clears the audio buffer and rolling linguistic context so the same Stream can begin a fresh logical session WITHOUT releasing its pool slot or worker. The whisper.State, pool slot, Events channel, and ActiveStreams count all survive; voice-activity detection state is cleared.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Behavior is tunable via ResetOption. Reset blocks until any in-flight decode finishes and the worker has applied the reset.`})]})]})]}),(0,G.jsx)(`nav`,{className:`doc-sidebar`,children:(0,G.jsxs)(`div`,{className:`doc-sidebar-content`,children:[(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#functions`,className:`doc-index-header`,children:`Functions`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-decode`,children:`Decode`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-decodechannels`,children:`DecodeChannels`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-langid`,children:`LangID`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-langmaxid`,children:`LangMaxID`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-langstr`,children:`LangStr`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-systeminfo`,children:`SystemInfo`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-newmodel`,children:`NewModel`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#types`,className:`doc-index-header`,children:`Types`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-audioformat`,children:`AudioFormat`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-channeltranscription`,children:`ChannelTranscription`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-config`,children:`Config`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-diarization`,children:`Diarization`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-diarizedsegment`,children:`DiarizedSegment`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-event`,children:`Event`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-eventkind`,children:`EventKind`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-model`,children:`Model`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-modelinfo`,children:`ModelInfo`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-option`,children:`Option`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-resetconfig`,children:`ResetConfig`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-resetoption`,children:`ResetOption`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-sampleencoding`,children:`SampleEncoding`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-segment`,children:`Segment`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-stream`,children:`Stream`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-streamconfig`,children:`StreamConfig`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-streamoption`,children:`StreamOption`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-transcribeconfig`,children:`TranscribeConfig`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-transcribeoption`,children:`TranscribeOption`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-transcription`,children:`Transcription`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-word`,children:`Word`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#methods`,className:`doc-index-header`,children:`Methods`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-withdefaults`,children:`Config.WithDefaults`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-config`,children:`Model.Config`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-detectlanguage`,children:`Model.DetectLanguage`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-modelinfo`,children:`Model.ModelInfo`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-newstream`,children:`Model.NewStream`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-transcribe`,children:`Model.Transcribe`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-transcribechannels`,children:`Model.TranscribeChannels`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-transcribechannelsfile`,children:`Model.TranscribeChannelsFile`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-transcribefile`,children:`Model.TranscribeFile`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-unload`,children:`Model.Unload`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-stream-close`,children:`Stream.Close`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-stream-events`,children:`Stream.Events`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-stream-feed`,children:`Stream.Feed`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-stream-feedpcm`,children:`Stream.FeedPCM`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-stream-reset`,children:`Stream.Reset`})})]})]})]})})]})]})}function $v(){let e=at();return(0,x.useEffect)(()=>{let t=document.querySelector(`.main-content`);if(!t)return;if(!e.hash){t.scrollTo({top:0});return}let n=e.hash.slice(1);requestAnimationFrame(()=>{let e=document.getElementById(n);if(!e)return;let r=t.getBoundingClientRect(),i=e.getBoundingClientRect().top-r.top+t.scrollTop;t.scrollTo({top:i-20,behavior:`smooth`})})},[e.key,e.hash]),(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{className:`page-header`,children:[(0,G.jsx)(`h2`,{children:`Malina Package`}),(0,G.jsx)(`p`,{children:`Package malina provides a concurrency-safe API for generating images with stable-diffusion.cpp through the Malina raw bindings.`}),(0,G.jsx)(`p`,{children:`Experimental: This package's public API is subject to change.`})]}),(0,G.jsxs)(`div`,{className:`doc-layout`,children:[(0,G.jsxs)(`div`,{className:`doc-content`,children:[(0,G.jsxs)(`div`,{className:`card`,children:[(0,G.jsx)(`h3`,{children:`Import`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`import "github.com/ardanlabs/kronk/sdk/malina"`})})]}),(0,G.jsxs)(`div`,{className:`card`,id:`functions`,children:[(0,G.jsx)(`h3`,{children:`Functions`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-init`,children:[(0,G.jsx)(`h4`,{children:`Init`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func Init(opts ...InitOption) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Init registers Malina tooling, then loads stable-diffusion.cpp and its dynamic backends. KRONK_MALINA_LIB_PATH (or legacy MALINA_LIB) is used when no library path is supplied.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-initialized`,children:[(0,G.jsx)(`h4`,{children:`Initialized`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func Initialized() bool`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Initialized reports whether the Malina backend has been successfully initialized.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-setfmtloggertraceid`,children:[(0,G.jsx)(`h4`,{children:`SetFmtLoggerTraceID`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func SetFmtLoggerTraceID(ctx context.Context, traceID string) context.Context`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`SetFmtLoggerTraceID allows you to set a trace id on the context that can be included in FmtLogger output.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-new`,children:[(0,G.jsx)(`h4`,{children:`New`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func New(opts ...model.Option) (*Malina, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`New provides pooled image generation using a background model-loading context.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-newwithcontext`,children:[(0,G.jsx)(`h4`,{children:`NewWithContext`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func NewWithContext(ctx context.Context, opts ...model.Option) (*Malina, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`NewWithContext provides pooled image generation and loads every configured model context using ctx.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-systeminfo`,children:[(0,G.jsx)(`h4`,{children:`SystemInfo`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func SystemInfo() (SystemDiagnostics, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`SystemInfo returns native library and host diagnostics after initialization.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-newupscaler`,children:[(0,G.jsx)(`h4`,{children:`NewUpscaler`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func NewUpscaler(ctx context.Context, cfg UpscalerConfig) (*Upscaler, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`NewUpscaler loads a standalone ESRGAN upscaler using ctx.`})]})]}),(0,G.jsxs)(`div`,{className:`card`,id:`types`,children:[(0,G.jsx)(`h3`,{children:`Types`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-initoption`,children:[(0,G.jsx)(`h4`,{children:`InitOption`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`type InitOption func(*initOptions)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`InitOption represents options for configuring Init.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-loglevel`,children:[(0,G.jsx)(`h4`,{children:`LogLevel`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`type LogLevel = applog.LogLevel`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`LogLevel represents the native logging level.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-logger`,children:[(0,G.jsx)(`h4`,{children:`Logger`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`type Logger = applog.Logger`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Logger provides a function for logging messages from different APIs.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-malina`,children:[(0,G.jsx)(`h4`,{children:`Malina`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`type Malina struct {
+}`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Word is one decoded word with its position in the source audio.`})]})]}),(0,G.jsxs)(`div`,{className:`card`,id:`methods`,children:[(0,G.jsx)(`h3`,{children:`Methods`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-config-withdefaults`,children:[(0,G.jsx)(`h4`,{children:`Config.WithDefaults`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (cfg Config) WithDefaults() Config`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`WithDefaults returns cfg with the zero-valued fields filled in.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-config`,children:[(0,G.jsx)(`h4`,{children:`Model.Config`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) Config() Config`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Config returns the resolved Config the Model was built with (defaults applied).`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-detectlanguage`,children:[(0,G.jsx)(`h4`,{children:`Model.DetectLanguage`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) DetectLanguage(ctx context.Context, samples []float32, withProbs bool) (string, []float32, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`DetectLanguage runs a short whisper pass on the supplied 16 kHz mono float32 PCM samples and returns the detected language code along with the per-language probability vector (length LangMaxID()+1) when withProbs is true.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`DetectLanguage acquires a whisper.State from the model's internal pool, so up to Config.NSeqMax goroutines may run DetectLanguage in parallel against the same Model.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-modelinfo`,children:[(0,G.jsx)(`h4`,{children:`Model.ModelInfo`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) ModelInfo() ModelInfo`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ModelInfo returns the static information about the loaded model.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-newstream`,children:[(0,G.jsx)(`h4`,{children:`Model.NewStream`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) NewStream(ctx context.Context, onClose func(), opts ...StreamOption) (*Stream, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`NewStream opens a streaming transcription session against the loaded model. It reserves one whisper.State from the pool for the lifetime of the stream; onClose, when non-nil, runs when the stream's worker exits (used by the bucky wrapper to release its backpressure slot). Caller must call Close exactly once.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-transcribe`,children:[(0,G.jsx)(`h4`,{children:`Model.Transcribe`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) Transcribe(ctx context.Context, samples []float32, opts ...TranscribeOption) (Transcription, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Transcribe runs the whisper.cpp pipeline on the provided 16 kHz mono float32 PCM samples and returns the decoded text along with per-segment metadata.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Transcribe acquires a whisper.State from the model's internal pool, so up to Config.NSeqMax goroutines may run Transcribe in parallel against the same Model. The acquired state is released back to the pool when Transcribe returns.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-transcribechannels`,children:[(0,G.jsx)(`h4`,{children:`Model.TranscribeChannels`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) TranscribeChannels(ctx context.Context, channels [][]float32, opts ...TranscribeOption) (Diarization, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`TranscribeChannels transcribes each supplied channel of 16 kHz mono float32 PCM separately and merges the results into a diarized transcript. Each channel is treated as one speaker, the common layout for call-center and meeting recordings where every participant has a dedicated channel. Pass the slices returned by DecodeChannels.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Channels are transcribed sequentially. Each channel acquires and releases a whisper.State from the model's internal pool, so other goroutines may still run Transcribe against the same Model between channels. Empty channels are skipped.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-transcribechannelsfile`,children:[(0,G.jsx)(`h4`,{children:`Model.TranscribeChannelsFile`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) TranscribeChannelsFile(ctx context.Context, r io.Reader, opts ...TranscribeOption) (Diarization, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`TranscribeChannelsFile decodes audio from r into one 16 kHz mono float32 channel per source channel (via DecodeChannels) and then runs TranscribeChannels. Native multi-channel formats (WAV, FLAC) yield true per-channel diarization; formats that require ffmpeg are downmixed to a single channel before transcription.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-transcribefile`,children:[(0,G.jsx)(`h4`,{children:`Model.TranscribeFile`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) TranscribeFile(ctx context.Context, r io.Reader, opts ...TranscribeOption) (Transcription, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`TranscribeFile is a convenience wrapper that decodes audio from r via Decode and then runs Transcribe on the resulting samples. It is intended for HTTP handlers and CLI callers that have an io.Reader (form upload, file on disk) rather than pre-decoded PCM.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-model-unload`,children:[(0,G.jsx)(`h4`,{children:`Model.Unload`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (m *Model) Unload(ctx context.Context) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Unload releases the state pool followed by the underlying whisper context. Unload is single-use per Model; subsequent calls return an error.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`The supplied ctx is accepted for parity with sdk/kronk.Model.Unload — whisper has no in-flight requests to drain at this layer because concurrency is owned by the sdk/bucky wrapper.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-stream-close`,children:[(0,G.jsx)(`h4`,{children:`Stream.Close`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (s *Stream) Close() error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Close performs one final flush over remaining audio, emits the resulting Final event when the Events buffer has room, closes Events, and returns the whisper.State to the pool. If the consumer has abandoned a full Events buffer, cleanup takes priority and the closing event is dropped. Close is idempotent and blocks until the worker has exited.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-stream-events`,children:[(0,G.jsx)(`h4`,{children:`Stream.Events`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (s *Stream) Events() <-chan Event`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Events returns the channel of transcript events. It is closed after Close finishes its final flush, or after an EventError. Range over it.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-stream-feed`,children:[(0,G.jsx)(`h4`,{children:`Stream.Feed`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (s *Stream) Feed(ctx context.Context, samples []float32) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Feed pushes 16 kHz mono float32 PCM into the stream. It blocks, respecting ctx, when the internal buffer is full, back-pressuring a fast producer. Returns ctx.Err() on cancellation. The samples slice may be reused by the caller after Feed returns.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`This is the zero-conversion fast path: callers that already hold normalized 16 kHz mono float32 (browser Web Audio, CoreAudio) feed it directly. Callers with raw microphone PCM should use FeedPCM.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-stream-feedpcm`,children:[(0,G.jsx)(`h4`,{children:`Stream.FeedPCM`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (s *Stream) FeedPCM(ctx context.Context, raw []byte, f AudioFormat) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`FeedPCM is the raw-microphone adapter for Feed. A capture device never hands you 16 kHz mono float32; it hands you raw interleaved PCM at the hardware rate (commonly 48 kHz) as int16 or float32, in arbitrary-size blocks. FeedPCM interprets, downmixes, resamples, and normalizes raw into the 16 kHz mono float32 the engine consumes, then funnels it into the same buffer Feed writes to.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`All conversion is pure Go with NO ffmpeg or other subprocess, reusing the helpers already in github.com/ardanlabs/bucky/pkg/audio. The pipeline is:`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`1. interpret raw bytes -> []float32 per f.Sample (int16 -> v/32768, or reinterpret little-endian float32); 2. downmix f.Channels interleaved -> mono via audio.DownmixToMono; 3. resample f.SampleRate -> 16000 via a per-stream audio.Resampler, the stateful streaming resampler that carries fractional phase across calls so block seams introduce no discontinuity or drift (linear interpolation, no anti-alias filter — adequate for whisper, which is trained on 16 kHz); 4. normalize clamp to [-1, 1].`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`raw need not contain a whole number of frames; a partial trailing frame is buffered until the next call so block boundaries that fall mid-frame do not corrupt the stream.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`method-stream-reset`,children:[(0,G.jsx)(`h4`,{children:`Stream.Reset`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func (s *Stream) Reset(ctx context.Context, opts ...ResetOption) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Reset clears the audio buffer and rolling linguistic context so the same Stream can begin a fresh logical session WITHOUT releasing its pool slot or worker. The whisper.State, pool slot, Events channel, and ActiveStreams count all survive; voice-activity detection state is cleared.`}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Behavior is tunable via ResetOption. Reset blocks until any in-flight decode finishes and the worker has applied the reset.`})]})]}),(0,G.jsxs)(`div`,{className:`card`,id:`variables`,children:[(0,G.jsx)(`h3`,{children:`Variables`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`var-errstreamstopped`,children:[(0,G.jsx)(`h4`,{children:`ErrStreamStopped`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`var ErrStreamStopped = errors.New("stream stopped")`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ErrStreamStopped indicates that a stream's worker exited after a terminal processing error or close.`})]})]})]}),(0,G.jsx)(`nav`,{className:`doc-sidebar`,children:(0,G.jsxs)(`div`,{className:`doc-sidebar-content`,children:[(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#functions`,className:`doc-index-header`,children:`Functions`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-decode`,children:`Decode`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-decodechannels`,children:`DecodeChannels`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-langid`,children:`LangID`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-langmaxid`,children:`LangMaxID`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-langstr`,children:`LangStr`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-systeminfo`,children:`SystemInfo`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#func-newmodel`,children:`NewModel`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#types`,className:`doc-index-header`,children:`Types`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-audioformat`,children:`AudioFormat`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-channeltranscription`,children:`ChannelTranscription`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-config`,children:`Config`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-diarization`,children:`Diarization`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-diarizedsegment`,children:`DiarizedSegment`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-event`,children:`Event`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-eventkind`,children:`EventKind`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-model`,children:`Model`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-modelinfo`,children:`ModelInfo`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-option`,children:`Option`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-resetconfig`,children:`ResetConfig`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-resetoption`,children:`ResetOption`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-sampleencoding`,children:`SampleEncoding`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-segment`,children:`Segment`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-stream`,children:`Stream`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-streamconfig`,children:`StreamConfig`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-streamoption`,children:`StreamOption`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-transcribeconfig`,children:`TranscribeConfig`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-transcribeoption`,children:`TranscribeOption`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-transcription`,children:`Transcription`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#type-word`,children:`Word`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#methods`,className:`doc-index-header`,children:`Methods`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-config-withdefaults`,children:`Config.WithDefaults`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-config`,children:`Model.Config`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-detectlanguage`,children:`Model.DetectLanguage`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-modelinfo`,children:`Model.ModelInfo`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-newstream`,children:`Model.NewStream`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-transcribe`,children:`Model.Transcribe`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-transcribechannels`,children:`Model.TranscribeChannels`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-transcribechannelsfile`,children:`Model.TranscribeChannelsFile`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-transcribefile`,children:`Model.TranscribeFile`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-model-unload`,children:`Model.Unload`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-stream-close`,children:`Stream.Close`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-stream-events`,children:`Stream.Events`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-stream-feed`,children:`Stream.Feed`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-stream-feedpcm`,children:`Stream.FeedPCM`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#method-stream-reset`,children:`Stream.Reset`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#variables`,className:`doc-index-header`,children:`Variables`}),(0,G.jsx)(`ul`,{children:(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#var-errstreamstopped`,children:`ErrStreamStopped`})})})]})]})})]})]})}function $v(){let e=at();return(0,x.useEffect)(()=>{let t=document.querySelector(`.main-content`);if(!t)return;if(!e.hash){t.scrollTo({top:0});return}let n=e.hash.slice(1);requestAnimationFrame(()=>{let e=document.getElementById(n);if(!e)return;let r=t.getBoundingClientRect(),i=e.getBoundingClientRect().top-r.top+t.scrollTop;t.scrollTo({top:i-20,behavior:`smooth`})})},[e.key,e.hash]),(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{className:`page-header`,children:[(0,G.jsx)(`h2`,{children:`Malina Package`}),(0,G.jsx)(`p`,{children:`Package malina provides a concurrency-safe API for generating images with stable-diffusion.cpp through the Malina raw bindings.`}),(0,G.jsx)(`p`,{children:`Experimental: This package's public API is subject to change.`})]}),(0,G.jsxs)(`div`,{className:`doc-layout`,children:[(0,G.jsxs)(`div`,{className:`doc-content`,children:[(0,G.jsxs)(`div`,{className:`card`,children:[(0,G.jsx)(`h3`,{children:`Import`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`import "github.com/ardanlabs/kronk/sdk/malina"`})})]}),(0,G.jsxs)(`div`,{className:`card`,id:`functions`,children:[(0,G.jsx)(`h3`,{children:`Functions`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-init`,children:[(0,G.jsx)(`h4`,{children:`Init`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func Init(opts ...InitOption) error`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Init registers Malina tooling, then loads stable-diffusion.cpp and its dynamic backends. KRONK_MALINA_LIB_PATH (or legacy MALINA_LIB) is used when no library path is supplied.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-initialized`,children:[(0,G.jsx)(`h4`,{children:`Initialized`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func Initialized() bool`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Initialized reports whether the Malina backend has been successfully initialized.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-setfmtloggertraceid`,children:[(0,G.jsx)(`h4`,{children:`SetFmtLoggerTraceID`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func SetFmtLoggerTraceID(ctx context.Context, traceID string) context.Context`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`SetFmtLoggerTraceID allows you to set a trace id on the context that can be included in FmtLogger output.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-new`,children:[(0,G.jsx)(`h4`,{children:`New`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func New(opts ...model.Option) (*Malina, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`New provides pooled image generation using a background model-loading context.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-newwithcontext`,children:[(0,G.jsx)(`h4`,{children:`NewWithContext`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func NewWithContext(ctx context.Context, opts ...model.Option) (*Malina, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`NewWithContext provides pooled image generation and loads every configured model context using ctx.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-systeminfo`,children:[(0,G.jsx)(`h4`,{children:`SystemInfo`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func SystemInfo() (SystemDiagnostics, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`SystemInfo returns native library and host diagnostics after initialization.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`func-newupscaler`,children:[(0,G.jsx)(`h4`,{children:`NewUpscaler`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`func NewUpscaler(ctx context.Context, cfg UpscalerConfig) (*Upscaler, error)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`NewUpscaler loads a standalone ESRGAN upscaler using ctx.`})]})]}),(0,G.jsxs)(`div`,{className:`card`,id:`types`,children:[(0,G.jsx)(`h3`,{children:`Types`}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-initoption`,children:[(0,G.jsx)(`h4`,{children:`InitOption`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`type InitOption func(*initOptions)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`InitOption represents options for configuring Init.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-loglevel`,children:[(0,G.jsx)(`h4`,{children:`LogLevel`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`type LogLevel = applog.LogLevel`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`LogLevel represents the native logging level.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-logger`,children:[(0,G.jsx)(`h4`,{children:`Logger`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`type Logger = applog.Logger`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Logger provides a function for logging messages from different APIs.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-malina`,children:[(0,G.jsx)(`h4`,{children:`Malina`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`type Malina struct {
// Has unexported fields.
}`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`Malina provides a concurrency-safe API around a pool of reusable native model contexts. Each context performs one generation at a time.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-progressfunc`,children:[(0,G.jsx)(`h4`,{children:`ProgressFunc`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`type ProgressFunc func(step int, steps int, secondsPerStep float32)`})}),(0,G.jsx)(`p`,{className:`doc-description`,children:`ProgressFunc receives process-global model loading and image generation progress. SecondsPerStep is the average elapsed time per completed step. The function can be called concurrently and must be concurrency-safe.`})]}),(0,G.jsxs)(`div`,{className:`doc-section`,id:`type-systemdiagnostics`,children:[(0,G.jsx)(`h4`,{children:`SystemDiagnostics`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`type SystemDiagnostics struct {
NativeVersion string
@@ -8071,7 +8071,7 @@ models:
ngpu-layers: 20`})}),(0,G.jsxs)(`table`,{className:`flags-table`,children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{children:`Value`}),(0,G.jsx)(`th`,{children:`Behavior`})]})}),(0,G.jsxs)(`tbody`,{children:[(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`0`})}),(0,G.jsx)(`td`,{children:`Offload all layers to the GPU`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`-1`})}),(0,G.jsx)(`td`,{children:`Keep all layers on the CPU`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Positive integer`}),(0,G.jsx)(`td`,{children:`Offload that many layers`})]})]})]}),(0,G.jsx)(`p`,{children:`Partial offload can make a model fit in limited VRAM, but CPU-resident layers usually reduce inference speed. On unified-memory systems, CPU and GPU do not have separate memory pools, although placement can still affect performance.`}),(0,G.jsx)(`h4`,{id:`model-weight-loading`,children:`Model weight loading`}),(0,G.jsxs)(`p`,{children:[(0,G.jsx)(`code`,{children:`load-mode`}),` controls how Kronk reads model weights. Its default and Go zero value are `,(0,G.jsx)(`code`,{children:`auto`}),`:`]}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{className:`language-yaml`,children:`some-provider/some-model:
load-mode: auto`})}),(0,G.jsxs)(`table`,{className:`flags-table`,children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{children:`Value`}),(0,G.jsx)(`th`,{children:`Behavior`})]})}),(0,G.jsxs)(`tbody`,{children:[(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`auto`})}),(0,G.jsx)(`td`,{children:`Use mmap when every selected device supports it; otherwise use ordinary loading; this is the default`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`mmap`})}),(0,G.jsx)(`td`,{children:`Force memory-mapped model weights and use the operating system page cache`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`none`})}),(0,G.jsx)(`td`,{children:`Load weights without mmap, mlock, or direct I/O`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`mlock`})}),(0,G.jsx)(`td`,{children:`Load weights and request that their pages remain resident in RAM without forcing mmap`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`mmap+mlock`})}),(0,G.jsx)(`td`,{children:`Memory-map weights and request that their pages remain resident in RAM`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`direct-io`})}),(0,G.jsx)(`td`,{children:`Bypass the operating system page cache where the platform and filesystem support it`})]})]})]}),(0,G.jsxs)(`p`,{children:[`Use `,(0,G.jsx)(`code`,{children:`none`}),` when mmap is unsuitable or when direct allocation is needed for a measured NUMA placement issue. Use `,(0,G.jsx)(`code`,{children:`mlock`}),` only when the host has enough physical and lockable RAM for the model plus the rest of the workload; process resource limits may prevent all pages from being locked. Use `,(0,G.jsx)(`code`,{children:`mmap+mlock`}),` when the model should be both memory mapped and kept resident. Direct I/O can avoid page-cache pollution for some local-storage and GPU-loading workloads, but it can also make repeated loads slower and is not supported by every filesystem. Benchmark the actual model path before selecting it.`]}),(0,G.jsxs)(`p`,{children:[`Kronk applies one load mode to the target model and any separate draft model. The Go SDK equivalent is `,(0,G.jsx)(`code`,{children:`model.WithLoadMode`}),`, using `,(0,G.jsx)(`code`,{children:`LoadModeAuto`}),`, `,(0,G.jsx)(`code`,{children:`LoadModeMMap`}),`, `,(0,G.jsx)(`code`,{children:`LoadModeNone`}),`, `,(0,G.jsx)(`code`,{children:`LoadModeMLock`}),`, `,(0,G.jsx)(`code`,{children:`LoadModeMMapMLock`}),`, or `,(0,G.jsx)(`code`,{children:`LoadModeDirectIO`}),`.`]}),(0,G.jsxs)(`p`,{children:[`The former `,(0,G.jsx)(`code`,{children:`use-mmap`}),` and `,(0,G.jsx)(`code`,{children:`use-direct-io`}),` keys are no longer supported. Migrate existing configuration as follows:`]}),(0,G.jsxs)(`table`,{className:`flags-table`,children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{children:`Removed configuration`}),(0,G.jsx)(`th`,{children:`Replacement`})]})}),(0,G.jsxs)(`tbody`,{children:[(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`use-mmap: true`})}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`load-mode: mmap`})})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`use-mmap: false`})}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`load-mode: none`})})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`use-direct-io: true`})}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`load-mode: direct-io`})})]})]})]}),(0,G.jsx)(`h4`,{id:`kv-cache-and-operations`,children:`KV cache and operations`}),(0,G.jsx)(`p`,{children:`The KV cache and host tensor operations are offloaded to the GPU by default:`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{className:`language-yaml`,children:`some-provider/some-model:
offload-kqv: false
- op-offload: false`})}),(0,G.jsxs)(`p`,{children:[(0,G.jsx)(`code`,{children:`offload-kqv: false`}),` keeps the KV cache on the CPU. `,(0,G.jsx)(`code`,{children:`op-offload: false`}),` keeps host tensor operations on the CPU. These options can reduce discrete-GPU VRAM pressure at a performance cost. They do not reduce total memory requirements.`]}),(0,G.jsxs)(`p`,{children:[`For multimodal models, `,(0,G.jsx)(`code`,{children:`proj-on-cpu: true`}),` keeps the media projector on the CPU without changing placement of the language model itself. To place the projector on a specific accelerator, set `,(0,G.jsx)(`code`,{children:`proj-device`}),` to a name reported by `,(0,G.jsx)(`code`,{children:`kronk devices`}),` (for example, `,(0,G.jsx)(`code`,{children:`CUDA1`}),` or `,(0,G.jsx)(`code`,{children:`MTL0`}),`). Omit both settings for automatic placement. `,(0,G.jsx)(`code`,{children:`proj-device`}),` cannot be combined with `,(0,G.jsx)(`code`,{children:`proj-on-cpu: true`}),`.`]}),(0,G.jsx)(`h4`,{id:`multiple-gpus`,children:`Multiple GPUs`}),(0,G.jsxs)(`p`,{children:[(0,G.jsx)(`code`,{children:`split-mode`}),` accepts:`]}),(0,G.jsxs)(`table`,{className:`flags-table`,children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{children:`Value`}),(0,G.jsx)(`th`,{children:`Behavior`})]})}),(0,G.jsxs)(`tbody`,{children:[(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`none`})}),(0,G.jsx)(`td`,{children:`Use one GPU`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`layer`})}),(0,G.jsx)(`td`,{children:`Distribute whole layers across GPUs`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`row`})}),(0,G.jsx)(`td`,{children:`Use legacy row-split parallelism where supported`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`tensor`})}),(0,G.jsx)(`td`,{children:`Use experimental tensor parallelism where supported`})]})]})]}),(0,G.jsxs)(`p`,{children:[`When the setting is omitted, Kronk selects `,(0,G.jsx)(`code`,{children:`layer`}),`, matching llama.cpp's default and most compatible multi-GPU mode. Layer mode can distribute a single GGUF file across multiple GPUs. `,(0,G.jsx)(`code`,{children:`row`}),` remains available for legacy configurations.`]}),(0,G.jsxs)(`p`,{children:[`With AutoTune enabled, Kronk selects `,(0,G.jsx)(`code`,{children:`tensor`}),` when exactly two selected devices use the ROCm backend, the model architecture supports llama.cpp tensor parallelism, Flash Attention is not disabled, and GPU offload is enabled. This allows llama.cpp to use RCCL when available or its two-GPU HIP AllReduce path otherwise. An explicit `,(0,G.jsx)(`code`,{children:`split-mode`}),`, disabled Flash Attention, CPU-only placement, a different backend, or any other GPU count keeps the normal selection behavior. Tensor mode is experimental and requires Flash Attention; set `,(0,G.jsx)(`code`,{children:`split-mode: layer`}),` to opt out.`]}),(0,G.jsxs)(`p`,{children:[`For explicit placement, `,(0,G.jsx)(`code`,{children:`devices`}),` names the devices and `,(0,G.jsx)(`code`,{children:`tensor-split`}),` gives their proportional shares:`]}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{className:`language-yaml`,children:`some-provider/some-model:
+ op-offload: false`})}),(0,G.jsxs)(`p`,{children:[(0,G.jsx)(`code`,{children:`offload-kqv: false`}),` keeps the KV cache on the CPU. `,(0,G.jsx)(`code`,{children:`op-offload: false`}),` keeps host tensor operations on the CPU. These options can reduce discrete-GPU VRAM pressure at a performance cost. They do not reduce total memory requirements.`]}),(0,G.jsxs)(`p`,{children:[`llama.cpp also supports the process-wide `,(0,G.jsx)(`code`,{children:`GGML_OP_OFFLOAD_MIN_BATCH`}),` environment variable. Set it before Kronk starts; GPU backends read it once during `,(0,G.jsx)(`code`,{children:`kronk.Init`}),`, so it cannot be configured independently per model.`]}),(0,G.jsxs)(`p`,{children:[`For multimodal models, `,(0,G.jsx)(`code`,{children:`proj-on-cpu: true`}),` keeps the media projector on the CPU without changing placement of the language model itself. To place the projector on a specific accelerator, set `,(0,G.jsx)(`code`,{children:`proj-device`}),` to a name reported by `,(0,G.jsx)(`code`,{children:`kronk devices`}),` (for example, `,(0,G.jsx)(`code`,{children:`CUDA1`}),` or `,(0,G.jsx)(`code`,{children:`MTL0`}),`). Omit both settings for automatic placement. `,(0,G.jsx)(`code`,{children:`proj-device`}),` cannot be combined with `,(0,G.jsx)(`code`,{children:`proj-on-cpu: true`}),`.`]}),(0,G.jsx)(`h4`,{id:`multiple-gpus`,children:`Multiple GPUs`}),(0,G.jsxs)(`p`,{children:[(0,G.jsx)(`code`,{children:`split-mode`}),` accepts:`]}),(0,G.jsxs)(`table`,{className:`flags-table`,children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{children:`Value`}),(0,G.jsx)(`th`,{children:`Behavior`})]})}),(0,G.jsxs)(`tbody`,{children:[(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`none`})}),(0,G.jsx)(`td`,{children:`Use one GPU`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`layer`})}),(0,G.jsx)(`td`,{children:`Distribute whole layers across GPUs`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`row`})}),(0,G.jsx)(`td`,{children:`Use legacy row-split parallelism where supported`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`tensor`})}),(0,G.jsx)(`td`,{children:`Use experimental tensor parallelism where supported`})]})]})]}),(0,G.jsxs)(`p`,{children:[`When the setting is omitted, Kronk selects `,(0,G.jsx)(`code`,{children:`layer`}),`, matching llama.cpp's default and most compatible multi-GPU mode. Layer mode can distribute a single GGUF file across multiple GPUs. `,(0,G.jsx)(`code`,{children:`row`}),` remains available for legacy configurations.`]}),(0,G.jsxs)(`p`,{children:[`With AutoTune enabled, Kronk selects `,(0,G.jsx)(`code`,{children:`tensor`}),` when exactly two selected devices use the ROCm backend, the model architecture supports llama.cpp tensor parallelism, Flash Attention is not disabled, and GPU offload is enabled. This allows llama.cpp to use RCCL when available or its two-GPU HIP AllReduce path otherwise. An explicit `,(0,G.jsx)(`code`,{children:`split-mode`}),`, disabled Flash Attention, CPU-only placement, a different backend, or any other GPU count keeps the normal selection behavior. Tensor mode is experimental and requires Flash Attention; set `,(0,G.jsx)(`code`,{children:`split-mode: layer`}),` to opt out.`]}),(0,G.jsxs)(`p`,{children:[`For explicit placement, `,(0,G.jsx)(`code`,{children:`devices`}),` names the devices and `,(0,G.jsx)(`code`,{children:`tensor-split`}),` gives their proportional shares:`]}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{className:`language-yaml`,children:`some-provider/some-model:
devices: [CUDA0, CUDA1]
split-mode: layer
tensor-split: [0.6, 0.4]`})}),(0,G.jsxs)(`p`,{children:[`The number of `,(0,G.jsx)(`code`,{children:`tensor-split`}),` values must match the number of devices. Omit the split to let the backend derive it from available memory. `,(0,G.jsx)(`code`,{children:`main-gpu`}),` selects the primary device when `,(0,G.jsx)(`code`,{children:`split-mode`}),` is `,(0,G.jsx)(`code`,{children:`none`}),`.`]}),(0,G.jsx)(`h3`,{id:`35-concurrency-and-batching`,children:`3.5 Concurrency and Batching`}),(0,G.jsxs)(`p`,{children:[(0,G.jsx)(`code`,{children:`nseq-max`}),` controls model concurrency:`]}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{className:`language-yaml`,children:`unsloth/Qwen3-0.6B-Q8_0:
@@ -8551,7 +8551,7 @@ resp, err := krn.Decision(ctx, req)`})}),(0,G.jsxs)(`p`,{children:[(0,G.jsx)(`co
}
}
}
-}`})}),(0,G.jsxs)(`p`,{children:[`Supported `,(0,G.jsx)(`code`,{children:`response_format.type`}),` values are `,(0,G.jsx)(`code`,{children:`text`}),`, `,(0,G.jsx)(`code`,{children:`json_object`}),`, and `,(0,G.jsx)(`code`,{children:`json_schema`}),`. Kronk also accepts a schema directly in the top-level `,(0,G.jsx)(`code`,{children:`json_schema`}),` field and accepts a custom GBNF string in `,(0,G.jsx)(`code`,{children:`grammar`}),`. Use one structured-output mechanism per request.`]}),(0,G.jsxs)(`p`,{children:[`When a constraint is present and `,(0,G.jsx)(`code`,{children:`enable_thinking`}),` is omitted, Kronk disables thinking automatically so free-form reasoning does not precede the structured answer. Explicitly enabling thinking overrides that default, but is generally counterproductive for constrained output.`]}),(0,G.jsxs)(`p`,{children:[`A grammar restricts which tokens can be emitted; it does not guarantee a complete result. A response cut short by `,(0,G.jsx)(`code`,{children:`max_tokens`}),`, context limits, or cancellation can still contain an incomplete JSON value.`]}),(0,G.jsx)(`h2`,{id:`107-token-log-probabilities`,children:`10.7 Token Log Probabilities`}),(0,G.jsxs)(`p`,{children:[`Set `,(0,G.jsx)(`code`,{children:`logprobs: true`}),` to return the log probability of each generated token. `,(0,G.jsx)(`code`,{children:`top_logprobs`}),` requests likely alternatives and is clamped to the range 0–5. Any positive `,(0,G.jsx)(`code`,{children:`top_logprobs`}),` value implicitly enables `,(0,G.jsx)(`code`,{children:`logprobs`}),`.`]}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{className:`language-json`,children:`{
+}`})}),(0,G.jsxs)(`p`,{children:[`Supported `,(0,G.jsx)(`code`,{children:`response_format.type`}),` values are `,(0,G.jsx)(`code`,{children:`text`}),`, `,(0,G.jsx)(`code`,{children:`json_object`}),`, and `,(0,G.jsx)(`code`,{children:`json_schema`}),`. Kronk also accepts a schema directly in the top-level `,(0,G.jsx)(`code`,{children:`json_schema`}),` field and accepts a custom GBNF string in `,(0,G.jsx)(`code`,{children:`grammar`}),`. Use one structured-output mechanism per request. JSON Schema `,(0,G.jsx)(`code`,{children:`pattern`}),` is not supported; Kronk rejects schemas containing it rather than interpreting its regular expression as GBNF.`]}),(0,G.jsxs)(`p`,{children:[`When a constraint is present and `,(0,G.jsx)(`code`,{children:`enable_thinking`}),` is omitted, Kronk disables thinking automatically so free-form reasoning does not precede the structured answer. Explicitly enabling thinking overrides that default, but is generally counterproductive for constrained output.`]}),(0,G.jsxs)(`p`,{children:[`A grammar restricts which tokens can be emitted; it does not guarantee a complete result. A response cut short by `,(0,G.jsx)(`code`,{children:`max_tokens`}),`, context limits, or cancellation can still contain an incomplete JSON value.`]}),(0,G.jsx)(`h2`,{id:`107-token-log-probabilities`,children:`10.7 Token Log Probabilities`}),(0,G.jsxs)(`p`,{children:[`Set `,(0,G.jsx)(`code`,{children:`logprobs: true`}),` to return the log probability of each generated token. `,(0,G.jsx)(`code`,{children:`top_logprobs`}),` requests likely alternatives and is clamped to the range 0–5. Any positive `,(0,G.jsx)(`code`,{children:`top_logprobs`}),` value implicitly enables `,(0,G.jsx)(`code`,{children:`logprobs`}),`.`]}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{className:`language-json`,children:`{
"model": "unsloth/Qwen3-1.7B-UD-Q8_K_XL",
"messages": [
{"role": "user", "content": "What is 2 + 2?"}
@@ -8586,7 +8586,7 @@ EOF`})}),(0,G.jsx)(`p`,{children:`An ordered content array can contain multiple
"data": "data:audio/wav;base64,UklGRi...",
"format": "wav"
}
-}`})}),(0,G.jsxs)(`p`,{children:[`Put this part before the text question. The `,(0,G.jsx)(`code`,{children:`format`}),` field is accepted for client compatibility, but Kronk currently determines the actual format from the decoded bytes rather than this value.`]}),(0,G.jsxs)(`p`,{children:[`Use a multimodal chat model when you need conversational questions, summaries, or reasoning about audio. For a dedicated speech-to-text API, use Bucky's `,(0,G.jsx)(`code`,{children:`POST /v1/audio/transcriptions`}),` endpoint described in `,(0,G.jsx)(`a`,{href:`https://www.kronkai.com/manual#1861-request-and-response`,children:`Chapter 18`}),`.`]}),(0,G.jsx)(`h2`,{id:`115-go-sdk-helpers`,children:`11.5 Go SDK Helpers`}),(0,G.jsx)(`p`,{children:`Go applications can read media into a byte slice and use:`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`code`,{children:`model.ImageMessage(question, image, format)`}),`; or`]}),(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`code`,{children:`model.AudioMessage(question, audio, format)`}),`.`]})]}),(0,G.jsxs)(`p`,{children:[`These helpers create one user turn with media before text. `,(0,G.jsx)(`code`,{children:`model.VideoMessage`}),` constructs a `,(0,G.jsx)(`code`,{children:`video_url`}),` part, but it does not add video-container decoding; send extracted frames with `,(0,G.jsx)(`code`,{children:`ImageMessage`}),` for the current media path.`]}),(0,G.jsx)(`h2`,{id:`116-configuration-and-resources`,children:`11.6 Configuration and Resources`}),(0,G.jsxs)(`p`,{children:[`Multimodal requests use the same batch engine and concurrency controls as text requests. The projector adds weights and runtime buffers, while image resolution, audio duration, context length, and `,(0,G.jsx)(`code`,{children:`nseq-max`}),` affect resource use. Use the BUI VRAM Calculator rather than adding model, projector, and KV file sizes as a complete memory estimate. See `,(0,G.jsx)(`a`,{href:`https://www.kronkai.com/manual#36-memory-planning-and-quantization`,children:`Chapter 3 §3.6`}),` for memory planning and `,(0,G.jsx)(`a`,{href:`https://www.kronkai.com/manual#chapter-4-batch-processing`,children:`Chapter 4`}),` for concurrency.`]}),(0,G.jsxs)(`p`,{children:[`Most deployments should leave `,(0,G.jsx)(`code`,{children:`prefill-batch-size`}),` at its 2048-token default. Kronk adds the model's per-slot generation reserve when deriving llama.cpp's internal batch capacities. A multimodal encoder may require an entire media-token chunk to fit in one physical batch, so lowering `,(0,G.jsx)(`code`,{children:`prefill-batch-size`}),` below that capacity can break media input. `,(0,G.jsx)(`code`,{children:`proj-on-cpu: true`}),` can keep the projector on the CPU when accelerator memory is constrained, at a performance cost.`]}),(0,G.jsx)(`h2`,{id:`117-message-caching`,children:`11.7 Message Caching`}),(0,G.jsxs)(`p`,{children:[`Incremental Message Caching can reuse unchanged media state for text-only follow-up turns without encoding the media again. Changing, reordering, removing, or appending media rebuilds the stable media plan through the multimodal pipeline. See `,(0,G.jsx)(`a`,{href:`https://www.kronkai.com/manual#54-media-requests`,children:`Chapter 5 §5.4`}),` for the cache behavior and limitations.`]}),(0,G.jsx)(`h2`,{id:`118-limitations`,children:`11.8 Limitations`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:`Media must be embedded as base64; Kronk does not fetch remote URLs.`}),(0,G.jsx)(`li`,{children:`The current path accepts image and audio containers, not video containers.`}),(0,G.jsx)(`li`,{children:`The selected model and projector must support the detected modality.`}),(0,G.jsx)(`li`,{children:`Image resolution, media count, and audio duration affect latency and memory.`}),(0,G.jsx)(`li`,{children:`Model quality and practical media limits vary by model and projector.`})]}),(0,G.jsx)(`hr`,{}),(0,G.jsx)(`p`,{children:(0,G.jsx)(`em`,{children:`Next: Chapter 12: Security & Authentication`})}),(0,G.jsx)(`h2`,{id:`chapter-12-security-and-authentication`,children:`Chapter 12: Security and Authentication`}),(0,G.jsx)(`p`,{children:`Kronk signs JWT bearer tokens with local RSA keys. A token can be an unrestricted administrator credential or a user credential limited to specific inference endpoints and request quotas.`}),(0,G.jsx)(`h2`,{id:`121-authorization-modes`,children:`12.1 Authorization Modes`}),(0,G.jsxs)(`p`,{children:[(0,G.jsx)(`code`,{children:`KRONK_AUTHORIZATION_MODE`}),` selects the API access policy independently of whether Kronk uses its embedded auth service or `,(0,G.jsx)(`code`,{children:`KRONK_AUTH_HOST`}),`:`]}),(0,G.jsxs)(`table`,{className:`flags-table`,children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{children:`Value`}),(0,G.jsx)(`th`,{children:`Model discovery`}),(0,G.jsx)(`th`,{children:`Inference`}),(0,G.jsx)(`th`,{children:`Management`})]})}),(0,G.jsxs)(`tbody`,{children:[(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`open`})}),(0,G.jsx)(`td`,{children:`Public`}),(0,G.jsx)(`td`,{children:`Public`}),(0,G.jsx)(`td`,{children:`Public`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`management`})}),(0,G.jsx)(`td`,{children:`Public`}),(0,G.jsx)(`td`,{children:`Public`}),(0,G.jsx)(`td`,{children:`Admin JWT`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`authenticated`})}),(0,G.jsx)(`td`,{children:`Valid JWT`}),(0,G.jsx)(`td`,{children:`Valid JWT without an endpoint grant`}),(0,G.jsx)(`td`,{children:`Admin JWT`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`full-protected`})}),(0,G.jsx)(`td`,{children:`Valid JWT`}),(0,G.jsx)(`td`,{children:`JWT with the matching endpoint grant`}),(0,G.jsx)(`td`,{children:`Admin JWT`})]})]})]}),(0,G.jsxs)(`p`,{children:[`Health endpoints remain public in every mode. Model discovery consists of `,(0,G.jsx)(`code`,{children:`GET /v1/models`}),` and `,(0,G.jsx)(`code`,{children:`GET /v1/models/{model}`}),`. Native Kronk model, integrity, catalog, device, diagnostic, pool, playground, and security endpoints are management APIs.`]}),(0,G.jsx)(`p`,{children:`For example:`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{className:`language-shell`,children:`export KRONK_AUTHORIZATION_MODE=full-protected
+}`})}),(0,G.jsxs)(`p`,{children:[`Put this part before the text question. The `,(0,G.jsx)(`code`,{children:`format`}),` field is accepted for client compatibility, but Kronk currently determines the actual format from the decoded bytes rather than this value.`]}),(0,G.jsxs)(`p`,{children:[`Use a multimodal chat model when you need conversational questions, summaries, or reasoning about audio. For a dedicated speech-to-text API, use Bucky's `,(0,G.jsx)(`code`,{children:`POST /v1/audio/transcriptions`}),` endpoint described in `,(0,G.jsx)(`a`,{href:`https://www.kronkai.com/manual#1861-request-and-response`,children:`Chapter 18`}),`.`]}),(0,G.jsx)(`h2`,{id:`115-go-sdk-helpers`,children:`11.5 Go SDK Helpers`}),(0,G.jsx)(`p`,{children:`Go applications can read media into a byte slice and use:`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`code`,{children:`model.ImageMessage(question, image, format)`}),`; or`]}),(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`code`,{children:`model.AudioMessage(question, audio, format)`}),`.`]})]}),(0,G.jsxs)(`p`,{children:[`These helpers create one user turn with media before text. `,(0,G.jsx)(`code`,{children:`model.VideoMessage`}),` constructs a `,(0,G.jsx)(`code`,{children:`video_url`}),` part, but it does not add video-container decoding; send extracted frames with `,(0,G.jsx)(`code`,{children:`ImageMessage`}),` for the current media path.`]}),(0,G.jsx)(`h2`,{id:`116-configuration-and-resources`,children:`11.6 Configuration and Resources`}),(0,G.jsxs)(`p`,{children:[`Multimodal requests use the same batch engine and concurrency controls as text requests. The projector adds weights and runtime buffers, while image resolution, audio duration, context length, and `,(0,G.jsx)(`code`,{children:`nseq-max`}),` affect resource use. Use the BUI VRAM Calculator rather than adding model, projector, and KV file sizes as a complete memory estimate. See `,(0,G.jsx)(`a`,{href:`https://www.kronkai.com/manual#36-memory-planning-and-quantization`,children:`Chapter 3 §3.6`}),` for memory planning and `,(0,G.jsx)(`a`,{href:`https://www.kronkai.com/manual#chapter-4-batch-processing`,children:`Chapter 4`}),` for concurrency.`]}),(0,G.jsxs)(`p`,{children:[`Most deployments should leave `,(0,G.jsx)(`code`,{children:`prefill-batch-size`}),` at its 2048-token default. Kronk adds the model's per-slot generation reserve when deriving llama.cpp's internal batch capacities. A multimodal encoder may require an entire media-token chunk to fit in one physical batch, so lowering `,(0,G.jsx)(`code`,{children:`prefill-batch-size`}),` below that capacity can break media input. `,(0,G.jsx)(`code`,{children:`proj-on-cpu: true`}),` can keep the projector on the CPU when accelerator memory is constrained, at a performance cost.`]}),(0,G.jsx)(`h2`,{id:`117-message-caching`,children:`11.7 Message Caching`}),(0,G.jsxs)(`p`,{children:[`Incremental Message Caching can reuse unchanged media state for text-only follow-up turns without encoding the media again. Changing, reordering, removing, or appending media rebuilds the stable media plan through the multimodal pipeline. See `,(0,G.jsx)(`a`,{href:`https://www.kronkai.com/manual#54-media-requests`,children:`Chapter 5 §5.4`}),` for the cache behavior and limitations.`]}),(0,G.jsx)(`h2`,{id:`118-limitations`,children:`11.8 Limitations`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:`Media must be embedded as base64; Kronk does not fetch remote URLs.`}),(0,G.jsx)(`li`,{children:`The current path accepts image and audio containers, not video containers.`}),(0,G.jsx)(`li`,{children:`The selected model and projector must support the detected modality.`}),(0,G.jsx)(`li`,{children:`Image resolution, media count, and audio duration affect latency and memory.`}),(0,G.jsx)(`li`,{children:`Model quality and practical media limits vary by model and projector.`}),(0,G.jsx)(`li`,{children:`Kronk does not impose fixed media payload, image-dimension, or media-count limits. Image decoding allocates memory in proportion to decoded dimensions, and a request can retain multiple decoded media items at once. Applications that accept media from untrusted sources must validate those resources before passing them to Kronk.`})]}),(0,G.jsx)(`hr`,{}),(0,G.jsx)(`p`,{children:(0,G.jsx)(`em`,{children:`Next: Chapter 12: Security & Authentication`})}),(0,G.jsx)(`h2`,{id:`chapter-12-security-and-authentication`,children:`Chapter 12: Security and Authentication`}),(0,G.jsx)(`p`,{children:`Kronk signs JWT bearer tokens with local RSA keys. A token can be an unrestricted administrator credential or a user credential limited to specific inference endpoints and request quotas.`}),(0,G.jsx)(`h2`,{id:`121-authorization-modes`,children:`12.1 Authorization Modes`}),(0,G.jsxs)(`p`,{children:[(0,G.jsx)(`code`,{children:`KRONK_AUTHORIZATION_MODE`}),` selects the API access policy independently of whether Kronk uses its embedded auth service or `,(0,G.jsx)(`code`,{children:`KRONK_AUTH_HOST`}),`:`]}),(0,G.jsxs)(`table`,{className:`flags-table`,children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{children:`Value`}),(0,G.jsx)(`th`,{children:`Model discovery`}),(0,G.jsx)(`th`,{children:`Inference`}),(0,G.jsx)(`th`,{children:`Management`})]})}),(0,G.jsxs)(`tbody`,{children:[(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`open`})}),(0,G.jsx)(`td`,{children:`Public`}),(0,G.jsx)(`td`,{children:`Public`}),(0,G.jsx)(`td`,{children:`Public`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`management`})}),(0,G.jsx)(`td`,{children:`Public`}),(0,G.jsx)(`td`,{children:`Public`}),(0,G.jsx)(`td`,{children:`Admin JWT`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`authenticated`})}),(0,G.jsx)(`td`,{children:`Valid JWT`}),(0,G.jsx)(`td`,{children:`Valid JWT without an endpoint grant`}),(0,G.jsx)(`td`,{children:`Admin JWT`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`full-protected`})}),(0,G.jsx)(`td`,{children:`Valid JWT`}),(0,G.jsx)(`td`,{children:`JWT with the matching endpoint grant`}),(0,G.jsx)(`td`,{children:`Admin JWT`})]})]})]}),(0,G.jsxs)(`p`,{children:[`Health endpoints remain public in every mode. Model discovery consists of `,(0,G.jsx)(`code`,{children:`GET /v1/models`}),` and `,(0,G.jsx)(`code`,{children:`GET /v1/models/{model}`}),`. Native Kronk model, integrity, catalog, device, diagnostic, pool, playground, and security endpoints are management APIs.`]}),(0,G.jsx)(`p`,{children:`For example:`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{className:`language-shell`,children:`export KRONK_AUTHORIZATION_MODE=full-protected
kronk server start`})}),(0,G.jsxs)(`p`,{children:[`When `,(0,G.jsx)(`code`,{children:`KRONK_AUTHORIZATION_MODE`}),` is set, it overrides the legacy `,(0,G.jsx)(`code`,{children:`KRONK_AUTH_LOCAL_ENABLED`}),` and `,(0,G.jsx)(`code`,{children:`KRONK_AUTH_ADMIN_ENABLED`}),` settings. When the new mode is unset, those settings retain their existing behavior for compatibility. This allows deployments to migrate before the legacy settings are deprecated.`]}),(0,G.jsxs)(`p`,{children:[(0,G.jsx)(`code`,{children:`KRONK_AUTH_HOST`}),` selects the authentication provider; it does not change the rights in this table. `,(0,G.jsx)(`code`,{children:`KRONK_WEB_ADMIN_ENABLED`}),` independently controls whether the BUI is served. When using an external auth host with a mode that protects management, disable the BUI because its password login uses the embedded security store.`]}),(0,G.jsx)(`h2`,{id:`122-initial-credentials`,children:`12.2 Initial Credentials`}),(0,G.jsx)(`p`,{children:`When the embedded security store initializes for the first time, Kronk creates:`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`code`,{children:`~/.kronk/keys/master.pem`}),`, the master private key;`]}),(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`code`,{children:`~/.kronk/keys/master.jwt`}),`, an admin token valid for ten years; and`]}),(0,G.jsx)(`li`,{children:`an additional UUID-named signing key used for subsequently created tokens.`})]}),(0,G.jsxs)(`p`,{children:[`This initialization occurs even in open mode when Kronk starts its embedded auth service. The key directory is set to mode `,(0,G.jsx)(`code`,{children:`0700`}),`, and private keys and the master token are set to `,(0,G.jsx)(`code`,{children:`0600`}),`.`]}),(0,G.jsx)(`p`,{children:`Treat both master files as recovery credentials. Keep secure backups and never distribute them to applications. Changing the configured JWT issuer causes existing tokens to fail issuer validation.`}),(0,G.jsx)(`h2`,{id:`123-admin-and-user-tokens`,children:`12.3 Admin and User Tokens`}),(0,G.jsx)(`p`,{children:`Load the initial admin token for CLI administration:`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{className:`language-shell`,children:`export KRONK_TOKEN=$(cat ~/.kronk/keys/master.jwt)`})}),(0,G.jsxs)(`p`,{children:[`Admin tokens bypass endpoint grants and rate limits. The security CLI requires `,(0,G.jsx)(`code`,{children:`KRONK_TOKEN`}),` for key and token commands. In protected modes, the server also verifies that it is an admin token.`]}),(0,G.jsx)(`p`,{children:`Create a short-lived application token with exact endpoint grants:`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{className:`language-shell`,children:`kronk security token create \\
--duration 24h \\
--endpoints chat-completions,responses,messages`})}),(0,G.jsxs)(`p`,{children:[(0,G.jsx)(`code`,{children:`--duration`}),` uses Go duration syntax such as `,(0,G.jsx)(`code`,{children:`1h`}),`, `,(0,G.jsx)(`code`,{children:`24h`}),`, or `,(0,G.jsx)(`code`,{children:`720h`}),`; it does not accept `,(0,G.jsx)(`code`,{children:`30d`}),`. Every generated token receives a unique subject UUID, so authorization and quotas are per token rather than per named human or account.`]}),(0,G.jsx)(`h2`,{id:`124-endpoint-grants-and-rate-limits`,children:`12.4 Endpoint Grants and Rate Limits`}),(0,G.jsx)(`p`,{children:`The grant names used by inference middleware are:`}),(0,G.jsxs)(`table`,{className:`flags-table`,children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{children:`Grant`}),(0,G.jsx)(`th`,{children:`Endpoint`})]})}),(0,G.jsxs)(`tbody`,{children:[(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`chat-completions`})}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`POST /v1/chat/completions`})})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`decision`})}),(0,G.jsxs)(`td`,{children:[(0,G.jsx)(`code`,{children:`POST /v1/systemone`}),` and `,(0,G.jsx)(`code`,{children:`/v1/decide`})]})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`responses`})}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`POST /v1/responses`})})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`messages`})}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`POST /v1/messages`})})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`embeddings`})}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`POST /v1/embeddings`})})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`rerank`})}),(0,G.jsxs)(`td`,{children:[(0,G.jsx)(`code`,{children:`POST /v1/rerank`}),` and `,(0,G.jsx)(`code`,{children:`/v1/reranking`})]})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`tokenize`})}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`POST /v1/tokenize`})})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`transcriptions`})}),(0,G.jsxs)(`td`,{children:[(0,G.jsx)(`code`,{children:`POST /v1/audio/transcriptions`}),`, `,(0,G.jsx)(`code`,{children:`POST /v1/audio/translations`})]})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`image-generations`})}),(0,G.jsxs)(`td`,{children:[(0,G.jsx)(`code`,{children:`POST /v1/images/generations`}),`, `,(0,G.jsx)(`code`,{children:`POST /v1/images/edits`}),`, `,(0,G.jsx)(`code`,{children:`GET /v1/images/events`})]})]})]})]}),(0,G.jsx)(`p`,{children:`Grant names are not validated when a token is created. Use the names above exactly; a typo produces a valid token with an unusable grant.`}),(0,G.jsxs)(`p`,{children:[`Each `,(0,G.jsx)(`code`,{children:`--endpoints`}),` entry has one of these forms:`]}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{className:`language-text`,children:`endpoint
@@ -8603,7 +8603,7 @@ curl http://localhost:11435/v1/chat/completions \\
"messages": [{"role": "user", "content": "Hello"}]
}'`})}),(0,G.jsxs)(`p`,{children:[`Kronk verifies the signature, issuer, expiration, required admin status or endpoint grant, and quota before processing a protected request. Authentication, missing-grant, and exhausted-quota failures return `,(0,G.jsx)(`code`,{children:`401 Unauthorized`}),`, `,(0,G.jsx)(`code`,{children:`403 Forbidden`}),`, and `,(0,G.jsx)(`code`,{children:`429 Too Many Requests`}),`, respectively. Authentication service failures return `,(0,G.jsx)(`code`,{children:`500 Internal Server Error`}),`, while unavailable external auth services return `,(0,G.jsx)(`code`,{children:`503 Service Unavailable`}),`.`]}),(0,G.jsx)(`h2`,{id:`126-key-rotation-and-revocation`,children:`12.6 Key Rotation and Revocation`}),(0,G.jsx)(`p`,{children:`Security commands use the running server by default:`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{className:`language-shell`,children:`kronk security key list
kronk security key create
-kronk security key delete --keyid "$KEY_ID"`})}),(0,G.jsxs)(`p`,{children:[(0,G.jsx)(`code`,{children:`key create`}),` generates a UUID-named private key. The newest key becomes the signing key for subsequently created tokens, while older public keys continue to verify existing tokens.`]}),(0,G.jsx)(`p`,{children:`Kronk does not maintain an individual token revocation list. Deleting a key immediately invalidates every token signed by that key. Rotate safely by:`}),(0,G.jsxs)(`ol`,{children:[(0,G.jsx)(`li`,{children:`Creating a new key.`}),(0,G.jsx)(`li`,{children:`Issuing replacement tokens, which use the new key.`}),(0,G.jsx)(`li`,{children:`Waiting for old tokens to expire or confirming they are no longer used.`}),(0,G.jsx)(`li`,{children:`Deleting the old non-master key.`})]}),(0,G.jsx)(`p`,{children:`The master key cannot be deleted through the security API. Keep it as the administrative recovery key.`}),(0,G.jsxs)(`p`,{children:[`Add `,(0,G.jsx)(`code`,{children:`--local`}),` to operate directly on the local key store without the server:`]}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{className:`language-shell`,children:`kronk security key list --local`})}),(0,G.jsxs)(`p`,{children:[`Local mode still requires `,(0,G.jsx)(`code`,{children:`KRONK_TOKEN`}),` containing a valid local admin token. Use it while the server is stopped because the local command opens the same Badger database.`]}),(0,G.jsx)(`h2`,{id:`127-embedded-and-standalone-authentication`,children:`12.7 Embedded and Standalone Authentication`}),(0,G.jsxs)(`p`,{children:[`By default, `,(0,G.jsx)(`code`,{children:`kronk server`}),` runs the auth service in-process over an in-memory listener. Relevant server settings are:`]}),(0,G.jsxs)(`table`,{className:`flags-table`,children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{children:`Flag`}),(0,G.jsx)(`th`,{children:`Environment variable`}),(0,G.jsx)(`th`,{children:`Purpose`})]})}),(0,G.jsxs)(`tbody`,{children:[(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`—`}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`KRONK_AUTHORIZATION_MODE`})}),(0,G.jsxs)(`td`,{children:[`Select `,(0,G.jsx)(`code`,{children:`open`}),`, `,(0,G.jsx)(`code`,{children:`management`}),`, `,(0,G.jsx)(`code`,{children:`authenticated`}),`, or `,(0,G.jsx)(`code`,{children:`full-protected`}),`; overrides the legacy authorization settings.`]})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`--auth-enabled`})}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`KRONK_AUTH_LOCAL_ENABLED`})}),(0,G.jsx)(`td`,{children:`Legacy setting that protects inference and administration.`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`--admin-auth-enabled`})}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`KRONK_AUTH_ADMIN_ENABLED`})}),(0,G.jsx)(`td`,{children:`Legacy setting that protects administration only.`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`--auth-issuer`})}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`KRONK_AUTH_LOCAL_ISSUER`})}),(0,G.jsx)(`td`,{children:`Set the expected JWT issuer.`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`--auth-host`})}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`KRONK_AUTH_HOST`})}),(0,G.jsx)(`td`,{children:`Connect to an external auth service instead.`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`--auth-tls-enabled`})}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`KRONK_AUTH_TLS_ENABLED`})}),(0,G.jsx)(`td`,{children:`Use TLS for an external auth connection.`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`--auth-tls-ca-file`})}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`KRONK_AUTH_TLS_CA_FILE`})}),(0,G.jsx)(`td`,{children:`Trust the certificates in this PEM CA file instead of the system roots.`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`--auth-tls-server-name`})}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`KRONK_AUTH_TLS_SERVER_NAME`})}),(0,G.jsx)(`td`,{children:`Override the TLS certificate server name.`})]})]})]}),(0,G.jsxs)(`p`,{children:[`Setting `,(0,G.jsx)(`code`,{children:`KRONK_AUTH_HOST`}),` skips embedded auth startup. The standalone `,(0,G.jsx)(`code`,{children:`auth`}),` service uses `,(0,G.jsx)(`code`,{children:`AUTH_AUTH_HOST`}),` (default `,(0,G.jsx)(`code`,{children:`localhost:6000`}),`), `,(0,G.jsx)(`code`,{children:`AUTH_AUTH_ISSUER`}),` (default `,(0,G.jsx)(`code`,{children:`kronk project`}),`), and `,(0,G.jsx)(`code`,{children:`AUTH_AUTH_ENABLED`}),`. Set `,(0,G.jsx)(`code`,{children:`AUTH_AUTH_TLS_ENABLED=true`}),`, `,(0,G.jsx)(`code`,{children:`AUTH_AUTH_TLS_CERT_FILE`}),`, and `,(0,G.jsx)(`code`,{children:`AUTH_AUTH_TLS_KEY_FILE`}),` to serve TLS. The Kronk client and auth service must agree on issuer, protection policy, and transport security. External plaintext connections remain supported for compatibility but produce a startup warning.`]}),(0,G.jsxs)(`p`,{children:[`The standalone MCP service uses `,(0,G.jsx)(`code`,{children:`MCP_AUTH_TLS_ENABLED`}),`, `,(0,G.jsx)(`code`,{children:`MCP_AUTH_TLS_CA_FILE`}),`, and `,(0,G.jsx)(`code`,{children:`MCP_AUTH_TLS_SERVER_NAME`}),` for its connection to the auth service.`]}),(0,G.jsxs)(`p`,{children:[`CLI web mode reads `,(0,G.jsx)(`code`,{children:`KRONK_WEB_API_HOST`}),`, which defaults to `,(0,G.jsx)(`code`,{children:`localhost:11435`}),`.`]}),(0,G.jsx)(`h2`,{id:`128-production-hardening`,children:`12.8 Production Hardening`}),(0,G.jsxs)(`p`,{children:[`Kronk listens on `,(0,G.jsx)(`code`,{children:`127.0.0.1:11435`}),` and serves plain HTTP by default. Before binding Kronk to another interface or allowing traffic outside a trusted host:`]}),(0,G.jsxs)(`ul`,{children:[(0,G.jsxs)(`li`,{children:[`select `,(0,G.jsx)(`code`,{children:`management`}),`, `,(0,G.jsx)(`code`,{children:`authenticated`}),`, or `,(0,G.jsx)(`code`,{children:`full-protected`}),` authorization as appropriate;`]}),(0,G.jsx)(`li`,{children:`terminate TLS at a trusted reverse proxy and do not expose the API port directly to the public internet;`}),(0,G.jsx)(`li`,{children:`enable auth TLS whenever the auth service is reached across an untrusted network, or use an authenticated encrypted service mesh;`}),(0,G.jsx)(`li`,{children:`restrict network access with host or cloud firewall rules;`}),(0,G.jsxs)(`li`,{children:[`restrict `,(0,G.jsx)(`code`,{children:`KRONK_WEB_CORS_ALLOWED_ORIGINS`}),` instead of retaining `,(0,G.jsx)(`code`,{children:`*`}),`;`]}),(0,G.jsx)(`li`,{children:`issue separate, short-lived, least-privilege tokens for each application;`}),(0,G.jsx)(`li`,{children:`set quotas based on the workload and monitor authentication failures;`}),(0,G.jsxs)(`li`,{children:[`protect and back up `,(0,G.jsx)(`code`,{children:`master.pem`}),` and `,(0,G.jsx)(`code`,{children:`master.jwt`}),`; and`]}),(0,G.jsx)(`li`,{children:`rotate non-master signing keys deliberately, accounting for all tokens that a deletion will revoke.`})]}),(0,G.jsx)(`hr`,{}),(0,G.jsx)(`p`,{children:(0,G.jsx)(`em`,{children:`Next: Chapter 13: Browser UI (BUI)`})}),(0,G.jsx)(`h2`,{id:`chapter-13-browser-ui-bui`,children:`Chapter 13: Browser UI (BUI)`}),(0,G.jsxs)(`p`,{children:[`Kronk includes a Browser UI (BUI) for managing a local server and trying models interactively. It is bundled in the `,(0,G.jsx)(`code`,{children:`kronk`}),` binary, served from the same port as the Web API, and uses the server's `,(0,G.jsx)(`code`,{children:`/v1`}),` endpoints rather than maintaining separate state.`]}),(0,G.jsx)(`p`,{children:`This chapter describes the main areas of the BUI without cataloging every control. The CLI remains useful for scripting and headless administration; the BUI is not intended to duplicate every CLI command.`}),(0,G.jsx)(`h3`,{id:`131-accessing-the-bui`,children:`13.1 Accessing the BUI`}),(0,G.jsx)(`p`,{children:`The BUI is enabled by default. Start the server and open:`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`http://localhost:11435/admin/`})}),(0,G.jsxs)(`p`,{children:[`The address comes from `,(0,G.jsx)(`code`,{children:`KRONK_WEB_API_HOST`}),`, whose default is `,(0,G.jsx)(`code`,{children:`127.0.0.1:11435`}),`. The server root and `,(0,G.jsx)(`code`,{children:`/admin`}),` redirect to `,(0,G.jsx)(`code`,{children:`/admin/`}),` while the BUI is enabled.`]}),(0,G.jsx)(`p`,{children:`For a headless deployment, disable it with either form:`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{className:`language-shell`,children:`export KRONK_WEB_ADMIN_ENABLED=false
+kronk security key delete --keyid "$KEY_ID"`})}),(0,G.jsxs)(`p`,{children:[(0,G.jsx)(`code`,{children:`key create`}),` generates a UUID-named private key. The newest key becomes the signing key for subsequently created tokens, while older public keys continue to verify existing tokens.`]}),(0,G.jsx)(`p`,{children:`Kronk does not maintain an individual token revocation list. Deleting a key immediately invalidates every token signed by that key. Rotate safely by:`}),(0,G.jsxs)(`ol`,{children:[(0,G.jsx)(`li`,{children:`Creating a new key.`}),(0,G.jsx)(`li`,{children:`Issuing replacement tokens, which use the new key.`}),(0,G.jsx)(`li`,{children:`Waiting for old tokens to expire or confirming they are no longer used.`}),(0,G.jsx)(`li`,{children:`Deleting the old non-master key.`})]}),(0,G.jsx)(`p`,{children:`The master key cannot be deleted through the security API. Keep it as the administrative recovery key.`}),(0,G.jsxs)(`p`,{children:[`Add `,(0,G.jsx)(`code`,{children:`--local`}),` to operate directly on the local key store without the server:`]}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{className:`language-shell`,children:`kronk security key list --local`})}),(0,G.jsxs)(`p`,{children:[`Local mode still requires `,(0,G.jsx)(`code`,{children:`KRONK_TOKEN`}),` containing a valid local admin token. Use it while the server is stopped because the local command opens the same Badger database.`]}),(0,G.jsx)(`h2`,{id:`127-embedded-and-standalone-authentication`,children:`12.7 Embedded and Standalone Authentication`}),(0,G.jsxs)(`p`,{children:[`By default, `,(0,G.jsx)(`code`,{children:`kronk server`}),` runs the auth service in-process over an in-memory listener. Relevant server settings are:`]}),(0,G.jsxs)(`table`,{className:`flags-table`,children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{children:`Flag`}),(0,G.jsx)(`th`,{children:`Environment variable`}),(0,G.jsx)(`th`,{children:`Purpose`})]})}),(0,G.jsxs)(`tbody`,{children:[(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`—`}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`KRONK_AUTHORIZATION_MODE`})}),(0,G.jsxs)(`td`,{children:[`Select `,(0,G.jsx)(`code`,{children:`open`}),`, `,(0,G.jsx)(`code`,{children:`management`}),`, `,(0,G.jsx)(`code`,{children:`authenticated`}),`, or `,(0,G.jsx)(`code`,{children:`full-protected`}),`; overrides the legacy authorization settings.`]})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`--auth-enabled`})}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`KRONK_AUTH_LOCAL_ENABLED`})}),(0,G.jsx)(`td`,{children:`Legacy setting that protects inference and administration.`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`--admin-auth-enabled`})}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`KRONK_AUTH_ADMIN_ENABLED`})}),(0,G.jsx)(`td`,{children:`Legacy setting that protects administration only.`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`--auth-issuer`})}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`KRONK_AUTH_LOCAL_ISSUER`})}),(0,G.jsx)(`td`,{children:`Set the expected JWT issuer.`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`--auth-host`})}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`KRONK_AUTH_HOST`})}),(0,G.jsx)(`td`,{children:`Connect to an external auth service instead.`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`--auth-tls-enabled`})}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`KRONK_AUTH_TLS_ENABLED`})}),(0,G.jsx)(`td`,{children:`Use TLS for an external auth connection.`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`--auth-tls-ca-file`})}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`KRONK_AUTH_TLS_CA_FILE`})}),(0,G.jsx)(`td`,{children:`Trust the certificates in this PEM CA file instead of the system roots.`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`--auth-tls-server-name`})}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`KRONK_AUTH_TLS_SERVER_NAME`})}),(0,G.jsx)(`td`,{children:`Override the TLS certificate server name.`})]})]})]}),(0,G.jsxs)(`p`,{children:[`Setting `,(0,G.jsx)(`code`,{children:`KRONK_AUTH_HOST`}),` skips embedded auth startup. The standalone `,(0,G.jsx)(`code`,{children:`auth`}),` service uses `,(0,G.jsx)(`code`,{children:`AUTH_AUTH_HOST`}),` (default `,(0,G.jsx)(`code`,{children:`localhost:6000`}),`), `,(0,G.jsx)(`code`,{children:`AUTH_AUTH_ISSUER`}),` (default `,(0,G.jsx)(`code`,{children:`kronk project`}),`), and `,(0,G.jsx)(`code`,{children:`AUTH_AUTH_ENABLED`}),`. Set `,(0,G.jsx)(`code`,{children:`AUTH_AUTH_TLS_ENABLED=true`}),`, `,(0,G.jsx)(`code`,{children:`AUTH_AUTH_TLS_CERT_FILE`}),`, and `,(0,G.jsx)(`code`,{children:`AUTH_AUTH_TLS_KEY_FILE`}),` to serve TLS. The Kronk client and auth service must agree on issuer, protection policy, and transport security. External plaintext connections remain supported for compatibility but produce a startup warning.`]}),(0,G.jsxs)(`p`,{children:[`The standalone MCP service uses `,(0,G.jsx)(`code`,{children:`MCP_AUTH_TLS_ENABLED`}),`, `,(0,G.jsx)(`code`,{children:`MCP_AUTH_TLS_CA_FILE`}),`, and `,(0,G.jsx)(`code`,{children:`MCP_AUTH_TLS_SERVER_NAME`}),` for its connection to the auth service.`]}),(0,G.jsxs)(`p`,{children:[`CLI web mode reads `,(0,G.jsx)(`code`,{children:`KRONK_WEB_API_HOST`}),`, which defaults to `,(0,G.jsx)(`code`,{children:`localhost:11435`}),`.`]}),(0,G.jsx)(`h2`,{id:`128-production-hardening`,children:`12.8 Production Hardening`}),(0,G.jsxs)(`p`,{children:[`Kronk listens on `,(0,G.jsx)(`code`,{children:`127.0.0.1:11435`}),` and serves plain HTTP by default. Before binding Kronk to another interface or allowing traffic outside a trusted host:`]}),(0,G.jsxs)(`ul`,{children:[(0,G.jsxs)(`li`,{children:[`select `,(0,G.jsx)(`code`,{children:`management`}),`, `,(0,G.jsx)(`code`,{children:`authenticated`}),`, or `,(0,G.jsx)(`code`,{children:`full-protected`}),` authorization as appropriate;`]}),(0,G.jsx)(`li`,{children:`terminate TLS at a trusted reverse proxy and do not expose the API port directly to the public internet;`}),(0,G.jsx)(`li`,{children:`enable auth TLS whenever the auth service is reached across an untrusted network, or use an authenticated encrypted service mesh;`}),(0,G.jsx)(`li`,{children:`restrict network access with host or cloud firewall rules;`}),(0,G.jsxs)(`li`,{children:[`restrict `,(0,G.jsx)(`code`,{children:`KRONK_WEB_CORS_ALLOWED_ORIGINS`}),` instead of retaining `,(0,G.jsx)(`code`,{children:`*`}),`;`]}),(0,G.jsx)(`li`,{children:`issue separate, short-lived, least-privilege tokens for each application;`}),(0,G.jsx)(`li`,{children:`set quotas based on the workload and monitor authentication failures;`}),(0,G.jsx)(`li`,{children:`when an application forwards untrusted media, validate request size, media count, payload size, and decoded image dimensions before forwarding it;`}),(0,G.jsxs)(`li`,{children:[`protect and back up `,(0,G.jsx)(`code`,{children:`master.pem`}),` and `,(0,G.jsx)(`code`,{children:`master.jwt`}),`; and`]}),(0,G.jsx)(`li`,{children:`rotate non-master signing keys deliberately, accounting for all tokens that a deletion will revoke.`})]}),(0,G.jsx)(`hr`,{}),(0,G.jsx)(`p`,{children:(0,G.jsx)(`em`,{children:`Next: Chapter 13: Browser UI (BUI)`})}),(0,G.jsx)(`h2`,{id:`chapter-13-browser-ui-bui`,children:`Chapter 13: Browser UI (BUI)`}),(0,G.jsxs)(`p`,{children:[`Kronk includes a Browser UI (BUI) for managing a local server and trying models interactively. It is bundled in the `,(0,G.jsx)(`code`,{children:`kronk`}),` binary, served from the same port as the Web API, and uses the server's `,(0,G.jsx)(`code`,{children:`/v1`}),` endpoints rather than maintaining separate state.`]}),(0,G.jsx)(`p`,{children:`This chapter describes the main areas of the BUI without cataloging every control. The CLI remains useful for scripting and headless administration; the BUI is not intended to duplicate every CLI command.`}),(0,G.jsx)(`h3`,{id:`131-accessing-the-bui`,children:`13.1 Accessing the BUI`}),(0,G.jsx)(`p`,{children:`The BUI is enabled by default. Start the server and open:`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{children:`http://localhost:11435/admin/`})}),(0,G.jsxs)(`p`,{children:[`The address comes from `,(0,G.jsx)(`code`,{children:`KRONK_WEB_API_HOST`}),`, whose default is `,(0,G.jsx)(`code`,{children:`127.0.0.1:11435`}),`. The server root and `,(0,G.jsx)(`code`,{children:`/admin`}),` redirect to `,(0,G.jsx)(`code`,{children:`/admin/`}),` while the BUI is enabled.`]}),(0,G.jsx)(`p`,{children:`For a headless deployment, disable it with either form:`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{className:`language-shell`,children:`export KRONK_WEB_ADMIN_ENABLED=false
kronk server start`})}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{className:`language-shell`,children:`kronk server start --web-admin-enabled=false`})}),(0,G.jsx)(`h3`,{id:`132-capabilities`,children:`13.2 Capabilities`}),(0,G.jsx)(`p`,{children:`The sidebar groups related operations by subsystem.`}),(0,G.jsx)(`h4`,{id:`apps`,children:`Apps`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`strong`,{children:`Chat`}),` provides multi-turn conversations, model selection, system prompts, chat history, and sampling controls.`]}),(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`strong`,{children:`Decision`}),` runs a customer-support example against a decision model from the catalog. The model selector shows download readiness and disables evaluation until the selected model is downloaded and validated. Edit the shared customer state, inspect the fixed choice, score, and Noul questions, then review typed answers, probability distributions, token usage, and the raw `,(0,G.jsx)(`code`,{children:`/v1/decide`}),` response.`]}),(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`strong`,{children:`VRAM Calculator`}),` estimates model memory requirements from a HuggingFace model without downloading the entire model. A calculator is also available in local model and catalog details. Set the intended context, sequence slots, KV precision and placement, layer/expert offload, devices, and tensor split before comparing the result with available memory. The estimate reads per-layer GGUF metadata, including full/SWA topology, recurrent layers, and embedded MTP/NextN layers when present.`]}),(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`strong`,{children:`Translator`}),` records or uploads audio for transcription through Bucky. You can select a whisper model, language, and response format and inspect timestamped segments. See `,(0,G.jsx)(`a`,{href:`https://www.kronkai.com/manual#185-browser-ui`,children:`Chapter 18 §18.5`}),`.`]}),(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`strong`,{children:`Image Generator`}),` creates an image from a text prompt or transforms an uploaded PNG or JPEG with an installed Malina model. Generation settings include negative prompt, output size, steps, CFG scale, seed, and image-to-image strength. The result includes a download action and image dimensions. A server-wide activity panel displays Malina model-loading and generation progress. See `,(0,G.jsx)(`a`,{href:`https://www.kronkai.com/manual#chapter-19-malina-image-generation`,children:`Chapter 19`}),`.`]})]}),(0,G.jsx)(`h4`,{id:`system`,children:`System`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`strong`,{children:`Info`}),` reports server, host, device, library, and model diagnostics.`]}),(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`strong`,{children:`Running`}),` shows models that are loading or resident in the pool, along with the current resource budget. Models can also be unloaded here.`]}),(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`strong`,{children:`Slots`}),` polls the live batch-engine scheduler for each loaded generation model. It shows each slot's phase and request age, prefill stage 1 establishing the sequence by copying reusable IMC session state into the slot, and prefill stage 2 decoding both stable-prefix IMC extensions (such as completed tool calls) and the remaining uncached request tail. The Stage 2 cards show active, next, and waiting slots for those two decode paths. The table also reports per-slot progress, generation mode, and row contribution. Use this view with the batch-engine logs to verify prefill ownership, rotation, and generation priority during concurrent requests. Embedding and reranking models do not have generation slots and are omitted. Each Stage 2 selector retains its selected slot until that decode path is complete, then advances to the next eligible slot.`]}),(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`strong`,{children:`IMC Sessions`}),` has separate tabs for bounded working sessions and model-owned, reusable System prompt caches.`]})]}),(0,G.jsx)(`h4`,{id:`kronk`,children:`Kronk`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`strong`,{children:`Models`}),` lists local GGUF models and their metadata, effective configuration, sampling defaults, chat templates, and estimated VRAM. Models can be pulled from HuggingFace, copied from another Kronk Model Server (KMS), or removed. Persistent configuration is read from `,(0,G.jsx)(`code`,{children:`~/.kronk/models/model_config.yaml`}),`; the model details are read-only. A pull source that includes `,(0,G.jsx)(`code`,{children:`owner/repo/file.gguf`}),` pins that exact Hugging Face repository and file; a repository-only source opens its GGUF file list for selection.`]}),(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`strong`,{children:`Catalog`}),` browses the personal catalog at `,(0,G.jsx)(`code`,{children:`~/.kronk/catalog/catalog.yaml`}),`. You can refresh its on-disk state, inspect entries, pull their files, and remove entries. See Chapter 8 for how the catalog is populated and resolved.`]}),(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`strong`,{children:`Libs`}),` downloads and removes llama.cpp bundles for supported operating system, architecture, and processor combinations. Bundles are stored below `,(0,G.jsx)(`code`,{children:`~/.kronk/libraries/`}),`.`]})]}),(0,G.jsx)(`h4`,{id:`bucky`,children:`Bucky`}),(0,G.jsxs)(`p`,{children:[`Bucky has separate pages for downloading and removing whisper models and managing whisper.cpp library bundles under `,(0,G.jsx)(`code`,{children:`~/.kronk/bucky-libraries/`}),`. See `,(0,G.jsx)(`a`,{href:`https://www.kronkai.com/manual#chapter-18-bucky-audio-transcription`,children:`Chapter 18`}),` for installation and transcription details.`]}),(0,G.jsx)(`h4`,{id:`security`,children:`Security`}),(0,G.jsxs)(`p`,{children:[`Security pages list, create, and delete signing keys and create user tokens. Token controls include duration, endpoint grants, and rate limits. The `,(0,G.jsx)(`strong`,{children:`Session`}),` page reports whether browser administration authentication is enabled and whether the browser has an authenticated admin session.`]}),(0,G.jsx)(`p`,{children:`These tools remain available in open mode. This lets you prepare keys and tokens before enabling authentication, but anyone who can reach an open server can also use its management APIs. See Chapter 12 before exposing the server beyond a trusted machine or network.`}),(0,G.jsx)(`h4`,{id:`testing`,children:`Testing`}),(0,G.jsx)(`p`,{children:`Testing provides several model evaluation workflows:`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`strong`,{children:`Accuracy`}),` compares a model's reproduction of source functions with the actual source, individually, in batches, or across models.`]}),(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`strong`,{children:`Efficiency`}),` compares generation throughput across selected models.`]}),(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`strong`,{children:`Basic`}),` exercises chat, prompt rendering, and tool calling against a model loaded with a chosen runtime configuration.`]}),(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`strong`,{children:`Sampling`}),` runs automated sampling-parameter sweeps.`]}),(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`strong`,{children:`Configuration`}),` runs automated runtime-configuration sweeps.`]})]}),(0,G.jsx)(`p`,{children:`The Basic, Sampling, and Configuration tools create server-side playground sessions. Their configuration applies to that test session; it does not edit the persistent model configuration file.`}),(0,G.jsxs)(`p`,{children:[`The VRAM calculator's SWA control follows runtime precedence. An explicit calculator value wins; for an installed model, its `,(0,G.jsx)(`code`,{children:`swa-full`}),` model setting is next; otherwise the calculator uses the llama.cpp default shipped with the Kronk release. Leaving the control unset therefore does not mean compact SWA. The result separates model weights, KV or recurrent state, compute buffers, and CPU/GPU placement. It is an estimate rather than a reservation guarantee, so retain operating headroom and use the same settings that will load the model.`]}),(0,G.jsx)(`h4`,{id:`docs`,children:`Docs`}),(0,G.jsx)(`p`,{children:`The binary includes an offline documentation snapshot built with that Kronk release:`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`strong`,{children:`Manual`}),` — this manual, with chapter navigation`]}),(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`strong`,{children:`SDK`}),` — SDK and model API references with examples`]}),(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`strong`,{children:`CLI`}),` — command reference`]}),(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`strong`,{children:`Web API`}),` — inference and management endpoint reference`]})]}),(0,G.jsx)(`h3`,{id:`133-authentication`,children:`13.3 Authentication`}),(0,G.jsx)(`p`,{children:`By default, the BUI and management APIs do not require a login. To protect browser administration, select a mode that protects management and configure the SHA-256 digest of the password:`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{className:`language-shell`,children:`export KRONK_AUTHORIZATION_MODE=management
export KRONK_WEB_ADMIN_PASSWORD_SHA_256="$(printf '%s' 'choose-a-password' | shasum -a 256 | awk '{print $1}')"
kronk server start`})}),(0,G.jsxs)(`p`,{children:[`Login creates a one-hour admin token in an HttpOnly, SameSite cookie. The browser cannot read the token, and the server uses it to authenticate the BUI's same-origin `,(0,G.jsx)(`code`,{children:`/v1`}),` requests. Sign out from the sidebar to end the browser session.`]}),(0,G.jsxs)(`p`,{children:[`Chapter 12 explains the `,(0,G.jsx)(`code`,{children:`open`}),`, `,(0,G.jsx)(`code`,{children:`management`}),`, `,(0,G.jsx)(`code`,{children:`authenticated`}),`, and `,(0,G.jsx)(`code`,{children:`full-protected`}),` modes, including TLS and reverse proxy considerations.`]}),(0,G.jsx)(`h3`,{id:`134-operational-notes`,children:`13.4 Operational Notes`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsxs)(`li`,{children:[`Downloading a library bundle does not switch the libraries used by the running process. Set `,(0,G.jsx)(`code`,{children:`KRONK_LIB_PATH`}),` or `,(0,G.jsx)(`code`,{children:`KRONK_BUCKY_LIB_PATH`}),` to the selected bundle and restart the server.`]}),(0,G.jsxs)(`li`,{children:[`Model details display the effective configuration but do not persist model overrides. Catalog details display catalog metadata, files, templates, and VRAM estimates rather than the effective model configuration. Playground settings, including load mode, apply only to that test session. Edit `,(0,G.jsx)(`code`,{children:`~/.kronk/models/model_config.yaml`}),` and reload the model when changing persistent configuration; see Chapter 3.`]}),(0,G.jsxs)(`li`,{children:[`Closing a browser tab does not explicitly delete its playground session. Use `,(0,G.jsx)(`strong`,{children:`Unload Model`}),` when finished. Otherwise, the model remains subject to the server pool's normal eviction policy and is removed on server restart.`]})]}),(0,G.jsx)(`hr`,{}),(0,G.jsx)(`p`,{children:(0,G.jsx)(`em`,{children:`Next: Chapter 14: Client Integration`})}),(0,G.jsx)(`h2`,{id:`chapter-14-client-integration`,children:`Chapter 14: Client Integration`}),(0,G.jsx)(`p`,{children:`Kronk's OpenAI-compatible API works with clients that let you configure a base URL and API key. This chapter covers the OpenCode configuration shipped with the repository and representative setups for OpenWebUI, the OpenAI Python SDK, curl, and LangChain.`}),(0,G.jsx)(`h3`,{id:`141-connection-settings`,children:`14.1 Connection Settings`}),(0,G.jsx)(`p`,{children:`Most clients need three values:`}),(0,G.jsxs)(`table`,{className:`flags-table`,children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{children:`Setting`}),(0,G.jsx)(`th`,{children:`Value`})]})}),(0,G.jsxs)(`tbody`,{children:[(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Base URL`}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`code`,{children:`http://localhost:11435/v1`})})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`API key`}),(0,G.jsx)(`td`,{children:`Any non-empty value in open mode; a valid user token in protected mode`})]}),(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{children:`Model`}),(0,G.jsxs)(`td`,{children:[`An ID returned by `,(0,G.jsx)(`code`,{children:`GET /v1/models`})]})]})]})]}),(0,G.jsx)(`p`,{children:`List the model IDs available to inference clients:`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{className:`language-shell`,children:`curl http://localhost:11435/v1/models`})}),(0,G.jsxs)(`p`,{children:[`When inference authentication is enabled, add `,(0,G.jsx)(`code`,{children:`-H "Authorization: Bearer $KRONK_TOKEN"`}),` and use a user token whose endpoint grants allow the API you are calling. See Chapter 12 for token creation and Chapter 9 for the supported endpoints.`]}),(0,G.jsxs)(`p`,{children:[`If the client runs in a container, `,(0,G.jsx)(`code`,{children:`localhost`}),` refers to the container rather than the host. Use the container runtime's host address, such as `,(0,G.jsx)(`code`,{children:`host.docker.internal`}),`, or place both services on the same container network.`]}),(0,G.jsx)(`h3`,{id:`142-opencode`,children:`14.2 OpenCode`}),(0,G.jsx)(`p`,{children:`OpenCode is the coding agent for which this repository ships a ready-to-use configuration. It registers Kronk as an OpenAI-compatible provider and connects OpenCode to Kronk's MCP service.`}),(0,G.jsx)(`h4`,{id:`launch-an-isolated-session`,children:`Launch an Isolated Session`}),(0,G.jsx)(`p`,{children:`For a disposable session, use the preferred launch workflow:`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{className:`language-shell`,children:`kronk model pull mradermacher/Qwopus3.5-4B-Coder.Q8_0 --local
@@ -8996,5 +8996,5 @@ staticcheck ./path/to/changed/package`})}),(0,G.jsxs)(`p`,{children:[`Use exact
export GITHUB_WORKSPACE="$(pwd -P)"`})}),(0,G.jsxs)(`p`,{children:[(0,G.jsx)(`code`,{children:`GITHUB_WORKSPACE`}),` must be the absolute repository root. Then run a package test or a specific test, for example:`]}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{className:`language-shell`,children:`go test -count=1 ./sdk/kronk/model
go test -count=1 -run 'TestSpecificBehavior' ./sdk/kronk/parsers/qwen`})}),(0,G.jsxs)(`p`,{children:[`Agents must `,(0,G.jsx)(`strong`,{children:`never prescribe or run a full repository test run`}),`, and must `,(0,G.jsx)(`strong`,{children:`never launch tests from sdk/kronk/tests`}),`. Those suites require managed libraries/models and belong to CI or deliberate human integration runs. Commands such as `,(0,G.jsx)(`code`,{children:`make test`}),` and `,(0,G.jsx)(`code`,{children:`make test-adversarial`}),` (`,(0,G.jsx)(`a`,{href:`#2042-server-adversarial-probes`,children:`20.4.2`}),`) exist as broad human/CI-maintainer context, but they are not the agent default. Do not use a broad command merely because focused ownership is unclear; inspect the owner.`]}),(0,G.jsx)(`h4`,{id:`2092-choosing-effective-checks`,children:`20.9.2 Choosing effective checks`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:`Pure logic changes: focused unit test plus package static checks.`}),(0,G.jsx)(`li`,{children:`Public API changes: owner tests, direct dependent package build/test, and generated SDK docs when comments/signatures changed.`}),(0,G.jsx)(`li`,{children:`Batch/native changes: focused model unit tests first; report model-backed validation as unavailable if prerequisites are absent rather than substituting unrelated tests.`}),(0,G.jsx)(`li`,{children:`Pool changes: engine tests plus the affected typed pool's reservation/load tests. Include failure and cancellation, not only warm acquisition.`}),(0,G.jsx)(`li`,{children:`Route changes: domain tests and a server build. Use the relevant API test only when its server/model prerequisites are available.`}),(0,G.jsxs)(`li`,{children:[`CLI changes: command package tests, `,(0,G.jsx)(`code`,{children:`go install ./cmd/kronk`}),`, and one safe invocation.`]}),(0,G.jsx)(`li`,{children:`Bucky changes: package tests; transcription integration only with installed Whisper libraries/model. Streaming changes require close/cancellation coverage.`}),(0,G.jsx)(`li`,{children:`Malina changes: package tests and affected example builds. Native generation requires compatible stable-diffusion.cpp libraries and multi-gigabyte model bundles, so keep model-backed runs deliberate and do not make them an unconditional CI requirement.`})]}),(0,G.jsx)(`h4`,{id:`2093-markdown-generated-docs-and-bui`,children:`20.9.3 Markdown, generated docs, and BUI`}),(0,G.jsxs)(`p`,{children:[`For a manual-only edit, run formatting/sanity checks appropriate to the task, including `,(0,G.jsx)(`code`,{children:`git diff --check`}),`. `,(0,G.jsx)(`code`,{children:`make kronk-docs`}),` validates the manual conversion pipeline but also changes generated `,(0,G.jsx)(`code`,{children:`DocsManual`}),`; honor any task restriction on edited files. For normal documentation changes, commit source and generated output together, then run the BUI build.`]}),(0,G.jsx)(`p`,{children:`For BUI changes, install dependencies according to its lockfile/workflow and run:`}),(0,G.jsx)(`pre`,{className:`code-block`,children:(0,G.jsx)(`code`,{className:`language-shell`,children:`npm run build`})}),(0,G.jsxs)(`p`,{children:[`Run it from `,(0,G.jsx)(`code`,{children:`cmd/server/api/frontends/bui/`}),`. For docs or BUI work that affects the production bundle, also build the server to verify the bundle embedded by `,(0,G.jsx)(`code`,{children:`cmd/server/api/services/kronk/main.go`}),` exists and compiles. A successful Vite build alone does not prove the Go binary contains current assets.`]}),(0,G.jsx)(`p`,{children:`Always report what actually ran, including skipped integration prerequisites. Never claim CI parity from a narrower local test.`}),(0,G.jsx)(`h3`,{id:`2010-ci-release-containers-and-nix`,children:`20.10 CI, Release, Containers, and Nix`}),(0,G.jsx)(`h4`,{id:`20101-linux-ci`,children:`20.10.1 Linux CI`}),(0,G.jsxs)(`p`,{children:[(0,G.jsx)(`code`,{children:`.github/workflows/linux.yml`}),` is the authoritative Linux pipeline. It currently has four parallel jobs:`]}),(0,G.jsxs)(`ul`,{children:[(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`code`,{children:`static`}),`: source/static quality checks;`]}),(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`code`,{children:`race`}),`: race-enabled focused coverage separated from static checks;`]}),(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`code`,{children:`api-tests`}),`: server/API integration coverage;`]}),(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`code`,{children:`sdk-tests`}),`: SDK/model integration coverage.`]})]}),(0,G.jsxs)(`p`,{children:[`The shared setup action is under `,(0,G.jsx)(`code`,{children:`.github/actions/setup-kronk/`}),`. CI model dependencies are declared in `,(0,G.jsx)(`code`,{children:`.github/test-models.txt`}),`; its contents also participate in cache behavior. When a CI test gains a required model, update the manifest with the correct backend and model ID and check the setup action's parser. Keep local human setup in sync where the Make workflow maintains a separate install list.`]}),(0,G.jsxs)(`p`,{children:[`The exact CI toolchain comes from `,(0,G.jsx)(`code`,{children:`.go-version`}),`, while `,(0,G.jsx)(`code`,{children:`go.mod`}),` declares the minimum language version. Their major/minor versions must match. Update workflow assumptions and run `,(0,G.jsx)(`code`,{children:`.github/scripts/check-go-version.sh`}),` when changing either.`]}),(0,G.jsx)(`h4`,{id:`20102-release`,children:`20.10.2 Release`}),(0,G.jsx)(`p`,{children:`The release workflow, GoReleaser configuration, scripts, and release notes divide responsibility:`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`code`,{children:`.github/workflows/release.yaml`}),` owns trigger, permissions, setup, checks, and release execution.`]}),(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`code`,{children:`.goreleaser.yaml`}),` owns binary/archive packaging and related release products.`]}),(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`code`,{children:`.github/scripts/check-version.sh`}),` enforces the release identity.`]}),(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`code`,{children:`sdk/kronk/kronk.go`}),` owns the exported `,(0,G.jsx)(`code`,{children:`Version`}),` constant.`]}),(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`code`,{children:`.release/`}),` owns maintained release-note/checklist material.`]})]}),(0,G.jsxs)(`p`,{children:[`The release tag must equal `,(0,G.jsx)(`code`,{children:`v`}),` plus the `,(0,G.jsx)(`code`,{children:`Version`}),` constant. Update the constant and release material intentionally before creating the tag; do not bypass the guard. Also confirm the Go major/minor guard, generated docs/BUI, clean tree, and relevant Linux jobs before tagging.`]}),(0,G.jsx)(`h4`,{id:`20103-containers`,children:`20.10.3 Containers`}),(0,G.jsxs)(`p`,{children:[(0,G.jsx)(`code`,{children:`.github/workflows/docker.yml`}),` is authoritative for image variants, target/platform matrix, registry publication, attestations, and signing. `,(0,G.jsx)(`code`,{children:`zarf/docker/`}),` owns Dockerfile, runtime configuration, and entrypoint behavior. Native llama and Bucky processor availability can differ by image variant, so inspect the workflow matrix and tooling combination tables before changing an image. Avoid copying a variant table into docs; it becomes stale faster than the workflow.`]}),(0,G.jsx)(`p`,{children:`For a container change, build the affected target and architecture where practical, exercise entrypoint startup/configuration, and verify expected native libraries. Do not infer publication or signature behavior from a local build; review the workflow.`}),(0,G.jsx)(`h4`,{id:`20104-nix`,children:`20.10.4 Nix`}),(0,G.jsxs)(`p`,{children:[`The flake at `,(0,G.jsx)(`code`,{children:`zarf/nix/flake.nix`}),` defines how developers/users enter or build the project; generated Go dependency data lives beside it. Entering a development shell runs `,(0,G.jsx)(`code`,{children:`gomod2nix import`}),` from its shell hook and may dirty that generated material. When Go module dependencies change, update the Nix dependency material with the repository's configured command and evaluate/build the relevant entry point. Keep Nix fixes in Nix owners rather than adding environment special cases to Go code.`]}),(0,G.jsx)(`h3`,{id:`2011-change-and-release-checklists`,children:`20.11 Change and Release Checklists`}),(0,G.jsx)(`h4`,{id:`20111-focused-change-checklist`,children:`20.11.1 Focused change checklist`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsxs)(`li`,{children:[`[ ] Read all applicable `,(0,G.jsx)(`code`,{children:`AGENTS.md`}),` files.`]}),(0,G.jsx)(`li`,{children:`[ ] Locate the owning package, direct caller, and focused tests.`}),(0,G.jsx)(`li`,{children:`[ ] State lifecycle/mutation/resource invariants before editing.`}),(0,G.jsx)(`li`,{children:`[ ] Change the owner rather than duplicating logic in a facade or transport.`}),(0,G.jsx)(`li`,{children:`[ ] Preserve cancellation and release behavior on every return path.`}),(0,G.jsxs)(`li`,{children:[`[ ] For Go: run `,(0,G.jsx)(`code`,{children:`gofmt -s`}),`, `,(0,G.jsx)(`code`,{children:`go fix`}),`, `,(0,G.jsx)(`code`,{children:`go vet`}),`, and `,(0,G.jsx)(`code`,{children:`staticcheck`}),` scoped to changed files/packages.`]}),(0,G.jsxs)(`li`,{children:[`[ ] Set `,(0,G.jsx)(`code`,{children:`RUN_IN_PARALLEL=yes`}),` and absolute `,(0,G.jsx)(`code`,{children:`GITHUB_WORKSPACE`}),` for focused tests.`]}),(0,G.jsxs)(`li`,{children:[`[ ] Do not run a full repository suite or launch tests from `,(0,G.jsx)(`code`,{children:`sdk/kronk/tests`}),` as an agent.`]}),(0,G.jsx)(`li`,{children:`[ ] Regenerate docs/BUI/Nix artifacts only when their sources changed and task scope permits it.`}),(0,G.jsxs)(`li`,{children:[`[ ] Run `,(0,G.jsx)(`code`,{children:`git diff --check`}),` and inspect the complete diff for unrelated changes.`]}),(0,G.jsx)(`li`,{children:`[ ] Report commands, results, skipped prerequisites, and residual uncertainty.`})]}),(0,G.jsx)(`h4`,{id:`20112-release-checklist`,children:`20.11.2 Release checklist`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsxs)(`li`,{children:[`[ ] Choose the release version and update `,(0,G.jsx)(`code`,{children:`sdk/kronk`}),`'s `,(0,G.jsx)(`code`,{children:`Version`}),` constant.`]}),(0,G.jsxs)(`li`,{children:[`[ ] Ensure the intended tag is exactly `,(0,G.jsx)(`code`,{children:`v`}),` and run the version guard.`]}),(0,G.jsxs)(`li`,{children:[`[ ] Confirm `,(0,G.jsx)(`code`,{children:`.go-version`}),` and `,(0,G.jsx)(`code`,{children:`go.mod`}),` major/minor agreement and run the Go-version guard.`]}),(0,G.jsx)(`li`,{children:`[ ] Update release notes/changelog material under the repository's release process.`}),(0,G.jsxs)(`li`,{children:[`[ ] Ensure `,(0,G.jsx)(`code`,{children:`.github/test-models.txt`}),` covers model-backed CI requirements.`]}),(0,G.jsx)(`li`,{children:`[ ] Regenerate documentation and BUI assets; build the BUI and server embedding.`}),(0,G.jsx)(`li`,{children:`[ ] Confirm focused package checks and the four Linux CI jobs are green.`}),(0,G.jsxs)(`li`,{children:[`[ ] Run `,(0,G.jsx)(`code`,{children:`make test-adversarial`}),` against a generation-capable model on a machine that has one, and review `,(0,G.jsx)(`code`,{children:`.tools/adversarial/output/findings.txt`}),`.`]}),(0,G.jsxs)(`li`,{children:[`[ ] Review `,(0,G.jsx)(`code`,{children:`.github/workflows/docker.yml`}),` for the intended image variants and publication/signing behavior.`]}),(0,G.jsx)(`li`,{children:`[ ] Review Nix dependency outputs if Go dependencies changed.`}),(0,G.jsx)(`li`,{children:`[ ] Verify GoReleaser configuration with an appropriate non-publishing check or snapshot.`}),(0,G.jsx)(`li`,{children:`[ ] Confirm the release commit is clean, then create/push the guarded tag through the maintainer release process.`})]}),(0,G.jsx)(`p`,{children:`The purpose of these lists is to protect ownership and lifecycle contracts, not to turn every patch into a release. Use the focused list for ordinary work and reserve broad integration/release machinery for humans and CI with the required models, native libraries, credentials, and platforms.`})]}),(0,G.jsx)(`nav`,{className:`doc-sidebar`,children:(0,G.jsxs)(`div`,{className:`doc-sidebar-content`,children:[(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#chapter-1-introduction`,className:`doc-index-header ${e===`chapter-1-introduction`?`active`:``}`,children:`Chapter 1: Introduction`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#11-what-is-kronk?`,className:e===`11-what-is-kronk?`?`active`:``,children:`1.1 What Is Kronk?`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#12-sdk-or-model-server?`,className:e===`12-sdk-or-model-server?`?`active`:``,children:`1.2 SDK or Model Server?`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#13-capabilities`,className:e===`13-capabilities`?`active`:``,children:`1.3 Capabilities`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#14-architecture`,className:e===`14-architecture`?`active`:``,children:`1.4 Architecture`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#15-where-to-go-next`,className:e===`15-where-to-go-next`?`active`:``,children:`1.5 Where to Go Next`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#chapter-2-installation-quick-start`,className:`doc-index-header ${e===`chapter-2-installation-quick-start`?`active`:``}`,children:`Chapter 2: Installation & Quick Start`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#21-native-quick-start`,className:e===`21-native-quick-start`?`active`:``,children:`2.1 Native Quick Start`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#22-choose-an-installation-method`,className:e===`22-choose-an-installation-method`?`active`:``,children:`2.2 Choose an Installation Method`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#23-container-quick-start`,className:e===`23-container-quick-start`?`active`:``,children:`2.3 Container Quick Start`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#24-libraries`,className:e===`24-libraries`?`active`:``,children:`2.4 Libraries`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#25-models-and-data-paths`,className:e===`25-models-and-data-paths`?`active`:``,children:`2.5 Models and Data Paths`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#26-running-the-server`,className:e===`26-running-the-server`?`active`:``,children:`2.6 Running the Server`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#27-verify-the-installation`,className:e===`27-verify-the-installation`?`active`:``,children:`2.7 Verify the Installation`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#28-security-and-next-steps`,className:e===`28-security-and-next-steps`?`active`:``,children:`2.8 Security and Next Steps`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#chapter-3-model-configuration`,className:`doc-index-header ${e===`chapter-3-model-configuration`?`active`:``}`,children:`Chapter 3: Model Configuration`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#31-configuration-file`,className:e===`31-configuration-file`?`active`:``,children:`3.1 Configuration File`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#32-automatic-tuning`,className:e===`32-automatic-tuning`?`active`:``,children:`3.2 Automatic Tuning`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#33-core-runtime-settings`,className:e===`33-core-runtime-settings`?`active`:``,children:`3.3 Core Runtime Settings`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#34-gpu-and-memory-placement`,className:e===`34-gpu-and-memory-placement`?`active`:``,children:`3.4 GPU and Memory Placement`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#35-concurrency-and-batching`,className:e===`35-concurrency-and-batching`?`active`:``,children:`3.5 Concurrency and Batching`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#36-memory-planning-and-quantization`,className:e===`36-memory-planning-and-quantization`?`active`:``,children:`3.6 Memory Planning and Quantization`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#37-advanced-features`,className:e===`37-advanced-features`?`active`:``,children:`3.7 Advanced Features`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#38-complete-example-and-key-reference`,className:e===`38-complete-example-and-key-reference`?`active`:``,children:`3.8 Complete Example and Key Reference`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#chapter-4-batch-processing`,className:`doc-index-header ${e===`chapter-4-batch-processing`?`active`:``}`,children:`Chapter 4: Batch Processing`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#41-runtime-mental-model`,className:e===`41-runtime-mental-model`?`active`:``,children:`4.1 Runtime Mental Model`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#42-the-four-stage-request-lifecycle`,className:e===`42-the-four-stage-request-lifecycle`?`active`:``,children:`4.2 The Four-Stage Request Lifecycle`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#43-the-generation-inference-lifecycle`,className:e===`43-the-generation-inference-lifecycle`?`active`:``,children:`4.3 The Generation Inference Lifecycle`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#44-stage-1-—-admit-the-request`,className:e===`44-stage-1-—-admit-the-request`?`active`:``,children:`4.4 Stage 1 — Admit the Request`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#45-stage-2-—-prepare-model-work`,className:e===`45-stage-2-—-prepare-model-work`?`active`:``,children:`4.5 Stage 2 — Prepare Model Work`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#46-stage-3-—-schedule-the-job`,className:e===`46-stage-3-—-schedule-the-job`?`active`:``,children:`4.6 Stage 3 — Schedule the Job`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#47-stage-4-—-execute-in-the-slot`,className:e===`47-stage-4-—-execute-in-the-slot`?`active`:``,children:`4.7 Stage 4 — Execute in the Slot`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#48-embedding-and-reranking`,className:e===`48-embedding-and-reranking`?`active`:``,children:`4.8 Embedding and Reranking`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#49-configuration-and-tuning`,className:e===`49-configuration-and-tuning`?`active`:``,children:`4.9 Configuration and Tuning`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#410-interaction-with-message-caching`,className:e===`410-interaction-with-message-caching`?`active`:``,children:`4.10 Interaction with Message Caching`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#411-observing-queue-behavior`,className:e===`411-observing-queue-behavior`?`active`:``,children:`4.11 Observing Queue Behavior`})})]})]}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#chapter-5-message-caching`,className:`doc-index-header ${e===`chapter-5-message-caching`?`active`:``}`,children:`Chapter 5: Message Caching`})}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#51-what-imc-does`,className:`doc-index-header ${e===`51-what-imc-does`?`active`:``}`,children:`5.1 What IMC Does`}),(0,G.jsx)(`ul`,{children:(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#511-quick-semantic-understanding`,className:e===`511-quick-semantic-understanding`?`active`:``,children:`5.1.1 Quick Semantic Understanding`})})})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#52-how-kronk-reuses-a-text-prefix`,className:`doc-index-header ${e===`52-how-kronk-reuses-a-text-prefix`?`active`:``}`,children:`5.2 How Kronk Reuses a Text Prefix`}),(0,G.jsx)(`ul`,{children:(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#521-system-cache-lifecycle-and-template-behavior`,className:e===`521-system-cache-lifecycle-and-template-behavior`?`active`:``,children:`5.2.1 System Cache Lifecycle and Template Behavior`})})})]}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#53-sessions-slots-and-snapshots`,className:`doc-index-header ${e===`53-sessions-slots-and-snapshots`?`active`:``}`,children:`5.3 Sessions, Slots, and Snapshots`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#54-media-requests`,className:`doc-index-header ${e===`54-media-requests`?`active`:``}`,children:`5.4 Media Requests`})}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#55-configuration-and-storage`,className:`doc-index-header ${e===`55-configuration-and-storage`?`active`:``}`,children:`5.5 Configuration and Storage`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#built-in-ram-storage`,className:e===`built-in-ram-storage`?`active`:``,children:`Built-in RAM storage`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#custom-sdk-storage`,className:e===`custom-sdk-storage`?`active`:``,children:`Custom SDK storage`})})]})]}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#56-invalidation-and-limitations`,className:`doc-index-header ${e===`56-invalidation-and-limitations`?`active`:``}`,children:`5.6 Invalidation and Limitations`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#57-observability`,className:`doc-index-header ${e===`57-observability`?`active`:``}`,children:`5.7 Observability`})}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#chapter-6-speculative-decoding-and-mtp`,className:`doc-index-header ${e===`chapter-6-speculative-decoding-and-mtp`?`active`:``}`,children:`Chapter 6: Speculative Decoding and MTP`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#61-what-speculative-decoding-does`,className:e===`61-what-speculative-decoding-does`?`active`:``,children:`6.1 What Speculative Decoding Does`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#62-drafter-sources-and-selection`,className:e===`62-drafter-sources-and-selection`?`active`:``,children:`6.2 Drafter Sources and Selection`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#63-choosing-a-drafter`,className:e===`63-choosing-a-drafter`?`active`:``,children:`6.3 Choosing a Drafter`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#64-draft-size-and-classic-adaptive-throttling`,className:e===`64-draft-size-and-classic-adaptive-throttling`?`active`:``,children:`6.4 Draft Size and Classic Adaptive Throttling`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#65-configuration`,className:e===`65-configuration`?`active`:``,children:`6.5 Configuration`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#66-measuring-the-result`,className:e===`66-measuring-the-result`?`active`:``,children:`6.6 Measuring the Result`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#67-limitations-and-fallbacks`,className:e===`67-limitations-and-fallbacks`?`active`:``,children:`6.7 Limitations and Fallbacks`})})]})]}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#chapter-7-yarn-extended-context`,className:`doc-index-header ${e===`chapter-7-yarn-extended-context`?`active`:``}`,children:`Chapter 7: YaRN Extended Context`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#71-context-size-and-rope-scaling`,className:`doc-index-header ${e===`71-context-size-and-rope-scaling`?`active`:``}`,children:`7.1 Context Size and RoPE Scaling`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#72-when-to-use-yarn`,className:`doc-index-header ${e===`72-when-to-use-yarn`?`active`:``}`,children:`7.2 When to Use YaRN`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#73-qwen3-configuration`,className:`doc-index-header ${e===`73-qwen3-configuration`?`active`:``}`,children:`7.3 Qwen3 Configuration`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#74-scaling-types-and-parameters`,className:`doc-index-header ${e===`74-scaling-types-and-parameters`?`active`:``}`,children:`7.4 Scaling Types and Parameters`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#75-memory-and-concurrency`,className:`doc-index-header ${e===`75-memory-and-concurrency`?`active`:``}`,children:`7.5 Memory and Concurrency`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#76-validate-quality`,className:`doc-index-header ${e===`76-validate-quality`?`active`:``}`,children:`7.6 Validate Quality`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#chapter-8-model-server`,className:`doc-index-header ${e===`chapter-8-model-server`?`active`:``}`,children:`Chapter 8: Model Server`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#81-server-lifecycle`,className:`doc-index-header ${e===`81-server-lifecycle`?`active`:``}`,children:`8.1 Server Lifecycle`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#82-local-and-server-backed-cli-commands`,className:`doc-index-header ${e===`82-local-and-server-backed-cli-commands`?`active`:``}`,children:`8.2 Local and Server-Backed CLI Commands`})}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#83-essential-server-configuration`,className:`doc-index-header ${e===`83-essential-server-configuration`?`active`:``}`,children:`8.3 Essential Server Configuration`}),(0,G.jsx)(`ul`,{children:(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#runtime-selection-and-overrides`,className:e===`runtime-selection-and-overrides`?`active`:``,children:`Runtime selection and overrides`})})})]}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#84-model-pool-and-resource-budgets`,className:`doc-index-header ${e===`84-model-pool-and-resource-budgets`?`active`:``}`,children:`8.4 Model Pool and Resource Budgets`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#85-model-configuration-files`,className:`doc-index-header ${e===`85-model-configuration-files`?`active`:``}`,children:`8.5 Model Configuration Files`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#86-catalog-operations`,className:`doc-index-header ${e===`86-catalog-operations`?`active`:``}`,children:`8.6 Catalog Operations`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#87-container-operations`,className:`doc-index-header ${e===`87-container-operations`?`active`:``}`,children:`8.7 Container Operations`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#88-related-administration-guides`,className:`doc-index-header ${e===`88-related-administration-guides`?`active`:``}`,children:`8.8 Related Administration Guides`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#chapter-9-api-endpoints`,className:`doc-index-header ${e===`chapter-9-api-endpoints`?`active`:``}`,children:`Chapter 9: API Endpoints`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#91-api-conventions`,className:`doc-index-header ${e===`91-api-conventions`?`active`:``}`,children:`9.1 API Conventions`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#92-endpoint-overview`,className:`doc-index-header ${e===`92-endpoint-overview`?`active`:``}`,children:`9.2 Endpoint Overview`})}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#93-chat-completions-and-tool-calls`,className:`doc-index-header ${e===`93-chat-completions-and-tool-calls`?`active`:``}`,children:`9.3 Chat Completions and Tool Calls`}),(0,G.jsx)(`ul`,{children:(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#tool-calls`,className:e===`tool-calls`?`active`:``,children:`Tool calls`})})})]}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#94-responses-api`,className:`doc-index-header ${e===`94-responses-api`?`active`:``}`,children:`9.4 Responses API`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#95-anthropic-messages-api`,className:`doc-index-header ${e===`95-anthropic-messages-api`?`active`:``}`,children:`9.5 Anthropic Messages API`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#96-embeddings`,className:`doc-index-header ${e===`96-embeddings`?`active`:``}`,children:`9.6 Embeddings`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#97-reranking`,className:`doc-index-header ${e===`97-reranking`?`active`:``}`,children:`9.7 Reranking`})}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#98-decisions`,className:`doc-index-header ${e===`98-decisions`?`active`:``}`,children:`9.8 Decisions`}),(0,G.jsx)(`ul`,{children:(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#go-sdk`,className:e===`go-sdk`?`active`:``,children:`Go SDK`})})})]}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#99-tokenization`,className:`doc-index-header ${e===`99-tokenization`?`active`:``}`,children:`9.9 Tokenization`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#910-models-image-generation-and-audio-transcription`,className:`doc-index-header ${e===`910-models-image-generation-and-audio-transcription`?`active`:``}`,children:`9.10 Models, Image Generation, and Audio Transcription`})}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#911-kronk-administration`,className:`doc-index-header ${e===`911-kronk-administration`?`active`:``}`,children:`9.11 Kronk Administration`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#libraries`,className:e===`libraries`?`active`:``,children:`Libraries`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#models`,className:e===`models`?`active`:``,children:`Models`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#catalog`,className:e===`catalog`?`active`:``,children:`Catalog`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#912-bucky-and-malina-administration`,className:`doc-index-header ${e===`912-bucky-and-malina-administration`?`active`:``}`,children:`9.12 Bucky and Malina Administration`}),(0,G.jsx)(`ul`,{children:(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#malina-models-and-runtime-integrity`,className:e===`malina-models-and-runtime-integrity`?`active`:``,children:`Malina Models and Runtime Integrity`})})})]}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#913-operations-and-evaluation`,className:`doc-index-header ${e===`913-operations-and-evaluation`?`active`:``}`,children:`9.13 Operations and Evaluation`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#914-security-administration`,className:`doc-index-header ${e===`914-security-administration`?`active`:``}`,children:`9.14 Security Administration`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#chapter-10-request-parameters`,className:`doc-index-header ${e===`chapter-10-request-parameters`?`active`:``}`,children:`Chapter 10: Request Parameters`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#101-scope-and-defaults`,className:`doc-index-header ${e===`101-scope-and-defaults`?`active`:``}`,children:`10.1 Scope and Defaults`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#102-core-sampling`,className:`doc-index-header ${e===`102-core-sampling`?`active`:``}`,children:`10.2 Core Sampling`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#103-repetition-control`,className:`doc-index-header ${e===`103-repetition-control`?`active`:``}`,children:`10.3 Repetition Control`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#104-advanced-sampling`,className:`doc-index-header ${e===`104-advanced-sampling`?`active`:``}`,children:`10.4 Advanced Sampling`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#105-generation-and-reasoning`,className:`doc-index-header ${e===`105-generation-and-reasoning`?`active`:``}`,children:`10.5 Generation and Reasoning`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#106-structured-output`,className:`doc-index-header ${e===`106-structured-output`?`active`:``}`,children:`10.6 Structured Output`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#107-token-log-probabilities`,className:`doc-index-header ${e===`107-token-log-probabilities`?`active`:``}`,children:`10.7 Token Log Probabilities`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#chapter-11-multimodal-models`,className:`doc-index-header ${e===`chapter-11-multimodal-models`?`active`:``}`,children:`Chapter 11: Multimodal Models`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#111-models-and-projectors`,className:`doc-index-header ${e===`111-models-and-projectors`?`active`:``}`,children:`11.1 Models and Projectors`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#112-supported-inputs`,className:`doc-index-header ${e===`112-supported-inputs`?`active`:``}`,children:`11.2 Supported Inputs`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#113-sending-an-image`,className:`doc-index-header ${e===`113-sending-an-image`?`active`:``}`,children:`11.3 Sending an Image`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#114-sending-audio`,className:`doc-index-header ${e===`114-sending-audio`?`active`:``}`,children:`11.4 Sending Audio`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#115-go-sdk-helpers`,className:`doc-index-header ${e===`115-go-sdk-helpers`?`active`:``}`,children:`11.5 Go SDK Helpers`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#116-configuration-and-resources`,className:`doc-index-header ${e===`116-configuration-and-resources`?`active`:``}`,children:`11.6 Configuration and Resources`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#117-message-caching`,className:`doc-index-header ${e===`117-message-caching`?`active`:``}`,children:`11.7 Message Caching`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#118-limitations`,className:`doc-index-header ${e===`118-limitations`?`active`:``}`,children:`11.8 Limitations`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#chapter-12-security-and-authentication`,className:`doc-index-header ${e===`chapter-12-security-and-authentication`?`active`:``}`,children:`Chapter 12: Security and Authentication`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#121-authorization-modes`,className:`doc-index-header ${e===`121-authorization-modes`?`active`:``}`,children:`12.1 Authorization Modes`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#122-initial-credentials`,className:`doc-index-header ${e===`122-initial-credentials`?`active`:``}`,children:`12.2 Initial Credentials`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#123-admin-and-user-tokens`,className:`doc-index-header ${e===`123-admin-and-user-tokens`?`active`:``}`,children:`12.3 Admin and User Tokens`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#124-endpoint-grants-and-rate-limits`,className:`doc-index-header ${e===`124-endpoint-grants-and-rate-limits`?`active`:``}`,children:`12.4 Endpoint Grants and Rate Limits`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#125-using-a-token`,className:`doc-index-header ${e===`125-using-a-token`?`active`:``}`,children:`12.5 Using a Token`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#126-key-rotation-and-revocation`,className:`doc-index-header ${e===`126-key-rotation-and-revocation`?`active`:``}`,children:`12.6 Key Rotation and Revocation`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#127-embedded-and-standalone-authentication`,className:`doc-index-header ${e===`127-embedded-and-standalone-authentication`?`active`:``}`,children:`12.7 Embedded and Standalone Authentication`})}),(0,G.jsx)(`div`,{className:`doc-index-section`,children:(0,G.jsx)(`a`,{href:`#128-production-hardening`,className:`doc-index-header ${e===`128-production-hardening`?`active`:``}`,children:`12.8 Production Hardening`})}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#chapter-13-browser-ui-bui`,className:`doc-index-header ${e===`chapter-13-browser-ui-bui`?`active`:``}`,children:`Chapter 13: Browser UI (BUI)`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#131-accessing-the-bui`,className:e===`131-accessing-the-bui`?`active`:``,children:`13.1 Accessing the BUI`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#132-capabilities`,className:e===`132-capabilities`?`active`:``,children:`13.2 Capabilities`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#133-authentication`,className:e===`133-authentication`?`active`:``,children:`13.3 Authentication`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#134-operational-notes`,className:e===`134-operational-notes`?`active`:``,children:`13.4 Operational Notes`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#chapter-14-client-integration`,className:`doc-index-header ${e===`chapter-14-client-integration`?`active`:``}`,children:`Chapter 14: Client Integration`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#141-connection-settings`,className:e===`141-connection-settings`?`active`:``,children:`14.1 Connection Settings`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#142-opencode`,className:e===`142-opencode`?`active`:``,children:`14.2 OpenCode`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#143-openwebui`,className:e===`143-openwebui`?`active`:``,children:`14.3 OpenWebUI`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#144-python-openai-sdk`,className:e===`144-python-openai-sdk`?`active`:``,children:`14.4 Python OpenAI SDK`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#145-curl-and-other-http-clients`,className:e===`145-curl-and-other-http-clients`?`active`:``,children:`14.5 curl and Other HTTP Clients`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#146-langchain`,className:e===`146-langchain`?`active`:``,children:`14.6 LangChain`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#chapter-15-observability`,className:`doc-index-header ${e===`chapter-15-observability`?`active`:``}`,children:`Chapter 15: Observability`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#151-debug-and-health-endpoints`,className:e===`151-debug-and-health-endpoints`?`active`:``,children:`15.1 Debug and Health Endpoints`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#152-prometheus-metrics`,className:e===`152-prometheus-metrics`?`active`:``,children:`15.2 Prometheus Metrics`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#153-bundled-observability-stack`,className:e===`153-bundled-observability-stack`?`active`:``,children:`15.3 Bundled Observability Stack`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#154-opentelemetry-tracing`,className:e===`154-opentelemetry-tracing`?`active`:``,children:`15.4 OpenTelemetry Tracing`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#155-profiling-and-runtime-visualization`,className:e===`155-profiling-and-runtime-visualization`?`active`:``,children:`15.5 Profiling and Runtime Visualization`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#156-logging`,className:e===`156-logging`?`active`:``,children:`15.6 Logging`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#chapter-16-mcp-service`,className:`doc-index-header ${e===`chapter-16-mcp-service`?`active`:``}`,children:`Chapter 16: MCP Service`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#161-architecture-and-security`,className:e===`161-architecture-and-security`?`active`:``,children:`16.1 Architecture and Security`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#162-prerequisites`,className:e===`162-prerequisites`?`active`:``,children:`16.2 Prerequisites`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#163-configuration`,className:e===`163-configuration`?`active`:``,children:`16.3 Configuration`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#164-available-tools`,className:e===`164-available-tools`?`active`:``,children:`16.4 Available Tools`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#165-client-configuration`,className:e===`165-client-configuration`?`active`:``,children:`16.5 Client Configuration`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#166-testing-with-curl`,className:e===`166-testing-with-curl`?`active`:``,children:`16.6 Testing with curl`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#chapter-17-troubleshooting`,className:`doc-index-header ${e===`chapter-17-troubleshooting`?`active`:``}`,children:`Chapter 17: Troubleshooting`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#171-start-with-diagnostics`,className:e===`171-start-with-diagnostics`?`active`:``,children:`17.1 Start with Diagnostics`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#172-libraries-and-devices`,className:e===`172-libraries-and-devices`?`active`:``,children:`17.2 Libraries and Devices`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#173-models-catalog-and-storage`,className:e===`173-models-catalog-and-storage`?`active`:``,children:`17.3 Models, Catalog, and Storage`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#174-memory-and-performance`,className:e===`174-memory-and-performance`?`active`:``,children:`17.4 Memory and Performance`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#175-requests-and-streaming`,className:e===`175-requests-and-streaming`?`active`:``,children:`17.5 Requests and Streaming`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#176-authentication`,className:e===`176-authentication`?`active`:``,children:`17.6 Authentication`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#177-imc`,className:e===`177-imc`?`active`:``,children:`17.7 IMC`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#178-mcp`,className:e===`178-mcp`?`active`:``,children:`17.8 MCP`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#179-ports-processes-and-permissions`,className:e===`179-ports-processes-and-permissions`?`active`:``,children:`17.9 Ports, Processes, and Permissions`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#1710-reporting-a-problem`,className:e===`1710-reporting-a-problem`?`active`:``,children:`17.10 Reporting a Problem`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#chapter-18-bucky-audio-transcription`,className:`doc-index-header ${e===`chapter-18-bucky-audio-transcription`?`active`:``}`,children:`Chapter 18: Bucky (Audio Transcription)`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#181-overview`,className:e===`181-overview`?`active`:``,children:`18.1 Overview`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#182-install-whisper-libraries`,className:e===`182-install-whisper-libraries`?`active`:``,children:`18.2 Install Whisper Libraries`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#183-manage-models`,className:e===`183-manage-models`?`active`:``,children:`18.3 Manage Models`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#184-server-configuration`,className:e===`184-server-configuration`?`active`:``,children:`18.4 Server Configuration`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#185-browser-ui`,className:e===`185-browser-ui`?`active`:``,children:`18.5 Browser UI`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#186-transcriptions-and-translations-api`,className:e===`186-transcriptions-and-translations-api`?`active`:``,children:`18.6 Transcriptions and Translations API`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#187-go-sdk`,className:e===`187-go-sdk`?`active`:``,children:`18.7 Go SDK`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#188-languages`,className:e===`188-languages`?`active`:``,children:`18.8 Languages`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#189-troubleshooting`,className:e===`189-troubleshooting`?`active`:``,children:`18.9 Troubleshooting`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#chapter-19-malina-image-generation`,className:`doc-index-header ${e===`chapter-19-malina-image-generation`?`active`:``}`,children:`Chapter 19: Malina (Image Generation)`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#191-overview`,className:e===`191-overview`?`active`:``,children:`19.1 Overview`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#192-install-stable-diffusion-libraries`,className:e===`192-install-stable-diffusion-libraries`?`active`:``,children:`19.2 Install Stable Diffusion Libraries`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#193-manage-model-bundles`,className:e===`193-manage-model-bundles`?`active`:``,children:`19.3 Manage Model Bundles`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#194-go-sdk`,className:e===`194-go-sdk`?`active`:``,children:`19.4 Go SDK`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#195-multi-file-model-bundles`,className:e===`195-multi-file-model-bundles`?`active`:``,children:`19.5 Multi-File Model Bundles`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#196-image-to-image-generation`,className:e===`196-image-to-image-generation`?`active`:``,children:`19.6 Image-to-Image Generation`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#197-logging-progress-and-diagnostics`,className:e===`197-logging-progress-and-diagnostics`?`active`:``,children:`19.7 Logging, Progress, and Diagnostics`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#198-motion-jpeg-encoding`,className:e===`198-motion-jpeg-encoding`?`active`:``,children:`19.8 Motion-JPEG Encoding`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#199-examples`,className:e===`199-examples`?`active`:``,children:`19.9 Examples`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#1910-current-scope-and-limitations`,className:e===`1910-current-scope-and-limitations`?`active`:``,children:`19.10 Current Scope and Limitations`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#1911-troubleshooting`,className:e===`1911-troubleshooting`?`active`:``,children:`19.11 Troubleshooting`})})]})]}),(0,G.jsxs)(`div`,{className:`doc-index-section`,children:[(0,G.jsx)(`a`,{href:`#chapter-20-developer-guide`,className:`doc-index-header ${e===`chapter-20-developer-guide`?`active`:``}`,children:`Chapter 20: Developer Guide`}),(0,G.jsxs)(`ul`,{children:[(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#201-how-to-use-this-guide`,className:e===`201-how-to-use-this-guide`?`active`:``,children:`20.1 How to Use This Guide`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#202-task-to-owner-and-verification-map`,className:e===`202-task-to-owner-and-verification-map`?`active`:``,children:`20.2 Task-to-Owner and Verification Map`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#203-repository-ownership-map`,className:e===`203-repository-ownership-map`?`active`:``,children:`20.3 Repository Ownership Map`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#204-developer-setup-and-daily-commands`,className:e===`204-developer-setup-and-daily-commands`?`active`:``,children:`20.4 Developer Setup and Daily Commands`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#205-request-and-model-lifecycle`,className:e===`205-request-and-model-lifecycle`?`active`:``,children:`20.5 Request and Model Lifecycle`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#206-core-inference-invariants`,className:e===`206-core-inference-invariants`?`active`:``,children:`20.6 Core Inference Invariants`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#207-server-bui-and-generated-documentation`,className:e===`207-server-bui-and-generated-documentation`?`active`:``,children:`20.7 Server, BUI, and Generated Documentation`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#208-bucky-implementation-map`,className:e===`208-bucky-implementation-map`?`active`:``,children:`20.8 Bucky Implementation Map`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#209-verification-for-llm-agents`,className:e===`209-verification-for-llm-agents`?`active`:``,children:`20.9 Verification for LLM Agents`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#2010-ci-release-containers-and-nix`,className:e===`2010-ci-release-containers-and-nix`?`active`:``,children:`20.10 CI, Release, Containers, and Nix`})}),(0,G.jsx)(`li`,{children:(0,G.jsx)(`a`,{href:`#2011-change-and-release-checklists`,className:e===`2011-change-and-release-checklists`?`active`:``,children:`20.11 Change and Release Checklists`})})]})]})]})})]})]})}function Xy(e,t,n){let r=e.trim(),i=t.trim();if(es(n)){let e=n.lastIndexOf(`/`),t=e>=0?n.slice(0,e):``;return t?`https://huggingface.co/${r}/${i}/tree/main/${t}`:`https://huggingface.co/${r}/${i}/tree/main`}return`https://huggingface.co/${r}/${i}/resolve/main/${n}`}function Zy(){let[e,t]=(0,x.useState)(``),[n,r]=(0,x.useState)(``),[i,a]=(0,x.useState)(``),[o,s]=(0,x.useState)(null),[c,l]=(0,x.useState)(null),[u,d]=(0,x.useState)(!1),[f,p]=(0,x.useState)(!1),[m,h]=(0,x.useState)(null),[g,_]=(0,x.useState)(``),[v,y]=(0,x.useState)(``),[b,S]=(0,x.useState)(``),C=(0,x.useRef)(``),{controlsProps:w,resultsProps:T}=Qa({serverResponse:m,enableHardwareOverrides:!0,modelId:v||void 0,modelUrl:b||void 0}),E=e.trim().length>0&&n.trim().length>0,D=(0,x.useCallback)(async t=>{if(u||f)return;let r=e.trim(),o=n.trim(),c=Wo((t??i).trim());if(!r||!o){l(`Provider and Family are required`);return}if(l(null),h(null),s(null),C.current=``,!c){d(!0);try{let e=await W.lookupHuggingFace(`${r}/${o}`);s(e.repo_files??[])}catch(e){l(e instanceof Error?e.message:String(e))}finally{d(!1)}return}if(qo(c)){d(!0);try{let e=((await W.lookupHuggingFace(`${r}/${o}`)).repo_files??[]).filter(e=>!Jo(e.filename)&&Xo(e.filename,c));if(e.length===0){l(`No GGUF file matching quant "${c}" found in ${r}/${o}`);return}if(new Set(e.map(e=>Go(e.filename))).size>1){s(e);return}let t=e[0];a(Go(t.filename)),await O(t.filename)}catch(e){l(e instanceof Error?e.message:String(e))}finally{d(!1)}return}p(!0);let m=`${r}/${c}`;try{let e=await W.calculateVRAM({model_id:m,context_window:w.contextWindow,bytes_per_element:w.bytesPerElement,slots:w.slots,expert_layers_on_gpu:Ca});h(e),_(m),y(m),S(``),p(!1);return}catch(e){let t=e instanceof Error?e.message:``;if(!/not found|no such model|404/i.test(t)){l(t),p(!1);return}}finally{p(!1)}await O(`${c}.gguf`)},[u,f,e,n,i,w]),O=(0,x.useCallback)(async t=>{let r=e.trim(),i=n.trim();if(!r||!i){l(`Provider and Family are required`);return}let a=Xy(r,i,t),o=`${r}/${i}/${t}`,s=[a,w.contextWindow,w.bytesPerElement,w.slots,w.gpuLayers,w.expertLayersOnGPU,w.kvCacheOnCPU,w.swaFull,w.deviceCount,w.tensorSplit].join(`|`);if(!(s===C.current&&m)){p(!0),l(null);try{let e=await W.calculateVRAM({model_url:a,context_window:w.contextWindow,bytes_per_element:w.bytesPerElement,slots:w.slots,expert_layers_on_gpu:Ca});h(e),_(o),y(``),S(a),C.current=s}catch(e){l(e instanceof Error?e.message:`Failed to calculate VRAM`),C.current=``}finally{p(!1)}}},[e,n,w,m]),k=e=>{a(Go(e)),s(null),O(e)},A=e=>{let n=Zo(e.clipboardData.getData(`text`));n&&(e.preventDefault(),t(n.provider),r(n.family),a(n.model))},j=e=>{e.key===`Enter`&&E&&(e.preventDefault(),D())};return(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{className:`page-header-with-action`,children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`h2`,{children:`VRAM Calculator`}),(0,G.jsx)(`p`,{className:`page-description`,children:`Calculate VRAM requirements for a model from HuggingFace. Only the model header is fetched, not the entire file.`})]}),(0,G.jsx)(`a`,{href:`https://www.kronkai.com/blog/understanding-the-kronk-vram-calculator`,target:`_blank`,rel:`noopener noreferrer`,className:`btn btn-secondary`,children:`Learn More`})]}),(0,G.jsxs)(`div`,{className:`page-header`,children:[(0,G.jsx)(`p`,{children:`Identify the model with three fields. Each one maps to a segment of the HuggingFace file URL:`}),(0,G.jsxs)(`pre`,{style:{fontSize:`14px`,lineHeight:`1.4`,padding:`12px 14px`,background:`var(--bg-2, #1a1a1a)`,border:`1px solid var(--border, #333)`,borderRadius:`4px`,margin:`8px 0`,overflowX:`auto`,fontFamily:`ui-monospace, SFMono-Regular, Menlo, monospace`,color:`var(--text, #e5e5e5)`},children:[(0,G.jsx)(`span`,{style:{opacity:.85},children:`https://huggingface.co/`}),(0,G.jsx)(`span`,{style:{color:`var(--accent, #60a5fa)`,fontWeight:600},children:`unsloth`}),(0,G.jsx)(`span`,{style:{opacity:.85},children:`/`}),(0,G.jsx)(`span`,{style:{color:`var(--success, #4ade80)`,fontWeight:600},children:`Qwen3.6-27B-GGUF`}),(0,G.jsx)(`span`,{style:{opacity:.85},children:`/blob/main/`}),(0,G.jsx)(`span`,{style:{color:`var(--warning, #fbbf24)`,fontWeight:600},children:`Qwen3.6-27B-Q4_K_M`}),(0,G.jsx)(`span`,{style:{opacity:.85},children:`.gguf`}),`
`,` `,(0,G.jsx)(`span`,{style:{color:`var(--accent, #60a5fa)`},children:`└─────┘`}),` `,(0,G.jsx)(`span`,{style:{color:`var(--success, #4ade80)`},children:`└──────────────┘`}),` `,(0,G.jsx)(`span`,{style:{color:`var(--warning, #fbbf24)`},children:`└────────────────┘`}),`
-`,` `,(0,G.jsx)(`span`,{style:{color:`var(--accent, #60a5fa)`,fontWeight:600},children:`Provider`}),` `,(0,G.jsx)(`span`,{style:{color:`var(--success, #4ade80)`,fontWeight:600},children:`Family`}),` `,(0,G.jsx)(`span`,{style:{color:`var(--warning, #fbbf24)`,fontWeight:600},children:`Model`})]}),(0,G.jsxs)(`ul`,{style:{margin:`4px 0 0 0`,paddingLeft:`20px`,fontSize:`13px`},children:[(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`strong`,{children:`Model is optional.`}),` Leave it blank and click `,(0,G.jsx)(`em`,{children:`Browse files`}),` to see every GGUF in the repo and pick one.`]}),(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`strong`,{children:`Quant shortcut.`}),` The Model field also accepts just a quant tag (e.g. `,(0,G.jsx)(`code`,{children:`Q4_K_M`}),`, `,(0,G.jsx)(`code`,{children:`Q8_0`}),`, `,(0,G.jsx)(`code`,{children:`BF16`}),`) — we'll find the matching file in the repo for you.`]}),(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`strong`,{children:`Local models.`}),` When the full basename is filled and the model is already installed, the calculator uses the on-disk file and skips HuggingFace.`]}),(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`strong`,{children:`Paste anything.`}),` Pasting a full HuggingFace URL or`,` `,(0,G.jsx)(`code`,{children:`owner/repo[/file.gguf]`}),` shorthand into the Provider field auto-splits it across all three fields.`]})]})]}),(0,G.jsxs)(`div`,{className:`card`,children:[(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsxs)(`label`,{htmlFor:`provider`,children:[`Provider `,(0,G.jsx)(`span`,{style:{opacity:.6},children:`(required)`})]}),(0,G.jsx)(`input`,{type:`text`,id:`provider`,value:e,onChange:e=>t(e.target.value),onPaste:A,onKeyDown:j,placeholder:`unsloth`,disabled:u||f})]}),(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsxs)(`label`,{htmlFor:`family`,children:[`Family `,(0,G.jsx)(`span`,{style:{opacity:.6},children:`(required)`})]}),(0,G.jsx)(`input`,{type:`text`,id:`family`,value:n,onChange:e=>r(e.target.value),onKeyDown:j,placeholder:`Qwen3-0.6B-GGUF`,disabled:u||f})]}),(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsxs)(`label`,{htmlFor:`model`,children:[`Model `,(0,G.jsx)(`span`,{style:{opacity:.6},children:`(optional — full basename, just a quant tag, or blank)`})]}),(0,G.jsx)(`input`,{type:`text`,id:`model`,value:i,onChange:e=>a(e.target.value),onKeyDown:j,placeholder:`Qwen3-0.6B-Q8_0 · Q4_K_M · (blank)`,disabled:u||f})]}),(0,G.jsxs)(`div`,{style:{display:`flex`,gap:`8px`},children:[(0,G.jsx)(`button`,{type:`button`,className:`btn btn-primary`,onClick:()=>{D()},disabled:u||f||!E,children:u?`Looking up…`:f?`Calculating…`:i.trim()?`Calculate VRAM`:`Browse files`}),(o||m||c)&&!f&&!u&&(0,G.jsx)(`button`,{type:`button`,className:`btn`,onClick:()=>{s(null),l(null),h(null),_(``),y(``),S(``),C.current=``},disabled:u,children:`Clear`})]}),c&&(0,G.jsx)(`div`,{className:`status-box`,children:(0,G.jsx)(`div`,{className:`status-line error`,children:c})}),o&&(()=>{let t=$o(o);return(0,G.jsxs)(`div`,{className:`card`,style:{background:`var(--bg-2, #1a1a1a)`,marginTop:`12px`},children:[(0,G.jsxs)(`div`,{style:{marginBottom:`12px`},children:[(0,G.jsx)(`strong`,{children:`Pick a file from `}),(0,G.jsxs)(`code`,{children:[e.trim(),`/`,n.trim()]}),(0,G.jsxs)(`span`,{style:{fontSize:`12px`,opacity:.7,marginLeft:`8px`},children:[`(`,t.length,` GGUF model`,t.length===1?``:`s`,`)`]})]}),t.length===0?(0,G.jsx)(`div`,{style:{opacity:.7},children:`No GGUF files found in this repository.`}):(0,G.jsxs)(`table`,{className:`kv-table`,children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{style:{textAlign:`left`},children:`Filename`}),(0,G.jsx)(`th`,{children:`Size`}),(0,G.jsx)(`th`,{})]})}),(0,G.jsx)(`tbody`,{children:t.map(e=>(0,G.jsxs)(`tr`,{children:[(0,G.jsxs)(`td`,{children:[(0,G.jsx)(`code`,{style:{wordBreak:`break-all`},children:e.label}),e.parts>1&&(0,G.jsxs)(`span`,{style:{fontSize:`11px`,opacity:.7,marginLeft:`8px`},children:[`(`,e.parts,` shards)`]})]}),(0,G.jsx)(`td`,{style:{whiteSpace:`nowrap`},children:e.sizeStr}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:()=>k(e.filename),disabled:u||f,children:`Select`})})]},e.label))})]})]})})(),(0,G.jsx)(`div`,{style:{marginTop:`16px`},children:(0,G.jsx)(Ha,{controlsProps:w,resultsProps:T,variant:`form`,hideResults:!0})})]}),(f||u)&&(0,G.jsxs)(`div`,{className:`vram-loading-banner`,children:[(0,G.jsx)(`span`,{className:`vram-loading-spinner`}),(0,G.jsx)(`span`,{children:u?`Looking up repository…`:`Fetching model header (up to 16 MB)…`})]}),T&&(0,G.jsx)(Ha,{controlsProps:w,resultsProps:T,hideControls:!0,modelUrl:g})]})}var Qy=[{kind:`sampling`,label:`Sampling Sweep`},{kind:`config`,label:`Config Sweep`}];function $y(e){if(!Number.isFinite(e))return`—`;let t=Math.max(0,Math.round(e));if(t<1e3)return`${t}ms`;let n=Math.floor(t/36e5),r=Math.floor(t%36e5/6e4),i=Math.floor(t%6e4/1e3),a=t%1e3;return n>0?`${n}h ${r}m ${i}s ${a}ms`:r>0?`${r}m ${i}s ${a}ms`:`${i}s ${a}ms`}function eb(e){return e>=80?`#2e7d32`:e>=50?`#f9a825`:`#c62828`}function tb(e){return eb(e??0)}function nb(e){return e!==void 0&&Number.isFinite(e)?e.toFixed(1):`—`}function rb(e,t){return e.scenarioResults.find(e=>e.scenarioId===t)?.score}function ib(e){return e.scenarioResults.find(e=>e.avgTPS!==void 0)?.avgTPS}function ab(e){return e.scenarioResults.find(e=>e.avgTTFT!==void 0)?.avgTTFT}function ob(e,t){return e.scenarioResults.find(e=>e.avgTPSByFill?.[t]!==void 0)?.avgTPSByFill?.[t]}function sb(e,t){return e.scenarioResults.find(e=>e.avgTTFTByFill?.[t]!==void 0)?.avgTTFTByFill?.[t]}function cb(e){let t=e.startedAt?Date.parse(e.startedAt):NaN;if(Number.isFinite(t))return(e.finishedAt?Date.parse(e.finishedAt):Date.now())-t}function lb(e,t,n,r){return n?r?`Error: ${r}`:`Error`:e.status===`failed`?`Failed`:t.isInProgress?`Running…`:e.status===`skipped`?`Skipped`:e.status===`queued`?`Queued`:t.isPending?`…`:`OK`}function ub(e,t,n){return n||e.status===`failed`?{color:`#c62828`,fontSize:`0.85em`}:t.isInProgress?{color:`#1565c0`}:e.status===`skipped`?{color:`#9e9e9e`,fontStyle:`italic`,fontSize:`0.85em`}:e.status===`queued`?{color:`#999`}:t.isPending?{color:`#666`}:{color:`#2e7d32`}}var db=[`0%`,`20%`,`50%`,`80%`];function fb(){let e=db.map(e=>({id:`tps_${e.replace(`%`,``)}`,title:`TPS @${e}`,sortable:!0,getValue:t=>t.avgTPSByFill?.[e]??ob(t,e),renderCell:(t,n)=>n.isPending?`…`:t.avgTPSByFill?.[e]?.toFixed(1)??`—`})),t=db.map(e=>({id:`ttft_${e.replace(`%`,``)}`,title:`TTFT @${e}`,sortable:!0,getValue:t=>t.avgTTFTByFill?.[e]??sb(t,e),renderCell:(t,n)=>n.isPending?`…`:t.avgTTFTByFill?.[e]===void 0?`—`:$y(t.avgTTFTByFill[e])}));return[{id:`avg_tps`,title:`Avg TPS`,sortable:!0,getValue:e=>e.avgTPS??ib(e),renderCell:(e,t)=>{if(t.isPending){let t=ib(e);return t===void 0?`…`:`~${t.toFixed(1)}`}return e.avgTPS?.toFixed(1)??`—`}},{id:`avg_ttft`,title:`Avg TTFT`,sortable:!0,getValue:e=>e.avgTTFT??ab(e),renderCell:(e,t)=>t.isPending?`…`:e.avgTTFT===void 0?`—`:$y(e.avgTTFT)},...e,...t]}function pb(){return{id:`status`,title:`Status`,sortable:!0,getValue:e=>e.status,renderCell:(e,t)=>(0,G.jsx)(`span`,{style:ub(e,t,e.status===`failed`),children:lb(e,t,e.status===`failed`)})}}function mb(){return{id:`status`,title:`Status`,sortable:!0,getValue:e=>e.error?`error`:e.status,renderCell:(e,t)=>(0,G.jsx)(`span`,{style:ub(e,t,!!e.error),children:lb(e,t,!!e.error,e.error)})}}function hb(){return{id:`duration`,title:`Duration`,sortable:!0,getValue:e=>cb(e),renderCell:e=>{let t=cb(e);return t===void 0?`—`:$y(t)}}}function gb(){return[{id:`temperature`,title:`Temperature`,sortable:!0,getValue:e=>e.candidate.temperature,renderCell:e=>e.candidate.temperature??`—`},{id:`top_p`,title:`Top P`,sortable:!0,getValue:e=>e.candidate.top_p,renderCell:e=>e.candidate.top_p??`—`},{id:`top_k`,title:`Top K`,sortable:!0,getValue:e=>e.candidate.top_k,renderCell:e=>e.candidate.top_k??`—`},{id:`min_p`,title:`Min P`,sortable:!0,getValue:e=>e.candidate.min_p,renderCell:e=>e.candidate.min_p??`—`}]}function _b(){return[{id:`chat_score`,title:`Chat Score`,sortable:!0,getValue:e=>rb(e,`chat`),renderCell:(e,t)=>{let n=t.isInProgress?rb(e,`chat`):void 0;if(t.isPending)return n===void 0?`…`:(0,G.jsxs)(`span`,{style:{color:eb(n),opacity:.7},children:[`~`,n.toFixed(1)]});let r=rb(e,`chat`);return(0,G.jsx)(`span`,{style:{color:eb(r??0)},children:r?.toFixed(1)??`—`})}},{id:`tool_score`,title:`Tool Score`,sortable:!0,getValue:e=>rb(e,`tool_call`),renderCell:(e,t)=>{let n=t.isInProgress?rb(e,`tool_call`):void 0;if(t.isPending)return n===void 0?`…`:(0,G.jsxs)(`span`,{style:{color:eb(n),opacity:.7},children:[`~`,n.toFixed(1)]});let r=rb(e,`tool_call`);return(0,G.jsx)(`span`,{style:{color:eb(r??0)},children:r?.toFixed(1)??`—`})}},{id:`total_score`,title:`Total Score`,sortable:!0,getValue:e=>e.totalScore,renderCell:(e,t)=>t.isPending?`…`:(0,G.jsx)(`span`,{style:{color:eb(e.totalScore??0)},children:e.totalScore?.toFixed(1)??`—`})}]}function vb(){return[{id:`context_window`,title:`Context Window`,sortable:!0,getValue:e=>e.config?.context_window,renderCell:e=>e.config?.context_window??`—`},{id:`prefill_batch_size`,title:`Prefill Batch Size`,sortable:!0,getValue:e=>e.config?.prefill_batch_size,renderCell:e=>e.config?.prefill_batch_size??`—`},{id:`nseq_max`,title:`NSeqMax`,sortable:!0,getValue:e=>e.config?.nseq_max,renderCell:e=>e.config?.nseq_max??`—`},{id:`flash_attention`,title:`Flash Attn`,sortable:!0,getValue:e=>e.config?.flash_attention,renderCell:e=>e.config?.flash_attention??`—`},{id:`cache_type`,title:`KV Cache`,sortable:!0,getValue:e=>e.config?.cache_type,renderCell:e=>e.config?.cache_type??`—`},{id:`cache_mode`,title:`Cache`,sortable:!0,getValue:e=>e.config?.cache_mode,renderCell:e=>{let t=e.config?.cache_mode;return t?t===`none`?`None`:t.toUpperCase():`—`}},{id:`moe_mode`,title:`MoE Mode`,sortable:!0,getValue:e=>e.config?.moe_mode,renderCell:e=>{let t=e.config?.moe_mode;return t?t===`experts_cpu`?`CPU`:t===`keep_top_n`?`Balanced`:t===`experts_gpu`?`GPU`:t:`—`}},{id:`moe_keep_experts_top_n`,title:`Expert Layers GPU`,sortable:!0,getValue:e=>e.config?.moe_keep_experts_top_n,renderCell:e=>e.config?.moe_keep_experts_top_n??`—`},{id:`est_vram`,title:`Est. VRAM`,sortable:!0,getValue:e=>e.estimatedVRAM,renderCell:e=>e.estimatedVRAM===void 0?`—`:J(e.estimatedVRAM)}]}function yb(){return[...gb(),pb(),hb(),..._b(),...fb()]}function bb(){return[...vb(),mb(),hb(),...fb()]}var xb={temperature:{validMin:0,validMax:2,defaultStep:.1},top_p:{validMin:0,validMax:1,defaultStep:.1},top_k:{validMin:0,validMax:200,defaultStep:10},min_p:{validMin:0,validMax:1,defaultStep:.05},repeat_penalty:{validMin:0,validMax:3,defaultStep:.1},repeat_last_n:{validMin:0,validMax:2048,defaultStep:64},frequency_penalty:{validMin:-2,validMax:2,defaultStep:.1},presence_penalty:{validMin:-2,validMax:2,defaultStep:.1},dry_multiplier:{validMin:0,validMax:5,defaultStep:.1},dry_base:{validMin:1,validMax:3,defaultStep:.25},dry_allowed_length:{validMin:0,validMax:100,defaultStep:1},dry_penalty_last_n:{validMin:0,validMax:2048,defaultStep:64},xtc_probability:{validMin:0,validMax:1,defaultStep:.1},xtc_threshold:{validMin:0,validMax:1,defaultStep:.1},xtc_min_keep:{validMin:1,validMax:100,defaultStep:1},max_tokens:{validMin:1,validMax:131072,defaultStep:512}};function Sb({title:e,entries:t,sweepInputs:n,setSweepInputs:r,commitTriple:i,catalogSampling:a,isRunning:o}){return(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`div`,{className:`playground-sweep-group-title`,children:e}),t.map(([e,t])=>{let s=xb[e],c=n[e];return(0,G.jsxs)(`div`,{className:`playground-sweep-param`,children:[(0,G.jsx)(X,{className:`playground-sweep-param-toggle`,tooltipKey:e,after:a&&a[e]!==void 0&&(0,G.jsxs)(`span`,{className:`sweep-catalog-hint`,title:`Default catalog value`,children:[`(default: `,a[e],`)`]}),children:t}),(0,G.jsxs)(`div`,{className:`playground-sweep-param-range`,children:[(0,G.jsxs)(`div`,{className:`playground-sweep-param-range-field`,children:[(0,G.jsxs)(`span`,{className:`playground-sweep-param-range-label`,children:[`Min (`,s.validMin,`)`]}),(0,G.jsx)(`input`,{type:`number`,value:c.min,min:s.validMin,max:s.validMax,step:s.defaultStep,onChange:t=>r(n=>({...n,[e]:{...n[e],min:t.target.value}})),onBlur:()=>i(e),onKeyDown:e=>e.key===`Enter`&&e.currentTarget.blur(),disabled:o})]}),(0,G.jsxs)(`div`,{className:`playground-sweep-param-range-field`,children:[(0,G.jsxs)(`span`,{className:`playground-sweep-param-range-label`,children:[`Max (`,s.validMax,`)`]}),(0,G.jsx)(`input`,{type:`number`,value:c.max,min:s.validMin,max:s.validMax,step:s.defaultStep,onChange:t=>r(n=>({...n,[e]:{...n[e],max:t.target.value}})),onBlur:()=>i(e),onKeyDown:e=>e.key===`Enter`&&e.currentTarget.blur(),disabled:o})]}),(0,G.jsxs)(`div`,{className:`playground-sweep-param-range-field`,children:[(0,G.jsxs)(`span`,{className:`playground-sweep-param-range-label`,children:[`Step (`,s.defaultStep,`)`]}),(0,G.jsx)(`input`,{type:`number`,value:c.step,min:0,step:s.defaultStep,onChange:t=>r(n=>({...n,[e]:{...n[e],step:t.target.value}})),onBlur:()=>i(e),onKeyDown:e=>e.key===`Enter`&&e.currentTarget.blur(),disabled:o})]})]})]},e)})]})}function Cb({sweepInputs:e,setSweepInputs:t,commitTriple:n,catalogSampling:r,isRunning:i,trialCount:a}){return(0,G.jsxs)(`div`,{className:`playground-autotest-section`,children:[(0,G.jsx)(`h4`,{children:`Sampling Sweep Parameters`}),(0,G.jsx)(`p`,{style:{fontSize:12,color:`var(--color-gray-600)`,marginBottom:8},children:`Set min, max, and step values to define the sweep range. Set min = max for no sweep.`}),(0,G.jsx)(`div`,{className:`playground-sweep-params`,children:(0,G.jsx)(Sb,{title:`Generation`,entries:[[`temperature`,`Temperature`],[`top_p`,`Top P`],[`top_k`,`Top K`]],sweepInputs:e,setSweepInputs:t,commitTriple:n,catalogSampling:r,isRunning:i})}),(0,G.jsxs)(`p`,{style:{fontSize:12,color:`var(--color-gray-600)`,marginTop:8},children:[`Trials: `,a]})]})}function wb({configSweepDef:e,setConfigSweepDef:t,rawPrefillBatchSize:n,setRawPrefillBatchSize:r,rawContextWindow:i,setRawContextWindow:a,rawNSeqMax:o,setRawNSeqMax:s,rawMoeKeepExpertsTopN:c,setRawMoeKeepExpertsTopN:l,rawOpOffloadMinBatch:u,setRawOpOffloadMinBatch:d,commitNumericSweep:f,isMoE:p,isRunning:m,trialCount:h}){return(0,G.jsxs)(`div`,{className:`playground-autotest-section`,children:[(0,G.jsx)(`p`,{style:{fontSize:12,color:`var(--color-warning-text)`,marginBottom:8},children:`⚠ Each candidate reloads the model. This is slower than sampling sweeps.`}),(0,G.jsxs)(`div`,{className:`playground-sweep-params`,children:[(0,G.jsxs)(`div`,{className:`playground-sweep-param`,children:[(0,G.jsx)(X,{className:`playground-sweep-param-toggle`,tooltipKey:`prefillBatchSize`,children:`Prefill Batch Size`}),(0,G.jsx)(`input`,{type:`text`,className:`playground-sweep-param-values`,value:n,onChange:e=>r(e.target.value),onBlur:()=>f(n,`prefillBatchSize`,r),onKeyDown:e=>e.key===`Enter`&&e.currentTarget.blur(),placeholder:`512, 1024, 2048, 4096`,disabled:m})]}),(0,G.jsxs)(`div`,{className:`playground-sweep-param`,children:[(0,G.jsx)(X,{className:`playground-sweep-param-toggle`,tooltipKey:`contextWindow`,children:`Context Window`}),(0,G.jsx)(`input`,{type:`text`,className:`playground-sweep-param-values`,value:i,onChange:e=>a(e.target.value),onBlur:()=>f(i,`contextWindow`,a),onKeyDown:e=>e.key===`Enter`&&e.currentTarget.blur(),placeholder:`2048, 4096, 8192, 16384, 32768`,disabled:m})]}),(0,G.jsxs)(`div`,{className:`playground-sweep-param`,children:[(0,G.jsx)(X,{className:`playground-sweep-param-toggle`,tooltipKey:`nSeqMax`,children:`NSeqMax`}),(0,G.jsx)(`input`,{type:`text`,className:`playground-sweep-param-values`,value:o,onChange:e=>s(e.target.value),onBlur:()=>f(o,`nSeqMax`,s),onKeyDown:e=>e.key===`Enter`&&e.currentTarget.blur(),placeholder:`1, 2, 4, 8`,disabled:m})]}),(0,G.jsxs)(`div`,{className:`playground-sweep-param`,children:[(0,G.jsx)(X,{className:`playground-sweep-param-toggle`,tooltipKey:`flashAttention`,children:`Flash Attention`}),(0,G.jsx)(`div`,{className:`playground-sweep-option-checks`,children:[`enabled`,`disabled`].map(n=>(0,G.jsxs)(`label`,{className:`playground-sweep-option-label`,children:[(0,G.jsx)(`input`,{type:`checkbox`,checked:e.flashAttention.values.includes(n),onChange:e=>{t(t=>{let r=t.flashAttention.values,i=e.target.checked?[...r,n]:r.filter(e=>e!==n);return{...t,flashAttention:{...t.flashAttention,values:i}}})},disabled:m}),n]},n))})]}),(0,G.jsxs)(`div`,{className:`playground-sweep-param`,children:[(0,G.jsx)(X,{className:`playground-sweep-param-toggle`,tooltipKey:`cacheType`,children:`Cache Type`}),(0,G.jsx)(`div`,{className:`playground-sweep-option-checks`,children:[`f16`,`q8_0`,`q4_0`].map(n=>(0,G.jsxs)(`label`,{className:`playground-sweep-option-label`,children:[(0,G.jsx)(`input`,{type:`checkbox`,checked:e.cacheType.values.includes(n),onChange:e=>{t(t=>{let r=t.cacheType.values,i=e.target.checked?[...r,n]:r.filter(e=>e!==n);return{...t,cacheType:{...t.cacheType,values:i}}})},disabled:m}),n]},n))})]}),(0,G.jsxs)(`div`,{className:`playground-sweep-param`,children:[(0,G.jsx)(X,{className:`playground-sweep-param-toggle`,tooltipKey:`cacheMode`,children:`Cache Mode`}),(0,G.jsx)(`div`,{className:`playground-sweep-option-checks`,children:[`none`,`imc`].map(n=>(0,G.jsxs)(`label`,{className:`playground-sweep-option-label`,children:[(0,G.jsx)(`input`,{type:`checkbox`,checked:e.cacheMode.values.includes(n),onChange:e=>{t(t=>{let r=t.cacheMode.values,i=e.target.checked?[...r,n]:r.filter(e=>e!==n);return{...t,cacheMode:{...t.cacheMode,values:i}}})},disabled:m}),n===`none`?`None`:n.toUpperCase()]},n))})]})]}),p&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`h4`,{style:{marginTop:16},children:`MoE Parameters`}),(0,G.jsxs)(`div`,{className:`playground-sweep-params`,children:[(0,G.jsxs)(`div`,{className:`playground-sweep-param`,children:[(0,G.jsx)(X,{className:`playground-sweep-param-toggle`,tooltipKey:`moeMode`,children:`Expert Strategy`}),(0,G.jsx)(`div`,{className:`playground-sweep-option-checks`,children:[`experts_cpu`,`keep_top_n`,`experts_gpu`].map(n=>(0,G.jsxs)(`label`,{className:`playground-sweep-option-label`,children:[(0,G.jsx)(`input`,{type:`checkbox`,checked:e.moeMode?.values.includes(n)??!1,onChange:e=>{t(t=>{let r=t.moeMode?.values??[],i=e.target.checked?[...r,n]:r.filter(e=>e!==n);return{...t,moeMode:{enabled:i.length>0,values:i}}})},disabled:m}),to[n]??n]},n))})]}),(0,G.jsxs)(`div`,{className:`playground-sweep-param`,children:[(0,G.jsx)(X,{className:`playground-sweep-param-toggle`,tooltipKey:`moeKeepExpertsTopN`,children:`GPU Expert Layers`}),(0,G.jsx)(`input`,{type:`text`,className:`playground-sweep-param-values`,value:c,onChange:e=>l(e.target.value),onBlur:()=>f(c,`moeKeepExpertsTopN`,l),onKeyDown:e=>e.key===`Enter`&&e.currentTarget.blur(),placeholder:`0, 4, 8, 16`,disabled:m})]}),(0,G.jsxs)(`div`,{className:`playground-sweep-param`,children:[(0,G.jsx)(X,{className:`playground-sweep-param-toggle`,tooltipKey:`opOffloadMinBatch`,children:`Op Offload Min Batch`}),(0,G.jsx)(`input`,{type:`text`,className:`playground-sweep-param-values`,value:u,onChange:e=>d(e.target.value),onBlur:()=>f(u,`opOffloadMinBatch`,d),onKeyDown:e=>e.key===`Enter`&&e.currentTarget.blur(),placeholder:`0, 128, 256, 512`,disabled:m})]})]})]}),(0,G.jsxs)(`p`,{style:{fontSize:12,color:`var(--color-gray-600)`,marginTop:8},children:[`Trials: `,h]})]})}function Tb(e){return e===null?`asc`:e===`asc`?`desc`:null}function Eb(e,t){return t.column!==e||t.direction===null?``:t.direction===`asc`?` ▲`:` ▼`}function Db(e,t,n){if(!t.column||!t.direction)return e;let r=t.direction===`asc`?1:-1;return[...e].sort((e,i)=>{let a=n(e,t.column),o=n(i,t.column),s=a??void 0,c=o??void 0;return s===void 0&&c===void 0?0:s===void 0?1:c===void 0?-1:typeof s==`number`&&typeof c==`number`?(s-c)*r:String(s).localeCompare(String(c))*r})}function Ob(e){if(!e)return;let t=e.completion_tokens,n=e.tokens_per_second;if(!Number.isFinite(t)||!Number.isFinite(n)||n<=0)return;let r=e.time_to_first_token_ms??0,i=t/n*1e3+r;if(!(!Number.isFinite(i)||i<0))return i}function kb(e){return new Date(e).toLocaleTimeString([],{hour:`2-digit`,minute:`2-digit`,second:`2-digit`})}function Ab(e,t){let n=t[e.scenarioId]?.name??e.scenarioId,r=t[e.scenarioId]?.prompts?.length,i=`${n} · Prompt ${e.promptIndex+1}${r?`/${r}`:``}`;return e.repeats&&e.repeats>1&&e.repeatIndex!=null&&(i+=` · Repeat ${e.repeatIndex}/${e.repeats}`),i}function jb({trial:e,showScores:t}){return(0,G.jsxs)(G.Fragment,{children:[t&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Chat Score:`}),` `,nb(rb(e,`chat`))]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Tool Score:`}),` `,nb(rb(e,`tool_call`))]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Total Score:`}),` `,nb(e.totalScore)]})]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Avg TPS:`}),` `,e.avgTPS?.toFixed(1)??`—`]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Avg TTFT:`}),` `,e.avgTTFT===void 0?`—`:$y(e.avgTTFT)]}),e.avgTPSByFill&&db.map(t=>(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`strong`,{children:[`TPS @`,t,`:`]}),` `,e.avgTPSByFill[t]?.toFixed(1)??`—`]},`tps-${t}`)),e.avgTTFTByFill&&db.map(t=>(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`strong`,{children:[`TTFT @`,t,`:`]}),` `,e.avgTTFTByFill[t]===void 0?`—`:$y(e.avgTTFTByFill[t])]},`ttft-${t}`))]})}function Mb({sr:e,scenarioName:t,hideScores:n}){return(0,G.jsxs)(`div`,{className:`autotest-detail-scenario-header`,children:[(0,G.jsx)(`span`,{className:`autotest-detail-scenario-name`,children:t}),!n&&(0,G.jsxs)(`span`,{className:`autotest-detail-scenario-score`,style:{color:tb(e.score)},children:[`Score: `,nb(e.score)]}),e.avgTPS!==void 0&&(0,G.jsxs)(`span`,{children:[`TPS: `,e.avgTPS.toFixed(1)]}),e.avgTTFT!==void 0&&(0,G.jsxs)(`span`,{children:[`TTFT: `,$y(e.avgTTFT)]}),e.avgTPSByFill&&Object.keys(e.avgTPSByFill).length>0&&(0,G.jsxs)(`span`,{style:{marginLeft:8,opacity:.85},children:[`Context Fill TPS:`,db.map(t=>e.avgTPSByFill[t]===void 0?null:` @${t}: ${e.avgTPSByFill[t].toFixed(1)}`)]}),e.avgTTFTByFill&&Object.keys(e.avgTTFTByFill).length>0&&(0,G.jsxs)(`span`,{style:{marginLeft:8,opacity:.85},children:[`Context Fill TTFT:`,db.map(t=>e.avgTTFTByFill[t]===void 0?null:` @${t}: ${$y(e.avgTTFTByFill[t])}`)]})]})}function Nb({trial:e,scenarioLookup:t,hideScores:n}){let[r,i]=(0,x.useState)(()=>new Set),a=(0,x.useCallback)(e=>{i(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},[]),o=(0,x.useRef)(null),[s,c]=(0,x.useState)(!1),[l,u]=(0,x.useState)(!1),d=e.status===`running`&&e.activePrompts&&e.activePrompts.length>0,f=e.logEntries&&e.logEntries.length>0;return(0,x.useEffect)(()=>{let t=o.current;t&&s&&e.status===`running`&&t.scrollHeight-t.scrollTop-t.clientHeight<40&&(t.scrollTop=t.scrollHeight)},[e.logEntries?.length,e.status,s]),e.scenarioResults.length===0&&!d&&!f?(0,G.jsx)(`div`,{className:`autotest-detail-empty`,children:`No scenario results yet.`}):(0,G.jsxs)(`div`,{className:`autotest-detail-content`,children:[d&&(0,G.jsxs)(`div`,{className:`autotest-detail-active`,children:[(0,G.jsxs)(`div`,{className:`autotest-detail-active-header`,children:[(0,G.jsx)(`span`,{className:`playground-autotest-spinner-inline`}),` Currently Running`]}),e.activePrompts.map(e=>(0,G.jsxs)(`div`,{className:`autotest-detail-active-prompt`,children:[(0,G.jsx)(`span`,{className:`autotest-detail-active-scenario`,children:t[e.scenarioId]?.name??e.scenarioId}),(0,G.jsx)(`span`,{className:`autotest-detail-active-id`,children:e.promptId}),e.repeats&&e.repeats>1&&e.repeatIndex&&(0,G.jsxs)(`span`,{className:`autotest-detail-active-repeat`,children:[`Repeat `,e.repeatIndex,`/`,e.repeats]}),e.preview&&(0,G.jsx)(`div`,{className:`autotest-detail-active-preview`,children:e.preview})]},`${e.scenarioId}-${e.promptIndex}`))]}),f&&(0,G.jsxs)(`div`,{className:`autotest-detail-log`,children:[(0,G.jsxs)(`button`,{type:`button`,className:`autotest-detail-log-header`,"aria-expanded":s,onClick:e=>{e.stopPropagation(),c(e=>!e)},children:[e.status===`running`&&(0,G.jsx)(`span`,{className:`playground-autotest-spinner-inline`}),(0,G.jsxs)(`span`,{children:[s?`▾`:`▸`,` Activity Log`]})]}),(0,G.jsx)(`div`,{className:`autotest-detail-log-body`,ref:o,children:s?e.logEntries.map((e,t)=>(0,G.jsxs)(`div`,{className:`autotest-detail-log-entry`,children:[(0,G.jsx)(`span`,{className:`autotest-detail-log-time`,children:kb(e.timestamp)}),(0,G.jsx)(`span`,{className:`autotest-detail-log-msg`,children:e.message})]},t)):(()=>{let t=e.logEntries[e.logEntries.length-1];return(0,G.jsxs)(`div`,{className:`autotest-detail-log-entry`,children:[(0,G.jsx)(`span`,{className:`autotest-detail-log-time`,children:kb(t.timestamp)}),(0,G.jsx)(`span`,{className:`autotest-detail-log-msg`,children:t.message})]})})()})]}),(e.scenarioResults.length>0||e.status===`running`&&e.activePrompts&&e.activePrompts.length>0)&&(0,G.jsxs)(`div`,{className:`autotest-detail-scenarios-section`,children:[(0,G.jsx)(`button`,{type:`button`,className:`autotest-detail-log-header`,"aria-expanded":l,onClick:e=>{e.stopPropagation(),u(e=>!e)},children:(0,G.jsxs)(`span`,{children:[l?`▾`:`▸`,` Performance`]})}),l?(()=>{let i=new Set(e.scenarioResults.map(e=>e.scenarioId)),o={};if(e.status===`running`&&e.activePrompts)for(let t of e.activePrompts)o[t.scenarioId]||(o[t.scenarioId]=[]),o[t.scenarioId].push(t);let s=[...i];for(let e of Object.keys(o)){let t=e;i.has(t)||s.push(t)}return s.map(i=>{let s=e.scenarioResults.find(e=>e.scenarioId===i),c=t[i],l=o[i]??[];return!s&&l.length===0?null:(0,G.jsxs)(`div`,{className:`autotest-detail-scenario`,children:[s?(0,G.jsx)(Mb,{sr:s,scenarioName:c?.name??i,hideScores:n}):(0,G.jsx)(`div`,{className:`autotest-detail-scenario-header`,children:(0,G.jsx)(`span`,{className:`autotest-detail-scenario-name`,children:c?.name??i})}),l.length>0&&(0,G.jsxs)(`div`,{className:`autotest-detail-running-indicator autotest-detail-running-indicator--expanded`,children:[(0,G.jsx)(`span`,{className:`playground-autotest-spinner-inline`}),` `,`Running: `,Ab(l[0],t)]}),s&&(0,G.jsx)(`div`,{className:`autotest-detail-prompts`,children:s.promptResults.map(e=>{let t=`${s.scenarioId}:${e.promptId}`,i=r.has(t),o=e.promptId.startsWith(`ctxfill-`),l=c?.prompts.find(t=>t.id===e.promptId),u=l?.messages.filter(e=>e.role===`user`).pop(),d=o?`Context fill test (${e.promptId.replace(`ctxfill-`,``)}% fill) — ${e.usage?.prompt_tokens??`?`} prompt tokens`:typeof u?.content==`string`?u.content:u?.content?.map(e=>`text`in e?e.text:``).join(``)??``,f=o?`Performance metric only`:l?.expected?l.expected.type===`tool_call`?`Tool call`:l.expected.type===`no_tool_call`?`No tool call`+(l.expected.value?` (text: ${l.expected.value})`:``):l.expected.type===`exact`?`Exact: "${l.expected.value}"`:`Regex: ${l.expected.value}`:`—`,p=Ob(e.usage),m=p===void 0?`—`:$y(p);return(0,G.jsxs)(`div`,{className:`autotest-detail-prompt ${i?`expanded`:`collapsed`}`,children:[(0,G.jsxs)(`div`,{className:`autotest-detail-prompt-header autotest-detail-prompt-header--clickable`,role:`button`,tabIndex:0,"aria-expanded":i,onClick:()=>a(t),onKeyDown:e=>{(e.key===`Enter`||e.key===` `)&&(e.preventDefault(),a(t))},children:[(0,G.jsxs)(`div`,{className:`autotest-detail-prompt-summary`,children:[(0,G.jsx)(`span`,{className:`autotest-detail-prompt-toggle`,children:i?`▼`:`▶`}),(0,G.jsx)(`span`,{className:`autotest-detail-prompt-id`,children:o?`Context Fill @${e.promptId.replace(`ctxfill-`,``)}%`:e.promptId}),(0,G.jsxs)(`span`,{className:`autotest-detail-prompt-duration`,children:[`Duration: `,m]}),(0,G.jsxs)(`span`,{className:`autotest-detail-prompt-usage-inline`,children:[(0,G.jsxs)(`span`,{children:[`In: `,e.usage?.prompt_tokens??`—`]}),(0,G.jsxs)(`span`,{children:[`Out: `,e.usage?.completion_tokens??`—`]}),(0,G.jsxs)(`span`,{children:[`TPS: `,e.usage?.tokens_per_second===void 0?`—`:e.usage.tokens_per_second.toFixed(1)]})]})]}),!n&&(0,G.jsx)(`span`,{className:`autotest-detail-prompt-score`,style:{color:tb(e.score)},children:nb(e.score)})]}),i&&(0,G.jsxs)(`div`,{className:`autotest-detail-prompt-grid`,children:[(0,G.jsxs)(`div`,{className:`autotest-detail-field`,children:[(0,G.jsx)(`div`,{className:`autotest-detail-label`,children:`Input`}),(0,G.jsx)(`div`,{className:`autotest-detail-value`,children:d||`—`})]}),(0,G.jsxs)(`div`,{className:`autotest-detail-field`,children:[(0,G.jsx)(`div`,{className:`autotest-detail-label`,children:`Expected`}),(0,G.jsx)(`div`,{className:`autotest-detail-value`,children:f})]}),(0,G.jsxs)(`div`,{className:`autotest-detail-field`,children:[(0,G.jsx)(`div`,{className:`autotest-detail-label`,children:`Output`}),(0,G.jsx)(`div`,{className:`autotest-detail-value`,children:e.toolCalls.length>0?e.toolCalls.map((e,t)=>(0,G.jsx)(`div`,{className:`autotest-detail-toolcall`,children:(0,G.jsxs)(`code`,{children:[e.function.name,`(`,e.function.arguments,`)`]})},t)):e.assistantText||`(empty)`})]}),e.usage&&(0,G.jsxs)(`div`,{className:`autotest-detail-field`,children:[(0,G.jsx)(`div`,{className:`autotest-detail-label`,children:`Usage`}),(0,G.jsxs)(`div`,{className:`autotest-detail-value autotest-detail-usage`,children:[(0,G.jsxs)(`span`,{children:[`In: `,e.usage.prompt_tokens]}),(0,G.jsxs)(`span`,{children:[`Out: `,e.usage.completion_tokens]}),(0,G.jsxs)(`span`,{children:[`TPS: `,e.usage.tokens_per_second.toFixed(1)]}),e.usage.time_to_first_token_ms!==void 0&&(0,G.jsxs)(`span`,{children:[`TTFT: `,$y(e.usage.time_to_first_token_ms)]})]})]}),e.notes&&e.notes.length>0&&(0,G.jsxs)(`div`,{className:`autotest-detail-field`,children:[(0,G.jsx)(`div`,{className:`autotest-detail-label`,children:`Notes`}),(0,G.jsx)(`div`,{className:`autotest-detail-value autotest-detail-notes`,children:e.notes.map((e,t)=>(0,G.jsx)(`div`,{children:e},t))})]})]})]},e.promptId)})})]},i)})})():(0,G.jsxs)(`div`,{className:`autotest-detail-scenarios-summary`,children:[e.status===`running`&&e.activePrompts&&e.activePrompts.length>0&&(0,G.jsxs)(`div`,{className:`autotest-detail-running-indicator`,children:[(0,G.jsx)(`span`,{className:`playground-autotest-spinner-inline`}),` `,`Running: `,Ab(e.activePrompts[0],t)]}),e.scenarioResults.map(e=>(0,G.jsx)(Mb,{sr:e,scenarioName:t[e.scenarioId]?.name??e.scenarioId,hideScores:n},e.scenarioId))]})]})]})}function Pb(e,t,n){return Math.min(n,Math.max(t,e))}function Fb(e,t){let n=xb[e],r=Number(t.min),i=Number(t.max),a=Number(t.step),o=Number.isFinite(r)?Pb(r,n.validMin,n.validMax):n.validMin,s=Number.isFinite(i)?Pb(i,n.validMin,n.validMax):o;o>s&&(s=o);let c=Number.isFinite(a)&&a>0?Math.max(a,1e-6):n.defaultStep;return{min:o,max:s,step:c}}function Ib(e,t,n){if(n<=0||e===t)return[e];let r=[],i=n*.001;for(let a=e;a<=t+i;){let e=Math.round(a*1e6)/1e6;if(e<=t+1e-9&&r.push(e),r.length>=200)break;let i=a+n;if(i===a)break;a=i}return r.length>0?r:[e]}function Lb(e,t){let n=xb[e];if(!t||t.length===0)return{min:String(n.validMin),max:String(n.validMin),step:String(n.defaultStep)};if(t.length===1)return{min:String(t[0]),max:String(t[0]),step:String(n.defaultStep)};let r=t[0],i=t[t.length-1],a=t[1]-t[0],o=a>0;for(let e=2;e1e-6&&(o=!1);let s=o&&a>0?Math.round(a*1e6)/1e6:n.defaultStep;return{min:String(r),max:String(i),step:String(s)}}function Rb(e){let t={};for(let n of Object.keys(xb))t[n]=Lb(n,e[n]);return t}function zb(e){let t=new Date,n=e.getDate()===t.getDate()&&e.getMonth()===t.getMonth()&&e.getFullYear()===t.getFullYear(),r=e.toLocaleTimeString([],{hour:`numeric`,minute:`2-digit`});return n?r:e.toLocaleDateString([],{month:`short`,day:`numeric`})+`, `+r}function Bb(e,t,n,r){let[,i]=(0,x.useState)(0),a=t.filter(e=>e?.finishedAt).length,o=r&&a{if(!o)return;let e=setInterval(()=>i(e=>e+1),1e3);return()=>clearInterval(e)},[o]);let s=e?Date.parse(e):NaN,c=t.map(e=>e?.startedAt?Date.parse(e.startedAt):NaN).filter(Number.isFinite),l=Number.isFinite(s)?s:c.length?Math.min(...c):NaN,u=Number.isFinite(l)?Math.max(0,Date.now()-l):0,d=Number.isFinite(l)?$y(u):null,f=null,p=null;if(a>0&&ae?.startedAt&&e?.finishedAt).map(e=>Date.parse(e.finishedAt)-Date.parse(e.startedAt)).filter(e=>Number.isFinite(e)&&e>0);if(e.length>0){let t=e.reduce((e,t)=>e+t,0)/e.length,r=Math.max(0,n-a),i=a>0?r:Math.max(0,r-1),o=t*r+Hn*i;f=$y(o),a>=3&&(p=zb(new Date(Date.now()+o)))}}return{elapsed:d,estimate:f,estimatedCompletion:p}}function Vb({totalTrials:e,trials:t,running:n,runStartedAt:r}){let{elapsed:i,estimate:a,estimatedCompletion:o}=Bb(r,t,e,n),s=t.filter(e=>e?.finishedAt).length,c=!!t.find(e=>e?.status===`running`),l=Math.min(100,e>0?(s+(c?.5:0))/e*100:0),u=t.find(e=>e?.status===`running`),d=null;if(u){let e=u.scenarioResults.reduce((e,t)=>e+t.promptResults.length,0);d=e>0?`Prompt ${e} completed`:`Starting…`}let f=Math.min(s+ +!!c,e),p=`${i??`0s`}${a?` · ~${a} left`:``}${o?` · ETA ${o}`:``}`,m=l>=50;return(0,G.jsxs)(`div`,{className:`playground-autotest-progress`,children:[(0,G.jsxs)(`div`,{className:`playground-autotest-progress-text`,children:[(0,G.jsxs)(`span`,{children:[`Trial `,f,` / `,e]}),d&&(0,G.jsxs)(`span`,{className:`playground-autotest-prompt-progress`,children:[` · `,d]})]}),(0,G.jsxs)(`div`,{className:`playground-autotest-progress-bar`,children:[(0,G.jsx)(`div`,{className:`playground-autotest-progress-fill`,style:{width:`${l}%`},children:m&&(0,G.jsx)(`span`,{className:`playground-autotest-progress-label`,children:p})}),!m&&(0,G.jsx)(`span`,{className:`playground-autotest-progress-label-outside`,children:p})]})]})}function Hb({session:e,sessionSeed:t,catalogSampling:n,isMoE:r,gpuVramBytes:i,lockSweep:a}){let{run:o,isRunning:s,startSamplingRun:c,startConfigRun:l,stopRun:u,clearRun:d,reevaluateBestTrial:f,reorderQueuedTrial:p,skipTrial:m,unskipTrial:h,stopTrial:g,rerunTrial:_}=Mi(),{sweepMode:v,setSweepMode:y}=Ui(),b=o?.kind===`sampling`?o.sweepDef:er,S=o?.kind===`config`?o.configSweepDef:tr,C=o?.weights??(o?.kind===`config`?ur:lr),[w,T]=(0,x.useState)(()=>o?.enabledScenarios??{chat:!0,tool_call:!0}),[E,D]=(0,x.useState)(()=>structuredClone(b)),[O,k]=(0,x.useState)(()=>Rb(b)),A=(0,x.useRef)(O);(0,x.useEffect)(()=>{A.current=O},[O]);let[j,M]=(0,x.useState)(!!o),[N,P]=(0,x.useState)(null),F=1/0,[I,L]=(0,x.useState)(()=>structuredClone(S)),[R,z]=(0,x.useState)(()=>({...C})),[ee,B]=(0,x.useState)(!1),V=(0,x.useRef)({...C});(0,x.useEffect)(()=>{if(!s&&!o){let e=v===`config`?ur:lr;z(e),V.current={...e},B(!1)}},[v,s,o]);let[te,H]=(0,x.useState)(!0),[ne,re]=(0,x.useState)(!1),[ie,ae]=(0,x.useState)(new Set),[oe,se]=(0,x.useState)(()=>o?.repeats??1),[ce,le]=(0,x.useState)({column:null,direction:null}),ue=s&&o?.status===`running_trials`&&ce.column===null,[de,fe]=(0,x.useState)(null),[pe,me]=(0,x.useState)(null),he=(0,x.useCallback)((e,t)=>{fe(t),e.dataTransfer.effectAllowed=`move`,e.dataTransfer.setData(`text/plain`,t)},[]),ge=(0,x.useCallback)((e,t)=>{e.preventDefault(),e.dataTransfer.dropEffect=`move`,me(t)},[]),_e=(0,x.useCallback)(()=>{me(null)},[]),ve=(0,x.useCallback)((e,t)=>{e.preventDefault();let n=e.dataTransfer.getData(`text/plain`);n&&n!==t&&p({trialId:n,targetId:t}),fe(null),me(null)},[p]),ye=(0,x.useCallback)(()=>{fe(null),me(null)},[]),[,be]=(0,x.useState)(0);(0,x.useEffect)(()=>{if(!s)return;let e=setInterval(()=>be(e=>e+1),1e3);return()=>clearInterval(e)},[s]);let xe=(0,x.useMemo)(()=>{let e={chat:v===`config`?Qn:Gn};return v!==`config`&&(e.tool_call=Zn),e},[v]),Se=(0,x.useCallback)(e=>{le(t=>({column:t.column===e&&Tb(t.direction)===null?null:e,direction:t.column===e?Tb(t.direction):`asc`}))},[]),Ce=(0,x.useCallback)(e=>{ae(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},[]),[we,Te]=(0,x.useState)(()=>S.prefillBatchSize.values.join(`, `)),[Ee,De]=(0,x.useState)(()=>S.contextWindow.values.join(`, `)),[Oe,ke]=(0,x.useState)(()=>S.nSeqMax.values.join(`, `)),[Ae,je]=(0,x.useState)(()=>i&&i>0?Math.round(i*.9/1073741824*10)/10:0),[Me,Ne]=(0,x.useState)(()=>S.moeKeepExpertsTopN?.values.join(`, `)??`0`),[Pe,Fe]=(0,x.useState)(()=>S.opOffloadMinBatch?.values.join(`, `)??`0`),Ie=(0,x.useRef)(Ae>0);(0,x.useEffect)(()=>{Ie.current||!i||i<=0||(Ie.current=!0,je(Math.round(i*.9/1073741824*10)/10))},[i]);let Le=(0,x.useRef)(o?.runId);(0,x.useEffect)(()=>{o&&o.runId!==Le.current&&(a&&o.kind!==v||(Le.current=o.runId,a||y(o.kind),T(o.enabledScenarios),se(o.repeats),z({...o.weights}),V.current={...o.weights},B(!1),o.kind===`sampling`?(D(structuredClone(o.sweepDef)),k(Rb(o.sweepDef)),M(!0)):(L(structuredClone(o.configSweepDef)),Te(o.configSweepDef.prefillBatchSize.values.join(`, `)),De(o.configSweepDef.contextWindow.values.join(`, `)),ke(o.configSweepDef.nSeqMax.values.join(`, `)),Ne(o.configSweepDef.moeKeepExpertsTopN?.values.join(`, `)??`0`),Fe(o.configSweepDef.opOffloadMinBatch?.values.join(`, `)??`0`))))},[o?.runId]);let Re=(0,x.useRef)(o);(0,x.useEffect)(()=>{Re.current&&!o&&(M(!1),Le.current=void 0),Re.current=o},[o]);let ze=(0,x.useCallback)((e,t,n)=>{let r=t===`moeKeepExpertsTopN`||t===`opOffloadMinBatch`?0:1,i=e.split(`,`).map(e=>Math.floor(Number(e.trim()))).filter(e=>Number.isFinite(e)&&e>=r);if(i.length===0){L(e=>(n(e[t]?.values.join(`, `)??`0`),e));return}L(e=>({...e,[t]:{...e[t]??{enabled:!1,values:[]},enabled:!0,values:i}})),n(i.join(`, `))},[]),Be=(0,x.useCallback)(e=>{let{min:t,max:n,step:r}=Fb(e,A.current[e]),i=Ib(t,n,r);k(i=>({...i,[e]:{min:String(t),max:String(n),step:String(r)}})),D(t=>({...t,[e]:i})),M(!0)},[]);(0,x.useEffect)(()=>{if(o||!n||n===N||(P(n),j))return;let e=n,t={temperature:[e.temperature??.8],top_p:[e.top_p??.9],top_k:[e.top_k??40],min_p:[e.min_p??0],repeat_penalty:[e.repeat_penalty??1],repeat_last_n:[e.repeat_last_n??64],frequency_penalty:[e.frequency_penalty??0],presence_penalty:[e.presence_penalty??0],dry_multiplier:[e.dry_multiplier??1.05],dry_base:[e.dry_base??1.75],dry_allowed_length:[e.dry_allowed_length??2],dry_penalty_last_n:[e.dry_penalty_last_n??0],xtc_probability:[e.xtc_probability??0],xtc_threshold:[e.xtc_threshold??.1],xtc_min_keep:[e.xtc_min_keep??1],max_tokens:[e.max_tokens??4096],enable_thinking:[e.enable_thinking||`true`],reasoning_effort:[e.reasoning_effort||`medium`]};D(t),k(Rb(t))},[n,N,j,o]);let Ve=a&&o&&o.kind!==v?null:o,He=s&&!Ve&&!!o,Ue=s&&!!Ve,We=Ve?.status??`idle`,Ge=Ve?.errorMessage??``,Ke=Ve?.templateRepairStatus??``,qe=Ve?.calibrationStatus??``,Je=Ve?.totalTrials??0,Ye=Ve?.kind===`sampling`?Ve.trials:[],Xe=Ve?.kind===`config`?Ve.trials:[],Ze=Ve?.kind===`sampling`&&Ve.bestTrialId?Ve.trials.find(e=>e.id===Ve.bestTrialId)??null:null,Qe=Ve?.kind===`config`&&Ve.bestTrialId?Ve.trials.find(e=>e.id===Ve.bestTrialId)??null:null,$e=a?v:o?o.kind:v,et=o?.kind;(0,x.useEffect)(()=>{et&&!a&&y(et)},[et,a]);let tt=$e===`config`?Xe:Ye,nt=(0,x.useMemo)(()=>$e===`config`?bb():yb(),[$e]),rt=(0,x.useMemo)(()=>Object.fromEntries(nt.map(e=>[e.id,e])),[nt]),it=(0,x.useCallback)((e,t)=>rt[t]?.getValue(e),[rt]),at=(0,x.useMemo)(()=>Db(tt,ce,it),[tt,ce,it]),ot=w.chat||w.tool_call,st=(0,x.useMemo)(()=>{let e=Object.keys(xb),t=Object.fromEntries(e.map(e=>{let{min:t,max:n,step:r}=Fb(e,O[e]);return[e,Ib(t,n,r)]}));return{...E,...t}},[O,E]),ct=(0,x.useMemo)(()=>$n(st,F).length,[st,F]),lt=(0,x.useMemo)(()=>t?rr(t.base_config,I).length:1,[t,I]),ut=(0,x.useRef)(0);(0,x.useEffect)(()=>{tt.length>0&&ut.current===0&&!ne&&re(!0),ut.current=tt.length},[tt.length,ne]);let dt=(0,x.useCallback)(()=>{if(v===`sampling`){if(!e&&!t?.model_id)return;c({sessionId:e?.session_id,sessionSeed:e?void 0:t??void 0,enabledScenarios:w,sweepDef:st,maxTrials:F,weights:R,repeats:oe,effectiveConfig:e?.effective_config})}else{if(!t?.model_id||e)return;let n=r?I:{...I,moeMode:void 0,moeKeepExpertsTopN:void 0,opOffloadMinBatch:void 0};l({sessionSeed:t,enabledScenarios:w,configSweepDef:n,weights:R,repeats:oe,availableVRAMGB:Ae})}H(!1),V.current={...R},B(!1)},[v,e,t,w,st,F,I,R,oe,Ae,c,l]),ft=(0,x.useCallback)((e,t)=>{z(n=>{let r={...n,[e]:t},i=V.current,a=Object.keys(r).some(e=>r[e]!==i[e]);return B(a),r})},[]),pt=(0,x.useCallback)(()=>{f(R),V.current={...R},B(!1)},[R,f]),mt=(0,x.useCallback)(e=>{let t=dr(e,o?.kind??v);z(t),V.current={...t},B(!1),f(t)},[o,v,f]),ht=(0,x.useCallback)(()=>{u()},[u]),gt=(0,x.useCallback)(()=>{H(!0),d()},[d]),_t=v===`sampling`?!(!e&&!t?.model_id||s||!ot):!(!t?.model_id||e||s||!ot);return(0,G.jsxs)(`div`,{className:`playground-autotest-container`,children:[(0,G.jsxs)(`div`,{className:`playground-autotest-section`,style:{display:`flex`,gap:32,alignItems:`flex-start`},children:[!a&&(0,G.jsxs)(`div`,{style:{width:`50%`},children:[(0,G.jsx)(`h4`,{children:`Sweep Mode`}),(0,G.jsx)(`div`,{className:`playground-inline-options`,style:{paddingBottom:`20px`},children:Qy.map(e=>(0,G.jsxs)(`label`,{className:`playground-inline-option`,children:[(0,G.jsx)(`input`,{type:`radio`,name:`sweepMode`,value:e.kind,checked:v===e.kind,onChange:()=>y(e.kind),disabled:s}),e.label]},e.kind))})]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`h4`,{children:`Repeats Per Test Case`}),(0,G.jsx)(`p`,{style:{fontSize:12,color:`var(--color-gray-600)`,marginBottom:8},children:`Each prompt is run this many times and scores are averaged for more stable results.`}),(0,G.jsx)(`div`,{className:`playground-sweep-param-range`,style:{maxWidth:120},children:(0,G.jsx)(`div`,{className:`playground-sweep-param-range-field`,children:(0,G.jsx)(`input`,{type:`number`,value:oe,onChange:e=>{let t=Math.floor(Number(e.target.value));Number.isFinite(t)&&t>=1&&se(t)},min:1,max:20,disabled:s})})})]})]}),v===`config`&&(0,G.jsxs)(`details`,{className:`playground-sampling-params`,open:te,onToggle:e=>H(e.currentTarget.open),children:[(0,G.jsxs)(`summary`,{children:[`Config Parameters`,r?` / MoE Parameters`:``]}),(0,G.jsx)(wb,{configSweepDef:I,setConfigSweepDef:L,rawPrefillBatchSize:we,setRawPrefillBatchSize:Te,rawContextWindow:Ee,setRawContextWindow:De,rawNSeqMax:Oe,setRawNSeqMax:ke,rawMoeKeepExpertsTopN:Me,setRawMoeKeepExpertsTopN:Ne,rawOpOffloadMinBatch:Pe,setRawOpOffloadMinBatch:Fe,commitNumericSweep:ze,isMoE:r,isRunning:s,trialCount:lt}),(0,G.jsx)(`div`,{className:`playground-autotest-section`,children:(0,G.jsx)(`div`,{className:`playground-sweep-params`,children:(0,G.jsxs)(`div`,{className:`playground-sweep-param`,children:[(0,G.jsx)(X,{className:`playground-sweep-param-toggle`,tooltipKey:`availableVRAM`,children:`Available GPU VRAM (GB)`}),(0,G.jsx)(`input`,{type:`number`,className:`playground-sweep-param-values`,value:Ae,onChange:e=>{let t=Number(e.target.value);Number.isFinite(t)&&t>=0&&(Ie.current=!0,je(t))},placeholder:`0 = no filtering`,min:0,step:.1,disabled:s,style:{maxWidth:120}})]})})})]}),v===`sampling`&&(0,G.jsxs)(`details`,{className:`playground-sampling-params`,open:te,onToggle:e=>H(e.currentTarget.open),children:[(0,G.jsx)(`summary`,{children:`Scenario Selection / Sampling Sweep Parameters`}),(0,G.jsxs)(`div`,{className:`playground-autotest-section`,children:[(0,G.jsx)(`h4`,{children:`Scenario Selection`}),(0,G.jsxs)(`div`,{className:`playground-inline-options`,children:[(0,G.jsxs)(`label`,{className:`playground-inline-option`,children:[(0,G.jsx)(`input`,{type:`checkbox`,checked:w.chat,onChange:e=>T(t=>({...t,chat:e.target.checked})),disabled:s}),`Chat Quality`]}),(0,G.jsxs)(`label`,{className:`playground-inline-option`,children:[(0,G.jsx)(`input`,{type:`checkbox`,checked:w.tool_call,onChange:e=>T(t=>({...t,tool_call:e.target.checked})),disabled:s}),`Tool Calling`]})]})]}),(0,G.jsx)(Cb,{sweepDef:E,setSweepDef:D,sweepInputs:O,setSweepInputs:k,commitTriple:Be,setSweepDirty:M,catalogSampling:n,isRunning:s,trialCount:ct})]}),(0,G.jsxs)(`div`,{className:`playground-autotest-actions`,children:[(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:dt,disabled:!_t,children:`Run Automated Testing`}),v===`config`&&r&&!s&&(0,G.jsx)(`button`,{type:`button`,className:`btn btn-small`,onClick:()=>{let e=nr;L(structuredClone(e)),Te(e.prefillBatchSize.values.join(`, `)),De(e.contextWindow.values.join(`, `)),ke(e.nSeqMax.values.join(`, `)),Ne(e.moeKeepExpertsTopN?.values.join(`, `)??`0`),Fe(e.opOffloadMinBatch?.values.join(`, `)??`0`)},children:`MoE Recommended`}),Ue&&(0,G.jsx)(`button`,{className:`btn btn-danger`,onClick:ht,children:`Stop`}),tt.length>0&&!s&&(0,G.jsx)(`button`,{className:`btn btn-secondary btn-small`,onClick:gt,children:`Clear Results`})]}),He&&o&&(0,G.jsxs)(`div`,{className:`playground-error`,children:[`A `,o.kind===`config`?`configuration`:`sampling`,` run is in progress. Stop it before starting a `,v===`config`?`configuration`:`sampling`,` run.`]}),v===`config`&&e&&!s&&(0,G.jsx)(`div`,{className:`playground-error`,children:`Unload the current model before running config sweeps`}),Ke&&s&&We!==`running_trials`&&(0,G.jsxs)(`div`,{className:`playground-autotest-status`,children:[(0,G.jsx)(`span`,{className:`playground-autotest-spinner`}),` `,Ke]}),qe&&s&&(We!==`running_trials`||tt.length===0)&&(0,G.jsxs)(`div`,{className:`playground-autotest-status`,children:[(0,G.jsx)(`span`,{className:`playground-autotest-spinner`}),` `,qe]}),Ge&&(0,G.jsx)(`div`,{className:`playground-error`,children:Ge}),We===`running_trials`&&o?.initialDelayUntil&&(0,G.jsxs)(`div`,{className:`playground-autotest-status`,children:[(0,G.jsx)(`span`,{className:`playground-autotest-spinner`}),` Starting first test in `,Math.max(0,Math.ceil((Date.parse(o.initialDelayUntil)-Date.now())/1e3)),`s…`]}),We===`running_trials`&&(0,G.jsx)(Vb,{totalTrials:Je,trials:tt,running:s,runStartedAt:o?.runStartedAt}),We===`completed`&&(()=>{let e=!!($e===`config`?Qe:Ze);return(0,G.jsxs)(`div`,{className:`playground-autotest-best`,children:[e?(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`h4`,{children:`Best Configuration Found`}),(0,G.jsxs)(`div`,{className:`playground-autotest-best-details`,children:[$e===`config`&&Qe?(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Context Window:`}),` `,Qe.config?.context_window??`—`]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Prefill Batch Size:`}),` `,Qe.config?.prefill_batch_size??`—`]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`NSeqMax:`}),` `,Qe.config?.nseq_max??`—`]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Flash Attention:`}),` `,Qe.config?.flash_attention??`—`]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`KV Cache Type:`}),` `,Qe.config?.cache_type??`—`]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Cache Mode:`}),` `,Qe.config?.cache_mode?Qe.config.cache_mode===`none`?`None`:Qe.config.cache_mode.toUpperCase():`—`]}),Qe.config?.moe_mode&&(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`MoE Mode:`}),` `,Qe.config.moe_mode===`experts_cpu`?`Experts on CPU`:Qe.config.moe_mode===`keep_top_n`?`Balanced (Top-N on GPU)`:Qe.config.moe_mode===`experts_gpu`?`Experts on GPU`:Qe.config.moe_mode]}),Qe.config?.moe_keep_experts_top_n!==void 0&&Qe.config?.moe_keep_experts_top_n!==null&&(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Expert Layers on GPU:`}),` `,Qe.config.moe_keep_experts_top_n]}),Qe.estimatedVRAM!==void 0&&(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Est. VRAM:`}),` `,J(Qe.estimatedVRAM)]})]}):Ze?(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Temperature:`}),` `,Ze.candidate.temperature]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Top P:`}),` `,Ze.candidate.top_p]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Top K:`}),` `,Ze.candidate.top_k]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Min P:`}),` `,Ze.candidate.min_p]})]}):null,(()=>{let e=$e===`config`?Qe:Ze;return e?(0,G.jsx)(jb,{trial:e,showScores:$e!==`config`}):null})()]})]}):(0,G.jsx)(`div`,{style:{fontSize:12,color:`var(--color-gray-700)`},children:`No best configuration could be selected. Adjust weights and reevaluate.`}),(0,G.jsxs)(`details`,{className:`playground-sampling-params`,style:{marginTop:e?12:0},children:[(0,G.jsx)(`summary`,{children:`Best Configuration Criteria`}),(0,G.jsx)(`p`,{style:{fontSize:12,color:`var(--color-gray-600)`,marginBottom:8},children:`Weights control how the best configuration is chosen. Higher weight = more influence.`}),(0,G.jsxs)(`div`,{style:{display:`flex`,gap:6,marginBottom:10},children:[(0,G.jsx)(`button`,{type:`button`,className:`btn btn-small`,onClick:()=>mt(`overall`),children:`Best overall`}),(0,G.jsx)(`button`,{type:`button`,className:`btn btn-small`,onClick:()=>mt(`0pct`),children:`Best at 0% context`}),(0,G.jsx)(`button`,{type:`button`,className:`btn btn-small`,onClick:()=>mt(`80pct`),children:`Best at 80% context`})]}),(0,G.jsx)(`div`,{className:`playground-sweep-params`,children:[...$e===`config`?[]:[[`chatScore`,`Chat Score`],[`toolScore`,`Tool Score`],[`totalScore`,`Total Score`]],[`avgTPS`,`Avg TPS`],[`avgTTFT`,`Avg TTFT (lower is better)`],[`tps0`,`TPS @0% Fill`],[`tps20`,`TPS @20% Fill`],[`tps50`,`TPS @50% Fill`],[`tps80`,`TPS @80% Fill`],[`ttft0`,`TTFT @0% Fill (lower is better)`],[`ttft20`,`TTFT @20% Fill (lower is better)`],[`ttft50`,`TTFT @50% Fill (lower is better)`],[`ttft80`,`TTFT @80% Fill (lower is better)`]].map(([e,t])=>(0,G.jsxs)(`div`,{className:`playground-sweep-param`,children:[(0,G.jsx)(`label`,{className:`playground-sweep-param-toggle`,htmlFor:`best-config-weight-${e}`,children:t}),(0,G.jsx)(`input`,{id:`best-config-weight-${e}`,type:`number`,className:`playground-sweep-param-values`,value:R[e],onChange:t=>{let n=Number(t.target.value);Number.isFinite(n)&&n>=0&&ft(e,n)},step:.1,min:0})]},e))}),R.totalScore>0&&(R.chatScore>0||R.toolScore>0)&&(0,G.jsx)(`p`,{style:{fontSize:11,color:`var(--color-warning-text)`,marginTop:6},children:`⚠ Total Score is derived from Chat/Tool weights. Weighting Total Score alongside Chat or Tool Score will double-count quality.`}),(0,G.jsx)(`button`,{className:`btn btn-primary btn-small`,style:{marginTop:8},onClick:pt,disabled:!ee,children:`Reevaluate`})]})]})})(),tt.length>0&&(0,G.jsxs)(`details`,{className:`playground-autotest-results`,open:ne,onToggle:e=>re(e.currentTarget.open),children:[(0,G.jsxs)(`summary`,{style:{cursor:`pointer`,fontWeight:600,fontSize:13,color:`var(--color-gray-700)`,marginBottom:8},children:[`Results (`,tt.length,` trials)`,(We===`completed`||We===`cancelled`)&&(()=>{let e=o?.runStartedAt?Date.parse(o.runStartedAt):NaN,t=tt.map(e=>e?.finishedAt?Date.parse(e.finishedAt):NaN).filter(Number.isFinite),n=t.length>0?Math.max(...t):NaN;if(!Number.isFinite(e)||!Number.isFinite(n))return null;let r=$y(Math.max(0,n-e)),i=new Date(n),a=i.toLocaleDateString([],{month:`short`,day:`numeric`,year:`numeric`})+`, `+i.toLocaleTimeString([],{hour:`numeric`,minute:`2-digit`,second:`2-digit`});return(0,G.jsxs)(`span`,{style:{fontWeight:400,fontSize:12,color:`var(--color-gray-500)`,marginLeft:8},children:[`— `,r,` total · finished `,a]})})()]}),(0,G.jsx)(`div`,{className:`playground-autotest-table-scroll`,children:(0,G.jsxs)(`table`,{className:`playground-autotest-table`,children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{children:`#`}),(s||o)&&(0,G.jsx)(`th`,{children:`Actions`}),nt.map(e=>(0,G.jsxs)(`th`,{className:e.sortable===!1?void 0:`sortable-th`,onClick:e.sortable===!1?void 0:()=>Se(e.id),children:[e.title,Eb(e.id,ce)]},e.id))]})}),(0,G.jsx)(`tbody`,{children:at.map((e,t)=>{let n=(e.totalScore===void 0||e.totalScore===null)&&e.status!==`skipped`,r=n&&e.status===`running`,i=$e===`config`?Qe:Ze,a=i&&e===i&&We===`completed`,c=ie.has(e.id),l=de===e.id,u=pe===e.id&&de!==e.id,d=ue&&e.status===`queued`,f={isPending:n,isInProgress:r,isBest:!!a,index:t};return(0,G.jsxs)(x.Fragment,{children:[(0,G.jsxs)(`tr`,{className:`autotest-trial-row${a?` autotest-best-row`:``}${r?` autotest-running-row`:``}${e.status===`skipped`?` autotest-skipped-row`:``}${l?` autotest-dragging-row`:``}${u?` autotest-dragover-row`:``}`,style:{cursor:`pointer`},onClick:()=>Ce(e.id),draggable:d,onDragStart:d?t=>he(t,e.id):void 0,onDragOver:d?t=>ge(t,e.id):void 0,onDragLeave:d?_e:void 0,onDrop:d?t=>ve(t,e.id):void 0,onDragEnd:d?ye:void 0,children:[(0,G.jsxs)(`td`,{children:[c?`▾`:`▸`,` `,r&&(0,G.jsx)(`span`,{className:`playground-autotest-spinner-inline`}),t+1]}),(s||o)&&(0,G.jsxs)(`td`,{className:`autotest-actions-cell`,onClick:e=>e.stopPropagation(),children:[e.status===`queued`&&(0,G.jsxs)(`span`,{className:`autotest-queue-controls`,children:[(0,G.jsx)(`span`,{className:`autotest-drag-handle${ue?``:` disabled`}`,title:ue?`Drag to reorder`:`Clear column sorting to reorder`,children:`☰`}),(0,G.jsx)(`button`,{className:`btn btn-small autotest-skip-btn`,onClick:()=>m({trialId:e.id}),title:`Skip this trial`,children:`Skip`})]}),e.status===`skipped`&&(0,G.jsx)(`button`,{className:`btn btn-small autotest-unskip-btn`,onClick:()=>h({trialId:e.id}),title:`Restore this trial to the queue`,children:`Unskip`}),e.status===`running`&&(0,G.jsx)(`button`,{className:`btn btn-small btn-danger`,onClick:()=>g(),title:`Stop this trial`,children:`Stop`}),(e.status===`completed`||e.status===`cancelled`||e.status===`failed`)&&(0,G.jsx)(`button`,{className:`btn btn-small`,onClick:()=>_({trialId:e.id}),title:`Rerun this trial (moves to top of queue)`,children:`Rerun`})]}),nt.map(t=>(0,G.jsx)(`td`,{children:t.renderCell(e,f)},t.id))]}),c&&(0,G.jsx)(`tr`,{className:`autotest-detail-row`,children:(0,G.jsx)(`td`,{colSpan:nt.length+(s||o?2:1),children:(0,G.jsx)(Nb,{trial:e,scenarioLookup:xe,hideScores:$e===`config`})})})]},e.id)})})]})})]})]})}function Ub(e){let t=new Map,n=0;for(let r of e){let e=r.id.lastIndexOf(`/`);if(e===-1){let e=t.get(r.id);e?e.baseId=r.id:t.set(r.id,{baseId:r.id,variants:[],order:n++})}else{let i=r.id.slice(0,e),a=r.id.slice(e+1);if(!i||!a)continue;let o=t.get(i);o?o.variants.push({id:r.id,suffix:a}):t.set(i,{baseId:null,variants:[{id:r.id,suffix:a}],order:n++})}}let r=Array.from(t.entries()).sort((e,t)=>e[1].order-t[1].order),i=[];for(let[e,t]of r)t.variants.length===0&&t.baseId?i.push({type:`standalone`,id:t.baseId}):i.push({type:`group`,base:e,baseId:t.baseId,variants:t.variants});return i}function Wb(e,t){return t?e.baseId===t||e.variants.some(e=>e.id===t):!1}function Gb(e){return Array.from(e.querySelectorAll(`[role="treeitem"]:not([aria-disabled="true"])`))}function Kb({expanded:e}){return(0,G.jsx)(`span`,{className:`model-selector-chevron${e?` expanded`:``}`,"data-role":`toggle`,"aria-hidden":`true`,children:`▶`})}function qb({models:e,selectedModel:t,onSelect:n,disabled:r=!1,placeholder:i=`Select a model...`,extraItems:a,draftModelIds:o}){let s=(0,x.useRef)(null),[c,l]=(0,x.useState)(()=>new Set),u=e??[],d=(0,x.useMemo)(()=>Ub(u),[u]),f=(0,x.useMemo)(()=>{if(o)return o;let e=new Set;for(let t of u)t.draft_model_id&&e.add(t.id);return e},[u,o]),p=d.length>0||a&&a.length>0;(0,x.useEffect)(()=>{if(t){for(let e of d)if(e.type===`group`&&Wb(e,t)){l(t=>{if(t.has(e.base))return t;let n=new Set(t);return n.add(e.base),n});break}}},[t,d]);let m=(0,x.useCallback)(e=>{l(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},[]),h=(0,x.useCallback)((e,t)=>{let n=s.current;if(!n)return;let r=Gb(n),i=r.indexOf(e),a=t===`down`?i+1:i-1;a>=0&&a{if(r)return;if(e.key===`ArrowDown`||e.key===`ArrowUp`){e.preventDefault(),h(e.currentTarget,e.key===`ArrowDown`?`down`:`up`);return}let t=e.currentTarget.dataset.groupBase;if(t){if(e.key===`ArrowRight`){e.preventDefault(),l(e=>{if(e.has(t))return requestAnimationFrame(()=>{let e=s.current;if(!e)return;let n=e.querySelector(`[data-group-container="${t}"]`)?.querySelector(`[role="treeitem"]`);n&&(n.focus(),n.scrollIntoView({block:`nearest`}))}),e;let n=new Set(e);return n.add(t),n});return}if(e.key===`ArrowLeft`){e.preventDefault(),l(e=>{if(!e.has(t))return e;let n=new Set(e);return n.delete(t),n});return}}if(!t&&e.key===`ArrowLeft`){e.preventDefault();let t=e.currentTarget.closest(`[data-group-container]`);if(t){let e=t.previousElementSibling;e&&e.getAttribute(`role`)===`treeitem`&&(e.focus(),e.scrollIntoView({block:`nearest`}))}return}(e.key===`Enter`||e.key===` `)&&(e.preventDefault(),e.currentTarget.click())},[r,h]),_=(0,x.useCallback)((e,t)=>{r||(e.target.closest(`[data-role="toggle"]`)?m(t.base):t.baseId?n(t.baseId):m(t.base))},[r,n,m]);return(0,G.jsxs)(`div`,{className:`model-selector${r?` model-selector-disabled`:``}`,role:`tree`,"aria-label":i,"aria-multiselectable":!1,ref:s,children:[!p&&(0,G.jsx)(`div`,{className:`model-selector-empty`,children:i}),d.map(e=>{if(e.type===`standalone`)return(0,G.jsx)(`div`,{role:`treeitem`,"aria-selected":t===e.id,"aria-level":1,"aria-disabled":r,tabIndex:r?-1:0,className:`model-selector-item${t===e.id?` active`:``}`,onClick:()=>{r||n(e.id)},onKeyDown:g,title:e.id,children:(0,G.jsxs)(`span`,{className:`model-selector-label`,children:[f.has(e.id)?`⚡ `:``,e.id]})},e.id);let i=c.has(e.base),a=Wb(e,t),o=e.baseId?f.has(e.baseId):e.variants.some(e=>f.has(e.id));return(0,G.jsxs)(`div`,{className:`model-selector-group`,children:[(0,G.jsxs)(`div`,{role:`treeitem`,"aria-expanded":i,"aria-selected":e.baseId?t===e.baseId:!1,"aria-level":1,"aria-disabled":r,"data-group-base":e.base,tabIndex:r?-1:0,className:`model-selector-item model-selector-group-header${a?` active`:``}`,onClick:t=>_(t,e),onKeyDown:g,title:e.base,children:[(0,G.jsx)(Kb,{expanded:i}),(0,G.jsxs)(`span`,{className:`model-selector-label`,children:[o?`⚡ `:``,e.base]})]}),i&&(0,G.jsx)(`div`,{role:`group`,"data-group-container":e.base,children:e.variants.map(e=>(0,G.jsx)(`div`,{role:`treeitem`,"aria-selected":t===e.id,"aria-level":2,"aria-disabled":r,tabIndex:r?-1:0,className:`model-selector-item model-selector-subitem${t===e.id?` active`:``}`,onClick:()=>{r||n(e.id)},onKeyDown:g,title:e.id,children:(0,G.jsxs)(`span`,{className:`model-selector-label`,children:[f.has(e.id)?`⚡ `:``,e.suffix]})},e.id))})]},e.base)}),a?.map(e=>(0,G.jsx)(`div`,{role:`treeitem`,"aria-selected":t===e.id,"aria-level":1,"aria-disabled":r,tabIndex:r?-1:0,className:`model-selector-item model-selector-extra${t===e.id?` active`:``}`,onClick:()=>{r||n(e.id)},onKeyDown:g,title:e.label,children:(0,G.jsx)(`span`,{className:`model-selector-label`,children:e.label})},e.id))]})}function Jb({filterMode:e}){let[t,n]=(0,x.useState)([]),r=(0,x.useMemo)(()=>e?t.filter(t=>t.sweepMode===e):t,[t,e]),[i,a]=(0,x.useState)(!0),[o,s]=(0,x.useState)(null),[c,l]=(0,x.useState)(new Set),[u,d]=(0,x.useState)({column:null,direction:null}),[f,p]=(0,x.useState)(new Set),[m,h]=(0,x.useState)(()=>({...lr})),[g,_]=(0,x.useState)(!1),[v,y]=(0,x.useState)(null),b=(0,x.useRef)({...lr}),S=(0,x.useRef)(null),C=(0,x.useRef)(null);(0,x.useEffect)(()=>{let e=!0;return bi().then(t=>{e&&(n(t),a(!1))}),()=>{e=!1}},[]),(0,x.useEffect)(()=>{let e=()=>{bi().then(n)},t=t=>{t instanceof StorageEvent&&t.key!==`playground:autoTestHistory:updatedAt`||e()};return window.addEventListener(`autotest-history-updated`,e),window.addEventListener(`storage`,t),()=>{window.removeEventListener(`autotest-history-updated`,e),window.removeEventListener(`storage`,t)}},[]),(0,x.useEffect)(()=>{if(!v)return;let e=setTimeout(()=>y(null),4e3);return()=>clearTimeout(e)},[v]),(0,x.useEffect)(()=>{let e=new Set(r.map(e=>e.id));l(t=>{let n=!1;for(let r of t)if(!e.has(r)){n=!0;break}if(!n)return t;let r=new Set;for(let n of t)e.has(n)&&r.add(n);return r})},[r]),(0,x.useEffect)(()=>{if(!C.current)return;let e=c.size,t=r.length;C.current.indeterminate=e>0&&er.find(e=>e.id===o)??null,[r,o]),T=(0,x.useCallback)(e=>{let t=r.find(t=>t.id===e);s(e),l(new Set),d({column:null,direction:null}),p(new Set);let n={...t?.run?.kind===`config`?ur:lr,...t?.run?.weights??{}};h({...n}),b.current={...n},_(!1)},[r]),E=(0,x.useCallback)(e=>{Ci(e),o===e&&s(null)},[o]),D=(0,x.useCallback)(()=>{c.size!==0&&(wi(Array.from(c)),o&&c.has(o)&&s(null),l(new Set))},[c,o]),O=(0,x.useCallback)(async()=>{let e=await Ti(),t=URL.createObjectURL(e),n=document.createElement(`a`),r=new Date().toISOString().slice(0,10);n.href=t,n.download=`autotest-history-${r}.json`,document.body.appendChild(n),n.click(),document.body.removeChild(n),URL.revokeObjectURL(t)},[]),k=(0,x.useCallback)(async e=>{try{let t=await Ei(await e.text());y(`Imported ${t.imported} entr${t.imported===1?`y`:`ies`}${t.skipped>0?` (${t.skipped} skipped)`:``}`)}catch(e){y(`Import failed: ${e instanceof Error?e.message:`unknown error`}`)}},[]),A=(0,x.useCallback)((e,t)=>{h(n=>{let r={...n,[e]:t},i=b.current,a=Object.keys(r).some(e=>r[e]!==i[e]);return _(a),r})},[]),j=(0,x.useCallback)(e=>{if(!w)return;let t=w.run?.trials;if(!Array.isArray(t))return;let n=t,r=null,i=-1/0,a=-1/0;for(let t of n){if(t.status!==`completed`)continue;let n=fr(t,e);(n>i||n===i&&(t.avgTPS??0)>a)&&(i=n,a=t.avgTPS??0,r=t.id)}Si(w.id,t=>({...t,run:{...t.run,bestTrialId:r??void 0,weights:{...e}}})),b.current={...e},_(!1)},[w]),M=(0,x.useCallback)(()=>{j(m)},[m,j]),N=(0,x.useCallback)(e=>{if(!w)return;let t=w.run.kind,n=dr(e,t);h(n),j(n)},[w,j]),P=(0,x.useCallback)(e=>{d(t=>({column:t.column===e&&Tb(t.direction)===null?null:e,direction:t.column===e?Tb(t.direction):`asc`}))},[]),F=(0,x.useCallback)(e=>{p(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},[]),I=w?w.run.kind:null,L=(0,x.useMemo)(()=>I===`config`?bb():yb(),[I]),R=(0,x.useMemo)(()=>Object.fromEntries(L.map(e=>[e.id,e])),[L]),z=(0,x.useCallback)((e,t)=>R[t]?.getValue(e),[R]),ee=w?w.run.trials:[],B=(0,x.useMemo)(()=>Db(ee,u,z),[ee,u,z]),V=w?.run.bestTrialId??null,te=I===`sampling`&&V?ee.find(e=>e.id===V)??null:null,H=I===`config`&&V?ee.find(e=>e.id===V)??null:null,ne=(0,x.useMemo)(()=>{let e={},t=I===`config`?Qn:Gn;return e[t.id]=t,I!==`config`&&(e[Zn.id]=Zn),e},[I]);if(w){let e=!!(I===`config`?H:te);return(0,G.jsxs)(`div`,{className:`playground-history-container`,children:[(0,G.jsx)(`button`,{className:`btn btn-small btn-secondary`,style:{marginBottom:12},onClick:()=>s(null),children:`← Back to list`}),(0,G.jsxs)(`div`,{style:{fontSize:13,color:`var(--color-gray-700)`,marginBottom:12},children:[(0,G.jsx)(`strong`,{children:w.modelId||`Unknown model`}),` · `,w.sweepMode===`config`?`Config Sweep`:`Sampling Sweep`,` · `,w.completedAt?new Date(w.completedAt).toLocaleDateString([],{month:`short`,day:`numeric`,year:`numeric`})+`, `+new Date(w.completedAt).toLocaleTimeString([],{hour:`numeric`,minute:`2-digit`}):`—`]}),(0,G.jsxs)(`div`,{className:`playground-autotest-best`,children:[e?(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`h4`,{children:`Best Configuration Found`}),(0,G.jsxs)(`div`,{className:`playground-autotest-best-details`,children:[I===`config`&&H?(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Context Window:`}),` `,H.config?.context_window??`—`]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Prefill Batch Size:`}),` `,H.config?.prefill_batch_size??`—`]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`NSeqMax:`}),` `,H.config?.nseq_max??`—`]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Flash Attention:`}),` `,H.config?.flash_attention??`—`]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`KV Cache Type:`}),` `,H.config?.cache_type??`—`]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Cache Mode:`}),` `,H.config?.cache_mode?H.config.cache_mode===`none`?`None`:H.config.cache_mode.toUpperCase():`—`]})]}):te?(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Temperature:`}),` `,te.candidate.temperature]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Top P:`}),` `,te.candidate.top_p]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Top K:`}),` `,te.candidate.top_k]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Min P:`}),` `,te.candidate.min_p]})]}):null,(()=>{let e=I===`config`?H:te;return e?(0,G.jsx)(jb,{trial:e,showScores:I!==`config`}):null})()]})]}):(0,G.jsx)(`div`,{style:{fontSize:12,color:`var(--color-gray-700)`},children:`No best configuration could be selected. Adjust weights and reevaluate.`}),(0,G.jsxs)(`details`,{className:`playground-sampling-params`,style:{marginTop:e?12:0},children:[(0,G.jsx)(`summary`,{children:`Best Configuration Criteria`}),(0,G.jsx)(`p`,{style:{fontSize:12,color:`var(--color-gray-600)`,marginBottom:8},children:`Weights control how the best configuration is chosen. Higher weight = more influence.`}),(0,G.jsxs)(`div`,{style:{display:`flex`,gap:6,marginBottom:10},children:[(0,G.jsx)(`button`,{type:`button`,className:`btn btn-small`,onClick:()=>N(`overall`),children:`Best overall`}),(0,G.jsx)(`button`,{type:`button`,className:`btn btn-small`,onClick:()=>N(`0pct`),children:`Best at 0% context`}),(0,G.jsx)(`button`,{type:`button`,className:`btn btn-small`,onClick:()=>N(`80pct`),children:`Best at 80% context`})]}),(0,G.jsx)(`div`,{className:`playground-sweep-params`,children:[...I===`config`?[]:[[`chatScore`,`Chat Score`],[`toolScore`,`Tool Score`],[`totalScore`,`Total Score`]],[`avgTPS`,`Avg TPS`],[`avgTTFT`,`Avg TTFT (lower is better)`],[`tps0`,`TPS @0% Fill`],[`tps20`,`TPS @20% Fill`],[`tps50`,`TPS @50% Fill`],[`tps80`,`TPS @80% Fill`],[`ttft0`,`TTFT @0% Fill (lower is better)`],[`ttft20`,`TTFT @20% Fill (lower is better)`],[`ttft50`,`TTFT @50% Fill (lower is better)`],[`ttft80`,`TTFT @80% Fill (lower is better)`]].map(([e,t])=>(0,G.jsxs)(`div`,{className:`playground-sweep-param`,children:[(0,G.jsx)(`label`,{className:`playground-sweep-param-toggle`,htmlFor:`history-weight-${e}`,children:t}),(0,G.jsx)(`input`,{id:`history-weight-${e}`,type:`number`,className:`playground-sweep-param-values`,value:m[e],onChange:t=>{let n=Number(t.target.value);Number.isFinite(n)&&n>=0&&A(e,n)},step:.1,min:0})]},e))}),m.totalScore>0&&(m.chatScore>0||m.toolScore>0)&&(0,G.jsx)(`p`,{style:{fontSize:11,color:`var(--color-warning-text)`,marginTop:6},children:`⚠ Total Score is derived from Chat/Tool weights. Weighting Total Score alongside Chat or Tool Score will double-count quality.`}),(0,G.jsx)(`button`,{className:`btn btn-primary btn-small`,style:{marginTop:8},onClick:M,disabled:!g,children:`Reevaluate`})]})]}),ee.length>0&&(0,G.jsxs)(`details`,{className:`playground-autotest-results`,open:!0,children:[(0,G.jsxs)(`summary`,{style:{cursor:`pointer`,fontWeight:600,fontSize:13,color:`var(--color-gray-700)`,marginBottom:8},children:[`Results (`,ee.length,` trials)`,(()=>{let e=w.run.runStartedAt?Date.parse(w.run.runStartedAt):NaN,t=ee.map(e=>e?.finishedAt?Date.parse(e.finishedAt):NaN).filter(Number.isFinite),n=t.length>0?Math.max(...t):NaN;if(!Number.isFinite(e)||!Number.isFinite(n))return null;let r=$y(Math.max(0,n-e)),i=new Date(n),a=i.toLocaleDateString([],{month:`short`,day:`numeric`,year:`numeric`})+`, `+i.toLocaleTimeString([],{hour:`numeric`,minute:`2-digit`,second:`2-digit`});return(0,G.jsxs)(`span`,{style:{fontWeight:400,fontSize:12,color:`var(--color-gray-500)`,marginLeft:8},children:[`— `,r,` total · finished `,a]})})()]}),(0,G.jsx)(`div`,{className:`playground-autotest-table-scroll`,children:(0,G.jsxs)(`table`,{className:`playground-autotest-table`,children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{children:`#`}),L.map(e=>(0,G.jsxs)(`th`,{className:e.sortable===!1?void 0:`sortable-th`,onClick:e.sortable===!1?void 0:()=>P(e.id),children:[e.title,Eb(e.id,u)]},e.id))]})}),(0,G.jsx)(`tbody`,{children:B.map((e,t)=>{let n=e.status===`queued`||e.status===`running`,r=I===`config`?H:te,i=r&&e===r,a=f.has(e.id),o={isPending:n,isInProgress:!1,isBest:!!i,index:t};return(0,G.jsxs)(x.Fragment,{children:[(0,G.jsxs)(`tr`,{className:`autotest-trial-row${i?` autotest-best-row`:``}${e.status===`skipped`?` autotest-skipped-row`:``}`,style:{cursor:`pointer`},onClick:()=>F(e.id),children:[(0,G.jsxs)(`td`,{children:[a?`▾`:`▸`,` `,t+1]}),L.map(t=>(0,G.jsx)(`td`,{children:t.renderCell(e,o)},t.id))]}),a&&(0,G.jsx)(`tr`,{className:`autotest-detail-row`,children:(0,G.jsx)(`td`,{colSpan:L.length+1,children:(0,G.jsx)(Nb,{trial:e,scenarioLookup:ne,hideScores:I===`config`})})})]},e.id)})})]})})]})]})}return i?(0,G.jsx)(`div`,{className:`playground-history-container`,children:(0,G.jsx)(`div`,{style:{fontSize:13,color:`var(--color-gray-500)`,padding:16},children:`Loading history…`})}):(0,G.jsx)(`div`,{className:`playground-history-container`,children:(0,G.jsxs)(`div`,{className:`playground-history-list`,children:[(0,G.jsxs)(`div`,{className:`playground-history-header`,children:[(0,G.jsx)(`h3`,{children:`Test Run History`}),r.length>0&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`input`,{ref:C,type:`checkbox`,checked:c.size===r.length&&r.length>0,onChange:()=>{c.size===r.length?l(new Set):l(new Set(r.map(e=>e.id)))},style:{marginLeft:8}}),(0,G.jsxs)(`span`,{style:{fontSize:12,color:`var(--color-gray-500)`},children:[r.length,` run`,r.length===1?``:`s`]})]}),c.size>0&&(0,G.jsxs)(`button`,{className:`btn btn-small btn-danger`,style:{marginLeft:8},onClick:D,children:[`Delete Selected (`,c.size,`)`]}),(0,G.jsx)(`button`,{className:`btn btn-small btn-secondary`,style:{marginLeft:8},onClick:()=>{O()},children:`Export`}),(0,G.jsx)(`button`,{className:`btn btn-small btn-secondary`,style:{marginLeft:4},onClick:()=>S.current?.click(),children:`Import`}),(0,G.jsx)(`input`,{ref:S,type:`file`,accept:`.json`,style:{display:`none`},onChange:e=>{let t=e.target.files?.[0];t&&k(t),e.target.value=``}}),v&&(0,G.jsx)(`span`,{style:{fontSize:12,color:`var(--color-gray-600)`,marginLeft:8},children:v})]}),r.length===0?(0,G.jsx)(`div`,{className:`playground-history-empty`,children:`No test runs saved yet. Complete an automated test run and it will appear here.`}):r.map(e=>(0,G.jsxs)(`div`,{className:`playground-history-item ${o===e.id?`active`:``}`,onClick:()=>T(e.id),children:[(0,G.jsx)(`input`,{type:`checkbox`,checked:c.has(e.id),onClick:e=>e.stopPropagation(),onChange:()=>{l(t=>{let n=new Set(t);return n.has(e.id)?n.delete(e.id):n.add(e.id),n})}}),(0,G.jsxs)(`div`,{className:`playground-history-item-content`,children:[(0,G.jsx)(`div`,{className:`playground-history-item-model`,children:e.modelId||`Unknown model`}),(0,G.jsxs)(`div`,{className:`playground-history-item-meta`,children:[(0,G.jsx)(`span`,{className:`playground-history-item-mode`,children:e.sweepMode===`config`?`Config Sweep`:`Sampling Sweep`}),(0,G.jsx)(`span`,{className:`playground-history-item-date`,children:e.completedAt?new Date(e.completedAt).toLocaleDateString([],{month:`short`,day:`numeric`,year:`numeric`})+`, `+new Date(e.completedAt).toLocaleTimeString([],{hour:`numeric`,minute:`2-digit`}):`—`})]}),(0,G.jsxs)(`div`,{className:`playground-history-item-stats`,children:[e.run.trials?.length??0,` trials`]})]}),(0,G.jsx)(`button`,{className:`btn btn-small btn-danger playground-history-delete`,onClick:t=>{t.stopPropagation(),E(e.id)},children:`Delete`})]},e.id))]})})}var Yb=`__new__`,Xb=JSON.stringify(K,null,2);function Zb({mode:e}){let{models:t,loadModels:n}=In(),{download:r,isDownloading:i,startDownload:a,cancelDownload:o,clearDownload:s}=zn(),{session:c,setSession:l,chatMessages:u,setChatMessages:d,selectedModel:f,setSelectedModel:p,playgroundMode:m,setPlaygroundMode:h,setSweepMode:g,activeTab:_,setActiveTab:v,systemPrompt:y,setSystemPrompt:b,templateMode:S,setTemplateMode:C,selectedTemplate:w,setSelectedTemplate:T,customScript:E,setCustomScript:D,contextWindow:O,setContextWindow:k,prefillBatchSize:A,setPrefillBatchSize:j,nSeqMax:M,setNSeqMax:N,flashAttention:P,setFlashAttention:F,cacheType:I,setCacheType:L,loadMode:R,setLoadMode:z,cacheMode:ee,setCacheMode:B,moeMode:V,setMoeMode:te,moeKeepTopN:H,setMoeKeepTopN:ne,tensorBuftOverrides:re,setTensorBuftOverrides:ie,hydratedModelId:ae,setHydratedModelId:oe}=Ui();(0,x.useEffect)(()=>{e===`manual`?h(`manual`):(h(`automated`),g(e))},[e,h,g]);let[se,ce]=(0,x.useState)([]),[le,ue]=(0,x.useState)(.8),[de,fe]=(0,x.useState)(.9),[pe,me]=(0,x.useState)(40),[he,ge]=(0,x.useState)(0),[_e,ve]=(0,x.useState)(4096),[ye,be]=(0,x.useState)(1),[xe,Se]=(0,x.useState)(64),[Ce,we]=(0,x.useState)(0),[Te,Ee]=(0,x.useState)(0),[De,Oe]=(0,x.useState)(1.05),[ke,Ae]=(0,x.useState)(1.75),[je,Me]=(0,x.useState)(2),[Ne,Pe]=(0,x.useState)(0),[Fe,Ie]=(0,x.useState)(0),[Le,Re]=(0,x.useState)(.1),[ze,Be]=(0,x.useState)(1),[Ve,He]=(0,x.useState)(`true`),[Ue,We]=(0,x.useState)(`medium`),[Ge,Ke]=(0,x.useState)(null),[qe,Je]=(0,x.useState)(null),[Ye,Xe]=(0,x.useState)(!1),[Ze,Qe]=(0,x.useState)(!1),[$e,et]=(0,x.useState)(``),tt=(0,x.useRef)(null),nt=(0,x.useRef)(c);nt.current=c;let[rt,it]=(0,x.useState)(!1),[at,ot]=(0,x.useState)(``),[st,ct]=(0,x.useState)(``),[lt,ut]=(0,x.useState)(!1),dt=(0,x.useRef)(new Set),ft=(0,x.useRef)(!1),pt=(0,x.useRef)(``),mt=Ka(),[ht,gt]=(0,x.useState)(void 0),_t=sa(ht),[vt,yt]=(0,x.useState)(0),[bt,xt]=(0,x.useState)(null),St=$a(bt,ht),Ct=(0,x.useMemo)(()=>ht?Object.entries(ht).some(([e,t])=>e.endsWith(`nextn_predict_layers`)&&parseInt(t,10)>0):!1,[ht]),wt=!!qe?.[`draft-model`]?.[`model-id`],Tt=Ct&&!wt,[Et,Dt]=(0,x.useState)(Xb),[Ot,kt]=(0,x.useState)(`What's the weather in Boston? Use the get_weather tool.`),[At,U]=(0,x.useState)(``),[jt,Mt]=(0,x.useState)([]),[Nt,Pt]=(0,x.useState)(!1),Ft=(0,x.useCallback)(async()=>{try{let e=await W.listPlaygroundTemplates();ce(e)}catch{}},[]);(0,x.useEffect)(()=>{n(),Ft()},[n,Ft]),(0,x.useEffect)(()=>{if(!f||f===Yb){Je(null);return}if(ae===f)return;let e=!1;return Xe(!0),W.showModel(f).then(t=>{if(e)return;let n=t.model_config;if(n){let e=n[`nseq-max`]||1;Je(n),k(n[`context-window`]||8192),j(n[`prefill-batch-size`]||2048),N(e),F(n[`flash-attention`]||`auto`),L(n[`cache-type-k`]||n[`cache-type-v`]||``),z(n[`load-mode`]||`auto`),B(n[`incremental-cache`]?`imc`:`none`),te(n.moe?.mode||``),ne(n.moe?.[`keep-experts-top-n`]??0)}if(gt(t.metadata),xt(t.vram||null),t.metadata){let e=Object.keys(t.metadata).find(e=>e.endsWith(`.block_count`));yt(e&&parseInt(t.metadata[e],10)||0)}oe(f)}).catch(t=>{e||et(t.message||`Failed to load model config`)}).finally(()=>{e||Xe(!1)}),()=>{e=!0}},[f,ae]),(0,x.useEffect)(()=>()=>{tt.current?.()},[]);let It=()=>{let e=at.trim();!e||i||c||(dt.current=new Set(t?.data?.map(e=>e.id)||[]),pt.current=e.split(`/`).pop()||``,ft.current=!0,a(e,st.trim()||void 0))};(0,x.useEffect)(()=>{if(!ft.current)return;if(r?.status===`error`){ft.current=!1;return}if(r?.status!==`complete`)return;let e=dt.current,n=t?.data??[],i=n.filter(t=>!e.has(t.id)),a=pt.current,o=i.find(e=>a&&e.id.includes(a))??i.find(e=>!e.id.includes(`mmproj`)&&!e.id.includes(`proj`))??i[0]??n.find(e=>a&&e.id.includes(a));ft.current=!1,o&&(p(o.id),it(!1),ot(``),ct(``),ut(!1)),s()},[t,r?.status]);let Lt=async()=>{if(f){Qe(!0),et(``);try{let e={};(!qe||O!==(qe[`context-window`]||8192))&&(e.context_window=O),(!qe||A!==(qe[`prefill-batch-size`]||2048))&&(e.prefill_batch_size=A),(!qe||M!==(qe[`nseq-max`]||1))&&(e.nseq_max=M),(!qe||P!==(qe[`flash-attention`]||`auto`))&&(e.flash_attention=P),(!qe||I!==(qe[`cache-type-k`]||``))&&(e.cache_type_k=I||`f16`,e.cache_type_v=I||`f16`),(!qe||R!==(qe[`load-mode`]||`auto`))&&(e.load_mode=R);let t=qe?.[`incremental-cache`]?`imc`:`none`;(!qe||ee!==t)&&(e.incremental_cache=ee===`imc`),V&&(e.moe_mode=V,V===`keep_top_n`&&(e.moe_keep_experts_top_n=H)),V===`custom`&&re.length>0&&(e.tensor_buft_overrides=re),Tt&&Ge!=null&&(e.draft_ndraft=Ge);let n=await W.createPlaygroundSession({model_id:f,template_mode:S,template_name:S===`builtin`?w:void 0,template_script:S===`custom`?E:void 0,config:e});l(n),d([])}catch(e){et(e.message||`Failed to load model`)}finally{Qe(!1)}}},Rt=async()=>{if(c){tt.current?.(),tt.current=null,Pt(!1);try{await W.deletePlaygroundSession(c.session_id),l(null),d([])}catch(e){et(e.message||`Failed to unload model`)}}},zt=(0,x.useCallback)(()=>{if(!c||Nt)return;Pt(!0),U(``),Mt([]);let e;try{e=JSON.parse(Et)}catch{U(`Invalid JSON in tool definitions`),Pt(!1);return}let t=[{role:`user`,content:Ot}],n=``,r=[],i=W.streamPlaygroundChat({session_id:c.session_id,messages:t,tools:e,stream:!0},e=>{let t=e.choices?.[0];if(t?.delta?.content&&(n+=t.delta.content),t?.delta?.tool_calls)for(let e of t.delta.tool_calls){let t=r.find(t=>t.index===e.index);t?(e.id&&!t.id&&(t.id=e.id),e.type&&(t.type=e.type),e.function?.name&&!t.function.name&&(t.function.name=e.function.name),e.function?.arguments&&(t.function.arguments+=e.function.arguments)):r.push({id:e.id||``,index:e.index,type:e.type||`function`,function:{name:e.function?.name||``,arguments:e.function?.arguments||``}})}t?.finish_reason===`tool_calls`&&Mt([...r])},e=>{tt.current=null,U(`Error: ${e}`),Pt(!1)},()=>{tt.current=null,U(n),r.length>0&&Mt([...r]),Pt(!1)});tt.current=i},[c,Nt,Et,Ot]),Bt=(0,x.useMemo)(()=>({maxTokens:_e,temperature:le,topP:de,topK:pe,minP:he,presencePenalty:Te,repeatPenalty:ye,repeatLastN:xe,dryMultiplier:De,dryBase:ke,dryAllowedLen:je,dryPenaltyLast:Ne,xtcProbability:Fe,xtcThreshold:Le,xtcMinKeep:ze,frequencyPenalty:Ce,enableThinking:Ve,reasoningEffort:Ue,includeUsage:!0,logprobs:!1,topLogprobs:0,grammar:``,systemPrompt:y}),[_e,le,de,pe,he,Te,ye,xe,De,ke,je,Ne,Fe,Le,ze,Ce,Ve,Ue,y]),Vt=(0,x.useCallback)(e=>{e.maxTokens!==void 0&&ve(e.maxTokens),e.temperature!==void 0&&ue(e.temperature),e.topP!==void 0&&fe(e.topP),e.topK!==void 0&&me(e.topK),e.minP!==void 0&&ge(e.minP),e.presencePenalty!==void 0&&Ee(e.presencePenalty),e.repeatPenalty!==void 0&&be(e.repeatPenalty),e.repeatLastN!==void 0&&Se(e.repeatLastN),e.dryMultiplier!==void 0&&Oe(e.dryMultiplier),e.dryBase!==void 0&&Ae(e.dryBase),e.dryAllowedLen!==void 0&&Me(e.dryAllowedLen),e.dryPenaltyLast!==void 0&&Pe(e.dryPenaltyLast),e.xtcProbability!==void 0&&Ie(e.xtcProbability),e.xtcThreshold!==void 0&&Re(e.xtcThreshold),e.xtcMinKeep!==void 0&&Be(e.xtcMinKeep),e.frequencyPenalty!==void 0&&we(e.frequencyPenalty),e.enableThinking!==void 0&&He(e.enableThinking),e.reasoningEffort!==void 0&&We(e.reasoningEffort),e.systemPrompt!==void 0&&b(e.systemPrompt)},[b]),Ht=(0,x.useCallback)(({messages:e,sampling:t,onMessage:n,onError:r,onComplete:i})=>c?W.streamPlaygroundChat({session_id:c.session_id,messages:e,stream:!0,stream_options:{include_usage:t.includeUsage},temperature:t.temperature,top_p:t.topP,top_k:t.topK,min_p:t.minP,max_tokens:t.maxTokens,repeat_penalty:t.repeatPenalty,repeat_last_n:t.repeatLastN,frequency_penalty:t.frequencyPenalty,presence_penalty:t.presencePenalty,dry_multiplier:t.dryMultiplier,dry_base:t.dryBase,dry_allowed_length:t.dryAllowedLen,dry_penalty_last_n:t.dryPenaltyLast,xtc_probability:t.xtcProbability,xtc_threshold:t.xtcThreshold,xtc_min_keep:t.xtcMinKeep,enable_thinking:t.enableThinking||void 0,reasoning_effort:t.reasoningEffort||void 0,grammar:t.grammar||void 0,logprobs:t.logprobs,top_logprobs:t.topLogprobs},n,r,i):(r(`No model loaded`),()=>{}),[c]),Ut=(0,x.useCallback)(()=>{d([])},[d]);return(0,G.jsxs)(`div`,{className:`playground-container`,children:[(0,G.jsx)(`div`,{className:`playground-header`,children:(0,G.jsxs)(`div`,{className:`playground-header-title`,children:[(0,G.jsx)(`h2`,{children:e===`manual`?`Basic`:e===`sampling`?`Sampling`:`Configuration`}),(0,G.jsx)(`p`,{className:`playground-header-subtitle`,children:e===`manual`?`Verify a model performs the basic tasks it needs to — chat and tool calling — correctly.`:e===`sampling`?`Find the sampling parameters that produce the best quality and speed for a model.`:`Find the runtime configuration that runs a model the fastest within your hardware limits.`})]})}),(0,G.jsxs)(`div`,{className:`playground-layout`,children:[(0,G.jsxs)(`div`,{className:`playground-mode-selector`,children:[(0,G.jsxs)(`div`,{className:`playground-model-config`,children:[(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(`label`,{children:`Model`}),(0,G.jsx)(qb,{models:t?.data,selectedModel:rt?Yb:f,onSelect:e=>{e===Yb?(p(``),it(!0)):(p(e),it(!1))},disabled:!!c,extraItems:[{id:Yb,label:`New…`}]})]}),rt&&!c&&(0,G.jsxs)(`div`,{className:`playground-pull-form`,children:[(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(`label`,{children:`HuggingFace Model URL or Shorthand`}),(0,G.jsx)(`input`,{type:`text`,value:at,onChange:e=>ot(e.target.value),placeholder:`owner/repo:Q4_K_M or org/repo/model.gguf`,disabled:i})]}),(0,G.jsx)(`button`,{type:`button`,className:`btn btn-secondary btn-small playground-pull-toggle`,onClick:()=>ut(e=>!e),disabled:i,children:lt?`− Hide projection URL`:`+ Projection URL (optional)`}),lt&&(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(`label`,{children:`Projection URL (vision/audio models)`}),(0,G.jsx)(`input`,{type:`text`,value:st,onChange:e=>ct(e.target.value),placeholder:`org/repo/mmproj.gguf`,disabled:i})]}),(0,G.jsxs)(`div`,{className:`playground-pull-actions`,children:[(0,G.jsx)(`button`,{className:`btn btn-primary`,type:`button`,onClick:It,disabled:i||!at.trim(),children:i?`Pulling…`:`Pull`}),i&&(0,G.jsx)(`button`,{className:`btn btn-danger`,type:`button`,onClick:o,children:`Cancel`}),r&&r.status!==`downloading`&&(0,G.jsx)(`button`,{className:`btn`,type:`button`,onClick:s,children:`Clear`})]}),r&&r.meta&&(0,G.jsx)(is,{meta:r.meta}),r&&r.progress&&i&&(0,G.jsx)(Uo,{progress:r.progress,meta:r.meta}),r&&r.messages.length>0&&(0,G.jsx)(`div`,{className:`status-box playground-pull-status`,children:r.messages.map((e,t)=>(0,G.jsx)(`div`,{className:`status-line ${e.type}`,children:e.text},t))})]}),(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(`label`,{htmlFor:`pg-template-mode`,children:`Template Mode`}),(0,G.jsxs)(`select`,{id:`pg-template-mode`,value:S,onChange:e=>C(e.target.value),disabled:!!c,children:[(0,G.jsx)(`option`,{value:`builtin`,children:`Builtin`}),(0,G.jsx)(`option`,{value:`custom`,children:`Custom`})]})]}),S===`builtin`?(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(`label`,{htmlFor:`pg-template`,children:`Template`}),(0,G.jsxs)(`select`,{id:`pg-template`,value:w,onChange:e=>T(e.target.value),disabled:!!c,children:[(0,G.jsx)(`option`,{value:``,children:`Auto (from catalog)`}),se.map(e=>(0,G.jsx)(`option`,{value:e.name,children:e.name},e.name))]})]}):(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(`label`,{htmlFor:`pg-template-script`,children:`Template Script`}),(0,G.jsx)(`textarea`,{id:`pg-template-script`,value:E,onChange:e=>D(e.target.value),disabled:!!c,rows:8,className:`playground-textarea`,placeholder:`Paste Jinja template...`})]})]}),mt&&(0,G.jsxs)(`div`,{className:`playground-system-info`,children:[mt.gpuCount>0&&(0,G.jsxs)(`span`,{children:[mt.gpuCount,` GPU`,mt.gpuCount>1?`s`:``,mt.gpuType?` (${mt.gpuType})`:``]}),mt.gpuDevices.map(e=>(0,G.jsxs)(`span`,{children:[e.name,`: `,e.description||e.name,` (`,e.hardware_type,`, `,e.backend,`)`]},e.index)),mt.gpuVramBytes>0&&(0,G.jsxs)(`span`,{children:[`Total VRAM: `,J(mt.gpuVramBytes)]}),mt.ramBytes>0&&(0,G.jsxs)(`span`,{children:[`System RAM: `,J(mt.ramBytes)]})]}),(0,G.jsx)(`button`,{className:`playground-mode-btn ${m===`history`?``:`active`}`,onClick:()=>h(e===`manual`?`manual`:`automated`),children:e===`manual`?`Basic`:e===`sampling`?`Sampling`:`Configuration`}),e!==`manual`&&(0,G.jsx)(`button`,{className:`playground-mode-btn ${m===`history`?`active`:``}`,onClick:()=>h(`history`),children:`History`})]}),m===`automated`&&(0,G.jsx)(`div`,{className:`playground-test`,style:{flex:1},children:(0,G.jsx)(`div`,{className:`playground-tab-content`,children:(0,G.jsx)(Hb,{session:c,catalogSampling:qe?.[`sampling-parameters`]??null,isMoE:St,gpuVramBytes:mt?.gpuVramBytes,lockSweep:e===`sampling`||e===`config`,sessionSeed:{model_id:f,template_mode:S,template_name:S===`builtin`?w:void 0,template_script:S===`custom`?E:void 0,base_config:{context_window:O,prefill_batch_size:A,nseq_max:M,flash_attention:P,cache_type_k:I||void 0,cache_type_v:I||void 0,load_mode:R,incremental_cache:ee===`imc`,moe_mode:V||void 0,moe_keep_experts_top_n:V===`keep_top_n`?H:void 0,tensor_buft_overrides:V===`custom`&&re.length>0?re:void 0,draft_ndraft:Tt&&Ge!=null?Ge:void 0}}})})}),m===`history`&&(0,G.jsx)(`div`,{className:`playground-test`,style:{flex:1},children:(0,G.jsx)(`div`,{className:`playground-tab-content`,children:(0,G.jsx)(Jb,{filterMode:e===`sampling`||e===`config`?e:void 0})})}),m===`manual`&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(`div`,{className:`playground-setup`,children:[(0,G.jsx)(`h3`,{children:`Setup`}),St&&!c&&mt&&(0,G.jsxs)(`div`,{className:`playground-moe-guide`,children:[(0,G.jsxs)(`div`,{className:`playground-moe-guide-header`,children:[(0,G.jsx)(`span`,{className:`playground-moe-guide-icon`,children:`🧩`}),(0,G.jsx)(`span`,{children:`Mixture of Experts Model Detected`})]}),(0,G.jsx)(`div`,{className:`playground-moe-guide-body`,children:(0,G.jsxs)(`div`,{className:`playground-moe-guide-hw`,children:[(0,G.jsx)(`strong`,{children:`Your Hardware:`}),` `,mt.gpuType||`GPU`,` — `,J(mt.gpuVramBytes),` VRAM, `,J(mt.ramBytes),` RAM`]})})]}),(0,G.jsx)(`h4`,{children:`Configuration`}),(0,G.jsxs)(`div`,{className:`playground-config-grid-fluid`,children:[(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(X,{htmlFor:`pg-context-window`,tooltipKey:`contextWindow`,children:`Context Window`}),(0,G.jsx)(`input`,{id:`pg-context-window`,type:`number`,value:O,onChange:e=>k(Number(e.target.value)),disabled:!!c,max:_t?.max}),_t&&_t.hasRoPE&&(0,G.jsx)(`div`,{style:{fontSize:`11px`,color:`var(--color-gray-500)`,marginTop:2},children:ca(_t)})]}),(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(X,{htmlFor:`pg-prefill-batch-size`,tooltipKey:`prefillBatchSize`,children:`Prefill Batch Size`}),(0,G.jsx)(`input`,{id:`pg-prefill-batch-size`,type:`number`,value:A,onChange:e=>j(Number(e.target.value)),min:1,disabled:!!c})]}),(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(X,{htmlFor:`pg-nseqmax`,tooltipKey:`nSeqMax`,children:`NSeqMax`}),(0,G.jsx)(`input`,{id:`pg-nseqmax`,type:`number`,value:M,onChange:e=>N(Number(e.target.value)),min:1,disabled:!!c})]}),(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(X,{htmlFor:`pg-flash-attn`,tooltipKey:`flashAttention`,children:`Flash Attention`}),(0,G.jsxs)(`select`,{id:`pg-flash-attn`,value:P,onChange:e=>F(e.target.value),disabled:!!c,children:[(0,G.jsx)(`option`,{value:`auto`,children:`Auto`}),(0,G.jsx)(`option`,{value:`enabled`,children:`Enabled`}),(0,G.jsx)(`option`,{value:`disabled`,children:`Disabled`})]})]}),(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(X,{htmlFor:`pg-cache-type`,tooltipKey:`cacheType`,children:`KV Cache Type`}),(0,G.jsxs)(`select`,{id:`pg-cache-type`,value:I,onChange:e=>L(e.target.value),disabled:!!c,children:[(0,G.jsx)(`option`,{value:``,children:`Default (f16)`}),(0,G.jsx)(`option`,{value:`f16`,children:`f16`}),(0,G.jsx)(`option`,{value:`q8_0`,children:`q8_0`}),(0,G.jsx)(`option`,{value:`q4_0`,children:`q4_0`})]})]}),(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(X,{htmlFor:`pg-load-mode`,tooltipKey:`loadMode`,children:`Load Mode`}),(0,G.jsxs)(`select`,{id:`pg-load-mode`,value:R,onChange:e=>z(e.target.value),disabled:!!c,children:[(0,G.jsx)(`option`,{value:`auto`,children:`auto (default)`}),(0,G.jsx)(`option`,{value:`mmap`,children:`mmap`}),(0,G.jsx)(`option`,{value:`none`,children:`none`}),(0,G.jsx)(`option`,{value:`mlock`,children:`mlock`}),(0,G.jsx)(`option`,{value:`mmap+mlock`,children:`mmap+mlock`}),(0,G.jsx)(`option`,{value:`direct-io`,children:`direct-io`})]})]}),(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(X,{tooltipKey:`cacheMode`,children:`Cache Mode`}),(0,G.jsxs)(`select`,{value:ee,onChange:e=>B(e.target.value),disabled:!!c,children:[(0,G.jsx)(`option`,{value:`none`,children:`None`}),(0,G.jsx)(`option`,{value:`imc`,children:`IMC (Incremental)`})]})]}),St&&(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(X,{htmlFor:`pg-moe-mode`,tooltipKey:`moeMode`,children:`Expert Strategy`}),(0,G.jsx)(`select`,{id:`pg-moe-mode`,value:V,onChange:e=>te(e.target.value),disabled:!!c,children:eo.map(e=>(0,G.jsx)(`option`,{value:e.value,children:e.label},e.value))})]}),St&&V===`keep_top_n`&&(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsxs)(X,{htmlFor:`pg-moe-topn`,tooltipKey:`moeKeepExpertsTopN`,children:[`GPU Expert Layers (`,H,` of `,vt||`?`,` — more = faster, more VRAM)`]}),(0,G.jsx)(`input`,{id:`pg-moe-topn`,type:`range`,value:H,onChange:e=>ne(Number(e.target.value)),min:0,max:vt||64,disabled:!!c})]}),Tt&&(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(X,{htmlFor:`pg-mtp-ndraft`,tooltipKey:`mtpNDraft`,children:`⚡ MTP Draft Tokens`}),(0,G.jsx)(`input`,{id:`pg-mtp-ndraft`,type:`number`,value:Ge??``,placeholder:`4 (default)`,onChange:e=>Ke(e.target.value===``?null:Number(e.target.value)),min:1,max:20,disabled:!!c})]})]}),St&&(V===`experts_cpu`||V===`keep_top_n`)&&(0,G.jsxs)(`div`,{className:`playground-moe-tips`,style:{fontSize:`0.85em`,color:`var(--color-text-secondary, #aaa)`,padding:`0 0 8px`,lineHeight:1.4},children:[`💡 `,ia.moeTipBatch,` `,ia.moeTipFlashAttention]}),St&&V===`custom`&&(0,G.jsxs)(`div`,{className:`playground-moe-custom`,children:[(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(`label`,{children:`Tensor Buffer Overrides`}),(0,G.jsx)(`p`,{style:{fontSize:`0.8em`,color:`var(--color-text-secondary, #aaa)`,margin:`0 0 8px`},children:`Select which tensors to offload to CPU. These are applied as tensor-buft-overrides.`})]}),(0,G.jsxs)(`div`,{className:`playground-moe-shortcuts`,children:[(0,G.jsxs)(`label`,{className:`playground-moe-shortcut`,children:[(0,G.jsx)(`input`,{type:`checkbox`,checked:re.includes(`moe-experts`),onChange:e=>{ie(t=>e.target.checked?[...t.filter(e=>e!==`moe-experts`),`moe-experts`]:t.filter(e=>e!==`moe-experts`))},disabled:!!c}),`All expert FFN tensors → CPU`,(0,G.jsx)(`span`,{className:`playground-moe-shortcut-hint`,children:`moe-experts`})]}),(0,G.jsxs)(`label`,{className:`playground-moe-shortcut`,children:[(0,G.jsx)(`input`,{type:`checkbox`,checked:re.includes(`all-ffn`),onChange:e=>{ie(t=>e.target.checked?[...t.filter(e=>e!==`all-ffn`),`all-ffn`]:t.filter(e=>e!==`all-ffn`))},disabled:!!c}),`All FFN tensors → CPU`,(0,G.jsx)(`span`,{className:`playground-moe-shortcut-hint`,children:`all-ffn`})]})]}),vt>0&&(0,G.jsxs)(`div`,{className:`form-group`,style:{marginTop:8},children:[(0,G.jsx)(`label`,{children:`Block-Specific Overrides`}),(0,G.jsx)(`div`,{style:{display:`flex`,gap:6,alignItems:`center`,flexWrap:`wrap`},children:(0,G.jsxs)(`select`,{id:`pg-moe-block-select`,disabled:!!c,defaultValue:``,onChange:e=>{let t=e.target.value;t&&(ie(e=>e.includes(t)?e:[...e,t]),e.target.value=``)},children:[(0,G.jsx)(`option`,{value:``,children:`Add block override…`}),Array.from({length:vt},(e,t)=>(0,G.jsxs)(`option`,{value:`moe-experts:block:${t}`,children:[`Block `,t,` expert tensors → CPU`]},t)),Array.from({length:vt},(e,t)=>(0,G.jsxs)(`option`,{value:`block:${t}`,children:[`Block `,t,` (all tensors) → CPU`]},`block-${t}`))]})})]}),re.length>0&&(0,G.jsx)(`div`,{className:`playground-moe-overrides-list`,children:re.map((e,t)=>(0,G.jsxs)(`div`,{className:`playground-moe-override-item`,children:[(0,G.jsx)(`code`,{children:e}),(0,G.jsx)(`button`,{type:`button`,className:`playground-moe-override-remove`,onClick:()=>ie(e=>e.filter((e,n)=>n!==t)),disabled:!!c,title:`Remove`,children:`×`})]},t))}),(0,G.jsxs)(`div`,{className:`form-group`,style:{marginTop:8},children:[(0,G.jsx)(`label`,{htmlFor:`pg-moe-raw-override`,children:`Custom Pattern (regex)`}),(0,G.jsx)(`div`,{style:{display:`flex`,gap:6},children:(0,G.jsx)(`input`,{id:`pg-moe-raw-override`,type:`text`,placeholder:`e.g., blk\\.5\\.ffn_.*`,disabled:!!c,onKeyDown:e=>{if(e.key===`Enter`){let t=e.target.value.trim();t&&(ie(e=>e.includes(t)?e:[...e,t]),e.target.value=``)}}})})]})]}),(0,G.jsx)(`div`,{className:`playground-session-controls`,children:c?(0,G.jsx)(`button`,{className:`btn btn-danger`,onClick:Rt,children:`Unload Model`}):(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:Lt,disabled:!f||Ze||Ye,children:Ze?`Loading Model...`:Ye?`Loading Config...`:`Load Model`})}),$e&&(0,G.jsx)(`div`,{className:`playground-error`,children:$e}),c&&(0,G.jsxs)(`div`,{className:`playground-session-info`,children:[(0,G.jsx)(`strong`,{children:`Status:`}),` `,c.status,c.effective_config&&(0,G.jsxs)(`div`,{className:`playground-effective-config`,children:[(0,G.jsx)(`strong`,{children:`Effective Config:`}),(0,G.jsx)(`div`,{className:`playground-config-grid`,children:Object.entries(c.effective_config).map(([e,t])=>(0,G.jsxs)(`div`,{className:`playground-config-item`,children:[(0,G.jsxs)(`span`,{className:`playground-config-key`,children:[e,`:`]}),` `,(0,G.jsx)(`span`,{className:`playground-config-value`,children:String(t)})]},e))})]})]})]}),(0,G.jsxs)(`div`,{className:`playground-test`,children:[(0,G.jsxs)(`div`,{className:`playground-tabs`,role:`tablist`,children:[(0,G.jsx)(`button`,{role:`tab`,id:`tab-chat`,"aria-selected":_===`chat`,"aria-controls":`tabpanel-chat`,className:`playground-tab ${_===`chat`?`active`:``}`,onClick:()=>v(`chat`),children:`Basic Chat`}),(0,G.jsx)(`button`,{role:`tab`,id:`tab-tools`,"aria-selected":_===`tools`,"aria-controls":`tabpanel-tools`,className:`playground-tab ${_===`tools`?`active`:``}`,onClick:()=>v(`tools`),children:`Tool Calling Test`})]}),(0,G.jsxs)(`div`,{className:`playground-tab-content`,children:[_===`chat`&&(0,G.jsx)(`div`,{role:`tabpanel`,id:`tabpanel-chat`,"aria-labelledby":`tab-chat`,className:`playground-chat`,children:(0,G.jsx)(xv,{messages:u,setMessages:d,onClear:Ut,sampling:Bt,setSampling:Vt,modelBaseline:null,transport:Ht,modelVRAM:bt,isMoE:St,disabled:!c,disabledPlaceholder:`Load a model to start chatting`,headerLeft:(0,G.jsx)(`h2`,{children:`Basic Chat`})})}),_===`tools`&&(0,G.jsxs)(`div`,{role:`tabpanel`,id:`tabpanel-tools`,"aria-labelledby":`tab-tools`,className:`playground-tools`,children:[(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(`label`,{children:`Tool Definitions (JSON)`}),(0,G.jsx)(`textarea`,{value:Et,onChange:e=>Dt(e.target.value),rows:12,className:`playground-textarea monospace`})]}),(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(`label`,{children:`Test Prompt`}),(0,G.jsx)(`input`,{type:`text`,value:Ot,onChange:e=>kt(e.target.value)})]}),(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:zt,disabled:!c||Nt,children:Nt?`Running...`:`Run Test`}),(jt.length>0||At)&&(0,G.jsxs)(`div`,{className:`playground-tool-results`,children:[(0,G.jsx)(`h4`,{children:`Results`}),jt.length>0?(0,G.jsxs)(`div`,{className:`playground-tool-pass`,children:[(0,G.jsx)(`span`,{className:`playground-badge success`,children:`PASS`}),`Model emitted `,jt.length,` tool call(s)`,jt.map((e,t)=>(0,G.jsxs)(`div`,{className:`playground-tool-call`,children:[(0,G.jsx)(`strong`,{children:e.function.name}),(0,G.jsx)(`pre`,{children:e.function.arguments}),e.id&&(0,G.jsxs)(`small`,{children:[`ID: `,e.id]})]},t))]}):(0,G.jsxs)(`div`,{className:`playground-tool-fail`,children:[(0,G.jsx)(`span`,{className:`playground-badge fail`,children:`NO TOOL CALLS`}),(0,G.jsx)(`pre`,{children:At})]})]})]})]})]})]})]})]})}function Qb(){return(0,G.jsx)(Zb,{mode:`manual`})}function $b(){return(0,G.jsx)(Zb,{mode:`sampling`})}function ex(){return(0,G.jsx)(Zb,{mode:`config`})}function tx(e,t){let n=[...e];return n.sort((e,n)=>{switch(t){case`loc`:return e.loc-n.loc||e.line-n.line;case`name`:return e.identifier.localeCompare(n.identifier);default:return e.line-n.line}}),n}function nx(e){return e>=90?`accuracy-match-good`:e>=50?`accuracy-match-mid`:`accuracy-match-bad`}function rx(e,t){return e.match_percent===t.match_percent?e.usage.tokens_per_second===t.usage.tokens_per_second?e.usage.completion_tokens-t.usage.completion_tokens:t.usage.tokens_per_second-e.usage.tokens_per_second:t.match_percent-e.match_percent}function ix({result:e,title:t=`Code Difference`}){return(0,G.jsxs)(`div`,{className:`accuracy-diff-wrap`,children:[(0,G.jsxs)(`div`,{className:`accuracy-diff-header`,children:[(0,G.jsx)(`span`,{className:`accuracy-diff-title`,children:t}),(0,G.jsxs)(`span`,{className:`accuracy-diff-key`,children:[(0,G.jsx)(`span`,{className:`accuracy-diff-key-item accuracy-diff-del`,children:`- got (model output)`}),(0,G.jsx)(`span`,{className:`accuracy-diff-key-item accuracy-diff-add`,children:`+ want (actual source)`})]})]}),(0,G.jsx)(`div`,{className:`accuracy-diff`,children:(0,G.jsx)(`pre`,{children:e.diff.map((e,t)=>(0,G.jsxs)(`div`,{className:`accuracy-diff-line accuracy-diff-${e.op}`,children:[(0,G.jsx)(`span`,{className:`accuracy-diff-gutter`,children:e.op===`add`?`+`:e.op===`del`?`-`:` `}),(0,G.jsx)(`span`,{className:`accuracy-diff-text`,children:e.text||` `})]},t))})})]})}function ax(){let{models:e,loading:t}=In(),{mode:n,setMode:r,selectedModel:i,setSelectedModel:a,functions:o,sortBy:s,setSortBy:c,error:l,selectedFn:u,setSelectedFn:d,running:f,result:p,runManual:m,stopManual:h,clearManual:g,checked:_,setChecked:v,randomCount:y,setRandomCount:b,rows:S,batchRunning:C,expanded:w,toggle:T,clearAll:E,pickRandom:D,runBatch:O,stopBatch:k,toggleExpand:A,compareModels:j,compareFn:M,setCompareFn:N,compareCells:P,comparing:F,compareLayout:I,setCompareLayout:L,toggleCompareModel:R,clearCompare:z,runCompare:ee,stopCompare:B,isRunning:V}=Ii(),te=(0,x.useMemo)(()=>o?tx(o,s):[],[o,s]),H=S.filter(e=>e.status===`done`||e.status===`error`),ne=S.filter(e=>e.status===`done`&&e.result),re=(0,x.useMemo)(()=>ne.length===0?null:ne.reduce((e,t)=>e+(t.result?.match_percent??0),0)/ne.length,[ne]),ie=P.filter(e=>e.status===`done`||e.status===`error`).length,ae=te.find(e=>e.identifier===M),oe=(0,x.useMemo)(()=>{let e=P.filter(e=>e.status===`done`&&e.result);if(e.length<2)return null;let t=[...e].sort((e,t)=>rx(e.result,t.result)),n=t[0].result,r=t.filter(e=>rx(e.result,n)===0).map(e=>e.model);if(r.length>1)return{winners:r,tied:!0,reason:`identical match, speed & length`};let i=t[1].result,a;return a=n.match_percent>i.match_percent?`highest match`:n.usage.tokens_per_second>i.usage.tokens_per_second?`fastest`:`fewest tokens`,{winners:r,tied:!1,reason:a}},[P]),se=(0,G.jsxs)(`span`,{className:`accuracy-functions-meta`,children:[(0,G.jsxs)(`span`,{className:`accuracy-count`,children:[o?.length??0,` functions`]}),(0,G.jsxs)(`span`,{className:`accuracy-sort`,children:[(0,G.jsx)(`label`,{htmlFor:`accuracy-sort`,children:`Sort by:`}),(0,G.jsxs)(`select`,{id:`accuracy-sort`,value:s,onChange:e=>c(e.target.value),children:[(0,G.jsx)(`option`,{value:`line`,children:`Line number`}),(0,G.jsx)(`option`,{value:`loc`,children:`Lines of Code`}),(0,G.jsx)(`option`,{value:`name`,children:`Name`})]})]})]});return(0,G.jsxs)(`div`,{className:`accuracy-page`,children:[(0,G.jsxs)(`div`,{className:`page-header`,children:[(0,G.jsx)(`h2`,{children:`Accuracy`}),(0,G.jsx)(`p`,{children:`Test how accurately a model recalls source code. Pick a model and a function, then compare the model's output to the real source — in single, batch, or compare mode.`})]}),(0,G.jsxs)(`div`,{className:`tabs`,children:[(0,G.jsx)(`button`,{className:`tab ${n===`manual`?`active`:``}`,onClick:()=>r(`manual`),children:`Manual`}),(0,G.jsx)(`button`,{className:`tab ${n===`batch`?`active`:``}`,onClick:()=>r(`batch`),children:`Batch`}),(0,G.jsx)(`button`,{className:`tab ${n===`compare`?`active`:``}`,onClick:()=>r(`compare`),children:`Compare`})]}),n!==`compare`&&(0,G.jsx)(`div`,{className:`card accuracy-setup`,children:(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(`label`,{children:`Model`}),(0,G.jsxs)(`select`,{value:i,onChange:e=>a(e.target.value),disabled:t||V,children:[t&&(0,G.jsx)(`option`,{children:`Loading models...`}),!t&&e?.data?.filter(e=>Ni(e.id)).length===0&&(0,G.jsx)(`option`,{children:`No models available`}),e?.data?.filter(e=>Ni(e.id)).map(e=>(0,G.jsx)(`option`,{value:e.id,children:e.id},e.id))]})]})}),l&&(0,G.jsx)(`div`,{className:`accuracy-error`,children:l}),o&&o.length>0&&(0,G.jsxs)(G.Fragment,{children:[n===`manual`&&(0,G.jsxs)(`div`,{className:`card`,children:[(0,G.jsxs)(`div`,{className:`form-row`,children:[(0,G.jsxs)(`div`,{className:`form-group`,style:{flex:1},children:[(0,G.jsxs)(`div`,{className:`accuracy-label-row`,children:[(0,G.jsx)(`label`,{children:`Select a Function:`}),se]}),(0,G.jsx)(`select`,{value:u,onChange:e=>d(e.target.value),disabled:f,children:te.map(e=>(0,G.jsxs)(`option`,{value:e.identifier,children:[e.identifier,` (`,e.loc,` loc) — line `,e.line]},e.identifier))})]}),(0,G.jsxs)(`div`,{className:`form-group`,style:{alignSelf:`flex-end`,display:`flex`,flexDirection:`row`,gap:`0.5rem`},children:[f?(0,G.jsx)(`button`,{className:`btn btn-danger`,onClick:h,children:`Stop`}):(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:m,disabled:!i||!u||V,children:`Run test`}),(0,G.jsx)(`button`,{className:`btn btn-secondary`,onClick:g,disabled:f||!p&&!l,children:`Clear`})]})]}),p&&(0,G.jsxs)(`div`,{className:`accuracy-result`,children:[(0,G.jsxs)(`div`,{className:`accuracy-result-top`,children:[(0,G.jsxs)(`span`,{className:`accuracy-match ${nx(p.match_percent)}`,children:[p.match_percent.toFixed(2),`% match`]}),(0,G.jsxs)(`span`,{className:`accuracy-meta`,children:[p.model,` · `,p.usage.prompt_tokens,` in /`,` `,p.usage.completion_tokens,` out · `,p.usage.tokens_per_second.toFixed(1),` tps`]})]}),(0,G.jsxs)(`div`,{className:`accuracy-fields`,children:[(0,G.jsxs)(`span`,{children:[`Function: `,(0,G.jsxs)(`strong`,{children:[p.function,` (`,p.want.split(`
+`,` `,(0,G.jsx)(`span`,{style:{color:`var(--accent, #60a5fa)`,fontWeight:600},children:`Provider`}),` `,(0,G.jsx)(`span`,{style:{color:`var(--success, #4ade80)`,fontWeight:600},children:`Family`}),` `,(0,G.jsx)(`span`,{style:{color:`var(--warning, #fbbf24)`,fontWeight:600},children:`Model`})]}),(0,G.jsxs)(`ul`,{style:{margin:`4px 0 0 0`,paddingLeft:`20px`,fontSize:`13px`},children:[(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`strong`,{children:`Model is optional.`}),` Leave it blank and click `,(0,G.jsx)(`em`,{children:`Browse files`}),` to see every GGUF in the repo and pick one.`]}),(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`strong`,{children:`Quant shortcut.`}),` The Model field also accepts just a quant tag (e.g. `,(0,G.jsx)(`code`,{children:`Q4_K_M`}),`, `,(0,G.jsx)(`code`,{children:`Q8_0`}),`, `,(0,G.jsx)(`code`,{children:`BF16`}),`) — we'll find the matching file in the repo for you.`]}),(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`strong`,{children:`Local models.`}),` When the full basename is filled and the model is already installed, the calculator uses the on-disk file and skips HuggingFace.`]}),(0,G.jsxs)(`li`,{children:[(0,G.jsx)(`strong`,{children:`Paste anything.`}),` Pasting a full HuggingFace URL or`,` `,(0,G.jsx)(`code`,{children:`owner/repo[/file.gguf]`}),` shorthand into the Provider field auto-splits it across all three fields.`]})]})]}),(0,G.jsxs)(`div`,{className:`card`,children:[(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsxs)(`label`,{htmlFor:`provider`,children:[`Provider `,(0,G.jsx)(`span`,{style:{opacity:.6},children:`(required)`})]}),(0,G.jsx)(`input`,{type:`text`,id:`provider`,value:e,onChange:e=>t(e.target.value),onPaste:A,onKeyDown:j,placeholder:`unsloth`,disabled:u||f})]}),(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsxs)(`label`,{htmlFor:`family`,children:[`Family `,(0,G.jsx)(`span`,{style:{opacity:.6},children:`(required)`})]}),(0,G.jsx)(`input`,{type:`text`,id:`family`,value:n,onChange:e=>r(e.target.value),onKeyDown:j,placeholder:`Qwen3-0.6B-GGUF`,disabled:u||f})]}),(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsxs)(`label`,{htmlFor:`model`,children:[`Model `,(0,G.jsx)(`span`,{style:{opacity:.6},children:`(optional — full basename, just a quant tag, or blank)`})]}),(0,G.jsx)(`input`,{type:`text`,id:`model`,value:i,onChange:e=>a(e.target.value),onKeyDown:j,placeholder:`Qwen3-0.6B-Q8_0 · Q4_K_M · (blank)`,disabled:u||f})]}),(0,G.jsxs)(`div`,{style:{display:`flex`,gap:`8px`},children:[(0,G.jsx)(`button`,{type:`button`,className:`btn btn-primary`,onClick:()=>{D()},disabled:u||f||!E,children:u?`Looking up…`:f?`Calculating…`:i.trim()?`Calculate VRAM`:`Browse files`}),(o||m||c)&&!f&&!u&&(0,G.jsx)(`button`,{type:`button`,className:`btn`,onClick:()=>{s(null),l(null),h(null),_(``),y(``),S(``),C.current=``},disabled:u,children:`Clear`})]}),c&&(0,G.jsx)(`div`,{className:`status-box`,children:(0,G.jsx)(`div`,{className:`status-line error`,children:c})}),o&&(()=>{let t=$o(o);return(0,G.jsxs)(`div`,{className:`card`,style:{background:`var(--bg-2, #1a1a1a)`,marginTop:`12px`},children:[(0,G.jsxs)(`div`,{style:{marginBottom:`12px`},children:[(0,G.jsx)(`strong`,{children:`Pick a file from `}),(0,G.jsxs)(`code`,{children:[e.trim(),`/`,n.trim()]}),(0,G.jsxs)(`span`,{style:{fontSize:`12px`,opacity:.7,marginLeft:`8px`},children:[`(`,t.length,` GGUF model`,t.length===1?``:`s`,`)`]})]}),t.length===0?(0,G.jsx)(`div`,{style:{opacity:.7},children:`No GGUF files found in this repository.`}):(0,G.jsxs)(`table`,{className:`kv-table`,children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{style:{textAlign:`left`},children:`Filename`}),(0,G.jsx)(`th`,{children:`Size`}),(0,G.jsx)(`th`,{})]})}),(0,G.jsx)(`tbody`,{children:t.map(e=>(0,G.jsxs)(`tr`,{children:[(0,G.jsxs)(`td`,{children:[(0,G.jsx)(`code`,{style:{wordBreak:`break-all`},children:e.label}),e.parts>1&&(0,G.jsxs)(`span`,{style:{fontSize:`11px`,opacity:.7,marginLeft:`8px`},children:[`(`,e.parts,` shards)`]})]}),(0,G.jsx)(`td`,{style:{whiteSpace:`nowrap`},children:e.sizeStr}),(0,G.jsx)(`td`,{children:(0,G.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:()=>k(e.filename),disabled:u||f,children:`Select`})})]},e.label))})]})]})})(),(0,G.jsx)(`div`,{style:{marginTop:`16px`},children:(0,G.jsx)(Ha,{controlsProps:w,resultsProps:T,variant:`form`,hideResults:!0})})]}),(f||u)&&(0,G.jsxs)(`div`,{className:`vram-loading-banner`,children:[(0,G.jsx)(`span`,{className:`vram-loading-spinner`}),(0,G.jsx)(`span`,{children:u?`Looking up repository…`:`Fetching model header (up to 16 MB)…`})]}),T&&(0,G.jsx)(Ha,{controlsProps:w,resultsProps:T,hideControls:!0,modelUrl:g})]})}var Qy=[{kind:`sampling`,label:`Sampling Sweep`},{kind:`config`,label:`Config Sweep`}];function $y(e){if(!Number.isFinite(e))return`—`;let t=Math.max(0,Math.round(e));if(t<1e3)return`${t}ms`;let n=Math.floor(t/36e5),r=Math.floor(t%36e5/6e4),i=Math.floor(t%6e4/1e3),a=t%1e3;return n>0?`${n}h ${r}m ${i}s ${a}ms`:r>0?`${r}m ${i}s ${a}ms`:`${i}s ${a}ms`}function eb(e){return e>=80?`#2e7d32`:e>=50?`#f9a825`:`#c62828`}function tb(e){return eb(e??0)}function nb(e){return e!==void 0&&Number.isFinite(e)?e.toFixed(1):`—`}function rb(e,t){return e.scenarioResults.find(e=>e.scenarioId===t)?.score}function ib(e){return e.scenarioResults.find(e=>e.avgTPS!==void 0)?.avgTPS}function ab(e){return e.scenarioResults.find(e=>e.avgTTFT!==void 0)?.avgTTFT}function ob(e,t){return e.scenarioResults.find(e=>e.avgTPSByFill?.[t]!==void 0)?.avgTPSByFill?.[t]}function sb(e,t){return e.scenarioResults.find(e=>e.avgTTFTByFill?.[t]!==void 0)?.avgTTFTByFill?.[t]}function cb(e){let t=e.startedAt?Date.parse(e.startedAt):NaN;if(Number.isFinite(t))return(e.finishedAt?Date.parse(e.finishedAt):Date.now())-t}function lb(e,t,n,r){return n?r?`Error: ${r}`:`Error`:e.status===`failed`?`Failed`:t.isInProgress?`Running…`:e.status===`skipped`?`Skipped`:e.status===`queued`?`Queued`:t.isPending?`…`:`OK`}function ub(e,t,n){return n||e.status===`failed`?{color:`#c62828`,fontSize:`0.85em`}:t.isInProgress?{color:`#1565c0`}:e.status===`skipped`?{color:`#9e9e9e`,fontStyle:`italic`,fontSize:`0.85em`}:e.status===`queued`?{color:`#999`}:t.isPending?{color:`#666`}:{color:`#2e7d32`}}var db=[`0%`,`20%`,`50%`,`80%`];function fb(){let e=db.map(e=>({id:`tps_${e.replace(`%`,``)}`,title:`TPS @${e}`,sortable:!0,getValue:t=>t.avgTPSByFill?.[e]??ob(t,e),renderCell:(t,n)=>n.isPending?`…`:t.avgTPSByFill?.[e]?.toFixed(1)??`—`})),t=db.map(e=>({id:`ttft_${e.replace(`%`,``)}`,title:`TTFT @${e}`,sortable:!0,getValue:t=>t.avgTTFTByFill?.[e]??sb(t,e),renderCell:(t,n)=>n.isPending?`…`:t.avgTTFTByFill?.[e]===void 0?`—`:$y(t.avgTTFTByFill[e])}));return[{id:`avg_tps`,title:`Avg TPS`,sortable:!0,getValue:e=>e.avgTPS??ib(e),renderCell:(e,t)=>{if(t.isPending){let t=ib(e);return t===void 0?`…`:`~${t.toFixed(1)}`}return e.avgTPS?.toFixed(1)??`—`}},{id:`avg_ttft`,title:`Avg TTFT`,sortable:!0,getValue:e=>e.avgTTFT??ab(e),renderCell:(e,t)=>t.isPending?`…`:e.avgTTFT===void 0?`—`:$y(e.avgTTFT)},...e,...t]}function pb(){return{id:`status`,title:`Status`,sortable:!0,getValue:e=>e.status,renderCell:(e,t)=>(0,G.jsx)(`span`,{style:ub(e,t,e.status===`failed`),children:lb(e,t,e.status===`failed`)})}}function mb(){return{id:`status`,title:`Status`,sortable:!0,getValue:e=>e.error?`error`:e.status,renderCell:(e,t)=>(0,G.jsx)(`span`,{style:ub(e,t,!!e.error),children:lb(e,t,!!e.error,e.error)})}}function hb(){return{id:`duration`,title:`Duration`,sortable:!0,getValue:e=>cb(e),renderCell:e=>{let t=cb(e);return t===void 0?`—`:$y(t)}}}function gb(){return[{id:`temperature`,title:`Temperature`,sortable:!0,getValue:e=>e.candidate.temperature,renderCell:e=>e.candidate.temperature??`—`},{id:`top_p`,title:`Top P`,sortable:!0,getValue:e=>e.candidate.top_p,renderCell:e=>e.candidate.top_p??`—`},{id:`top_k`,title:`Top K`,sortable:!0,getValue:e=>e.candidate.top_k,renderCell:e=>e.candidate.top_k??`—`},{id:`min_p`,title:`Min P`,sortable:!0,getValue:e=>e.candidate.min_p,renderCell:e=>e.candidate.min_p??`—`}]}function _b(){return[{id:`chat_score`,title:`Chat Score`,sortable:!0,getValue:e=>rb(e,`chat`),renderCell:(e,t)=>{let n=t.isInProgress?rb(e,`chat`):void 0;if(t.isPending)return n===void 0?`…`:(0,G.jsxs)(`span`,{style:{color:eb(n),opacity:.7},children:[`~`,n.toFixed(1)]});let r=rb(e,`chat`);return(0,G.jsx)(`span`,{style:{color:eb(r??0)},children:r?.toFixed(1)??`—`})}},{id:`tool_score`,title:`Tool Score`,sortable:!0,getValue:e=>rb(e,`tool_call`),renderCell:(e,t)=>{let n=t.isInProgress?rb(e,`tool_call`):void 0;if(t.isPending)return n===void 0?`…`:(0,G.jsxs)(`span`,{style:{color:eb(n),opacity:.7},children:[`~`,n.toFixed(1)]});let r=rb(e,`tool_call`);return(0,G.jsx)(`span`,{style:{color:eb(r??0)},children:r?.toFixed(1)??`—`})}},{id:`total_score`,title:`Total Score`,sortable:!0,getValue:e=>e.totalScore,renderCell:(e,t)=>t.isPending?`…`:(0,G.jsx)(`span`,{style:{color:eb(e.totalScore??0)},children:e.totalScore?.toFixed(1)??`—`})}]}function vb(){return[{id:`context_window`,title:`Context Window`,sortable:!0,getValue:e=>e.config?.context_window,renderCell:e=>e.config?.context_window??`—`},{id:`prefill_batch_size`,title:`Prefill Batch Size`,sortable:!0,getValue:e=>e.config?.prefill_batch_size,renderCell:e=>e.config?.prefill_batch_size??`—`},{id:`nseq_max`,title:`NSeqMax`,sortable:!0,getValue:e=>e.config?.nseq_max,renderCell:e=>e.config?.nseq_max??`—`},{id:`flash_attention`,title:`Flash Attn`,sortable:!0,getValue:e=>e.config?.flash_attention,renderCell:e=>e.config?.flash_attention??`—`},{id:`cache_type`,title:`KV Cache`,sortable:!0,getValue:e=>e.config?.cache_type,renderCell:e=>e.config?.cache_type??`—`},{id:`cache_mode`,title:`Cache`,sortable:!0,getValue:e=>e.config?.cache_mode,renderCell:e=>{let t=e.config?.cache_mode;return t?t===`none`?`None`:t.toUpperCase():`—`}},{id:`moe_mode`,title:`MoE Mode`,sortable:!0,getValue:e=>e.config?.moe_mode,renderCell:e=>{let t=e.config?.moe_mode;return t?t===`experts_cpu`?`CPU`:t===`keep_top_n`?`Balanced`:t===`experts_gpu`?`GPU`:t:`—`}},{id:`moe_keep_experts_top_n`,title:`Expert Layers GPU`,sortable:!0,getValue:e=>e.config?.moe_keep_experts_top_n,renderCell:e=>e.config?.moe_keep_experts_top_n??`—`},{id:`est_vram`,title:`Est. VRAM`,sortable:!0,getValue:e=>e.estimatedVRAM,renderCell:e=>e.estimatedVRAM===void 0?`—`:J(e.estimatedVRAM)}]}function yb(){return[...gb(),pb(),hb(),..._b(),...fb()]}function bb(){return[...vb(),mb(),hb(),...fb()]}var xb={temperature:{validMin:0,validMax:2,defaultStep:.1},top_p:{validMin:0,validMax:1,defaultStep:.1},top_k:{validMin:0,validMax:200,defaultStep:10},min_p:{validMin:0,validMax:1,defaultStep:.05},repeat_penalty:{validMin:0,validMax:3,defaultStep:.1},repeat_last_n:{validMin:0,validMax:2048,defaultStep:64},frequency_penalty:{validMin:-2,validMax:2,defaultStep:.1},presence_penalty:{validMin:-2,validMax:2,defaultStep:.1},dry_multiplier:{validMin:0,validMax:5,defaultStep:.1},dry_base:{validMin:1,validMax:3,defaultStep:.25},dry_allowed_length:{validMin:0,validMax:100,defaultStep:1},dry_penalty_last_n:{validMin:0,validMax:2048,defaultStep:64},xtc_probability:{validMin:0,validMax:1,defaultStep:.1},xtc_threshold:{validMin:0,validMax:1,defaultStep:.1},xtc_min_keep:{validMin:1,validMax:100,defaultStep:1},max_tokens:{validMin:1,validMax:131072,defaultStep:512}};function Sb({title:e,entries:t,sweepInputs:n,setSweepInputs:r,commitTriple:i,catalogSampling:a,isRunning:o}){return(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`div`,{className:`playground-sweep-group-title`,children:e}),t.map(([e,t])=>{let s=xb[e],c=n[e];return(0,G.jsxs)(`div`,{className:`playground-sweep-param`,children:[(0,G.jsx)(X,{className:`playground-sweep-param-toggle`,tooltipKey:e,after:a&&a[e]!==void 0&&(0,G.jsxs)(`span`,{className:`sweep-catalog-hint`,title:`Default catalog value`,children:[`(default: `,a[e],`)`]}),children:t}),(0,G.jsxs)(`div`,{className:`playground-sweep-param-range`,children:[(0,G.jsxs)(`div`,{className:`playground-sweep-param-range-field`,children:[(0,G.jsxs)(`span`,{className:`playground-sweep-param-range-label`,children:[`Min (`,s.validMin,`)`]}),(0,G.jsx)(`input`,{type:`number`,value:c.min,min:s.validMin,max:s.validMax,step:s.defaultStep,onChange:t=>r(n=>({...n,[e]:{...n[e],min:t.target.value}})),onBlur:()=>i(e),onKeyDown:e=>e.key===`Enter`&&e.currentTarget.blur(),disabled:o})]}),(0,G.jsxs)(`div`,{className:`playground-sweep-param-range-field`,children:[(0,G.jsxs)(`span`,{className:`playground-sweep-param-range-label`,children:[`Max (`,s.validMax,`)`]}),(0,G.jsx)(`input`,{type:`number`,value:c.max,min:s.validMin,max:s.validMax,step:s.defaultStep,onChange:t=>r(n=>({...n,[e]:{...n[e],max:t.target.value}})),onBlur:()=>i(e),onKeyDown:e=>e.key===`Enter`&&e.currentTarget.blur(),disabled:o})]}),(0,G.jsxs)(`div`,{className:`playground-sweep-param-range-field`,children:[(0,G.jsxs)(`span`,{className:`playground-sweep-param-range-label`,children:[`Step (`,s.defaultStep,`)`]}),(0,G.jsx)(`input`,{type:`number`,value:c.step,min:0,step:s.defaultStep,onChange:t=>r(n=>({...n,[e]:{...n[e],step:t.target.value}})),onBlur:()=>i(e),onKeyDown:e=>e.key===`Enter`&&e.currentTarget.blur(),disabled:o})]})]})]},e)})]})}function Cb({sweepInputs:e,setSweepInputs:t,commitTriple:n,catalogSampling:r,isRunning:i,trialCount:a}){return(0,G.jsxs)(`div`,{className:`playground-autotest-section`,children:[(0,G.jsx)(`h4`,{children:`Sampling Sweep Parameters`}),(0,G.jsx)(`p`,{style:{fontSize:12,color:`var(--color-gray-600)`,marginBottom:8},children:`Set min, max, and step values to define the sweep range. Set min = max for no sweep.`}),(0,G.jsx)(`div`,{className:`playground-sweep-params`,children:(0,G.jsx)(Sb,{title:`Generation`,entries:[[`temperature`,`Temperature`],[`top_p`,`Top P`],[`top_k`,`Top K`]],sweepInputs:e,setSweepInputs:t,commitTriple:n,catalogSampling:r,isRunning:i})}),(0,G.jsxs)(`p`,{style:{fontSize:12,color:`var(--color-gray-600)`,marginTop:8},children:[`Trials: `,a]})]})}function wb({configSweepDef:e,setConfigSweepDef:t,rawPrefillBatchSize:n,setRawPrefillBatchSize:r,rawContextWindow:i,setRawContextWindow:a,rawNSeqMax:o,setRawNSeqMax:s,rawMoeKeepExpertsTopN:c,setRawMoeKeepExpertsTopN:l,commitNumericSweep:u,isMoE:d,isRunning:f,trialCount:p}){return(0,G.jsxs)(`div`,{className:`playground-autotest-section`,children:[(0,G.jsx)(`p`,{style:{fontSize:12,color:`var(--color-warning-text)`,marginBottom:8},children:`⚠ Each candidate reloads the model. This is slower than sampling sweeps.`}),(0,G.jsxs)(`div`,{className:`playground-sweep-params`,children:[(0,G.jsxs)(`div`,{className:`playground-sweep-param`,children:[(0,G.jsx)(X,{className:`playground-sweep-param-toggle`,tooltipKey:`prefillBatchSize`,children:`Prefill Batch Size`}),(0,G.jsx)(`input`,{type:`text`,className:`playground-sweep-param-values`,value:n,onChange:e=>r(e.target.value),onBlur:()=>u(n,`prefillBatchSize`,r),onKeyDown:e=>e.key===`Enter`&&e.currentTarget.blur(),placeholder:`512, 1024, 2048, 4096`,disabled:f})]}),(0,G.jsxs)(`div`,{className:`playground-sweep-param`,children:[(0,G.jsx)(X,{className:`playground-sweep-param-toggle`,tooltipKey:`contextWindow`,children:`Context Window`}),(0,G.jsx)(`input`,{type:`text`,className:`playground-sweep-param-values`,value:i,onChange:e=>a(e.target.value),onBlur:()=>u(i,`contextWindow`,a),onKeyDown:e=>e.key===`Enter`&&e.currentTarget.blur(),placeholder:`2048, 4096, 8192, 16384, 32768`,disabled:f})]}),(0,G.jsxs)(`div`,{className:`playground-sweep-param`,children:[(0,G.jsx)(X,{className:`playground-sweep-param-toggle`,tooltipKey:`nSeqMax`,children:`NSeqMax`}),(0,G.jsx)(`input`,{type:`text`,className:`playground-sweep-param-values`,value:o,onChange:e=>s(e.target.value),onBlur:()=>u(o,`nSeqMax`,s),onKeyDown:e=>e.key===`Enter`&&e.currentTarget.blur(),placeholder:`1, 2, 4, 8`,disabled:f})]}),(0,G.jsxs)(`div`,{className:`playground-sweep-param`,children:[(0,G.jsx)(X,{className:`playground-sweep-param-toggle`,tooltipKey:`flashAttention`,children:`Flash Attention`}),(0,G.jsx)(`div`,{className:`playground-sweep-option-checks`,children:[`enabled`,`disabled`].map(n=>(0,G.jsxs)(`label`,{className:`playground-sweep-option-label`,children:[(0,G.jsx)(`input`,{type:`checkbox`,checked:e.flashAttention.values.includes(n),onChange:e=>{t(t=>{let r=t.flashAttention.values,i=e.target.checked?[...r,n]:r.filter(e=>e!==n);return{...t,flashAttention:{...t.flashAttention,values:i}}})},disabled:f}),n]},n))})]}),(0,G.jsxs)(`div`,{className:`playground-sweep-param`,children:[(0,G.jsx)(X,{className:`playground-sweep-param-toggle`,tooltipKey:`cacheType`,children:`Cache Type`}),(0,G.jsx)(`div`,{className:`playground-sweep-option-checks`,children:[`f16`,`q8_0`,`q4_0`].map(n=>(0,G.jsxs)(`label`,{className:`playground-sweep-option-label`,children:[(0,G.jsx)(`input`,{type:`checkbox`,checked:e.cacheType.values.includes(n),onChange:e=>{t(t=>{let r=t.cacheType.values,i=e.target.checked?[...r,n]:r.filter(e=>e!==n);return{...t,cacheType:{...t.cacheType,values:i}}})},disabled:f}),n]},n))})]}),(0,G.jsxs)(`div`,{className:`playground-sweep-param`,children:[(0,G.jsx)(X,{className:`playground-sweep-param-toggle`,tooltipKey:`cacheMode`,children:`Cache Mode`}),(0,G.jsx)(`div`,{className:`playground-sweep-option-checks`,children:[`none`,`imc`].map(n=>(0,G.jsxs)(`label`,{className:`playground-sweep-option-label`,children:[(0,G.jsx)(`input`,{type:`checkbox`,checked:e.cacheMode.values.includes(n),onChange:e=>{t(t=>{let r=t.cacheMode.values,i=e.target.checked?[...r,n]:r.filter(e=>e!==n);return{...t,cacheMode:{...t.cacheMode,values:i}}})},disabled:f}),n===`none`?`None`:n.toUpperCase()]},n))})]})]}),d&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`h4`,{style:{marginTop:16},children:`MoE Parameters`}),(0,G.jsxs)(`div`,{className:`playground-sweep-params`,children:[(0,G.jsxs)(`div`,{className:`playground-sweep-param`,children:[(0,G.jsx)(X,{className:`playground-sweep-param-toggle`,tooltipKey:`moeMode`,children:`Expert Strategy`}),(0,G.jsx)(`div`,{className:`playground-sweep-option-checks`,children:[`experts_cpu`,`keep_top_n`,`experts_gpu`].map(n=>(0,G.jsxs)(`label`,{className:`playground-sweep-option-label`,children:[(0,G.jsx)(`input`,{type:`checkbox`,checked:e.moeMode?.values.includes(n)??!1,onChange:e=>{t(t=>{let r=t.moeMode?.values??[],i=e.target.checked?[...r,n]:r.filter(e=>e!==n);return{...t,moeMode:{enabled:i.length>0,values:i}}})},disabled:f}),to[n]??n]},n))})]}),(0,G.jsxs)(`div`,{className:`playground-sweep-param`,children:[(0,G.jsx)(X,{className:`playground-sweep-param-toggle`,tooltipKey:`moeKeepExpertsTopN`,children:`GPU Expert Layers`}),(0,G.jsx)(`input`,{type:`text`,className:`playground-sweep-param-values`,value:c,onChange:e=>l(e.target.value),onBlur:()=>u(c,`moeKeepExpertsTopN`,l),onKeyDown:e=>e.key===`Enter`&&e.currentTarget.blur(),placeholder:`0, 4, 8, 16`,disabled:f})]})]})]}),(0,G.jsxs)(`p`,{style:{fontSize:12,color:`var(--color-gray-600)`,marginTop:8},children:[`Trials: `,p]})]})}function Tb(e){return e===null?`asc`:e===`asc`?`desc`:null}function Eb(e,t){return t.column!==e||t.direction===null?``:t.direction===`asc`?` ▲`:` ▼`}function Db(e,t,n){if(!t.column||!t.direction)return e;let r=t.direction===`asc`?1:-1;return[...e].sort((e,i)=>{let a=n(e,t.column),o=n(i,t.column),s=a??void 0,c=o??void 0;return s===void 0&&c===void 0?0:s===void 0?1:c===void 0?-1:typeof s==`number`&&typeof c==`number`?(s-c)*r:String(s).localeCompare(String(c))*r})}function Ob(e){if(!e)return;let t=e.completion_tokens,n=e.tokens_per_second;if(!Number.isFinite(t)||!Number.isFinite(n)||n<=0)return;let r=e.time_to_first_token_ms??0,i=t/n*1e3+r;if(!(!Number.isFinite(i)||i<0))return i}function kb(e){return new Date(e).toLocaleTimeString([],{hour:`2-digit`,minute:`2-digit`,second:`2-digit`})}function Ab(e,t){let n=t[e.scenarioId]?.name??e.scenarioId,r=t[e.scenarioId]?.prompts?.length,i=`${n} · Prompt ${e.promptIndex+1}${r?`/${r}`:``}`;return e.repeats&&e.repeats>1&&e.repeatIndex!=null&&(i+=` · Repeat ${e.repeatIndex}/${e.repeats}`),i}function jb({trial:e,showScores:t}){return(0,G.jsxs)(G.Fragment,{children:[t&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Chat Score:`}),` `,nb(rb(e,`chat`))]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Tool Score:`}),` `,nb(rb(e,`tool_call`))]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Total Score:`}),` `,nb(e.totalScore)]})]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Avg TPS:`}),` `,e.avgTPS?.toFixed(1)??`—`]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Avg TTFT:`}),` `,e.avgTTFT===void 0?`—`:$y(e.avgTTFT)]}),e.avgTPSByFill&&db.map(t=>(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`strong`,{children:[`TPS @`,t,`:`]}),` `,e.avgTPSByFill[t]?.toFixed(1)??`—`]},`tps-${t}`)),e.avgTTFTByFill&&db.map(t=>(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`strong`,{children:[`TTFT @`,t,`:`]}),` `,e.avgTTFTByFill[t]===void 0?`—`:$y(e.avgTTFTByFill[t])]},`ttft-${t}`))]})}function Mb({sr:e,scenarioName:t,hideScores:n}){return(0,G.jsxs)(`div`,{className:`autotest-detail-scenario-header`,children:[(0,G.jsx)(`span`,{className:`autotest-detail-scenario-name`,children:t}),!n&&(0,G.jsxs)(`span`,{className:`autotest-detail-scenario-score`,style:{color:tb(e.score)},children:[`Score: `,nb(e.score)]}),e.avgTPS!==void 0&&(0,G.jsxs)(`span`,{children:[`TPS: `,e.avgTPS.toFixed(1)]}),e.avgTTFT!==void 0&&(0,G.jsxs)(`span`,{children:[`TTFT: `,$y(e.avgTTFT)]}),e.avgTPSByFill&&Object.keys(e.avgTPSByFill).length>0&&(0,G.jsxs)(`span`,{style:{marginLeft:8,opacity:.85},children:[`Context Fill TPS:`,db.map(t=>e.avgTPSByFill[t]===void 0?null:` @${t}: ${e.avgTPSByFill[t].toFixed(1)}`)]}),e.avgTTFTByFill&&Object.keys(e.avgTTFTByFill).length>0&&(0,G.jsxs)(`span`,{style:{marginLeft:8,opacity:.85},children:[`Context Fill TTFT:`,db.map(t=>e.avgTTFTByFill[t]===void 0?null:` @${t}: ${$y(e.avgTTFTByFill[t])}`)]})]})}function Nb({trial:e,scenarioLookup:t,hideScores:n}){let[r,i]=(0,x.useState)(()=>new Set),a=(0,x.useCallback)(e=>{i(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},[]),o=(0,x.useRef)(null),[s,c]=(0,x.useState)(!1),[l,u]=(0,x.useState)(!1),d=e.status===`running`&&e.activePrompts&&e.activePrompts.length>0,f=e.logEntries&&e.logEntries.length>0;return(0,x.useEffect)(()=>{let t=o.current;t&&s&&e.status===`running`&&t.scrollHeight-t.scrollTop-t.clientHeight<40&&(t.scrollTop=t.scrollHeight)},[e.logEntries?.length,e.status,s]),e.scenarioResults.length===0&&!d&&!f?(0,G.jsx)(`div`,{className:`autotest-detail-empty`,children:`No scenario results yet.`}):(0,G.jsxs)(`div`,{className:`autotest-detail-content`,children:[d&&(0,G.jsxs)(`div`,{className:`autotest-detail-active`,children:[(0,G.jsxs)(`div`,{className:`autotest-detail-active-header`,children:[(0,G.jsx)(`span`,{className:`playground-autotest-spinner-inline`}),` Currently Running`]}),e.activePrompts.map(e=>(0,G.jsxs)(`div`,{className:`autotest-detail-active-prompt`,children:[(0,G.jsx)(`span`,{className:`autotest-detail-active-scenario`,children:t[e.scenarioId]?.name??e.scenarioId}),(0,G.jsx)(`span`,{className:`autotest-detail-active-id`,children:e.promptId}),e.repeats&&e.repeats>1&&e.repeatIndex&&(0,G.jsxs)(`span`,{className:`autotest-detail-active-repeat`,children:[`Repeat `,e.repeatIndex,`/`,e.repeats]}),e.preview&&(0,G.jsx)(`div`,{className:`autotest-detail-active-preview`,children:e.preview})]},`${e.scenarioId}-${e.promptIndex}`))]}),f&&(0,G.jsxs)(`div`,{className:`autotest-detail-log`,children:[(0,G.jsxs)(`button`,{type:`button`,className:`autotest-detail-log-header`,"aria-expanded":s,onClick:e=>{e.stopPropagation(),c(e=>!e)},children:[e.status===`running`&&(0,G.jsx)(`span`,{className:`playground-autotest-spinner-inline`}),(0,G.jsxs)(`span`,{children:[s?`▾`:`▸`,` Activity Log`]})]}),(0,G.jsx)(`div`,{className:`autotest-detail-log-body`,ref:o,children:s?e.logEntries.map((e,t)=>(0,G.jsxs)(`div`,{className:`autotest-detail-log-entry`,children:[(0,G.jsx)(`span`,{className:`autotest-detail-log-time`,children:kb(e.timestamp)}),(0,G.jsx)(`span`,{className:`autotest-detail-log-msg`,children:e.message})]},t)):(()=>{let t=e.logEntries[e.logEntries.length-1];return(0,G.jsxs)(`div`,{className:`autotest-detail-log-entry`,children:[(0,G.jsx)(`span`,{className:`autotest-detail-log-time`,children:kb(t.timestamp)}),(0,G.jsx)(`span`,{className:`autotest-detail-log-msg`,children:t.message})]})})()})]}),(e.scenarioResults.length>0||e.status===`running`&&e.activePrompts&&e.activePrompts.length>0)&&(0,G.jsxs)(`div`,{className:`autotest-detail-scenarios-section`,children:[(0,G.jsx)(`button`,{type:`button`,className:`autotest-detail-log-header`,"aria-expanded":l,onClick:e=>{e.stopPropagation(),u(e=>!e)},children:(0,G.jsxs)(`span`,{children:[l?`▾`:`▸`,` Performance`]})}),l?(()=>{let i=new Set(e.scenarioResults.map(e=>e.scenarioId)),o={};if(e.status===`running`&&e.activePrompts)for(let t of e.activePrompts)o[t.scenarioId]||(o[t.scenarioId]=[]),o[t.scenarioId].push(t);let s=[...i];for(let e of Object.keys(o)){let t=e;i.has(t)||s.push(t)}return s.map(i=>{let s=e.scenarioResults.find(e=>e.scenarioId===i),c=t[i],l=o[i]??[];return!s&&l.length===0?null:(0,G.jsxs)(`div`,{className:`autotest-detail-scenario`,children:[s?(0,G.jsx)(Mb,{sr:s,scenarioName:c?.name??i,hideScores:n}):(0,G.jsx)(`div`,{className:`autotest-detail-scenario-header`,children:(0,G.jsx)(`span`,{className:`autotest-detail-scenario-name`,children:c?.name??i})}),l.length>0&&(0,G.jsxs)(`div`,{className:`autotest-detail-running-indicator autotest-detail-running-indicator--expanded`,children:[(0,G.jsx)(`span`,{className:`playground-autotest-spinner-inline`}),` `,`Running: `,Ab(l[0],t)]}),s&&(0,G.jsx)(`div`,{className:`autotest-detail-prompts`,children:s.promptResults.map(e=>{let t=`${s.scenarioId}:${e.promptId}`,i=r.has(t),o=e.promptId.startsWith(`ctxfill-`),l=c?.prompts.find(t=>t.id===e.promptId),u=l?.messages.filter(e=>e.role===`user`).pop(),d=o?`Context fill test (${e.promptId.replace(`ctxfill-`,``)}% fill) — ${e.usage?.prompt_tokens??`?`} prompt tokens`:typeof u?.content==`string`?u.content:u?.content?.map(e=>`text`in e?e.text:``).join(``)??``,f=o?`Performance metric only`:l?.expected?l.expected.type===`tool_call`?`Tool call`:l.expected.type===`no_tool_call`?`No tool call`+(l.expected.value?` (text: ${l.expected.value})`:``):l.expected.type===`exact`?`Exact: "${l.expected.value}"`:`Regex: ${l.expected.value}`:`—`,p=Ob(e.usage),m=p===void 0?`—`:$y(p);return(0,G.jsxs)(`div`,{className:`autotest-detail-prompt ${i?`expanded`:`collapsed`}`,children:[(0,G.jsxs)(`div`,{className:`autotest-detail-prompt-header autotest-detail-prompt-header--clickable`,role:`button`,tabIndex:0,"aria-expanded":i,onClick:()=>a(t),onKeyDown:e=>{(e.key===`Enter`||e.key===` `)&&(e.preventDefault(),a(t))},children:[(0,G.jsxs)(`div`,{className:`autotest-detail-prompt-summary`,children:[(0,G.jsx)(`span`,{className:`autotest-detail-prompt-toggle`,children:i?`▼`:`▶`}),(0,G.jsx)(`span`,{className:`autotest-detail-prompt-id`,children:o?`Context Fill @${e.promptId.replace(`ctxfill-`,``)}%`:e.promptId}),(0,G.jsxs)(`span`,{className:`autotest-detail-prompt-duration`,children:[`Duration: `,m]}),(0,G.jsxs)(`span`,{className:`autotest-detail-prompt-usage-inline`,children:[(0,G.jsxs)(`span`,{children:[`In: `,e.usage?.prompt_tokens??`—`]}),(0,G.jsxs)(`span`,{children:[`Out: `,e.usage?.completion_tokens??`—`]}),(0,G.jsxs)(`span`,{children:[`TPS: `,e.usage?.tokens_per_second===void 0?`—`:e.usage.tokens_per_second.toFixed(1)]})]})]}),!n&&(0,G.jsx)(`span`,{className:`autotest-detail-prompt-score`,style:{color:tb(e.score)},children:nb(e.score)})]}),i&&(0,G.jsxs)(`div`,{className:`autotest-detail-prompt-grid`,children:[(0,G.jsxs)(`div`,{className:`autotest-detail-field`,children:[(0,G.jsx)(`div`,{className:`autotest-detail-label`,children:`Input`}),(0,G.jsx)(`div`,{className:`autotest-detail-value`,children:d||`—`})]}),(0,G.jsxs)(`div`,{className:`autotest-detail-field`,children:[(0,G.jsx)(`div`,{className:`autotest-detail-label`,children:`Expected`}),(0,G.jsx)(`div`,{className:`autotest-detail-value`,children:f})]}),(0,G.jsxs)(`div`,{className:`autotest-detail-field`,children:[(0,G.jsx)(`div`,{className:`autotest-detail-label`,children:`Output`}),(0,G.jsx)(`div`,{className:`autotest-detail-value`,children:e.toolCalls.length>0?e.toolCalls.map((e,t)=>(0,G.jsx)(`div`,{className:`autotest-detail-toolcall`,children:(0,G.jsxs)(`code`,{children:[e.function.name,`(`,e.function.arguments,`)`]})},t)):e.assistantText||`(empty)`})]}),e.usage&&(0,G.jsxs)(`div`,{className:`autotest-detail-field`,children:[(0,G.jsx)(`div`,{className:`autotest-detail-label`,children:`Usage`}),(0,G.jsxs)(`div`,{className:`autotest-detail-value autotest-detail-usage`,children:[(0,G.jsxs)(`span`,{children:[`In: `,e.usage.prompt_tokens]}),(0,G.jsxs)(`span`,{children:[`Out: `,e.usage.completion_tokens]}),(0,G.jsxs)(`span`,{children:[`TPS: `,e.usage.tokens_per_second.toFixed(1)]}),e.usage.time_to_first_token_ms!==void 0&&(0,G.jsxs)(`span`,{children:[`TTFT: `,$y(e.usage.time_to_first_token_ms)]})]})]}),e.notes&&e.notes.length>0&&(0,G.jsxs)(`div`,{className:`autotest-detail-field`,children:[(0,G.jsx)(`div`,{className:`autotest-detail-label`,children:`Notes`}),(0,G.jsx)(`div`,{className:`autotest-detail-value autotest-detail-notes`,children:e.notes.map((e,t)=>(0,G.jsx)(`div`,{children:e},t))})]})]})]},e.promptId)})})]},i)})})():(0,G.jsxs)(`div`,{className:`autotest-detail-scenarios-summary`,children:[e.status===`running`&&e.activePrompts&&e.activePrompts.length>0&&(0,G.jsxs)(`div`,{className:`autotest-detail-running-indicator`,children:[(0,G.jsx)(`span`,{className:`playground-autotest-spinner-inline`}),` `,`Running: `,Ab(e.activePrompts[0],t)]}),e.scenarioResults.map(e=>(0,G.jsx)(Mb,{sr:e,scenarioName:t[e.scenarioId]?.name??e.scenarioId,hideScores:n},e.scenarioId))]})]})]})}function Pb(e,t,n){return Math.min(n,Math.max(t,e))}function Fb(e,t){let n=xb[e],r=Number(t.min),i=Number(t.max),a=Number(t.step),o=Number.isFinite(r)?Pb(r,n.validMin,n.validMax):n.validMin,s=Number.isFinite(i)?Pb(i,n.validMin,n.validMax):o;o>s&&(s=o);let c=Number.isFinite(a)&&a>0?Math.max(a,1e-6):n.defaultStep;return{min:o,max:s,step:c}}function Ib(e,t,n){if(n<=0||e===t)return[e];let r=[],i=n*.001;for(let a=e;a<=t+i;){let e=Math.round(a*1e6)/1e6;if(e<=t+1e-9&&r.push(e),r.length>=200)break;let i=a+n;if(i===a)break;a=i}return r.length>0?r:[e]}function Lb(e,t){let n=xb[e];if(!t||t.length===0)return{min:String(n.validMin),max:String(n.validMin),step:String(n.defaultStep)};if(t.length===1)return{min:String(t[0]),max:String(t[0]),step:String(n.defaultStep)};let r=t[0],i=t[t.length-1],a=t[1]-t[0],o=a>0;for(let e=2;e1e-6&&(o=!1);let s=o&&a>0?Math.round(a*1e6)/1e6:n.defaultStep;return{min:String(r),max:String(i),step:String(s)}}function Rb(e){let t={};for(let n of Object.keys(xb))t[n]=Lb(n,e[n]);return t}function zb(e){let t=new Date,n=e.getDate()===t.getDate()&&e.getMonth()===t.getMonth()&&e.getFullYear()===t.getFullYear(),r=e.toLocaleTimeString([],{hour:`numeric`,minute:`2-digit`});return n?r:e.toLocaleDateString([],{month:`short`,day:`numeric`})+`, `+r}function Bb(e,t,n,r){let[,i]=(0,x.useState)(0),a=t.filter(e=>e?.finishedAt).length,o=r&&a{if(!o)return;let e=setInterval(()=>i(e=>e+1),1e3);return()=>clearInterval(e)},[o]);let s=e?Date.parse(e):NaN,c=t.map(e=>e?.startedAt?Date.parse(e.startedAt):NaN).filter(Number.isFinite),l=Number.isFinite(s)?s:c.length?Math.min(...c):NaN,u=Number.isFinite(l)?Math.max(0,Date.now()-l):0,d=Number.isFinite(l)?$y(u):null,f=null,p=null;if(a>0&&ae?.startedAt&&e?.finishedAt).map(e=>Date.parse(e.finishedAt)-Date.parse(e.startedAt)).filter(e=>Number.isFinite(e)&&e>0);if(e.length>0){let t=e.reduce((e,t)=>e+t,0)/e.length,r=Math.max(0,n-a),i=a>0?r:Math.max(0,r-1),o=t*r+Hn*i;f=$y(o),a>=3&&(p=zb(new Date(Date.now()+o)))}}return{elapsed:d,estimate:f,estimatedCompletion:p}}function Vb({totalTrials:e,trials:t,running:n,runStartedAt:r}){let{elapsed:i,estimate:a,estimatedCompletion:o}=Bb(r,t,e,n),s=t.filter(e=>e?.finishedAt).length,c=!!t.find(e=>e?.status===`running`),l=Math.min(100,e>0?(s+(c?.5:0))/e*100:0),u=t.find(e=>e?.status===`running`),d=null;if(u){let e=u.scenarioResults.reduce((e,t)=>e+t.promptResults.length,0);d=e>0?`Prompt ${e} completed`:`Starting…`}let f=Math.min(s+ +!!c,e),p=`${i??`0s`}${a?` · ~${a} left`:``}${o?` · ETA ${o}`:``}`,m=l>=50;return(0,G.jsxs)(`div`,{className:`playground-autotest-progress`,children:[(0,G.jsxs)(`div`,{className:`playground-autotest-progress-text`,children:[(0,G.jsxs)(`span`,{children:[`Trial `,f,` / `,e]}),d&&(0,G.jsxs)(`span`,{className:`playground-autotest-prompt-progress`,children:[` · `,d]})]}),(0,G.jsxs)(`div`,{className:`playground-autotest-progress-bar`,children:[(0,G.jsx)(`div`,{className:`playground-autotest-progress-fill`,style:{width:`${l}%`},children:m&&(0,G.jsx)(`span`,{className:`playground-autotest-progress-label`,children:p})}),!m&&(0,G.jsx)(`span`,{className:`playground-autotest-progress-label-outside`,children:p})]})]})}function Hb({session:e,sessionSeed:t,catalogSampling:n,isMoE:r,gpuVramBytes:i,lockSweep:a}){let{run:o,isRunning:s,startSamplingRun:c,startConfigRun:l,stopRun:u,clearRun:d,reevaluateBestTrial:f,reorderQueuedTrial:p,skipTrial:m,unskipTrial:h,stopTrial:g,rerunTrial:_}=Mi(),{sweepMode:v,setSweepMode:y}=Ui(),b=o?.kind===`sampling`?o.sweepDef:er,S=o?.kind===`config`?o.configSweepDef:tr,C=o?.weights??(o?.kind===`config`?ur:lr),[w,T]=(0,x.useState)(()=>o?.enabledScenarios??{chat:!0,tool_call:!0}),[E,D]=(0,x.useState)(()=>structuredClone(b)),[O,k]=(0,x.useState)(()=>Rb(b)),A=(0,x.useRef)(O);(0,x.useEffect)(()=>{A.current=O},[O]);let[j,M]=(0,x.useState)(!!o),[N,P]=(0,x.useState)(null),F=1/0,[I,L]=(0,x.useState)(()=>structuredClone(S)),[R,z]=(0,x.useState)(()=>({...C})),[ee,B]=(0,x.useState)(!1),V=(0,x.useRef)({...C});(0,x.useEffect)(()=>{if(!s&&!o){let e=v===`config`?ur:lr;z(e),V.current={...e},B(!1)}},[v,s,o]);let[te,H]=(0,x.useState)(!0),[ne,re]=(0,x.useState)(!1),[ie,ae]=(0,x.useState)(new Set),[oe,se]=(0,x.useState)(()=>o?.repeats??1),[ce,le]=(0,x.useState)({column:null,direction:null}),ue=s&&o?.status===`running_trials`&&ce.column===null,[de,fe]=(0,x.useState)(null),[pe,me]=(0,x.useState)(null),he=(0,x.useCallback)((e,t)=>{fe(t),e.dataTransfer.effectAllowed=`move`,e.dataTransfer.setData(`text/plain`,t)},[]),ge=(0,x.useCallback)((e,t)=>{e.preventDefault(),e.dataTransfer.dropEffect=`move`,me(t)},[]),_e=(0,x.useCallback)(()=>{me(null)},[]),ve=(0,x.useCallback)((e,t)=>{e.preventDefault();let n=e.dataTransfer.getData(`text/plain`);n&&n!==t&&p({trialId:n,targetId:t}),fe(null),me(null)},[p]),ye=(0,x.useCallback)(()=>{fe(null),me(null)},[]),[,be]=(0,x.useState)(0);(0,x.useEffect)(()=>{if(!s)return;let e=setInterval(()=>be(e=>e+1),1e3);return()=>clearInterval(e)},[s]);let xe=(0,x.useMemo)(()=>{let e={chat:v===`config`?Qn:Gn};return v!==`config`&&(e.tool_call=Zn),e},[v]),Se=(0,x.useCallback)(e=>{le(t=>({column:t.column===e&&Tb(t.direction)===null?null:e,direction:t.column===e?Tb(t.direction):`asc`}))},[]),Ce=(0,x.useCallback)(e=>{ae(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},[]),[we,Te]=(0,x.useState)(()=>S.prefillBatchSize.values.join(`, `)),[Ee,De]=(0,x.useState)(()=>S.contextWindow.values.join(`, `)),[Oe,ke]=(0,x.useState)(()=>S.nSeqMax.values.join(`, `)),[Ae,je]=(0,x.useState)(()=>i&&i>0?Math.round(i*.9/1073741824*10)/10:0),[Me,Ne]=(0,x.useState)(()=>S.moeKeepExpertsTopN?.values.join(`, `)??`0`),Pe=(0,x.useRef)(Ae>0);(0,x.useEffect)(()=>{Pe.current||!i||i<=0||(Pe.current=!0,je(Math.round(i*.9/1073741824*10)/10))},[i]);let Fe=(0,x.useRef)(o?.runId);(0,x.useEffect)(()=>{o&&o.runId!==Fe.current&&(a&&o.kind!==v||(Fe.current=o.runId,a||y(o.kind),T(o.enabledScenarios),se(o.repeats),z({...o.weights}),V.current={...o.weights},B(!1),o.kind===`sampling`?(D(structuredClone(o.sweepDef)),k(Rb(o.sweepDef)),M(!0)):(L(structuredClone(o.configSweepDef)),Te(o.configSweepDef.prefillBatchSize.values.join(`, `)),De(o.configSweepDef.contextWindow.values.join(`, `)),ke(o.configSweepDef.nSeqMax.values.join(`, `)),Ne(o.configSweepDef.moeKeepExpertsTopN?.values.join(`, `)??`0`))))},[o?.runId]);let Ie=(0,x.useRef)(o);(0,x.useEffect)(()=>{Ie.current&&!o&&(M(!1),Fe.current=void 0),Ie.current=o},[o]);let Le=(0,x.useCallback)((e,t,n)=>{let r=t===`moeKeepExpertsTopN`?0:1,i=e.split(`,`).map(e=>Math.floor(Number(e.trim()))).filter(e=>Number.isFinite(e)&&e>=r);if(i.length===0){L(e=>(n(e[t]?.values.join(`, `)??`0`),e));return}L(e=>({...e,[t]:{...e[t]??{enabled:!1,values:[]},enabled:!0,values:i}})),n(i.join(`, `))},[]),Re=(0,x.useCallback)(e=>{let{min:t,max:n,step:r}=Fb(e,A.current[e]),i=Ib(t,n,r);k(i=>({...i,[e]:{min:String(t),max:String(n),step:String(r)}})),D(t=>({...t,[e]:i})),M(!0)},[]);(0,x.useEffect)(()=>{if(o||!n||n===N||(P(n),j))return;let e=n,t={temperature:[e.temperature??.8],top_p:[e.top_p??.9],top_k:[e.top_k??40],min_p:[e.min_p??0],repeat_penalty:[e.repeat_penalty??1],repeat_last_n:[e.repeat_last_n??64],frequency_penalty:[e.frequency_penalty??0],presence_penalty:[e.presence_penalty??0],dry_multiplier:[e.dry_multiplier??1.05],dry_base:[e.dry_base??1.75],dry_allowed_length:[e.dry_allowed_length??2],dry_penalty_last_n:[e.dry_penalty_last_n??0],xtc_probability:[e.xtc_probability??0],xtc_threshold:[e.xtc_threshold??.1],xtc_min_keep:[e.xtc_min_keep??1],max_tokens:[e.max_tokens??4096],enable_thinking:[e.enable_thinking||`true`],reasoning_effort:[e.reasoning_effort||`medium`]};D(t),k(Rb(t))},[n,N,j,o]);let ze=a&&o&&o.kind!==v?null:o,Be=s&&!ze&&!!o,Ve=s&&!!ze,He=ze?.status??`idle`,Ue=ze?.errorMessage??``,We=ze?.templateRepairStatus??``,Ge=ze?.calibrationStatus??``,Ke=ze?.totalTrials??0,qe=ze?.kind===`sampling`?ze.trials:[],Je=ze?.kind===`config`?ze.trials:[],Ye=ze?.kind===`sampling`&&ze.bestTrialId?ze.trials.find(e=>e.id===ze.bestTrialId)??null:null,Xe=ze?.kind===`config`&&ze.bestTrialId?ze.trials.find(e=>e.id===ze.bestTrialId)??null:null,Ze=a?v:o?o.kind:v,Qe=o?.kind;(0,x.useEffect)(()=>{Qe&&!a&&y(Qe)},[Qe,a]);let $e=Ze===`config`?Je:qe,et=(0,x.useMemo)(()=>Ze===`config`?bb():yb(),[Ze]),tt=(0,x.useMemo)(()=>Object.fromEntries(et.map(e=>[e.id,e])),[et]),nt=(0,x.useCallback)((e,t)=>tt[t]?.getValue(e),[tt]),rt=(0,x.useMemo)(()=>Db($e,ce,nt),[$e,ce,nt]),it=w.chat||w.tool_call,at=(0,x.useMemo)(()=>{let e=Object.keys(xb),t=Object.fromEntries(e.map(e=>{let{min:t,max:n,step:r}=Fb(e,O[e]);return[e,Ib(t,n,r)]}));return{...E,...t}},[O,E]),ot=(0,x.useMemo)(()=>$n(at,F).length,[at,F]),st=(0,x.useMemo)(()=>t?rr(t.base_config,I).length:1,[t,I]),ct=(0,x.useRef)(0);(0,x.useEffect)(()=>{$e.length>0&&ct.current===0&&!ne&&re(!0),ct.current=$e.length},[$e.length,ne]);let lt=(0,x.useCallback)(()=>{if(v===`sampling`){if(!e&&!t?.model_id)return;c({sessionId:e?.session_id,sessionSeed:e?void 0:t??void 0,enabledScenarios:w,sweepDef:at,maxTrials:F,weights:R,repeats:oe,effectiveConfig:e?.effective_config})}else{if(!t?.model_id||e)return;let n=r?I:{...I,moeMode:void 0,moeKeepExpertsTopN:void 0};l({sessionSeed:t,enabledScenarios:w,configSweepDef:n,weights:R,repeats:oe,availableVRAMGB:Ae})}H(!1),V.current={...R},B(!1)},[v,e,t,w,at,F,I,R,oe,Ae,c,l]),ut=(0,x.useCallback)((e,t)=>{z(n=>{let r={...n,[e]:t},i=V.current,a=Object.keys(r).some(e=>r[e]!==i[e]);return B(a),r})},[]),dt=(0,x.useCallback)(()=>{f(R),V.current={...R},B(!1)},[R,f]),ft=(0,x.useCallback)(e=>{let t=dr(e,o?.kind??v);z(t),V.current={...t},B(!1),f(t)},[o,v,f]),pt=(0,x.useCallback)(()=>{u()},[u]),mt=(0,x.useCallback)(()=>{H(!0),d()},[d]),ht=v===`sampling`?!(!e&&!t?.model_id||s||!it):!(!t?.model_id||e||s||!it);return(0,G.jsxs)(`div`,{className:`playground-autotest-container`,children:[(0,G.jsxs)(`div`,{className:`playground-autotest-section`,style:{display:`flex`,gap:32,alignItems:`flex-start`},children:[!a&&(0,G.jsxs)(`div`,{style:{width:`50%`},children:[(0,G.jsx)(`h4`,{children:`Sweep Mode`}),(0,G.jsx)(`div`,{className:`playground-inline-options`,style:{paddingBottom:`20px`},children:Qy.map(e=>(0,G.jsxs)(`label`,{className:`playground-inline-option`,children:[(0,G.jsx)(`input`,{type:`radio`,name:`sweepMode`,value:e.kind,checked:v===e.kind,onChange:()=>y(e.kind),disabled:s}),e.label]},e.kind))})]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`h4`,{children:`Repeats Per Test Case`}),(0,G.jsx)(`p`,{style:{fontSize:12,color:`var(--color-gray-600)`,marginBottom:8},children:`Each prompt is run this many times and scores are averaged for more stable results.`}),(0,G.jsx)(`div`,{className:`playground-sweep-param-range`,style:{maxWidth:120},children:(0,G.jsx)(`div`,{className:`playground-sweep-param-range-field`,children:(0,G.jsx)(`input`,{type:`number`,value:oe,onChange:e=>{let t=Math.floor(Number(e.target.value));Number.isFinite(t)&&t>=1&&se(t)},min:1,max:20,disabled:s})})})]})]}),v===`config`&&(0,G.jsxs)(`details`,{className:`playground-sampling-params`,open:te,onToggle:e=>H(e.currentTarget.open),children:[(0,G.jsxs)(`summary`,{children:[`Config Parameters`,r?` / MoE Parameters`:``]}),(0,G.jsx)(wb,{configSweepDef:I,setConfigSweepDef:L,rawPrefillBatchSize:we,setRawPrefillBatchSize:Te,rawContextWindow:Ee,setRawContextWindow:De,rawNSeqMax:Oe,setRawNSeqMax:ke,rawMoeKeepExpertsTopN:Me,setRawMoeKeepExpertsTopN:Ne,commitNumericSweep:Le,isMoE:r,isRunning:s,trialCount:st}),(0,G.jsx)(`div`,{className:`playground-autotest-section`,children:(0,G.jsx)(`div`,{className:`playground-sweep-params`,children:(0,G.jsxs)(`div`,{className:`playground-sweep-param`,children:[(0,G.jsx)(X,{className:`playground-sweep-param-toggle`,tooltipKey:`availableVRAM`,children:`Available GPU VRAM (GB)`}),(0,G.jsx)(`input`,{type:`number`,className:`playground-sweep-param-values`,value:Ae,onChange:e=>{let t=Number(e.target.value);Number.isFinite(t)&&t>=0&&(Pe.current=!0,je(t))},placeholder:`0 = no filtering`,min:0,step:.1,disabled:s,style:{maxWidth:120}})]})})})]}),v===`sampling`&&(0,G.jsxs)(`details`,{className:`playground-sampling-params`,open:te,onToggle:e=>H(e.currentTarget.open),children:[(0,G.jsx)(`summary`,{children:`Scenario Selection / Sampling Sweep Parameters`}),(0,G.jsxs)(`div`,{className:`playground-autotest-section`,children:[(0,G.jsx)(`h4`,{children:`Scenario Selection`}),(0,G.jsxs)(`div`,{className:`playground-inline-options`,children:[(0,G.jsxs)(`label`,{className:`playground-inline-option`,children:[(0,G.jsx)(`input`,{type:`checkbox`,checked:w.chat,onChange:e=>T(t=>({...t,chat:e.target.checked})),disabled:s}),`Chat Quality`]}),(0,G.jsxs)(`label`,{className:`playground-inline-option`,children:[(0,G.jsx)(`input`,{type:`checkbox`,checked:w.tool_call,onChange:e=>T(t=>({...t,tool_call:e.target.checked})),disabled:s}),`Tool Calling`]})]})]}),(0,G.jsx)(Cb,{sweepDef:E,setSweepDef:D,sweepInputs:O,setSweepInputs:k,commitTriple:Re,setSweepDirty:M,catalogSampling:n,isRunning:s,trialCount:ot})]}),(0,G.jsxs)(`div`,{className:`playground-autotest-actions`,children:[(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:lt,disabled:!ht,children:`Run Automated Testing`}),v===`config`&&r&&!s&&(0,G.jsx)(`button`,{type:`button`,className:`btn btn-small`,onClick:()=>{let e=nr;L(structuredClone(e)),Te(e.prefillBatchSize.values.join(`, `)),De(e.contextWindow.values.join(`, `)),ke(e.nSeqMax.values.join(`, `)),Ne(e.moeKeepExpertsTopN?.values.join(`, `)??`0`)},children:`MoE Recommended`}),Ve&&(0,G.jsx)(`button`,{className:`btn btn-danger`,onClick:pt,children:`Stop`}),$e.length>0&&!s&&(0,G.jsx)(`button`,{className:`btn btn-secondary btn-small`,onClick:mt,children:`Clear Results`})]}),Be&&o&&(0,G.jsxs)(`div`,{className:`playground-error`,children:[`A `,o.kind===`config`?`configuration`:`sampling`,` run is in progress. Stop it before starting a `,v===`config`?`configuration`:`sampling`,` run.`]}),v===`config`&&e&&!s&&(0,G.jsx)(`div`,{className:`playground-error`,children:`Unload the current model before running config sweeps`}),We&&s&&He!==`running_trials`&&(0,G.jsxs)(`div`,{className:`playground-autotest-status`,children:[(0,G.jsx)(`span`,{className:`playground-autotest-spinner`}),` `,We]}),Ge&&s&&(He!==`running_trials`||$e.length===0)&&(0,G.jsxs)(`div`,{className:`playground-autotest-status`,children:[(0,G.jsx)(`span`,{className:`playground-autotest-spinner`}),` `,Ge]}),Ue&&(0,G.jsx)(`div`,{className:`playground-error`,children:Ue}),He===`running_trials`&&o?.initialDelayUntil&&(0,G.jsxs)(`div`,{className:`playground-autotest-status`,children:[(0,G.jsx)(`span`,{className:`playground-autotest-spinner`}),` Starting first test in `,Math.max(0,Math.ceil((Date.parse(o.initialDelayUntil)-Date.now())/1e3)),`s…`]}),He===`running_trials`&&(0,G.jsx)(Vb,{totalTrials:Ke,trials:$e,running:s,runStartedAt:o?.runStartedAt}),He===`completed`&&(()=>{let e=!!(Ze===`config`?Xe:Ye);return(0,G.jsxs)(`div`,{className:`playground-autotest-best`,children:[e?(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`h4`,{children:`Best Configuration Found`}),(0,G.jsxs)(`div`,{className:`playground-autotest-best-details`,children:[Ze===`config`&&Xe?(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Context Window:`}),` `,Xe.config?.context_window??`—`]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Prefill Batch Size:`}),` `,Xe.config?.prefill_batch_size??`—`]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`NSeqMax:`}),` `,Xe.config?.nseq_max??`—`]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Flash Attention:`}),` `,Xe.config?.flash_attention??`—`]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`KV Cache Type:`}),` `,Xe.config?.cache_type??`—`]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Cache Mode:`}),` `,Xe.config?.cache_mode?Xe.config.cache_mode===`none`?`None`:Xe.config.cache_mode.toUpperCase():`—`]}),Xe.config?.moe_mode&&(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`MoE Mode:`}),` `,Xe.config.moe_mode===`experts_cpu`?`Experts on CPU`:Xe.config.moe_mode===`keep_top_n`?`Balanced (Top-N on GPU)`:Xe.config.moe_mode===`experts_gpu`?`Experts on GPU`:Xe.config.moe_mode]}),Xe.config?.moe_keep_experts_top_n!==void 0&&Xe.config?.moe_keep_experts_top_n!==null&&(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Expert Layers on GPU:`}),` `,Xe.config.moe_keep_experts_top_n]}),Xe.estimatedVRAM!==void 0&&(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Est. VRAM:`}),` `,J(Xe.estimatedVRAM)]})]}):Ye?(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Temperature:`}),` `,Ye.candidate.temperature]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Top P:`}),` `,Ye.candidate.top_p]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Top K:`}),` `,Ye.candidate.top_k]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Min P:`}),` `,Ye.candidate.min_p]})]}):null,(()=>{let e=Ze===`config`?Xe:Ye;return e?(0,G.jsx)(jb,{trial:e,showScores:Ze!==`config`}):null})()]})]}):(0,G.jsx)(`div`,{style:{fontSize:12,color:`var(--color-gray-700)`},children:`No best configuration could be selected. Adjust weights and reevaluate.`}),(0,G.jsxs)(`details`,{className:`playground-sampling-params`,style:{marginTop:e?12:0},children:[(0,G.jsx)(`summary`,{children:`Best Configuration Criteria`}),(0,G.jsx)(`p`,{style:{fontSize:12,color:`var(--color-gray-600)`,marginBottom:8},children:`Weights control how the best configuration is chosen. Higher weight = more influence.`}),(0,G.jsxs)(`div`,{style:{display:`flex`,gap:6,marginBottom:10},children:[(0,G.jsx)(`button`,{type:`button`,className:`btn btn-small`,onClick:()=>ft(`overall`),children:`Best overall`}),(0,G.jsx)(`button`,{type:`button`,className:`btn btn-small`,onClick:()=>ft(`0pct`),children:`Best at 0% context`}),(0,G.jsx)(`button`,{type:`button`,className:`btn btn-small`,onClick:()=>ft(`80pct`),children:`Best at 80% context`})]}),(0,G.jsx)(`div`,{className:`playground-sweep-params`,children:[...Ze===`config`?[]:[[`chatScore`,`Chat Score`],[`toolScore`,`Tool Score`],[`totalScore`,`Total Score`]],[`avgTPS`,`Avg TPS`],[`avgTTFT`,`Avg TTFT (lower is better)`],[`tps0`,`TPS @0% Fill`],[`tps20`,`TPS @20% Fill`],[`tps50`,`TPS @50% Fill`],[`tps80`,`TPS @80% Fill`],[`ttft0`,`TTFT @0% Fill (lower is better)`],[`ttft20`,`TTFT @20% Fill (lower is better)`],[`ttft50`,`TTFT @50% Fill (lower is better)`],[`ttft80`,`TTFT @80% Fill (lower is better)`]].map(([e,t])=>(0,G.jsxs)(`div`,{className:`playground-sweep-param`,children:[(0,G.jsx)(`label`,{className:`playground-sweep-param-toggle`,htmlFor:`best-config-weight-${e}`,children:t}),(0,G.jsx)(`input`,{id:`best-config-weight-${e}`,type:`number`,className:`playground-sweep-param-values`,value:R[e],onChange:t=>{let n=Number(t.target.value);Number.isFinite(n)&&n>=0&&ut(e,n)},step:.1,min:0})]},e))}),R.totalScore>0&&(R.chatScore>0||R.toolScore>0)&&(0,G.jsx)(`p`,{style:{fontSize:11,color:`var(--color-warning-text)`,marginTop:6},children:`⚠ Total Score is derived from Chat/Tool weights. Weighting Total Score alongside Chat or Tool Score will double-count quality.`}),(0,G.jsx)(`button`,{className:`btn btn-primary btn-small`,style:{marginTop:8},onClick:dt,disabled:!ee,children:`Reevaluate`})]})]})})(),$e.length>0&&(0,G.jsxs)(`details`,{className:`playground-autotest-results`,open:ne,onToggle:e=>re(e.currentTarget.open),children:[(0,G.jsxs)(`summary`,{style:{cursor:`pointer`,fontWeight:600,fontSize:13,color:`var(--color-gray-700)`,marginBottom:8},children:[`Results (`,$e.length,` trials)`,(He===`completed`||He===`cancelled`)&&(()=>{let e=o?.runStartedAt?Date.parse(o.runStartedAt):NaN,t=$e.map(e=>e?.finishedAt?Date.parse(e.finishedAt):NaN).filter(Number.isFinite),n=t.length>0?Math.max(...t):NaN;if(!Number.isFinite(e)||!Number.isFinite(n))return null;let r=$y(Math.max(0,n-e)),i=new Date(n),a=i.toLocaleDateString([],{month:`short`,day:`numeric`,year:`numeric`})+`, `+i.toLocaleTimeString([],{hour:`numeric`,minute:`2-digit`,second:`2-digit`});return(0,G.jsxs)(`span`,{style:{fontWeight:400,fontSize:12,color:`var(--color-gray-500)`,marginLeft:8},children:[`— `,r,` total · finished `,a]})})()]}),(0,G.jsx)(`div`,{className:`playground-autotest-table-scroll`,children:(0,G.jsxs)(`table`,{className:`playground-autotest-table`,children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{children:`#`}),(s||o)&&(0,G.jsx)(`th`,{children:`Actions`}),et.map(e=>(0,G.jsxs)(`th`,{className:e.sortable===!1?void 0:`sortable-th`,onClick:e.sortable===!1?void 0:()=>Se(e.id),children:[e.title,Eb(e.id,ce)]},e.id))]})}),(0,G.jsx)(`tbody`,{children:rt.map((e,t)=>{let n=(e.totalScore===void 0||e.totalScore===null)&&e.status!==`skipped`,r=n&&e.status===`running`,i=Ze===`config`?Xe:Ye,a=i&&e===i&&He===`completed`,c=ie.has(e.id),l=de===e.id,u=pe===e.id&&de!==e.id,d=ue&&e.status===`queued`,f={isPending:n,isInProgress:r,isBest:!!a,index:t};return(0,G.jsxs)(x.Fragment,{children:[(0,G.jsxs)(`tr`,{className:`autotest-trial-row${a?` autotest-best-row`:``}${r?` autotest-running-row`:``}${e.status===`skipped`?` autotest-skipped-row`:``}${l?` autotest-dragging-row`:``}${u?` autotest-dragover-row`:``}`,style:{cursor:`pointer`},onClick:()=>Ce(e.id),draggable:d,onDragStart:d?t=>he(t,e.id):void 0,onDragOver:d?t=>ge(t,e.id):void 0,onDragLeave:d?_e:void 0,onDrop:d?t=>ve(t,e.id):void 0,onDragEnd:d?ye:void 0,children:[(0,G.jsxs)(`td`,{children:[c?`▾`:`▸`,` `,r&&(0,G.jsx)(`span`,{className:`playground-autotest-spinner-inline`}),t+1]}),(s||o)&&(0,G.jsxs)(`td`,{className:`autotest-actions-cell`,onClick:e=>e.stopPropagation(),children:[e.status===`queued`&&(0,G.jsxs)(`span`,{className:`autotest-queue-controls`,children:[(0,G.jsx)(`span`,{className:`autotest-drag-handle${ue?``:` disabled`}`,title:ue?`Drag to reorder`:`Clear column sorting to reorder`,children:`☰`}),(0,G.jsx)(`button`,{className:`btn btn-small autotest-skip-btn`,onClick:()=>m({trialId:e.id}),title:`Skip this trial`,children:`Skip`})]}),e.status===`skipped`&&(0,G.jsx)(`button`,{className:`btn btn-small autotest-unskip-btn`,onClick:()=>h({trialId:e.id}),title:`Restore this trial to the queue`,children:`Unskip`}),e.status===`running`&&(0,G.jsx)(`button`,{className:`btn btn-small btn-danger`,onClick:()=>g(),title:`Stop this trial`,children:`Stop`}),(e.status===`completed`||e.status===`cancelled`||e.status===`failed`)&&(0,G.jsx)(`button`,{className:`btn btn-small`,onClick:()=>_({trialId:e.id}),title:`Rerun this trial (moves to top of queue)`,children:`Rerun`})]}),et.map(t=>(0,G.jsx)(`td`,{children:t.renderCell(e,f)},t.id))]}),c&&(0,G.jsx)(`tr`,{className:`autotest-detail-row`,children:(0,G.jsx)(`td`,{colSpan:et.length+(s||o?2:1),children:(0,G.jsx)(Nb,{trial:e,scenarioLookup:xe,hideScores:Ze===`config`})})})]},e.id)})})]})})]})]})}function Ub(e){let t=new Map,n=0;for(let r of e){let e=r.id.lastIndexOf(`/`);if(e===-1){let e=t.get(r.id);e?e.baseId=r.id:t.set(r.id,{baseId:r.id,variants:[],order:n++})}else{let i=r.id.slice(0,e),a=r.id.slice(e+1);if(!i||!a)continue;let o=t.get(i);o?o.variants.push({id:r.id,suffix:a}):t.set(i,{baseId:null,variants:[{id:r.id,suffix:a}],order:n++})}}let r=Array.from(t.entries()).sort((e,t)=>e[1].order-t[1].order),i=[];for(let[e,t]of r)t.variants.length===0&&t.baseId?i.push({type:`standalone`,id:t.baseId}):i.push({type:`group`,base:e,baseId:t.baseId,variants:t.variants});return i}function Wb(e,t){return t?e.baseId===t||e.variants.some(e=>e.id===t):!1}function Gb(e){return Array.from(e.querySelectorAll(`[role="treeitem"]:not([aria-disabled="true"])`))}function Kb({expanded:e}){return(0,G.jsx)(`span`,{className:`model-selector-chevron${e?` expanded`:``}`,"data-role":`toggle`,"aria-hidden":`true`,children:`▶`})}function qb({models:e,selectedModel:t,onSelect:n,disabled:r=!1,placeholder:i=`Select a model...`,extraItems:a,draftModelIds:o}){let s=(0,x.useRef)(null),[c,l]=(0,x.useState)(()=>new Set),u=e??[],d=(0,x.useMemo)(()=>Ub(u),[u]),f=(0,x.useMemo)(()=>{if(o)return o;let e=new Set;for(let t of u)t.draft_model_id&&e.add(t.id);return e},[u,o]),p=d.length>0||a&&a.length>0;(0,x.useEffect)(()=>{if(t){for(let e of d)if(e.type===`group`&&Wb(e,t)){l(t=>{if(t.has(e.base))return t;let n=new Set(t);return n.add(e.base),n});break}}},[t,d]);let m=(0,x.useCallback)(e=>{l(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},[]),h=(0,x.useCallback)((e,t)=>{let n=s.current;if(!n)return;let r=Gb(n),i=r.indexOf(e),a=t===`down`?i+1:i-1;a>=0&&a{if(r)return;if(e.key===`ArrowDown`||e.key===`ArrowUp`){e.preventDefault(),h(e.currentTarget,e.key===`ArrowDown`?`down`:`up`);return}let t=e.currentTarget.dataset.groupBase;if(t){if(e.key===`ArrowRight`){e.preventDefault(),l(e=>{if(e.has(t))return requestAnimationFrame(()=>{let e=s.current;if(!e)return;let n=e.querySelector(`[data-group-container="${t}"]`)?.querySelector(`[role="treeitem"]`);n&&(n.focus(),n.scrollIntoView({block:`nearest`}))}),e;let n=new Set(e);return n.add(t),n});return}if(e.key===`ArrowLeft`){e.preventDefault(),l(e=>{if(!e.has(t))return e;let n=new Set(e);return n.delete(t),n});return}}if(!t&&e.key===`ArrowLeft`){e.preventDefault();let t=e.currentTarget.closest(`[data-group-container]`);if(t){let e=t.previousElementSibling;e&&e.getAttribute(`role`)===`treeitem`&&(e.focus(),e.scrollIntoView({block:`nearest`}))}return}(e.key===`Enter`||e.key===` `)&&(e.preventDefault(),e.currentTarget.click())},[r,h]),_=(0,x.useCallback)((e,t)=>{r||(e.target.closest(`[data-role="toggle"]`)?m(t.base):t.baseId?n(t.baseId):m(t.base))},[r,n,m]);return(0,G.jsxs)(`div`,{className:`model-selector${r?` model-selector-disabled`:``}`,role:`tree`,"aria-label":i,"aria-multiselectable":!1,ref:s,children:[!p&&(0,G.jsx)(`div`,{className:`model-selector-empty`,children:i}),d.map(e=>{if(e.type===`standalone`)return(0,G.jsx)(`div`,{role:`treeitem`,"aria-selected":t===e.id,"aria-level":1,"aria-disabled":r,tabIndex:r?-1:0,className:`model-selector-item${t===e.id?` active`:``}`,onClick:()=>{r||n(e.id)},onKeyDown:g,title:e.id,children:(0,G.jsxs)(`span`,{className:`model-selector-label`,children:[f.has(e.id)?`⚡ `:``,e.id]})},e.id);let i=c.has(e.base),a=Wb(e,t),o=e.baseId?f.has(e.baseId):e.variants.some(e=>f.has(e.id));return(0,G.jsxs)(`div`,{className:`model-selector-group`,children:[(0,G.jsxs)(`div`,{role:`treeitem`,"aria-expanded":i,"aria-selected":e.baseId?t===e.baseId:!1,"aria-level":1,"aria-disabled":r,"data-group-base":e.base,tabIndex:r?-1:0,className:`model-selector-item model-selector-group-header${a?` active`:``}`,onClick:t=>_(t,e),onKeyDown:g,title:e.base,children:[(0,G.jsx)(Kb,{expanded:i}),(0,G.jsxs)(`span`,{className:`model-selector-label`,children:[o?`⚡ `:``,e.base]})]}),i&&(0,G.jsx)(`div`,{role:`group`,"data-group-container":e.base,children:e.variants.map(e=>(0,G.jsx)(`div`,{role:`treeitem`,"aria-selected":t===e.id,"aria-level":2,"aria-disabled":r,tabIndex:r?-1:0,className:`model-selector-item model-selector-subitem${t===e.id?` active`:``}`,onClick:()=>{r||n(e.id)},onKeyDown:g,title:e.id,children:(0,G.jsxs)(`span`,{className:`model-selector-label`,children:[f.has(e.id)?`⚡ `:``,e.suffix]})},e.id))})]},e.base)}),a?.map(e=>(0,G.jsx)(`div`,{role:`treeitem`,"aria-selected":t===e.id,"aria-level":1,"aria-disabled":r,tabIndex:r?-1:0,className:`model-selector-item model-selector-extra${t===e.id?` active`:``}`,onClick:()=>{r||n(e.id)},onKeyDown:g,title:e.label,children:(0,G.jsx)(`span`,{className:`model-selector-label`,children:e.label})},e.id))]})}function Jb({filterMode:e}){let[t,n]=(0,x.useState)([]),r=(0,x.useMemo)(()=>e?t.filter(t=>t.sweepMode===e):t,[t,e]),[i,a]=(0,x.useState)(!0),[o,s]=(0,x.useState)(null),[c,l]=(0,x.useState)(new Set),[u,d]=(0,x.useState)({column:null,direction:null}),[f,p]=(0,x.useState)(new Set),[m,h]=(0,x.useState)(()=>({...lr})),[g,_]=(0,x.useState)(!1),[v,y]=(0,x.useState)(null),b=(0,x.useRef)({...lr}),S=(0,x.useRef)(null),C=(0,x.useRef)(null);(0,x.useEffect)(()=>{let e=!0;return bi().then(t=>{e&&(n(t),a(!1))}),()=>{e=!1}},[]),(0,x.useEffect)(()=>{let e=()=>{bi().then(n)},t=t=>{t instanceof StorageEvent&&t.key!==`playground:autoTestHistory:updatedAt`||e()};return window.addEventListener(`autotest-history-updated`,e),window.addEventListener(`storage`,t),()=>{window.removeEventListener(`autotest-history-updated`,e),window.removeEventListener(`storage`,t)}},[]),(0,x.useEffect)(()=>{if(!v)return;let e=setTimeout(()=>y(null),4e3);return()=>clearTimeout(e)},[v]),(0,x.useEffect)(()=>{let e=new Set(r.map(e=>e.id));l(t=>{let n=!1;for(let r of t)if(!e.has(r)){n=!0;break}if(!n)return t;let r=new Set;for(let n of t)e.has(n)&&r.add(n);return r})},[r]),(0,x.useEffect)(()=>{if(!C.current)return;let e=c.size,t=r.length;C.current.indeterminate=e>0&&er.find(e=>e.id===o)??null,[r,o]),T=(0,x.useCallback)(e=>{let t=r.find(t=>t.id===e);s(e),l(new Set),d({column:null,direction:null}),p(new Set);let n={...t?.run?.kind===`config`?ur:lr,...t?.run?.weights??{}};h({...n}),b.current={...n},_(!1)},[r]),E=(0,x.useCallback)(e=>{Ci(e),o===e&&s(null)},[o]),D=(0,x.useCallback)(()=>{c.size!==0&&(wi(Array.from(c)),o&&c.has(o)&&s(null),l(new Set))},[c,o]),O=(0,x.useCallback)(async()=>{let e=await Ti(),t=URL.createObjectURL(e),n=document.createElement(`a`),r=new Date().toISOString().slice(0,10);n.href=t,n.download=`autotest-history-${r}.json`,document.body.appendChild(n),n.click(),document.body.removeChild(n),URL.revokeObjectURL(t)},[]),k=(0,x.useCallback)(async e=>{try{let t=await Ei(await e.text());y(`Imported ${t.imported} entr${t.imported===1?`y`:`ies`}${t.skipped>0?` (${t.skipped} skipped)`:``}`)}catch(e){y(`Import failed: ${e instanceof Error?e.message:`unknown error`}`)}},[]),A=(0,x.useCallback)((e,t)=>{h(n=>{let r={...n,[e]:t},i=b.current,a=Object.keys(r).some(e=>r[e]!==i[e]);return _(a),r})},[]),j=(0,x.useCallback)(e=>{if(!w)return;let t=w.run?.trials;if(!Array.isArray(t))return;let n=t,r=null,i=-1/0,a=-1/0;for(let t of n){if(t.status!==`completed`)continue;let n=fr(t,e);(n>i||n===i&&(t.avgTPS??0)>a)&&(i=n,a=t.avgTPS??0,r=t.id)}Si(w.id,t=>({...t,run:{...t.run,bestTrialId:r??void 0,weights:{...e}}})),b.current={...e},_(!1)},[w]),M=(0,x.useCallback)(()=>{j(m)},[m,j]),N=(0,x.useCallback)(e=>{if(!w)return;let t=w.run.kind,n=dr(e,t);h(n),j(n)},[w,j]),P=(0,x.useCallback)(e=>{d(t=>({column:t.column===e&&Tb(t.direction)===null?null:e,direction:t.column===e?Tb(t.direction):`asc`}))},[]),F=(0,x.useCallback)(e=>{p(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},[]),I=w?w.run.kind:null,L=(0,x.useMemo)(()=>I===`config`?bb():yb(),[I]),R=(0,x.useMemo)(()=>Object.fromEntries(L.map(e=>[e.id,e])),[L]),z=(0,x.useCallback)((e,t)=>R[t]?.getValue(e),[R]),ee=w?w.run.trials:[],B=(0,x.useMemo)(()=>Db(ee,u,z),[ee,u,z]),V=w?.run.bestTrialId??null,te=I===`sampling`&&V?ee.find(e=>e.id===V)??null:null,H=I===`config`&&V?ee.find(e=>e.id===V)??null:null,ne=(0,x.useMemo)(()=>{let e={},t=I===`config`?Qn:Gn;return e[t.id]=t,I!==`config`&&(e[Zn.id]=Zn),e},[I]);if(w){let e=!!(I===`config`?H:te);return(0,G.jsxs)(`div`,{className:`playground-history-container`,children:[(0,G.jsx)(`button`,{className:`btn btn-small btn-secondary`,style:{marginBottom:12},onClick:()=>s(null),children:`← Back to list`}),(0,G.jsxs)(`div`,{style:{fontSize:13,color:`var(--color-gray-700)`,marginBottom:12},children:[(0,G.jsx)(`strong`,{children:w.modelId||`Unknown model`}),` · `,w.sweepMode===`config`?`Config Sweep`:`Sampling Sweep`,` · `,w.completedAt?new Date(w.completedAt).toLocaleDateString([],{month:`short`,day:`numeric`,year:`numeric`})+`, `+new Date(w.completedAt).toLocaleTimeString([],{hour:`numeric`,minute:`2-digit`}):`—`]}),(0,G.jsxs)(`div`,{className:`playground-autotest-best`,children:[e?(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`h4`,{children:`Best Configuration Found`}),(0,G.jsxs)(`div`,{className:`playground-autotest-best-details`,children:[I===`config`&&H?(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Context Window:`}),` `,H.config?.context_window??`—`]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Prefill Batch Size:`}),` `,H.config?.prefill_batch_size??`—`]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`NSeqMax:`}),` `,H.config?.nseq_max??`—`]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Flash Attention:`}),` `,H.config?.flash_attention??`—`]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`KV Cache Type:`}),` `,H.config?.cache_type??`—`]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Cache Mode:`}),` `,H.config?.cache_mode?H.config.cache_mode===`none`?`None`:H.config.cache_mode.toUpperCase():`—`]})]}):te?(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Temperature:`}),` `,te.candidate.temperature]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Top P:`}),` `,te.candidate.top_p]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Top K:`}),` `,te.candidate.top_k]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`strong`,{children:`Min P:`}),` `,te.candidate.min_p]})]}):null,(()=>{let e=I===`config`?H:te;return e?(0,G.jsx)(jb,{trial:e,showScores:I!==`config`}):null})()]})]}):(0,G.jsx)(`div`,{style:{fontSize:12,color:`var(--color-gray-700)`},children:`No best configuration could be selected. Adjust weights and reevaluate.`}),(0,G.jsxs)(`details`,{className:`playground-sampling-params`,style:{marginTop:e?12:0},children:[(0,G.jsx)(`summary`,{children:`Best Configuration Criteria`}),(0,G.jsx)(`p`,{style:{fontSize:12,color:`var(--color-gray-600)`,marginBottom:8},children:`Weights control how the best configuration is chosen. Higher weight = more influence.`}),(0,G.jsxs)(`div`,{style:{display:`flex`,gap:6,marginBottom:10},children:[(0,G.jsx)(`button`,{type:`button`,className:`btn btn-small`,onClick:()=>N(`overall`),children:`Best overall`}),(0,G.jsx)(`button`,{type:`button`,className:`btn btn-small`,onClick:()=>N(`0pct`),children:`Best at 0% context`}),(0,G.jsx)(`button`,{type:`button`,className:`btn btn-small`,onClick:()=>N(`80pct`),children:`Best at 80% context`})]}),(0,G.jsx)(`div`,{className:`playground-sweep-params`,children:[...I===`config`?[]:[[`chatScore`,`Chat Score`],[`toolScore`,`Tool Score`],[`totalScore`,`Total Score`]],[`avgTPS`,`Avg TPS`],[`avgTTFT`,`Avg TTFT (lower is better)`],[`tps0`,`TPS @0% Fill`],[`tps20`,`TPS @20% Fill`],[`tps50`,`TPS @50% Fill`],[`tps80`,`TPS @80% Fill`],[`ttft0`,`TTFT @0% Fill (lower is better)`],[`ttft20`,`TTFT @20% Fill (lower is better)`],[`ttft50`,`TTFT @50% Fill (lower is better)`],[`ttft80`,`TTFT @80% Fill (lower is better)`]].map(([e,t])=>(0,G.jsxs)(`div`,{className:`playground-sweep-param`,children:[(0,G.jsx)(`label`,{className:`playground-sweep-param-toggle`,htmlFor:`history-weight-${e}`,children:t}),(0,G.jsx)(`input`,{id:`history-weight-${e}`,type:`number`,className:`playground-sweep-param-values`,value:m[e],onChange:t=>{let n=Number(t.target.value);Number.isFinite(n)&&n>=0&&A(e,n)},step:.1,min:0})]},e))}),m.totalScore>0&&(m.chatScore>0||m.toolScore>0)&&(0,G.jsx)(`p`,{style:{fontSize:11,color:`var(--color-warning-text)`,marginTop:6},children:`⚠ Total Score is derived from Chat/Tool weights. Weighting Total Score alongside Chat or Tool Score will double-count quality.`}),(0,G.jsx)(`button`,{className:`btn btn-primary btn-small`,style:{marginTop:8},onClick:M,disabled:!g,children:`Reevaluate`})]})]}),ee.length>0&&(0,G.jsxs)(`details`,{className:`playground-autotest-results`,open:!0,children:[(0,G.jsxs)(`summary`,{style:{cursor:`pointer`,fontWeight:600,fontSize:13,color:`var(--color-gray-700)`,marginBottom:8},children:[`Results (`,ee.length,` trials)`,(()=>{let e=w.run.runStartedAt?Date.parse(w.run.runStartedAt):NaN,t=ee.map(e=>e?.finishedAt?Date.parse(e.finishedAt):NaN).filter(Number.isFinite),n=t.length>0?Math.max(...t):NaN;if(!Number.isFinite(e)||!Number.isFinite(n))return null;let r=$y(Math.max(0,n-e)),i=new Date(n),a=i.toLocaleDateString([],{month:`short`,day:`numeric`,year:`numeric`})+`, `+i.toLocaleTimeString([],{hour:`numeric`,minute:`2-digit`,second:`2-digit`});return(0,G.jsxs)(`span`,{style:{fontWeight:400,fontSize:12,color:`var(--color-gray-500)`,marginLeft:8},children:[`— `,r,` total · finished `,a]})})()]}),(0,G.jsx)(`div`,{className:`playground-autotest-table-scroll`,children:(0,G.jsxs)(`table`,{className:`playground-autotest-table`,children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{children:`#`}),L.map(e=>(0,G.jsxs)(`th`,{className:e.sortable===!1?void 0:`sortable-th`,onClick:e.sortable===!1?void 0:()=>P(e.id),children:[e.title,Eb(e.id,u)]},e.id))]})}),(0,G.jsx)(`tbody`,{children:B.map((e,t)=>{let n=e.status===`queued`||e.status===`running`,r=I===`config`?H:te,i=r&&e===r,a=f.has(e.id),o={isPending:n,isInProgress:!1,isBest:!!i,index:t};return(0,G.jsxs)(x.Fragment,{children:[(0,G.jsxs)(`tr`,{className:`autotest-trial-row${i?` autotest-best-row`:``}${e.status===`skipped`?` autotest-skipped-row`:``}`,style:{cursor:`pointer`},onClick:()=>F(e.id),children:[(0,G.jsxs)(`td`,{children:[a?`▾`:`▸`,` `,t+1]}),L.map(t=>(0,G.jsx)(`td`,{children:t.renderCell(e,o)},t.id))]}),a&&(0,G.jsx)(`tr`,{className:`autotest-detail-row`,children:(0,G.jsx)(`td`,{colSpan:L.length+1,children:(0,G.jsx)(Nb,{trial:e,scenarioLookup:ne,hideScores:I===`config`})})})]},e.id)})})]})})]})]})}return i?(0,G.jsx)(`div`,{className:`playground-history-container`,children:(0,G.jsx)(`div`,{style:{fontSize:13,color:`var(--color-gray-500)`,padding:16},children:`Loading history…`})}):(0,G.jsx)(`div`,{className:`playground-history-container`,children:(0,G.jsxs)(`div`,{className:`playground-history-list`,children:[(0,G.jsxs)(`div`,{className:`playground-history-header`,children:[(0,G.jsx)(`h3`,{children:`Test Run History`}),r.length>0&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`input`,{ref:C,type:`checkbox`,checked:c.size===r.length&&r.length>0,onChange:()=>{c.size===r.length?l(new Set):l(new Set(r.map(e=>e.id)))},style:{marginLeft:8}}),(0,G.jsxs)(`span`,{style:{fontSize:12,color:`var(--color-gray-500)`},children:[r.length,` run`,r.length===1?``:`s`]})]}),c.size>0&&(0,G.jsxs)(`button`,{className:`btn btn-small btn-danger`,style:{marginLeft:8},onClick:D,children:[`Delete Selected (`,c.size,`)`]}),(0,G.jsx)(`button`,{className:`btn btn-small btn-secondary`,style:{marginLeft:8},onClick:()=>{O()},children:`Export`}),(0,G.jsx)(`button`,{className:`btn btn-small btn-secondary`,style:{marginLeft:4},onClick:()=>S.current?.click(),children:`Import`}),(0,G.jsx)(`input`,{ref:S,type:`file`,accept:`.json`,style:{display:`none`},onChange:e=>{let t=e.target.files?.[0];t&&k(t),e.target.value=``}}),v&&(0,G.jsx)(`span`,{style:{fontSize:12,color:`var(--color-gray-600)`,marginLeft:8},children:v})]}),r.length===0?(0,G.jsx)(`div`,{className:`playground-history-empty`,children:`No test runs saved yet. Complete an automated test run and it will appear here.`}):r.map(e=>(0,G.jsxs)(`div`,{className:`playground-history-item ${o===e.id?`active`:``}`,onClick:()=>T(e.id),children:[(0,G.jsx)(`input`,{type:`checkbox`,checked:c.has(e.id),onClick:e=>e.stopPropagation(),onChange:()=>{l(t=>{let n=new Set(t);return n.has(e.id)?n.delete(e.id):n.add(e.id),n})}}),(0,G.jsxs)(`div`,{className:`playground-history-item-content`,children:[(0,G.jsx)(`div`,{className:`playground-history-item-model`,children:e.modelId||`Unknown model`}),(0,G.jsxs)(`div`,{className:`playground-history-item-meta`,children:[(0,G.jsx)(`span`,{className:`playground-history-item-mode`,children:e.sweepMode===`config`?`Config Sweep`:`Sampling Sweep`}),(0,G.jsx)(`span`,{className:`playground-history-item-date`,children:e.completedAt?new Date(e.completedAt).toLocaleDateString([],{month:`short`,day:`numeric`,year:`numeric`})+`, `+new Date(e.completedAt).toLocaleTimeString([],{hour:`numeric`,minute:`2-digit`}):`—`})]}),(0,G.jsxs)(`div`,{className:`playground-history-item-stats`,children:[e.run.trials?.length??0,` trials`]})]}),(0,G.jsx)(`button`,{className:`btn btn-small btn-danger playground-history-delete`,onClick:t=>{t.stopPropagation(),E(e.id)},children:`Delete`})]},e.id))]})})}var Yb=`__new__`,Xb=JSON.stringify(K,null,2);function Zb({mode:e}){let{models:t,loadModels:n}=In(),{download:r,isDownloading:i,startDownload:a,cancelDownload:o,clearDownload:s}=zn(),{session:c,setSession:l,chatMessages:u,setChatMessages:d,selectedModel:f,setSelectedModel:p,playgroundMode:m,setPlaygroundMode:h,setSweepMode:g,activeTab:_,setActiveTab:v,systemPrompt:y,setSystemPrompt:b,templateMode:S,setTemplateMode:C,selectedTemplate:w,setSelectedTemplate:T,customScript:E,setCustomScript:D,contextWindow:O,setContextWindow:k,prefillBatchSize:A,setPrefillBatchSize:j,nSeqMax:M,setNSeqMax:N,flashAttention:P,setFlashAttention:F,cacheType:I,setCacheType:L,loadMode:R,setLoadMode:z,cacheMode:ee,setCacheMode:B,moeMode:V,setMoeMode:te,moeKeepTopN:H,setMoeKeepTopN:ne,tensorBuftOverrides:re,setTensorBuftOverrides:ie,hydratedModelId:ae,setHydratedModelId:oe}=Ui();(0,x.useEffect)(()=>{e===`manual`?h(`manual`):(h(`automated`),g(e))},[e,h,g]);let[se,ce]=(0,x.useState)([]),[le,ue]=(0,x.useState)(.8),[de,fe]=(0,x.useState)(.9),[pe,me]=(0,x.useState)(40),[he,ge]=(0,x.useState)(0),[_e,ve]=(0,x.useState)(4096),[ye,be]=(0,x.useState)(1),[xe,Se]=(0,x.useState)(64),[Ce,we]=(0,x.useState)(0),[Te,Ee]=(0,x.useState)(0),[De,Oe]=(0,x.useState)(1.05),[ke,Ae]=(0,x.useState)(1.75),[je,Me]=(0,x.useState)(2),[Ne,Pe]=(0,x.useState)(0),[Fe,Ie]=(0,x.useState)(0),[Le,Re]=(0,x.useState)(.1),[ze,Be]=(0,x.useState)(1),[Ve,He]=(0,x.useState)(`true`),[Ue,We]=(0,x.useState)(`medium`),[Ge,Ke]=(0,x.useState)(null),[qe,Je]=(0,x.useState)(null),[Ye,Xe]=(0,x.useState)(!1),[Ze,Qe]=(0,x.useState)(!1),[$e,et]=(0,x.useState)(``),tt=(0,x.useRef)(null),nt=(0,x.useRef)(c);nt.current=c;let[rt,it]=(0,x.useState)(!1),[at,ot]=(0,x.useState)(``),[st,ct]=(0,x.useState)(``),[lt,ut]=(0,x.useState)(!1),dt=(0,x.useRef)(new Set),ft=(0,x.useRef)(!1),pt=(0,x.useRef)(``),mt=Ka(),[ht,gt]=(0,x.useState)(void 0),_t=sa(ht),[vt,yt]=(0,x.useState)(0),[bt,xt]=(0,x.useState)(null),St=$a(bt,ht),Ct=(0,x.useMemo)(()=>ht?Object.entries(ht).some(([e,t])=>e.endsWith(`nextn_predict_layers`)&&parseInt(t,10)>0):!1,[ht]),wt=!!qe?.[`draft-model`]?.[`model-id`],Tt=Ct&&!wt,[Et,Dt]=(0,x.useState)(Xb),[Ot,kt]=(0,x.useState)(`What's the weather in Boston? Use the get_weather tool.`),[At,U]=(0,x.useState)(``),[jt,Mt]=(0,x.useState)([]),[Nt,Pt]=(0,x.useState)(!1),Ft=(0,x.useCallback)(async()=>{try{let e=await W.listPlaygroundTemplates();ce(e)}catch{}},[]);(0,x.useEffect)(()=>{n(),Ft()},[n,Ft]),(0,x.useEffect)(()=>{if(!f||f===Yb){Je(null);return}if(ae===f)return;let e=!1;return Xe(!0),W.showModel(f).then(t=>{if(e)return;let n=t.model_config;if(n){let e=n[`nseq-max`]||1;Je(n),k(n[`context-window`]||8192),j(n[`prefill-batch-size`]||2048),N(e),F(n[`flash-attention`]||`auto`),L(n[`cache-type-k`]||n[`cache-type-v`]||``),z(n[`load-mode`]||`auto`),B(n[`incremental-cache`]?`imc`:`none`),te(n.moe?.mode||``),ne(n.moe?.[`keep-experts-top-n`]??0)}if(gt(t.metadata),xt(t.vram||null),t.metadata){let e=Object.keys(t.metadata).find(e=>e.endsWith(`.block_count`));yt(e&&parseInt(t.metadata[e],10)||0)}oe(f)}).catch(t=>{e||et(t.message||`Failed to load model config`)}).finally(()=>{e||Xe(!1)}),()=>{e=!0}},[f,ae]),(0,x.useEffect)(()=>()=>{tt.current?.()},[]);let It=()=>{let e=at.trim();!e||i||c||(dt.current=new Set(t?.data?.map(e=>e.id)||[]),pt.current=e.split(`/`).pop()||``,ft.current=!0,a(e,st.trim()||void 0))};(0,x.useEffect)(()=>{if(!ft.current)return;if(r?.status===`error`){ft.current=!1;return}if(r?.status!==`complete`)return;let e=dt.current,n=t?.data??[],i=n.filter(t=>!e.has(t.id)),a=pt.current,o=i.find(e=>a&&e.id.includes(a))??i.find(e=>!e.id.includes(`mmproj`)&&!e.id.includes(`proj`))??i[0]??n.find(e=>a&&e.id.includes(a));ft.current=!1,o&&(p(o.id),it(!1),ot(``),ct(``),ut(!1)),s()},[t,r?.status]);let Lt=async()=>{if(f){Qe(!0),et(``);try{let e={};(!qe||O!==(qe[`context-window`]||8192))&&(e.context_window=O),(!qe||A!==(qe[`prefill-batch-size`]||2048))&&(e.prefill_batch_size=A),(!qe||M!==(qe[`nseq-max`]||1))&&(e.nseq_max=M),(!qe||P!==(qe[`flash-attention`]||`auto`))&&(e.flash_attention=P),(!qe||I!==(qe[`cache-type-k`]||``))&&(e.cache_type_k=I||`f16`,e.cache_type_v=I||`f16`),(!qe||R!==(qe[`load-mode`]||`auto`))&&(e.load_mode=R);let t=qe?.[`incremental-cache`]?`imc`:`none`;(!qe||ee!==t)&&(e.incremental_cache=ee===`imc`),V&&(e.moe_mode=V,V===`keep_top_n`&&(e.moe_keep_experts_top_n=H)),V===`custom`&&re.length>0&&(e.tensor_buft_overrides=re),Tt&&Ge!=null&&(e.draft_ndraft=Ge);let n=await W.createPlaygroundSession({model_id:f,template_mode:S,template_name:S===`builtin`?w:void 0,template_script:S===`custom`?E:void 0,config:e});l(n),d([])}catch(e){et(e.message||`Failed to load model`)}finally{Qe(!1)}}},Rt=async()=>{if(c){tt.current?.(),tt.current=null,Pt(!1);try{await W.deletePlaygroundSession(c.session_id),l(null),d([])}catch(e){et(e.message||`Failed to unload model`)}}},zt=(0,x.useCallback)(()=>{if(!c||Nt)return;Pt(!0),U(``),Mt([]);let e;try{e=JSON.parse(Et)}catch{U(`Invalid JSON in tool definitions`),Pt(!1);return}let t=[{role:`user`,content:Ot}],n=``,r=[],i=W.streamPlaygroundChat({session_id:c.session_id,messages:t,tools:e,stream:!0},e=>{let t=e.choices?.[0];if(t?.delta?.content&&(n+=t.delta.content),t?.delta?.tool_calls)for(let e of t.delta.tool_calls){let t=r.find(t=>t.index===e.index);t?(e.id&&!t.id&&(t.id=e.id),e.type&&(t.type=e.type),e.function?.name&&!t.function.name&&(t.function.name=e.function.name),e.function?.arguments&&(t.function.arguments+=e.function.arguments)):r.push({id:e.id||``,index:e.index,type:e.type||`function`,function:{name:e.function?.name||``,arguments:e.function?.arguments||``}})}t?.finish_reason===`tool_calls`&&Mt([...r])},e=>{tt.current=null,U(`Error: ${e}`),Pt(!1)},()=>{tt.current=null,U(n),r.length>0&&Mt([...r]),Pt(!1)});tt.current=i},[c,Nt,Et,Ot]),Bt=(0,x.useMemo)(()=>({maxTokens:_e,temperature:le,topP:de,topK:pe,minP:he,presencePenalty:Te,repeatPenalty:ye,repeatLastN:xe,dryMultiplier:De,dryBase:ke,dryAllowedLen:je,dryPenaltyLast:Ne,xtcProbability:Fe,xtcThreshold:Le,xtcMinKeep:ze,frequencyPenalty:Ce,enableThinking:Ve,reasoningEffort:Ue,includeUsage:!0,logprobs:!1,topLogprobs:0,grammar:``,systemPrompt:y}),[_e,le,de,pe,he,Te,ye,xe,De,ke,je,Ne,Fe,Le,ze,Ce,Ve,Ue,y]),Vt=(0,x.useCallback)(e=>{e.maxTokens!==void 0&&ve(e.maxTokens),e.temperature!==void 0&&ue(e.temperature),e.topP!==void 0&&fe(e.topP),e.topK!==void 0&&me(e.topK),e.minP!==void 0&&ge(e.minP),e.presencePenalty!==void 0&&Ee(e.presencePenalty),e.repeatPenalty!==void 0&&be(e.repeatPenalty),e.repeatLastN!==void 0&&Se(e.repeatLastN),e.dryMultiplier!==void 0&&Oe(e.dryMultiplier),e.dryBase!==void 0&&Ae(e.dryBase),e.dryAllowedLen!==void 0&&Me(e.dryAllowedLen),e.dryPenaltyLast!==void 0&&Pe(e.dryPenaltyLast),e.xtcProbability!==void 0&&Ie(e.xtcProbability),e.xtcThreshold!==void 0&&Re(e.xtcThreshold),e.xtcMinKeep!==void 0&&Be(e.xtcMinKeep),e.frequencyPenalty!==void 0&&we(e.frequencyPenalty),e.enableThinking!==void 0&&He(e.enableThinking),e.reasoningEffort!==void 0&&We(e.reasoningEffort),e.systemPrompt!==void 0&&b(e.systemPrompt)},[b]),Ht=(0,x.useCallback)(({messages:e,sampling:t,onMessage:n,onError:r,onComplete:i})=>c?W.streamPlaygroundChat({session_id:c.session_id,messages:e,stream:!0,stream_options:{include_usage:t.includeUsage},temperature:t.temperature,top_p:t.topP,top_k:t.topK,min_p:t.minP,max_tokens:t.maxTokens,repeat_penalty:t.repeatPenalty,repeat_last_n:t.repeatLastN,frequency_penalty:t.frequencyPenalty,presence_penalty:t.presencePenalty,dry_multiplier:t.dryMultiplier,dry_base:t.dryBase,dry_allowed_length:t.dryAllowedLen,dry_penalty_last_n:t.dryPenaltyLast,xtc_probability:t.xtcProbability,xtc_threshold:t.xtcThreshold,xtc_min_keep:t.xtcMinKeep,enable_thinking:t.enableThinking||void 0,reasoning_effort:t.reasoningEffort||void 0,grammar:t.grammar||void 0,logprobs:t.logprobs,top_logprobs:t.topLogprobs},n,r,i):(r(`No model loaded`),()=>{}),[c]),Ut=(0,x.useCallback)(()=>{d([])},[d]);return(0,G.jsxs)(`div`,{className:`playground-container`,children:[(0,G.jsx)(`div`,{className:`playground-header`,children:(0,G.jsxs)(`div`,{className:`playground-header-title`,children:[(0,G.jsx)(`h2`,{children:e===`manual`?`Basic`:e===`sampling`?`Sampling`:`Configuration`}),(0,G.jsx)(`p`,{className:`playground-header-subtitle`,children:e===`manual`?`Verify a model performs the basic tasks it needs to — chat and tool calling — correctly.`:e===`sampling`?`Find the sampling parameters that produce the best quality and speed for a model.`:`Find the runtime configuration that runs a model the fastest within your hardware limits.`})]})}),(0,G.jsxs)(`div`,{className:`playground-layout`,children:[(0,G.jsxs)(`div`,{className:`playground-mode-selector`,children:[(0,G.jsxs)(`div`,{className:`playground-model-config`,children:[(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(`label`,{children:`Model`}),(0,G.jsx)(qb,{models:t?.data,selectedModel:rt?Yb:f,onSelect:e=>{e===Yb?(p(``),it(!0)):(p(e),it(!1))},disabled:!!c,extraItems:[{id:Yb,label:`New…`}]})]}),rt&&!c&&(0,G.jsxs)(`div`,{className:`playground-pull-form`,children:[(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(`label`,{children:`HuggingFace Model URL or Shorthand`}),(0,G.jsx)(`input`,{type:`text`,value:at,onChange:e=>ot(e.target.value),placeholder:`owner/repo:Q4_K_M or org/repo/model.gguf`,disabled:i})]}),(0,G.jsx)(`button`,{type:`button`,className:`btn btn-secondary btn-small playground-pull-toggle`,onClick:()=>ut(e=>!e),disabled:i,children:lt?`− Hide projection URL`:`+ Projection URL (optional)`}),lt&&(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(`label`,{children:`Projection URL (vision/audio models)`}),(0,G.jsx)(`input`,{type:`text`,value:st,onChange:e=>ct(e.target.value),placeholder:`org/repo/mmproj.gguf`,disabled:i})]}),(0,G.jsxs)(`div`,{className:`playground-pull-actions`,children:[(0,G.jsx)(`button`,{className:`btn btn-primary`,type:`button`,onClick:It,disabled:i||!at.trim(),children:i?`Pulling…`:`Pull`}),i&&(0,G.jsx)(`button`,{className:`btn btn-danger`,type:`button`,onClick:o,children:`Cancel`}),r&&r.status!==`downloading`&&(0,G.jsx)(`button`,{className:`btn`,type:`button`,onClick:s,children:`Clear`})]}),r&&r.meta&&(0,G.jsx)(is,{meta:r.meta}),r&&r.progress&&i&&(0,G.jsx)(Uo,{progress:r.progress,meta:r.meta}),r&&r.messages.length>0&&(0,G.jsx)(`div`,{className:`status-box playground-pull-status`,children:r.messages.map((e,t)=>(0,G.jsx)(`div`,{className:`status-line ${e.type}`,children:e.text},t))})]}),(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(`label`,{htmlFor:`pg-template-mode`,children:`Template Mode`}),(0,G.jsxs)(`select`,{id:`pg-template-mode`,value:S,onChange:e=>C(e.target.value),disabled:!!c,children:[(0,G.jsx)(`option`,{value:`builtin`,children:`Builtin`}),(0,G.jsx)(`option`,{value:`custom`,children:`Custom`})]})]}),S===`builtin`?(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(`label`,{htmlFor:`pg-template`,children:`Template`}),(0,G.jsxs)(`select`,{id:`pg-template`,value:w,onChange:e=>T(e.target.value),disabled:!!c,children:[(0,G.jsx)(`option`,{value:``,children:`Auto (from catalog)`}),se.map(e=>(0,G.jsx)(`option`,{value:e.name,children:e.name},e.name))]})]}):(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(`label`,{htmlFor:`pg-template-script`,children:`Template Script`}),(0,G.jsx)(`textarea`,{id:`pg-template-script`,value:E,onChange:e=>D(e.target.value),disabled:!!c,rows:8,className:`playground-textarea`,placeholder:`Paste Jinja template...`})]})]}),mt&&(0,G.jsxs)(`div`,{className:`playground-system-info`,children:[mt.gpuCount>0&&(0,G.jsxs)(`span`,{children:[mt.gpuCount,` GPU`,mt.gpuCount>1?`s`:``,mt.gpuType?` (${mt.gpuType})`:``]}),mt.gpuDevices.map(e=>(0,G.jsxs)(`span`,{children:[e.name,`: `,e.description||e.name,` (`,e.hardware_type,`, `,e.backend,`)`]},e.index)),mt.gpuVramBytes>0&&(0,G.jsxs)(`span`,{children:[`Total VRAM: `,J(mt.gpuVramBytes)]}),mt.ramBytes>0&&(0,G.jsxs)(`span`,{children:[`System RAM: `,J(mt.ramBytes)]})]}),(0,G.jsx)(`button`,{className:`playground-mode-btn ${m===`history`?``:`active`}`,onClick:()=>h(e===`manual`?`manual`:`automated`),children:e===`manual`?`Basic`:e===`sampling`?`Sampling`:`Configuration`}),e!==`manual`&&(0,G.jsx)(`button`,{className:`playground-mode-btn ${m===`history`?`active`:``}`,onClick:()=>h(`history`),children:`History`})]}),m===`automated`&&(0,G.jsx)(`div`,{className:`playground-test`,style:{flex:1},children:(0,G.jsx)(`div`,{className:`playground-tab-content`,children:(0,G.jsx)(Hb,{session:c,catalogSampling:qe?.[`sampling-parameters`]??null,isMoE:St,gpuVramBytes:mt?.gpuVramBytes,lockSweep:e===`sampling`||e===`config`,sessionSeed:{model_id:f,template_mode:S,template_name:S===`builtin`?w:void 0,template_script:S===`custom`?E:void 0,base_config:{context_window:O,prefill_batch_size:A,nseq_max:M,flash_attention:P,cache_type_k:I||void 0,cache_type_v:I||void 0,load_mode:R,incremental_cache:ee===`imc`,moe_mode:V||void 0,moe_keep_experts_top_n:V===`keep_top_n`?H:void 0,tensor_buft_overrides:V===`custom`&&re.length>0?re:void 0,draft_ndraft:Tt&&Ge!=null?Ge:void 0}}})})}),m===`history`&&(0,G.jsx)(`div`,{className:`playground-test`,style:{flex:1},children:(0,G.jsx)(`div`,{className:`playground-tab-content`,children:(0,G.jsx)(Jb,{filterMode:e===`sampling`||e===`config`?e:void 0})})}),m===`manual`&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(`div`,{className:`playground-setup`,children:[(0,G.jsx)(`h3`,{children:`Setup`}),St&&!c&&mt&&(0,G.jsxs)(`div`,{className:`playground-moe-guide`,children:[(0,G.jsxs)(`div`,{className:`playground-moe-guide-header`,children:[(0,G.jsx)(`span`,{className:`playground-moe-guide-icon`,children:`🧩`}),(0,G.jsx)(`span`,{children:`Mixture of Experts Model Detected`})]}),(0,G.jsx)(`div`,{className:`playground-moe-guide-body`,children:(0,G.jsxs)(`div`,{className:`playground-moe-guide-hw`,children:[(0,G.jsx)(`strong`,{children:`Your Hardware:`}),` `,mt.gpuType||`GPU`,` — `,J(mt.gpuVramBytes),` VRAM, `,J(mt.ramBytes),` RAM`]})})]}),(0,G.jsx)(`h4`,{children:`Configuration`}),(0,G.jsxs)(`div`,{className:`playground-config-grid-fluid`,children:[(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(X,{htmlFor:`pg-context-window`,tooltipKey:`contextWindow`,children:`Context Window`}),(0,G.jsx)(`input`,{id:`pg-context-window`,type:`number`,value:O,onChange:e=>k(Number(e.target.value)),disabled:!!c,max:_t?.max}),_t&&_t.hasRoPE&&(0,G.jsx)(`div`,{style:{fontSize:`11px`,color:`var(--color-gray-500)`,marginTop:2},children:ca(_t)})]}),(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(X,{htmlFor:`pg-prefill-batch-size`,tooltipKey:`prefillBatchSize`,children:`Prefill Batch Size`}),(0,G.jsx)(`input`,{id:`pg-prefill-batch-size`,type:`number`,value:A,onChange:e=>j(Number(e.target.value)),min:1,disabled:!!c})]}),(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(X,{htmlFor:`pg-nseqmax`,tooltipKey:`nSeqMax`,children:`NSeqMax`}),(0,G.jsx)(`input`,{id:`pg-nseqmax`,type:`number`,value:M,onChange:e=>N(Number(e.target.value)),min:1,disabled:!!c})]}),(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(X,{htmlFor:`pg-flash-attn`,tooltipKey:`flashAttention`,children:`Flash Attention`}),(0,G.jsxs)(`select`,{id:`pg-flash-attn`,value:P,onChange:e=>F(e.target.value),disabled:!!c,children:[(0,G.jsx)(`option`,{value:`auto`,children:`Auto`}),(0,G.jsx)(`option`,{value:`enabled`,children:`Enabled`}),(0,G.jsx)(`option`,{value:`disabled`,children:`Disabled`})]})]}),(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(X,{htmlFor:`pg-cache-type`,tooltipKey:`cacheType`,children:`KV Cache Type`}),(0,G.jsxs)(`select`,{id:`pg-cache-type`,value:I,onChange:e=>L(e.target.value),disabled:!!c,children:[(0,G.jsx)(`option`,{value:``,children:`Default (f16)`}),(0,G.jsx)(`option`,{value:`f16`,children:`f16`}),(0,G.jsx)(`option`,{value:`q8_0`,children:`q8_0`}),(0,G.jsx)(`option`,{value:`q4_0`,children:`q4_0`})]})]}),(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(X,{htmlFor:`pg-load-mode`,tooltipKey:`loadMode`,children:`Load Mode`}),(0,G.jsxs)(`select`,{id:`pg-load-mode`,value:R,onChange:e=>z(e.target.value),disabled:!!c,children:[(0,G.jsx)(`option`,{value:`auto`,children:`auto (default)`}),(0,G.jsx)(`option`,{value:`mmap`,children:`mmap`}),(0,G.jsx)(`option`,{value:`none`,children:`none`}),(0,G.jsx)(`option`,{value:`mlock`,children:`mlock`}),(0,G.jsx)(`option`,{value:`mmap+mlock`,children:`mmap+mlock`}),(0,G.jsx)(`option`,{value:`direct-io`,children:`direct-io`})]})]}),(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(X,{tooltipKey:`cacheMode`,children:`Cache Mode`}),(0,G.jsxs)(`select`,{value:ee,onChange:e=>B(e.target.value),disabled:!!c,children:[(0,G.jsx)(`option`,{value:`none`,children:`None`}),(0,G.jsx)(`option`,{value:`imc`,children:`IMC (Incremental)`})]})]}),St&&(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(X,{htmlFor:`pg-moe-mode`,tooltipKey:`moeMode`,children:`Expert Strategy`}),(0,G.jsx)(`select`,{id:`pg-moe-mode`,value:V,onChange:e=>te(e.target.value),disabled:!!c,children:eo.map(e=>(0,G.jsx)(`option`,{value:e.value,children:e.label},e.value))})]}),St&&V===`keep_top_n`&&(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsxs)(X,{htmlFor:`pg-moe-topn`,tooltipKey:`moeKeepExpertsTopN`,children:[`GPU Expert Layers (`,H,` of `,vt||`?`,` — more = faster, more VRAM)`]}),(0,G.jsx)(`input`,{id:`pg-moe-topn`,type:`range`,value:H,onChange:e=>ne(Number(e.target.value)),min:0,max:vt||64,disabled:!!c})]}),Tt&&(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(X,{htmlFor:`pg-mtp-ndraft`,tooltipKey:`mtpNDraft`,children:`⚡ MTP Draft Tokens`}),(0,G.jsx)(`input`,{id:`pg-mtp-ndraft`,type:`number`,value:Ge??``,placeholder:`4 (default)`,onChange:e=>Ke(e.target.value===``?null:Number(e.target.value)),min:1,max:20,disabled:!!c})]})]}),St&&(V===`experts_cpu`||V===`keep_top_n`)&&(0,G.jsxs)(`div`,{className:`playground-moe-tips`,style:{fontSize:`0.85em`,color:`var(--color-text-secondary, #aaa)`,padding:`0 0 8px`,lineHeight:1.4},children:[`💡 `,ia.moeTipBatch,` `,ia.moeTipFlashAttention]}),St&&V===`custom`&&(0,G.jsxs)(`div`,{className:`playground-moe-custom`,children:[(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(`label`,{children:`Tensor Buffer Overrides`}),(0,G.jsx)(`p`,{style:{fontSize:`0.8em`,color:`var(--color-text-secondary, #aaa)`,margin:`0 0 8px`},children:`Select which tensors to offload to CPU. These are applied as tensor-buft-overrides.`})]}),(0,G.jsxs)(`div`,{className:`playground-moe-shortcuts`,children:[(0,G.jsxs)(`label`,{className:`playground-moe-shortcut`,children:[(0,G.jsx)(`input`,{type:`checkbox`,checked:re.includes(`moe-experts`),onChange:e=>{ie(t=>e.target.checked?[...t.filter(e=>e!==`moe-experts`),`moe-experts`]:t.filter(e=>e!==`moe-experts`))},disabled:!!c}),`All expert FFN tensors → CPU`,(0,G.jsx)(`span`,{className:`playground-moe-shortcut-hint`,children:`moe-experts`})]}),(0,G.jsxs)(`label`,{className:`playground-moe-shortcut`,children:[(0,G.jsx)(`input`,{type:`checkbox`,checked:re.includes(`all-ffn`),onChange:e=>{ie(t=>e.target.checked?[...t.filter(e=>e!==`all-ffn`),`all-ffn`]:t.filter(e=>e!==`all-ffn`))},disabled:!!c}),`All FFN tensors → CPU`,(0,G.jsx)(`span`,{className:`playground-moe-shortcut-hint`,children:`all-ffn`})]})]}),vt>0&&(0,G.jsxs)(`div`,{className:`form-group`,style:{marginTop:8},children:[(0,G.jsx)(`label`,{children:`Block-Specific Overrides`}),(0,G.jsx)(`div`,{style:{display:`flex`,gap:6,alignItems:`center`,flexWrap:`wrap`},children:(0,G.jsxs)(`select`,{id:`pg-moe-block-select`,disabled:!!c,defaultValue:``,onChange:e=>{let t=e.target.value;t&&(ie(e=>e.includes(t)?e:[...e,t]),e.target.value=``)},children:[(0,G.jsx)(`option`,{value:``,children:`Add block override…`}),Array.from({length:vt},(e,t)=>(0,G.jsxs)(`option`,{value:`moe-experts:block:${t}`,children:[`Block `,t,` expert tensors → CPU`]},t)),Array.from({length:vt},(e,t)=>(0,G.jsxs)(`option`,{value:`block:${t}`,children:[`Block `,t,` (all tensors) → CPU`]},`block-${t}`))]})})]}),re.length>0&&(0,G.jsx)(`div`,{className:`playground-moe-overrides-list`,children:re.map((e,t)=>(0,G.jsxs)(`div`,{className:`playground-moe-override-item`,children:[(0,G.jsx)(`code`,{children:e}),(0,G.jsx)(`button`,{type:`button`,className:`playground-moe-override-remove`,onClick:()=>ie(e=>e.filter((e,n)=>n!==t)),disabled:!!c,title:`Remove`,children:`×`})]},t))}),(0,G.jsxs)(`div`,{className:`form-group`,style:{marginTop:8},children:[(0,G.jsx)(`label`,{htmlFor:`pg-moe-raw-override`,children:`Custom Pattern (regex)`}),(0,G.jsx)(`div`,{style:{display:`flex`,gap:6},children:(0,G.jsx)(`input`,{id:`pg-moe-raw-override`,type:`text`,placeholder:`e.g., blk\\.5\\.ffn_.*`,disabled:!!c,onKeyDown:e=>{if(e.key===`Enter`){let t=e.target.value.trim();t&&(ie(e=>e.includes(t)?e:[...e,t]),e.target.value=``)}}})})]})]}),(0,G.jsx)(`div`,{className:`playground-session-controls`,children:c?(0,G.jsx)(`button`,{className:`btn btn-danger`,onClick:Rt,children:`Unload Model`}):(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:Lt,disabled:!f||Ze||Ye,children:Ze?`Loading Model...`:Ye?`Loading Config...`:`Load Model`})}),$e&&(0,G.jsx)(`div`,{className:`playground-error`,children:$e}),c&&(0,G.jsxs)(`div`,{className:`playground-session-info`,children:[(0,G.jsx)(`strong`,{children:`Status:`}),` `,c.status,c.effective_config&&(0,G.jsxs)(`div`,{className:`playground-effective-config`,children:[(0,G.jsx)(`strong`,{children:`Effective Config:`}),(0,G.jsx)(`div`,{className:`playground-config-grid`,children:Object.entries(c.effective_config).map(([e,t])=>(0,G.jsxs)(`div`,{className:`playground-config-item`,children:[(0,G.jsxs)(`span`,{className:`playground-config-key`,children:[e,`:`]}),` `,(0,G.jsx)(`span`,{className:`playground-config-value`,children:String(t)})]},e))})]})]})]}),(0,G.jsxs)(`div`,{className:`playground-test`,children:[(0,G.jsxs)(`div`,{className:`playground-tabs`,role:`tablist`,children:[(0,G.jsx)(`button`,{role:`tab`,id:`tab-chat`,"aria-selected":_===`chat`,"aria-controls":`tabpanel-chat`,className:`playground-tab ${_===`chat`?`active`:``}`,onClick:()=>v(`chat`),children:`Basic Chat`}),(0,G.jsx)(`button`,{role:`tab`,id:`tab-tools`,"aria-selected":_===`tools`,"aria-controls":`tabpanel-tools`,className:`playground-tab ${_===`tools`?`active`:``}`,onClick:()=>v(`tools`),children:`Tool Calling Test`})]}),(0,G.jsxs)(`div`,{className:`playground-tab-content`,children:[_===`chat`&&(0,G.jsx)(`div`,{role:`tabpanel`,id:`tabpanel-chat`,"aria-labelledby":`tab-chat`,className:`playground-chat`,children:(0,G.jsx)(xv,{messages:u,setMessages:d,onClear:Ut,sampling:Bt,setSampling:Vt,modelBaseline:null,transport:Ht,modelVRAM:bt,isMoE:St,disabled:!c,disabledPlaceholder:`Load a model to start chatting`,headerLeft:(0,G.jsx)(`h2`,{children:`Basic Chat`})})}),_===`tools`&&(0,G.jsxs)(`div`,{role:`tabpanel`,id:`tabpanel-tools`,"aria-labelledby":`tab-tools`,className:`playground-tools`,children:[(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(`label`,{children:`Tool Definitions (JSON)`}),(0,G.jsx)(`textarea`,{value:Et,onChange:e=>Dt(e.target.value),rows:12,className:`playground-textarea monospace`})]}),(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(`label`,{children:`Test Prompt`}),(0,G.jsx)(`input`,{type:`text`,value:Ot,onChange:e=>kt(e.target.value)})]}),(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:zt,disabled:!c||Nt,children:Nt?`Running...`:`Run Test`}),(jt.length>0||At)&&(0,G.jsxs)(`div`,{className:`playground-tool-results`,children:[(0,G.jsx)(`h4`,{children:`Results`}),jt.length>0?(0,G.jsxs)(`div`,{className:`playground-tool-pass`,children:[(0,G.jsx)(`span`,{className:`playground-badge success`,children:`PASS`}),`Model emitted `,jt.length,` tool call(s)`,jt.map((e,t)=>(0,G.jsxs)(`div`,{className:`playground-tool-call`,children:[(0,G.jsx)(`strong`,{children:e.function.name}),(0,G.jsx)(`pre`,{children:e.function.arguments}),e.id&&(0,G.jsxs)(`small`,{children:[`ID: `,e.id]})]},t))]}):(0,G.jsxs)(`div`,{className:`playground-tool-fail`,children:[(0,G.jsx)(`span`,{className:`playground-badge fail`,children:`NO TOOL CALLS`}),(0,G.jsx)(`pre`,{children:At})]})]})]})]})]})]})]})]})}function Qb(){return(0,G.jsx)(Zb,{mode:`manual`})}function $b(){return(0,G.jsx)(Zb,{mode:`sampling`})}function ex(){return(0,G.jsx)(Zb,{mode:`config`})}function tx(e,t){let n=[...e];return n.sort((e,n)=>{switch(t){case`loc`:return e.loc-n.loc||e.line-n.line;case`name`:return e.identifier.localeCompare(n.identifier);default:return e.line-n.line}}),n}function nx(e){return e>=90?`accuracy-match-good`:e>=50?`accuracy-match-mid`:`accuracy-match-bad`}function rx(e,t){return e.match_percent===t.match_percent?e.usage.tokens_per_second===t.usage.tokens_per_second?e.usage.completion_tokens-t.usage.completion_tokens:t.usage.tokens_per_second-e.usage.tokens_per_second:t.match_percent-e.match_percent}function ix({result:e,title:t=`Code Difference`}){return(0,G.jsxs)(`div`,{className:`accuracy-diff-wrap`,children:[(0,G.jsxs)(`div`,{className:`accuracy-diff-header`,children:[(0,G.jsx)(`span`,{className:`accuracy-diff-title`,children:t}),(0,G.jsxs)(`span`,{className:`accuracy-diff-key`,children:[(0,G.jsx)(`span`,{className:`accuracy-diff-key-item accuracy-diff-del`,children:`- got (model output)`}),(0,G.jsx)(`span`,{className:`accuracy-diff-key-item accuracy-diff-add`,children:`+ want (actual source)`})]})]}),(0,G.jsx)(`div`,{className:`accuracy-diff`,children:(0,G.jsx)(`pre`,{children:e.diff.map((e,t)=>(0,G.jsxs)(`div`,{className:`accuracy-diff-line accuracy-diff-${e.op}`,children:[(0,G.jsx)(`span`,{className:`accuracy-diff-gutter`,children:e.op===`add`?`+`:e.op===`del`?`-`:` `}),(0,G.jsx)(`span`,{className:`accuracy-diff-text`,children:e.text||` `})]},t))})})]})}function ax(){let{models:e,loading:t}=In(),{mode:n,setMode:r,selectedModel:i,setSelectedModel:a,functions:o,sortBy:s,setSortBy:c,error:l,selectedFn:u,setSelectedFn:d,running:f,result:p,runManual:m,stopManual:h,clearManual:g,checked:_,setChecked:v,randomCount:y,setRandomCount:b,rows:S,batchRunning:C,expanded:w,toggle:T,clearAll:E,pickRandom:D,runBatch:O,stopBatch:k,toggleExpand:A,compareModels:j,compareFn:M,setCompareFn:N,compareCells:P,comparing:F,compareLayout:I,setCompareLayout:L,toggleCompareModel:R,clearCompare:z,runCompare:ee,stopCompare:B,isRunning:V}=Ii(),te=(0,x.useMemo)(()=>o?tx(o,s):[],[o,s]),H=S.filter(e=>e.status===`done`||e.status===`error`),ne=S.filter(e=>e.status===`done`&&e.result),re=(0,x.useMemo)(()=>ne.length===0?null:ne.reduce((e,t)=>e+(t.result?.match_percent??0),0)/ne.length,[ne]),ie=P.filter(e=>e.status===`done`||e.status===`error`).length,ae=te.find(e=>e.identifier===M),oe=(0,x.useMemo)(()=>{let e=P.filter(e=>e.status===`done`&&e.result);if(e.length<2)return null;let t=[...e].sort((e,t)=>rx(e.result,t.result)),n=t[0].result,r=t.filter(e=>rx(e.result,n)===0).map(e=>e.model);if(r.length>1)return{winners:r,tied:!0,reason:`identical match, speed & length`};let i=t[1].result,a;return a=n.match_percent>i.match_percent?`highest match`:n.usage.tokens_per_second>i.usage.tokens_per_second?`fastest`:`fewest tokens`,{winners:r,tied:!1,reason:a}},[P]),se=(0,G.jsxs)(`span`,{className:`accuracy-functions-meta`,children:[(0,G.jsxs)(`span`,{className:`accuracy-count`,children:[o?.length??0,` functions`]}),(0,G.jsxs)(`span`,{className:`accuracy-sort`,children:[(0,G.jsx)(`label`,{htmlFor:`accuracy-sort`,children:`Sort by:`}),(0,G.jsxs)(`select`,{id:`accuracy-sort`,value:s,onChange:e=>c(e.target.value),children:[(0,G.jsx)(`option`,{value:`line`,children:`Line number`}),(0,G.jsx)(`option`,{value:`loc`,children:`Lines of Code`}),(0,G.jsx)(`option`,{value:`name`,children:`Name`})]})]})]});return(0,G.jsxs)(`div`,{className:`accuracy-page`,children:[(0,G.jsxs)(`div`,{className:`page-header`,children:[(0,G.jsx)(`h2`,{children:`Accuracy`}),(0,G.jsx)(`p`,{children:`Test how accurately a model recalls source code. Pick a model and a function, then compare the model's output to the real source — in single, batch, or compare mode.`})]}),(0,G.jsxs)(`div`,{className:`tabs`,children:[(0,G.jsx)(`button`,{className:`tab ${n===`manual`?`active`:``}`,onClick:()=>r(`manual`),children:`Manual`}),(0,G.jsx)(`button`,{className:`tab ${n===`batch`?`active`:``}`,onClick:()=>r(`batch`),children:`Batch`}),(0,G.jsx)(`button`,{className:`tab ${n===`compare`?`active`:``}`,onClick:()=>r(`compare`),children:`Compare`})]}),n!==`compare`&&(0,G.jsx)(`div`,{className:`card accuracy-setup`,children:(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(`label`,{children:`Model`}),(0,G.jsxs)(`select`,{value:i,onChange:e=>a(e.target.value),disabled:t||V,children:[t&&(0,G.jsx)(`option`,{children:`Loading models...`}),!t&&e?.data?.filter(e=>Ni(e.id)).length===0&&(0,G.jsx)(`option`,{children:`No models available`}),e?.data?.filter(e=>Ni(e.id)).map(e=>(0,G.jsx)(`option`,{value:e.id,children:e.id},e.id))]})]})}),l&&(0,G.jsx)(`div`,{className:`accuracy-error`,children:l}),o&&o.length>0&&(0,G.jsxs)(G.Fragment,{children:[n===`manual`&&(0,G.jsxs)(`div`,{className:`card`,children:[(0,G.jsxs)(`div`,{className:`form-row`,children:[(0,G.jsxs)(`div`,{className:`form-group`,style:{flex:1},children:[(0,G.jsxs)(`div`,{className:`accuracy-label-row`,children:[(0,G.jsx)(`label`,{children:`Select a Function:`}),se]}),(0,G.jsx)(`select`,{value:u,onChange:e=>d(e.target.value),disabled:f,children:te.map(e=>(0,G.jsxs)(`option`,{value:e.identifier,children:[e.identifier,` (`,e.loc,` loc) — line `,e.line]},e.identifier))})]}),(0,G.jsxs)(`div`,{className:`form-group`,style:{alignSelf:`flex-end`,display:`flex`,flexDirection:`row`,gap:`0.5rem`},children:[f?(0,G.jsx)(`button`,{className:`btn btn-danger`,onClick:h,children:`Stop`}):(0,G.jsx)(`button`,{className:`btn btn-primary`,onClick:m,disabled:!i||!u||V,children:`Run test`}),(0,G.jsx)(`button`,{className:`btn btn-secondary`,onClick:g,disabled:f||!p&&!l,children:`Clear`})]})]}),p&&(0,G.jsxs)(`div`,{className:`accuracy-result`,children:[(0,G.jsxs)(`div`,{className:`accuracy-result-top`,children:[(0,G.jsxs)(`span`,{className:`accuracy-match ${nx(p.match_percent)}`,children:[p.match_percent.toFixed(2),`% match`]}),(0,G.jsxs)(`span`,{className:`accuracy-meta`,children:[p.model,` · `,p.usage.prompt_tokens,` in /`,` `,p.usage.completion_tokens,` out · `,p.usage.tokens_per_second.toFixed(1),` tps`]})]}),(0,G.jsxs)(`div`,{className:`accuracy-fields`,children:[(0,G.jsxs)(`span`,{children:[`Function: `,(0,G.jsxs)(`strong`,{children:[p.function,` (`,p.want.split(`
`).length,` loc)`]})]}),(0,G.jsxs)(`span`,{children:[`line: `,p.line]})]}),(0,G.jsx)(ix,{result:p})]})]}),n===`batch`&&(0,G.jsxs)(`div`,{className:`card`,children:[(0,G.jsxs)(`div`,{className:`accuracy-batch-controls`,children:[(0,G.jsxs)(`span`,{className:`accuracy-random`,children:[(0,G.jsx)(`select`,{value:y,onChange:e=>{b(Number(e.target.value)),v(new Set)},disabled:C,style:{width:`4rem`},children:Array.from({length:5},(e,t)=>t+1).map(e=>(0,G.jsx)(`option`,{value:e,children:e},e))}),(0,G.jsx)(`button`,{className:`btn btn-secondary btn-sm`,onClick:D,disabled:C,children:`Pick random`})]}),(0,G.jsx)(`button`,{className:`btn btn-secondary btn-sm`,onClick:E,disabled:C,children:`Clear`}),(0,G.jsxs)(`span`,{className:`accuracy-count`,children:[_.size,` selected`]}),(0,G.jsx)(`span`,{className:`accuracy-batch-run`,children:C?(0,G.jsxs)(`button`,{className:`btn btn-danger`,onClick:k,children:[`Stop (`,H.length,`/`,S.length,`)`]}):(0,G.jsxs)(`button`,{className:`btn btn-primary`,onClick:O,disabled:!i||_.size===0||V,children:[`Run `,_.size||``,` tests`]})})]}),(0,G.jsxs)(`div`,{className:`accuracy-label-row`,children:[(0,G.jsx)(`label`,{children:`Select Functions:`}),se]}),(0,G.jsx)(`div`,{className:`accuracy-func-grid`,children:te.map(e=>(0,G.jsxs)(`label`,{className:`accuracy-func-item`,children:[(0,G.jsx)(`input`,{type:`checkbox`,checked:_.has(e.identifier),onChange:()=>T(e.identifier),disabled:C||!_.has(e.identifier)&&_.size>=5}),(0,G.jsx)(`span`,{className:`accuracy-func-name`,title:e.identifier,children:e.identifier}),(0,G.jsxs)(`span`,{className:`accuracy-func-loc`,children:[`(`,e.loc,` loc)`]}),(0,G.jsxs)(`span`,{className:`accuracy-func-line`,children:[`line `,e.line]})]},e.identifier))}),S.length>0&&(0,G.jsxs)(`div`,{className:`accuracy-batch-results`,children:[re!==null&&(0,G.jsxs)(`div`,{className:`accuracy-batch-summary`,children:[(0,G.jsxs)(`span`,{className:`accuracy-match ${nx(re)}`,children:[re.toFixed(2),`% average`]}),(0,G.jsxs)(`span`,{className:`accuracy-meta`,children:[ne.length,`/`,S.length,` completed · `,i]})]}),(0,G.jsx)(`div`,{className:`table-container`,children:(0,G.jsxs)(`table`,{children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{children:`Function`}),(0,G.jsx)(`th`,{children:`Line`}),(0,G.jsx)(`th`,{children:`Match`}),(0,G.jsx)(`th`,{children:`Tokens`}),(0,G.jsx)(`th`,{title:`Click a row to expand its code difference`,children:`Code Diff ▸`})]})}),(0,G.jsx)(`tbody`,{children:S.map(e=>(0,G.jsx)(ox,{row:e,expanded:w.has(e.identifier),onToggle:()=>A(e.identifier)},e.identifier))})]})})]})]}),n===`compare`&&(0,G.jsxs)(`div`,{className:`card`,children:[(0,G.jsxs)(`div`,{className:`form-row`,children:[(0,G.jsxs)(`div`,{className:`form-group`,style:{flex:1},children:[(0,G.jsxs)(`div`,{className:`accuracy-label-row`,children:[(0,G.jsx)(`label`,{children:`Select a Function:`}),se]}),(0,G.jsx)(`select`,{value:M,onChange:e=>N(e.target.value),disabled:F,children:te.map(e=>(0,G.jsxs)(`option`,{value:e.identifier,children:[e.identifier,` (`,e.loc,` loc) — line `,e.line]},e.identifier))})]}),(0,G.jsxs)(`div`,{className:`form-group`,style:{alignSelf:`flex-end`,display:`flex`,flexDirection:`row`,gap:`0.5rem`},children:[F?(0,G.jsxs)(`button`,{className:`btn btn-danger`,onClick:B,children:[`Stop (`,ie,`/`,P.length,`)`]}):(0,G.jsxs)(`button`,{className:`btn btn-primary`,onClick:ee,disabled:j.size<2||!M||V,children:[`Compare `,j.size||``,` models`]}),(0,G.jsx)(`button`,{className:`btn btn-secondary`,onClick:z,disabled:F,children:`Clear`})]})]}),(0,G.jsxs)(`label`,{className:`accuracy-compare-label`,children:[`Models — pick `,2,` (`,j.size,` selected)`]}),(0,G.jsx)(`div`,{className:`accuracy-func-grid`,children:e?.data?.filter(e=>Ni(e.id)).map(e=>(0,G.jsxs)(`label`,{className:`accuracy-func-item`,children:[(0,G.jsx)(`input`,{type:`checkbox`,checked:j.has(e.id),onChange:()=>R(e.id),disabled:F}),(0,G.jsx)(`span`,{className:`accuracy-func-name`,title:e.id,children:e.id})]},e.id))}),P.length>0&&(0,G.jsxs)(`div`,{className:`accuracy-compare-results`,children:[(0,G.jsxs)(`div`,{className:`accuracy-compare-toolbar`,children:[(0,G.jsxs)(`div`,{className:`accuracy-fields`,children:[(0,G.jsxs)(`span`,{children:[`Function:`,` `,(0,G.jsxs)(`strong`,{children:[M,ae?` (${ae.loc} loc)`:``]})]}),ae&&(0,G.jsxs)(`span`,{children:[`line: `,ae.line]})]}),(0,G.jsxs)(`div`,{className:`accuracy-compare-layout`,children:[(0,G.jsx)(`button`,{className:`btn btn-sm ${I===`columns`?`btn-primary`:`btn-secondary`}`,onClick:()=>L(`columns`),children:`Side by side`}),(0,G.jsx)(`button`,{className:`btn btn-sm ${I===`stacked`?`btn-primary`:`btn-secondary`}`,onClick:()=>L(`stacked`),children:`Stacked`})]})]}),(0,G.jsx)(`div`,{className:`accuracy-compare-grid${I===`stacked`?` stacked`:``}`,children:P.map(e=>{let t=oe?.winners.includes(e.model)??!1,n=oe?.tied??!1;return(0,G.jsxs)(`div`,{className:`accuracy-compare-card${t?n?` accuracy-compare-tied`:` accuracy-compare-winner`:``}`,children:[(0,G.jsxs)(`div`,{className:`accuracy-compare-card-head`,children:[(0,G.jsx)(`span`,{className:`accuracy-compare-model`,title:e.model,children:e.model}),t&&(0,G.jsx)(`span`,{className:`accuracy-compare-badge${n?` accuracy-compare-badge-tied`:``}`,title:n?`Tied — identical match %, tokens/sec, and completion tokens`:`Best — won on ${oe.reason}`,children:n?`Tied`:`Best · ${oe.reason}`})]}),e.status===`done`&&e.result?(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(`div`,{className:`accuracy-result-top`,children:[(0,G.jsxs)(`span`,{className:`accuracy-match ${nx(e.result.match_percent)}`,children:[e.result.match_percent.toFixed(2),`% match`]}),(0,G.jsxs)(`span`,{className:`accuracy-meta`,children:[e.result.usage.prompt_tokens,` in /`,` `,e.result.usage.completion_tokens,` out ·`,` `,e.result.usage.tokens_per_second.toFixed(1),` tps`]})]}),(0,G.jsx)(ix,{result:e.result})]}):e.status===`running`?(0,G.jsx)(`div`,{className:`accuracy-meta`,children:`running…`}):e.status===`error`?(0,G.jsx)(`div`,{className:`accuracy-error-cell`,children:e.error}):(0,G.jsx)(`div`,{className:`accuracy-meta`,children:`pending`})]},e.model)})})]})]})]})]})}function ox({row:e,expanded:t,onToggle:n}){let r=e.status===`done`&&!!e.result;return(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(`tr`,{className:r?`accuracy-row-clickable`:``,onClick:r?n:void 0,children:[(0,G.jsxs)(`td`,{children:[e.identifier,` (`,e.loc,` loc)`]}),(0,G.jsx)(`td`,{children:e.line}),(0,G.jsx)(`td`,{children:e.status===`done`&&e.result?(0,G.jsxs)(`span`,{className:`accuracy-match ${nx(e.result.match_percent)}`,children:[e.result.match_percent.toFixed(2),`%`]}):e.status===`running`?(0,G.jsx)(`span`,{className:`accuracy-meta`,children:`running…`}):e.status===`error`?(0,G.jsx)(`span`,{className:`accuracy-match accuracy-match-bad`,children:`error`}):(0,G.jsx)(`span`,{className:`accuracy-meta`,children:`pending`})}),(0,G.jsx)(`td`,{children:e.result?`${e.result.usage.prompt_tokens}/${e.result.usage.completion_tokens}`:`—`}),(0,G.jsx)(`td`,{children:r&&(0,G.jsx)(`button`,{className:`btn btn-secondary btn-sm accuracy-diff-toggle`,onClick:e=>{e.stopPropagation(),n()},children:t?`▾ Hide`:`▸ Show`})})]}),t&&e.result&&(0,G.jsx)(`tr`,{children:(0,G.jsx)(`td`,{colSpan:5,children:(0,G.jsx)(ix,{result:e.result,title:`Code Difference — ${e.identifier}`})})}),e.status===`error`&&(0,G.jsx)(`tr`,{children:(0,G.jsx)(`td`,{colSpan:5,className:`accuracy-error-cell`,children:e.error})})]})}var sx=`efficiency:history`,cx=`efficiency:history:updatedAt`,lx=100,ux=`efficiency-history-updated`;function dx(){return typeof crypto<`u`&&`randomUUID`in crypto?crypto.randomUUID():`${Date.now()}-${Math.random().toString(36).slice(2)}`}function fx(e){if(typeof e!=`object`||!e)return!1;let t=e;if(typeof t.id!=`string`||t.id.length===0||typeof t.model!=`string`||typeof t.prompt!=`string`||typeof t.savedAt!=`number`||typeof t.result!=`object`||t.result===null)return!1;let n=t.result.usage;if(typeof n!=`object`||!n)return!1;let r=n;return typeof r.prompt_tokens==`number`&&typeof r.completion_tokens==`number`&&typeof r.in_tps==`number`&&typeof r.out_tps==`number`&&typeof r.ttft_ms==`number`&&typeof r.wallclock_ms==`number`}function px(){try{let e=localStorage.getItem(sx);if(!e)return[];let t=JSON.parse(e);return Array.isArray(t)?t.filter(fx):[]}catch{return[]}}function mx(e){try{localStorage.setItem(sx,JSON.stringify(e.slice(0,lx))),localStorage.setItem(cx,String(Date.now()))}catch{}window.dispatchEvent(new Event(ux))}function hx(e,t,n){let r={id:dx(),model:e,prompt:t,result:n,savedAt:Date.now()};return mx([r,...px()]),r}function gx(e){mx(px().filter(t=>!e.has(t.id)))}function _x(e){let t=t=>{(t.key===cx||t.key===sx)&&e()};return window.addEventListener(ux,e),window.addEventListener(`storage`,t),()=>{window.removeEventListener(ux,e),window.removeEventListener(`storage`,t)}}var vx={date:`desc`,model:`asc`,prompt:`asc`,out_tps:`desc`,ttft:`asc`,wall:`asc`,tokens:`desc`};function yx(e,t,n){switch(n){case`model`:return e.model.localeCompare(t.model);case`prompt`:return e.prompt.localeCompare(t.prompt);case`out_tps`:return e.result.usage.out_tps-t.result.usage.out_tps;case`ttft`:return e.result.usage.ttft_ms-t.result.usage.ttft_ms;case`wall`:return e.result.usage.wallclock_ms-t.result.usage.wallclock_ms;case`tokens`:return e.result.usage.completion_tokens-t.result.usage.completion_tokens;default:return e.savedAt-t.savedAt}}function bx(e,t,n){switch(n){case`model`:return e.model.localeCompare(t.model);case`ttft`:return e.result.usage.ttft_ms-t.result.usage.ttft_ms;case`wall`:return e.result.usage.wallclock_ms-t.result.usage.wallclock_ms;case`tokens`:return e.result.usage.completion_tokens-t.result.usage.completion_tokens;default:return e.result.usage.out_tps-t.result.usage.out_tps}}var xx=4,Sx={out_tps:`output speed (tps)`,ttft:`first token (ttft)`,wall:`wall clock`};function Cx(e,t){return e.length<2?null:[...e].sort((e,n)=>{let r=e.result.usage,i=n.result.usage;switch(t){case`out_tps`:return i.out_tps-r.out_tps;case`ttft`:return r.ttft_ms-i.ttft_ms;case`wall`:return r.wallclock_ms-i.wallclock_ms}})[0].id}function wx(e){return`${(e/1e3).toFixed(1)}s`}function Tx(e){return e.toFixed(1)}function Ex(e){switch(e){case`loading`:return{text:`loading model…`,cls:`loading`};case`running`:return{text:`running…`,cls:`running`};case`done`:return{text:`done`,cls:`done`};case`error`:return{text:`error`,cls:`error`};default:return{text:`idle`,cls:`idle`}}}function Dx({usage:e,bests:t}){let n=e=>t?.[e]?`efficiency-metric efficiency-metric-best`:`efficiency-metric`;return(0,G.jsxs)(`div`,{className:`efficiency-metrics`,children:[(0,G.jsxs)(`div`,{children:[e.prompt_tokens,` in / `,e.completion_tokens,` out`]}),(0,G.jsxs)(`div`,{className:n(`out_tps`),children:[`output: `,Tx(e.out_tps),` tps`]}),(0,G.jsxs)(`div`,{className:`efficiency-metric`,children:[`prefill: `,Tx(e.in_tps),` tps`]}),(0,G.jsxs)(`div`,{className:n(`ttft`),children:[`ttft: `,e.ttft_ms.toFixed(0),` ms`]}),(0,G.jsxs)(`div`,{className:n(`wall`),title:`Generation time only — excludes model load and prefill`,children:[`wall clock: `,wx(e.wallclock_ms)]})]})}function Ox(){let{models:e}=In(),{selectedModels:t,toggleModel:n,prompt:r,setPrompt:i,maxTokens:a,setMaxTokens:o,clear:s,runs:c,runModel:l,runAll:u,stopActive:d,isRunning:f}=Bi(),p=(e?.data??[]).filter(e=>Li(e.id)),m=Array.from(t),[h,g]=(0,x.useState)(`out_tps`),[_,v]=(0,x.useState)(`desc`),y=[...m.map(e=>({model:e,state:c.get(e)})).filter(e=>e.state?.status===`done`&&e.state.result).map(e=>({model:e.model,result:e.state.result}))].sort((e,t)=>{let n=bx(e,t,h);return _===`asc`?n:-n}),b=e=>{e===h?v(e=>e===`asc`?`desc`:`asc`):(g(e),v(vx[e]))},S=e=>{let t=e===h;return(0,G.jsx)(`span`,{className:`efficiency-sort-ind${t?` active`:``}`,children:t?_===`asc`?`▲`:`▼`:`⇅`})};return(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(`div`,{className:`accuracy-label-row`,children:[(0,G.jsx)(`label`,{children:`Select Models:`}),(0,G.jsxs)(`span`,{className:`efficiency-count`,children:[t.size,`/`,2,` selected`]})]}),(0,G.jsxs)(`div`,{className:`accuracy-func-grid`,style:{marginBottom:`1.25rem`},children:[p.length===0&&(0,G.jsx)(`div`,{className:`efficiency-muted`,children:`No models available`}),p.map(e=>{let r=t.has(e.id),i=!r&&t.size>=2;return(0,G.jsxs)(`label`,{className:`accuracy-func-item`,style:i?{opacity:.5}:void 0,children:[(0,G.jsx)(`input`,{type:`checkbox`,checked:r,onChange:()=>n(e.id),disabled:f||i}),(0,G.jsx)(`span`,{className:`accuracy-func-name`,title:e.id,children:e.id})]},e.id)})]}),(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsxs)(`div`,{className:`efficiency-section-head`,children:[(0,G.jsx)(`label`,{children:`Choose Prompt:`}),(0,G.jsx)(`div`,{className:`efficiency-prompt-controls`,children:(0,G.jsx)(`button`,{className:`btn btn-secondary btn-sm`,onClick:s,disabled:f,children:`clear`})})]}),(0,G.jsx)(`textarea`,{className:`efficiency-prompt`,value:r,onChange:e=>i(e.target.value),placeholder:`Write a hello world program in Go.`,rows:3,disabled:f}),(0,G.jsxs)(`div`,{className:`efficiency-maxtokens`,children:[(0,G.jsx)(`label`,{children:`max_tokens`}),(0,G.jsx)(`input`,{type:`number`,min:1,value:a,onChange:e=>o(Math.max(1,Number(e.target.value)||1)),disabled:f}),f?(0,G.jsx)(`button`,{className:`btn btn-danger efficiency-run-all`,onClick:d,children:`Stop`}):(0,G.jsx)(`button`,{className:`btn btn-primary efficiency-run-all`,onClick:u,disabled:m.length===0||!r.trim(),children:`Run all`})]})]}),y.length>0&&(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(`label`,{children:`Summary`}),(0,G.jsx)(`div`,{className:`efficiency-history-list`,children:(0,G.jsxs)(`table`,{className:`efficiency-history-table`,children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsxs)(`th`,{onClick:()=>b(`model`),children:[`Model`,S(`model`)]}),(0,G.jsxs)(`th`,{className:`efficiency-th-num`,onClick:()=>b(`out_tps`),children:[`Output tps`,S(`out_tps`)]}),(0,G.jsxs)(`th`,{className:`efficiency-th-num`,onClick:()=>b(`ttft`),children:[`TTFT`,S(`ttft`)]}),(0,G.jsxs)(`th`,{className:`efficiency-th-num`,onClick:()=>b(`wall`),children:[`Wall`,S(`wall`)]}),(0,G.jsxs)(`th`,{className:`efficiency-th-num`,onClick:()=>b(`tokens`),children:[`In/Out`,S(`tokens`)]})]})}),(0,G.jsx)(`tbody`,{children:y.map(({model:e,result:t})=>{let n=t.usage;return(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`td`,{className:`efficiency-cell-model`,title:e,children:e}),(0,G.jsx)(`td`,{className:`efficiency-th-num`,children:Tx(n.out_tps)}),(0,G.jsxs)(`td`,{className:`efficiency-th-num`,children:[n.ttft_ms.toFixed(0),` ms`]}),(0,G.jsx)(`td`,{className:`efficiency-th-num`,children:wx(n.wallclock_ms)}),(0,G.jsxs)(`td`,{className:`efficiency-th-num`,children:[n.prompt_tokens,`/`,n.completion_tokens]})]},e)})})]})})]}),m.length>0&&(0,G.jsxs)(`div`,{className:`form-group`,children:[(0,G.jsx)(`label`,{children:`Results`}),(0,G.jsx)(`div`,{className:`accuracy-compare-grid`,children:m.map(e=>(0,G.jsx)(kx,{model:e,state:c.get(e),onRun:()=>l(e),onStop:d,prompt:r,disabled:f},e))})]})]})}function kx({model:e,state:t,onRun:n,onStop:r,prompt:i,disabled:a}){let o=t?.status??`idle`,{text:s,cls:c}=Ex(o),l=o===`loading`||o===`running`,[u,d]=(0,x.useState)(!1);return(0,x.useEffect)(()=>{d(!1)},[t?.result]),(0,G.jsxs)(`div`,{className:`accuracy-compare-card`,children:[(0,G.jsxs)(`div`,{className:`accuracy-compare-card-head`,children:[(0,G.jsx)(`span`,{className:`accuracy-compare-model`,title:e,children:e}),t?.result&&o===`done`&&(0,G.jsx)(`button`,{className:`btn btn-secondary btn-sm efficiency-run-btn`,onClick:()=>{t?.result&&!u&&(hx(e,t.result.prompt,t.result),d(!0))},disabled:u,children:u?`saved ✓`:`save to history`})]}),(0,G.jsxs)(`div`,{className:`efficiency-status-row`,children:[(0,G.jsx)(`span`,{className:`efficiency-dot ${c}`,children:`●`}),(0,G.jsx)(`span`,{className:`efficiency-status-text`,children:s}),l?(0,G.jsx)(`button`,{className:`btn btn-danger btn-sm efficiency-run-btn`,onClick:r,children:`stop`}):(0,G.jsx)(`button`,{className:`btn btn-secondary btn-sm efficiency-run-btn`,onClick:n,disabled:a||!i.trim(),children:t?.result?`run again`:`run`})]}),o===`error`&&(0,G.jsx)(`div`,{className:`accuracy-error-cell`,children:t?.error}),t?.result&&o===`done`&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(Dx,{usage:t.result.usage}),(0,G.jsx)(`div`,{className:`efficiency-output-label`,children:`Output`}),(0,G.jsx)(ya,{code:t.result.output||`(empty)`,language:`go`,collapsible:!0})]})]})}function Ax(){let[e,t]=(0,x.useState)(()=>px()),[n,r]=(0,x.useState)(new Set),[i,a]=(0,x.useState)(`date`),[o,s]=(0,x.useState)(`desc`),[c,l]=(0,x.useState)(null),[u,d]=(0,x.useState)(`columns`),[f,p]=(0,x.useState)(`out_tps`);(0,x.useEffect)(()=>_x(()=>t(px())),[]),(0,x.useEffect)(()=>{let t=new Set(e.map(e=>e.id));r(e=>{let n=new Set(Array.from(e).filter(e=>t.has(e)));return n.size===e.size?e:n}),l(e=>e&&e.filter(e=>t.has(e.id)))},[e]);let m=[...e].sort((e,t)=>{let n=yx(e,t,i);return o===`asc`?n:-n}),h=e=>{e===i?s(e=>e===`asc`?`desc`:`asc`):(a(e),s(vx[e]))},g=e=>{let t=e===i;return(0,G.jsx)(`span`,{className:`efficiency-sort-ind${t?` active`:``}`,children:t?o===`asc`?`▲`:`▼`:`⇅`})},_=m.length>0&&m.every(e=>n.has(e.id)),v=()=>{r(_?new Set:new Set(m.map(e=>e.id)))},y=(0,x.useCallback)(e=>{r(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},[]),b=()=>{l(e.filter(e=>n.has(e.id)))},S=()=>{gx(n),r(new Set)},C=c?Cx(c,f):null;return(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(`div`,{className:`efficiency-history-toolbar`,children:[(0,G.jsx)(`label`,{children:`Saved Runs`}),(0,G.jsxs)(`div`,{className:`efficiency-history-controls`,children:[(0,G.jsxs)(`button`,{className:`btn btn-primary btn-sm`,onClick:b,disabled:n.size<2||n.size>xx,title:`Select 2–${xx} runs to compare`,children:[`Compare Selected (`,n.size,`/`,xx,`)`]}),(0,G.jsxs)(`button`,{className:`btn btn-danger btn-sm`,onClick:S,disabled:n.size===0,children:[`Delete Selected (`,n.size,`)`]})]})]}),m.length===0?(0,G.jsx)(`div`,{className:`efficiency-muted`,style:{padding:`1rem`},children:`No saved runs yet. Run a model in the Manual tab and click "save to history".`}):(0,G.jsx)(`div`,{className:`efficiency-history-list`,children:(0,G.jsxs)(`table`,{className:`efficiency-history-table`,children:[(0,G.jsx)(`thead`,{children:(0,G.jsxs)(`tr`,{children:[(0,G.jsx)(`th`,{className:`efficiency-th-check`,children:(0,G.jsx)(`input`,{type:`checkbox`,checked:_,onChange:v,title:`Select all`})}),(0,G.jsxs)(`th`,{onClick:()=>h(`model`),children:[`Model`,g(`model`)]}),(0,G.jsxs)(`th`,{onClick:()=>h(`prompt`),children:[`Prompt`,g(`prompt`)]}),(0,G.jsxs)(`th`,{className:`efficiency-th-num`,onClick:()=>h(`out_tps`),children:[`Output tps`,g(`out_tps`)]}),(0,G.jsxs)(`th`,{className:`efficiency-th-num`,onClick:()=>h(`ttft`),children:[`TTFT`,g(`ttft`)]}),(0,G.jsxs)(`th`,{className:`efficiency-th-num`,onClick:()=>h(`wall`),children:[`Wall`,g(`wall`)]}),(0,G.jsxs)(`th`,{className:`efficiency-th-num`,onClick:()=>h(`tokens`),children:[`In/Out`,g(`tokens`)]}),(0,G.jsxs)(`th`,{className:`efficiency-th-num`,onClick:()=>h(`date`),children:[`Saved`,g(`date`)]})]})}),(0,G.jsx)(`tbody`,{children:m.map(e=>{let t=e.result.usage;return(0,G.jsxs)(`tr`,{className:n.has(e.id)?`efficiency-row-selected`:void 0,onClick:()=>y(e.id),children:[(0,G.jsx)(`td`,{className:`efficiency-th-check`,children:(0,G.jsx)(`input`,{type:`checkbox`,checked:n.has(e.id),onChange:()=>y(e.id),onClick:e=>e.stopPropagation()})}),(0,G.jsx)(`td`,{className:`efficiency-cell-model`,title:e.model,children:e.model}),(0,G.jsx)(`td`,{className:`efficiency-cell-prompt`,title:e.prompt,children:e.prompt}),(0,G.jsx)(`td`,{className:`efficiency-th-num`,children:Tx(t.out_tps)}),(0,G.jsxs)(`td`,{className:`efficiency-th-num`,children:[t.ttft_ms.toFixed(0),` ms`]}),(0,G.jsx)(`td`,{className:`efficiency-th-num`,children:wx(t.wallclock_ms)}),(0,G.jsxs)(`td`,{className:`efficiency-th-num`,children:[t.prompt_tokens,`/`,t.completion_tokens]}),(0,G.jsx)(`td`,{className:`efficiency-th-num efficiency-cell-date`,children:new Date(e.savedAt).toLocaleString([],{month:`short`,day:`numeric`,hour:`numeric`,minute:`2-digit`})})]},e.id)})})]})}),c&&c.length>=2&&(0,G.jsxs)(`div`,{className:`form-group`,style:{marginTop:`1.5rem`},children:[(0,G.jsxs)(`div`,{className:`accuracy-compare-toolbar`,children:[(0,G.jsx)(`label`,{children:`Comparison`}),(0,G.jsxs)(`div`,{className:`accuracy-compare-layout`,children:[(0,G.jsxs)(`label`,{className:`efficiency-rankby`,children:[`Best by:`,` `,(0,G.jsxs)(`select`,{value:f,onChange:e=>p(e.target.value),children:[(0,G.jsx)(`option`,{value:`out_tps`,children:`Output speed (tps)`}),(0,G.jsx)(`option`,{value:`ttft`,children:`First token (ttft)`}),(0,G.jsx)(`option`,{value:`wall`,children:`Wall clock`})]})]}),(0,G.jsx)(`button`,{className:`btn btn-sm ${u===`columns`?`btn-primary`:`btn-secondary`}`,onClick:()=>d(`columns`),children:`side by side`}),(0,G.jsx)(`button`,{className:`btn btn-sm ${u===`stacked`?`btn-primary`:`btn-secondary`}`,onClick:()=>d(`stacked`),children:`stacked`}),(0,G.jsx)(`button`,{className:`btn btn-secondary btn-sm`,onClick:()=>{l(null),r(new Set)},children:`Clear`})]})]}),(0,G.jsx)(`div`,{className:`accuracy-compare-grid${u===`stacked`?` stacked`:``}`,children:c.map(e=>(0,G.jsxs)(`div`,{className:`accuracy-compare-card${e.id===C?` accuracy-compare-winner`:``}`,children:[(0,G.jsxs)(`div`,{className:`accuracy-compare-card-head`,children:[(0,G.jsx)(`span`,{className:`accuracy-compare-model`,title:e.model,children:e.model}),e.id===C&&(0,G.jsxs)(`span`,{className:`accuracy-compare-badge`,children:[`best · `,Sx[f]]})]}),(0,G.jsxs)(`div`,{className:`efficiency-history-prompt`,children:[`Prompt: "`,e.prompt,`"`]}),(0,G.jsx)(Dx,{usage:e.result.usage,bests:e.id===C?{[f]:!0}:void 0}),(0,G.jsx)(`div`,{className:`efficiency-output-label`,children:`Output`}),(0,G.jsx)(ya,{code:e.result.output||`(empty)`,language:`go`,collapsible:!0})]},e.id))})]})]})}function jx(){let[e,t]=(0,x.useState)(`manual`);return(0,G.jsxs)(`div`,{className:`accuracy-page`,children:[(0,G.jsxs)(`div`,{className:`page-header`,children:[(0,G.jsx)(`h2`,{children:`Efficiency`}),(0,G.jsx)(`p`,{children:`Measure how fast a model runs a prompt — tokens-per-second, time-to-first-token, and wall clock (model load and warm-up excluded). Save runs to History to compare across models or prompts.`})]}),(0,G.jsxs)(`div`,{className:`tabs`,children:[(0,G.jsx)(`button`,{className:`tab ${e===`manual`?`active`:``}`,onClick:()=>t(`manual`),children:`Manual`}),(0,G.jsx)(`button`,{className:`tab ${e===`history`?`active`:``}`,onClick:()=>t(`history`),children:`History`})]}),(0,G.jsx)(`div`,{className:`card`,children:e===`manual`?(0,G.jsx)(Ox,{}):(0,G.jsx)(Ax,{})})]})}var Mx={home:`/`,chat:`/chat`,decision:`/decision`,"vram-calculator":`/vram-calculator`,accuracy:`/accuracy`,efficiency:`/efficiency`,"testing-basic":`/testing/basic`,"testing-sampling":`/testing/sampling`,"testing-configurator":`/testing/configurator`,diagnose:`/system/info`,"model-list":`/models`,"model-ps":`/system/running`,"imc-sessions":`/system/imc-sessions`,slots:`/system/slots`,"model-pull":`/models/pull`,"kms-pull":`/models/kms-pull`,"catalog-list":`/catalog`,"libs-pull":`/libs/pull`,"bucky-libs":`/bucky/libs`,"bucky-model-list":`/bucky/models`,"malina-libs":`/malina/libs`,"malina-model-list":`/malina/models`,translator:`/bucky/translator`,"image-generator":`/malina/image-generator`,"security-key-list":`/security/keys`,"security-key-create":`/security/keys/create`,"security-key-delete":`/security/keys/delete`,"security-token-create":`/security/tokens/create`,settings:`/settings`,"docs-sdk":`/docs/sdk`,"docs-sdk-kronk":`/docs/sdk/kronk`,"docs-sdk-model":`/docs/sdk/model`,"docs-sdk-pool":`/docs/sdk/pool`,"docs-sdk-bucky":`/docs/sdk/bucky`,"docs-sdk-bucky-model":`/docs/sdk/bucky/model`,"docs-sdk-malina":`/docs/sdk/malina`,"docs-sdk-malina-model":`/docs/sdk/malina/model`,"docs-sdk-examples":`/docs/sdk/examples`,"docs-cli-bucky":`/docs/cli/bucky`,"docs-cli-catalog":`/docs/cli/catalog`,"docs-cli-completion":`/docs/cli/completion`,"docs-cli-devices":`/docs/cli/devices`,"docs-cli-diagnose":`/docs/cli/diagnose`,"docs-cli-libs":`/docs/cli/libs`,"docs-cli-launch":`/docs/cli/launch`,"docs-cli-model":`/docs/cli/model`,"docs-cli-security":`/docs/cli/security`,"docs-cli-server":`/docs/cli/server`,"docs-api-chat":`/docs/api/chat`,"docs-api-messages":`/docs/api/messages`,"docs-api-responses":`/docs/api/responses`,"docs-api-embeddings":`/docs/api/embeddings`,"docs-api-rerank":`/docs/api/rerank`,"docs-api-decision":`/docs/api/decision`,"docs-api-tokenize":`/docs/api/tokenize`,"docs-api-tools":`/docs/api/tools`,"docs-manual":`/docs/manual`},Nx=Object.fromEntries(Object.entries(Mx).map(([e,t])=>[t,e]));function Px(){let{authenticationRequired:e}=Zi(),[t,n]=(0,x.useState)(()=>{try{return localStorage.getItem(`kronk_insecure_admin_warning_dismissed`)===`true`}catch{return!1}});return(0,G.jsxs)(`div`,{className:`home-page`,children:[(0,G.jsxs)(`div`,{className:`hero-section`,children:[(0,G.jsx)(`img`,{src:`https://raw.githubusercontent.com/ardanlabs/kronk/refs/heads/main/images/project/kronk_banner.jpg?v6`,alt:`Kronk Banner`,className:`hero-banner`}),!e&&!t&&(0,G.jsxs)(`div`,{className:`insecure-admin-warning`,role:`status`,children:[(0,G.jsxs)(`div`,{children:[`Your Kronk instance is running unsecured on all ports without an admin password. Consider setting a password.`,` `,(0,G.jsx)(vn,{to:`/docs/manual#28-securing-the-server-and-bui`,children:`View the security documentation.`})]}),(0,G.jsx)(`button`,{type:`button`,onClick:()=>{try{localStorage.setItem(`kronk_insecure_admin_warning_dismissed`,`true`)}catch{}n(!0)},"aria-label":`Dismiss unsecured instance warning`,children:`Dismiss`})]}),(0,G.jsx)(`p`,{className:`hero-tagline`,children:`Hardware-accelerated local inference with llama.cpp directly integrated into your Go applications`}),(0,G.jsx)(`div`,{className:`hero-actions`,children:(0,G.jsx)(vn,{to:`/docs/manual#getting-started`,className:`hero-cta-button`,children:`🚀 Getting Started`})})]}),(0,G.jsxs)(`div`,{className:`features-grid`,children:[(0,G.jsxs)(`div`,{className:`feature-card`,children:[(0,G.jsx)(`div`,{className:`feature-icon`,children:`🚀`}),(0,G.jsx)(`h3`,{children:`High-Level Go API`}),(0,G.jsx)(`p`,{children:`Feels similar to using an OpenAI compatible API, but runs entirely on your hardware`})]}),(0,G.jsxs)(`div`,{className:`feature-card`,children:[(0,G.jsx)(`div`,{className:`feature-icon`,children:`🔧`}),(0,G.jsx)(`h3`,{children:`OpenAI Compatible Server`}),(0,G.jsx)(`p`,{children:`Model server for chat completions and embeddings, compatible with OpenWebUI`})]}),(0,G.jsxs)(`div`,{className:`feature-card`,children:[(0,G.jsx)(`div`,{className:`feature-icon`,children:`🎯`}),(0,G.jsx)(`h3`,{children:`Multimodal Support`}),(0,G.jsx)(`p`,{children:`Text, vision, and audio models with full hardware acceleration`})]}),(0,G.jsxs)(`div`,{className:`feature-card`,children:[(0,G.jsx)(`div`,{className:`feature-icon`,children:`⚡`}),(0,G.jsx)(`h3`,{children:`GPU Acceleration`}),(0,G.jsx)(`p`,{children:`Metal on macOS, CUDA/Vulkan/ROCm on Linux, CUDA/Vulkan on Windows`})]})]}),(0,G.jsx)(`div`,{className:`home-cta`,children:(0,G.jsx)(`p`,{children:`Use the sidebar to manage models, browse the catalog, or explore the SDK documentation.`})})]})}function Fx(){return(0,G.jsx)(_n,{basename:`/admin`,children:(0,G.jsx)(Ki,{children:(0,G.jsx)(Xi,{children:(0,G.jsx)(Fn,{children:(0,G.jsx)(Fi,{children:(0,G.jsx)(zi,{children:(0,G.jsx)(Rn,{children:(0,G.jsx)(ji,{children:(0,G.jsx)(Hi,{children:(0,G.jsx)(rc,{children:(0,G.jsx)(yc,{children:(0,G.jsx)(cc,{children:(0,G.jsx)(ea,{children:(0,G.jsxs)(Mt,{children:[(0,G.jsx)(U,{path:`/`,element:(0,G.jsx)(Px,{})}),(0,G.jsx)(U,{path:`/chat`,element:(0,G.jsx)(Cv,{})}),(0,G.jsx)(U,{path:`/decision`,element:(0,G.jsx)(Av,{})}),(0,G.jsx)(U,{path:`/vram-calculator`,element:(0,G.jsx)(Zy,{})}),(0,G.jsx)(U,{path:`/accuracy`,element:(0,G.jsx)(ax,{})}),(0,G.jsx)(U,{path:`/efficiency`,element:(0,G.jsx)(jx,{})}),(0,G.jsx)(U,{path:`/testing/basic`,element:(0,G.jsx)(Qb,{})}),(0,G.jsx)(U,{path:`/testing/sampling`,element:(0,G.jsx)($b,{})}),(0,G.jsx)(U,{path:`/testing/configurator`,element:(0,G.jsx)(ex,{})}),(0,G.jsx)(U,{path:`/system/info`,element:(0,G.jsx)(Bo,{})}),(0,G.jsx)(U,{path:`/system/running`,element:(0,G.jsx)(lo,{})}),(0,G.jsx)(U,{path:`/system/imc-sessions`,element:(0,G.jsx)(xo,{})}),(0,G.jsx)(U,{path:`/system/slots`,element:(0,G.jsx)(Io,{})}),(0,G.jsx)(U,{path:`/models`,element:(0,G.jsx)(ao,{})}),(0,G.jsx)(U,{path:`/models/pull`,element:(0,G.jsx)(ns,{})}),(0,G.jsx)(U,{path:`/models/kms-pull`,element:(0,G.jsx)(ss,{})}),(0,G.jsx)(U,{path:`/catalog`,element:(0,G.jsx)(Cs,{})}),(0,G.jsx)(U,{path:`/libs/pull`,element:(0,G.jsx)(ws,{})}),(0,G.jsx)(U,{path:`/bucky/libs`,element:(0,G.jsx)(Ms,{})}),(0,G.jsx)(U,{path:`/bucky/models`,element:(0,G.jsx)(Ls,{})}),(0,G.jsx)(U,{path:`/bucky/translator`,element:(0,G.jsx)(Hv,{})}),(0,G.jsx)(U,{path:`/malina/libs`,element:(0,G.jsx)(Vs,{})}),(0,G.jsx)(U,{path:`/malina/models`,element:(0,G.jsx)(qs,{})}),(0,G.jsx)(U,{path:`/malina/image-generator`,element:(0,G.jsx)(Kv,{})}),(0,G.jsx)(U,{path:`/security/keys`,element:(0,G.jsx)(Js,{})}),(0,G.jsx)(U,{path:`/security/keys/create`,element:(0,G.jsx)(Ys,{})}),(0,G.jsx)(U,{path:`/security/keys/delete`,element:(0,G.jsx)(Xs,{})}),(0,G.jsx)(U,{path:`/security/tokens/create`,element:(0,G.jsx)(ec,{})}),(0,G.jsx)(U,{path:`/settings`,element:(0,G.jsx)(tc,{})}),(0,G.jsx)(U,{path:`/docs/sdk`,element:(0,G.jsx)(qv,{})}),(0,G.jsx)(U,{path:`/docs/sdk/kronk`,element:(0,G.jsx)(Jv,{})}),(0,G.jsx)(U,{path:`/docs/sdk/model`,element:(0,G.jsx)(Yv,{})}),(0,G.jsx)(U,{path:`/docs/sdk/pool`,element:(0,G.jsx)(Xv,{})}),(0,G.jsx)(U,{path:`/docs/sdk/bucky`,element:(0,G.jsx)(Zv,{})}),(0,G.jsx)(U,{path:`/docs/sdk/bucky/model`,element:(0,G.jsx)(Qv,{})}),(0,G.jsx)(U,{path:`/docs/sdk/malina`,element:(0,G.jsx)($v,{})}),(0,G.jsx)(U,{path:`/docs/sdk/malina/model`,element:(0,G.jsx)(ey,{})}),(0,G.jsx)(U,{path:`/docs/sdk/examples`,element:(0,G.jsx)(Oy,{})}),(0,G.jsx)(U,{path:`/docs/cli/bucky`,element:(0,G.jsx)(ky,{})}),(0,G.jsx)(U,{path:`/docs/cli/catalog`,element:(0,G.jsx)(Ay,{})}),(0,G.jsx)(U,{path:`/docs/cli/completion`,element:(0,G.jsx)(jy,{})}),(0,G.jsx)(U,{path:`/docs/cli/devices`,element:(0,G.jsx)(My,{})}),(0,G.jsx)(U,{path:`/docs/cli/diagnose`,element:(0,G.jsx)(Ny,{})}),(0,G.jsx)(U,{path:`/docs/cli/libs`,element:(0,G.jsx)(Py,{})}),(0,G.jsx)(U,{path:`/docs/cli/launch`,element:(0,G.jsx)(Fy,{})}),(0,G.jsx)(U,{path:`/docs/cli/model`,element:(0,G.jsx)(Iy,{})}),(0,G.jsx)(U,{path:`/docs/cli/security`,element:(0,G.jsx)(Ly,{})}),(0,G.jsx)(U,{path:`/docs/cli/server`,element:(0,G.jsx)(Ry,{})}),(0,G.jsx)(U,{path:`/docs/api/chat`,element:(0,G.jsx)(zy,{})}),(0,G.jsx)(U,{path:`/docs/api/messages`,element:(0,G.jsx)(By,{})}),(0,G.jsx)(U,{path:`/docs/api/responses`,element:(0,G.jsx)(Vy,{})}),(0,G.jsx)(U,{path:`/docs/api/embeddings`,element:(0,G.jsx)(Hy,{})}),(0,G.jsx)(U,{path:`/docs/api/rerank`,element:(0,G.jsx)(Uy,{})}),(0,G.jsx)(U,{path:`/docs/api/decision`,element:(0,G.jsx)(Wy,{})}),(0,G.jsx)(U,{path:`/docs/api/tokenize`,element:(0,G.jsx)(Gy,{})}),(0,G.jsx)(U,{path:`/docs/api/tools`,element:(0,G.jsx)(Jy,{})}),(0,G.jsx)(U,{path:`/docs/manual`,element:(0,G.jsx)(Yy,{})})]})})})})})})})})})})})})})})}An.createRoot(document.getElementById(`root`)).render((0,G.jsx)(x.StrictMode,{children:(0,G.jsx)(Fx,{})}));
\ No newline at end of file
diff --git a/cmd/server/api/tooling/logfmt/main.go b/cmd/server/api/tooling/logfmt/main.go
index 35b00d9f5..fe2f58679 100644
--- a/cmd/server/api/tooling/logfmt/main.go
+++ b/cmd/server/api/tooling/logfmt/main.go
@@ -46,7 +46,7 @@ func main() {
}
// If a service filter was provided, check.
- if service != "" && strings.ToLower(m["service"].(string)) != service {
+ if !matchesService(m, service) {
continue
}
@@ -92,3 +92,12 @@ func main() {
log.Println(err)
}
}
+
+func matchesService(fields map[string]any, service string) bool {
+ if service == "" {
+ return true
+ }
+
+ value, ok := fields["service"].(string)
+ return ok && strings.EqualFold(value, service)
+}
diff --git a/cmd/server/api/tooling/logfmt/main_test.go b/cmd/server/api/tooling/logfmt/main_test.go
new file mode 100644
index 000000000..7c4994d3e
--- /dev/null
+++ b/cmd/server/api/tooling/logfmt/main_test.go
@@ -0,0 +1,26 @@
+package main
+
+import "testing"
+
+func TestMatchesService(t *testing.T) {
+ tests := []struct {
+ name string
+ fields map[string]any
+ service string
+ want bool
+ }{
+ {name: "no filter", fields: map[string]any{}, want: true},
+ {name: "matching", fields: map[string]any{"service": "KRONK"}, service: "kronk", want: true},
+ {name: "different", fields: map[string]any{"service": "AUTH"}, service: "kronk"},
+ {name: "missing", fields: map[string]any{}, service: "kronk"},
+ {name: "not a string", fields: map[string]any{"service": 42}, service: "kronk"},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ if got := matchesService(tt.fields, tt.service); got != tt.want {
+ t.Errorf("matchesService: got %t, want %t", got, tt.want)
+ }
+ })
+ }
+}
diff --git a/cmd/server/app/domain/audioapp/audioapp.go b/cmd/server/app/domain/audioapp/audioapp.go
index feba32aee..8a7c997a5 100644
--- a/cmd/server/app/domain/audioapp/audioapp.go
+++ b/cmd/server/app/domain/audioapp/audioapp.go
@@ -9,7 +9,6 @@ import (
"net/http"
"net/url"
"strconv"
- "time"
"github.com/ardanlabs/kronk/cmd/server/app/sdk/errs"
"github.com/ardanlabs/kronk/cmd/server/foundation/logger"
@@ -125,9 +124,6 @@ func (a *app) transcribe(ctx context.Context, r *http.Request, forceTranslate bo
return errs.Errorf(errs.InvalidArgument, "model[%s] is english-only but language[%s] was requested", modelID, language)
}
- ctx, cancel := context.WithTimeout(ctx, 30*time.Minute)
- defer cancel()
-
tr, err := b.TranscribeFile(ctx, file, opts...)
if err != nil {
return errs.FromSDK(fmt.Errorf("transcribe: %w", err))
diff --git a/cmd/server/app/domain/audioapp/route.go b/cmd/server/app/domain/audioapp/route.go
index 5c4b38882..112c9b000 100644
--- a/cmd/server/app/domain/audioapp/route.go
+++ b/cmd/server/app/domain/audioapp/route.go
@@ -2,6 +2,7 @@ package audioapp
import (
"net/http"
+ "time"
"github.com/ardanlabs/kronk/cmd/server/app/sdk/authclient"
"github.com/ardanlabs/kronk/cmd/server/app/sdk/mid"
@@ -17,6 +18,7 @@ type Config struct {
AuthClient *authclient.Client
Pool *pool.Pool
AuthorizationMode auth.Mode
+ InferenceTimeout time.Duration
}
// Routes adds specific routes for this group.
@@ -26,7 +28,8 @@ func Routes(app *web.App, cfg Config) {
api := newApp(cfg)
inferenceAccess := mid.NewAccess(cfg.AuthClient, cfg.AuthorizationMode, false).Inference("transcriptions")
+ timeout := mid.Timeout(cfg.InferenceTimeout)
- app.HandlerFunc(http.MethodPost, version, "/audio/transcriptions", api.transcriptions, inferenceAccess)
- app.HandlerFunc(http.MethodPost, version, "/audio/translations", api.translations, inferenceAccess)
+ app.HandlerFunc(http.MethodPost, version, "/audio/transcriptions", api.transcriptions, timeout, inferenceAccess)
+ app.HandlerFunc(http.MethodPost, version, "/audio/translations", api.translations, timeout, inferenceAccess)
}
diff --git a/cmd/server/app/domain/downapp/downapp.go b/cmd/server/app/domain/downapp/downapp.go
index d78ef4ef9..82611d045 100644
--- a/cmd/server/app/domain/downapp/downapp.go
+++ b/cmd/server/app/domain/downapp/downapp.go
@@ -6,6 +6,7 @@ package downapp
import (
"encoding/json"
"fmt"
+ "io/fs"
"net/http"
"os"
"path/filepath"
@@ -251,46 +252,39 @@ func (a *app) handle(w http.ResponseWriter, r *http.Request) {
switch action {
case "resolve":
- filePath = filepath.Join(a.modelsPath, org, repo, fileName)
+ filePath = filepath.Join(org, repo, fileName)
case "raw":
- filePath = filepath.Join(a.modelsPath, org, repo, "sha", fileName)
+ filePath = filepath.Join(org, repo, "sha", fileName)
default:
http.Error(w, fmt.Sprintf("unsupported action: %s", action), http.StatusBadRequest)
return
}
-
- // Prevent directory traversal.
- absModels, err := filepath.Abs(a.modelsPath)
- if err != nil {
- http.Error(w, "internal error", http.StatusInternalServerError)
+ if !filepath.IsLocal(filePath) {
+ http.Error(w, "invalid path", http.StatusBadRequest)
return
}
- absFile, err := filepath.Abs(filePath)
+ root, err := os.OpenRoot(a.modelsPath)
if err != nil {
http.Error(w, "internal error", http.StatusInternalServerError)
return
}
+ defer root.Close()
- if !strings.HasPrefix(absFile, absModels) {
- http.Error(w, "invalid path", http.StatusBadRequest)
- return
- }
-
- // If the exact file doesn't exist and the request is for a projection file,
- // look for the Kronk-renamed mmproj file in the same directory.
- if _, err := os.Stat(filePath); os.IsNotExist(err) && strings.Contains(fileName, "mmproj") {
- if found := findMmproj(filepath.Dir(filePath)); found != "" {
+ // Open and serve the file through an os.Root so path components and
+ // symlinks cannot escape the configured models directory.
+ f, err := root.Open(filePath)
+ if os.IsNotExist(err) && strings.Contains(fileName, "mmproj") {
+ if found := findMmproj(root, filepath.Dir(filePath)); found != "" {
filePath = found
+ f, err = root.Open(filePath)
}
}
a.log.Info(r.Context(), "download", "status", "resolved path", "org", org, "repo", repo, "action", action, "file", fileName, "filePath", filePath)
- // Open and serve the file.
- f, err := os.Open(filePath)
if err != nil {
if os.IsNotExist(err) {
a.log.Info(r.Context(), "download", "status", "file not found", "path", filePath)
@@ -324,8 +318,8 @@ func (a *app) handle(w http.ResponseWriter, r *http.Request) {
// findMmproj searches a directory for a file whose name starts with "mmproj".
// This handles the case where Kronk renamed the projection file from its
// original HuggingFace name to the Kronk naming convention.
-func findMmproj(dir string) string {
- entries, err := os.ReadDir(dir)
+func findMmproj(root *os.Root, dir string) string {
+ entries, err := fs.ReadDir(root.FS(), dir)
if err != nil {
return ""
}
diff --git a/cmd/server/app/domain/downapp/downapp_test.go b/cmd/server/app/domain/downapp/downapp_test.go
new file mode 100644
index 000000000..c43e66986
--- /dev/null
+++ b/cmd/server/app/domain/downapp/downapp_test.go
@@ -0,0 +1,75 @@
+package downapp
+
+import (
+ "context"
+ "io"
+ "net/http"
+ "net/http/httptest"
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+
+ "github.com/ardanlabs/kronk/cmd/server/foundation/logger"
+)
+
+func TestHandleRejectsPathOutsideModelsRoot(t *testing.T) {
+ basePath := t.TempDir()
+ modelsPath := filepath.Join(basePath, "models")
+ outsidePath := filepath.Join(basePath, "models-private", "repo")
+ if err := os.MkdirAll(modelsPath, 0755); err != nil {
+ t.Fatalf("create models directory: %v", err)
+ }
+ if err := os.MkdirAll(outsidePath, 0755); err != nil {
+ t.Fatalf("create outside directory: %v", err)
+ }
+ if err := os.WriteFile(filepath.Join(outsidePath, "secret.gguf"), []byte("secret model"), 0644); err != nil {
+ t.Fatalf("write outside file: %v", err)
+ }
+
+ log := logger.New(io.Discard, logger.LevelInfo, "TEST", func(context.Context) string { return "" })
+ a := app{log: log, modelsPath: modelsPath}
+
+ t.Run("parent traversal", func(t *testing.T) {
+ r := httptest.NewRequest(http.MethodGet, "/download/../models-private/resolve/main/repo/secret.gguf", nil)
+ w := httptest.NewRecorder()
+
+ a.handle(w, r)
+
+ if w.Code != http.StatusBadRequest {
+ t.Fatalf("status: got %d, want %d", w.Code, http.StatusBadRequest)
+ }
+ if strings.Contains(w.Body.String(), "secret model") {
+ t.Fatalf("body: served file outside models root: %q", w.Body.String())
+ }
+ })
+
+ t.Run("symlink escape", func(t *testing.T) {
+ orgPath := filepath.Join(modelsPath, "org")
+ if err := os.MkdirAll(orgPath, 0755); err != nil {
+ t.Fatalf("create org directory: %v", err)
+ }
+ if err := os.Symlink(outsidePath, filepath.Join(orgPath, "repo")); err != nil {
+ t.Skipf("create symlink: %v", err)
+ }
+
+ r := httptest.NewRequest(http.MethodGet, "/download/org/repo/resolve/main/secret.gguf", nil)
+ w := httptest.NewRecorder()
+
+ a.handle(w, r)
+
+ if w.Code == http.StatusOK {
+ t.Fatalf("status: got %d, want path rejection", w.Code)
+ }
+ if strings.Contains(w.Body.String(), "secret model") {
+ t.Fatalf("body: served symlink target outside models root: %q", w.Body.String())
+ }
+ })
+}
+
+func TestPeerPullEventEndsWithBlankLine(t *testing.T) {
+ event := toPeerPullEvent(PeerPullEvent{Status: "downloading"})
+ if !strings.HasSuffix(event, "\n\n") {
+ t.Errorf("event: got %q, want blank-line terminator", event)
+ }
+}
diff --git a/cmd/server/app/domain/downapp/peer.go b/cmd/server/app/domain/downapp/peer.go
index d9c9772a2..0f2d78cc2 100644
--- a/cmd/server/app/domain/downapp/peer.go
+++ b/cmd/server/app/domain/downapp/peer.go
@@ -98,9 +98,9 @@ type PeerPullEvent struct {
func toPeerPullEvent(p PeerPullEvent) string {
d, err := json.Marshal(p)
if err != nil {
- return fmt.Sprintf("data: {\"status\":%q}\n", err.Error())
+ return fmt.Sprintf("data: {\"status\":%q}\n\n", err.Error())
}
- return fmt.Sprintf("data: %s\n", string(d))
+ return fmt.Sprintf("data: %s\n\n", string(d))
}
// =============================================================================
@@ -262,7 +262,7 @@ func (a *app) pullLibsFromPeer(ctx context.Context, r *http.Request) web.Encoder
emit := func(payload PeerPullEvent) {
line := toPeerPullEvent(payload)
- a.log.Info(ctx, "pull-libs-from-peer", "info", strings.TrimSuffix(line, "\n"))
+ a.log.Info(ctx, "pull-libs-from-peer", "info", strings.TrimSpace(line))
fmt.Fprint(w, line)
f.Flush()
}
diff --git a/cmd/server/app/domain/msgsapp/models.go b/cmd/server/app/domain/msgsapp/models.go
index 09fca2746..822199326 100644
--- a/cmd/server/app/domain/msgsapp/models.go
+++ b/cmd/server/app/domain/msgsapp/models.go
@@ -203,6 +203,10 @@ func toOpenAI(req MessagesRequest) model.D {
d["top_p"] = *req.TopP
}
switch {
+ case req.TopK != nil:
+ d["top_k"] = *req.TopK
+ }
+ switch {
case len(req.Tools) > 0:
d["tools"] = convertTools(req.Tools)
}
diff --git a/cmd/server/app/domain/msgsapp/msgsapp.go b/cmd/server/app/domain/msgsapp/msgsapp.go
index d431b665f..a5c70717e 100644
--- a/cmd/server/app/domain/msgsapp/msgsapp.go
+++ b/cmd/server/app/domain/msgsapp/msgsapp.go
@@ -4,6 +4,7 @@ package msgsapp
import (
"context"
"encoding/json"
+ "errors"
"fmt"
"net/http"
@@ -125,7 +126,7 @@ func (a *app) handleStreaming(ctx context.Context, krn *kronk.Kronk, d model.D)
}
}
- return true, state.finish()
+ return committed, state.finish()
}
// =============================================================================
@@ -134,6 +135,7 @@ type streamState struct {
w http.ResponseWriter
messageID string
started bool
+ failed bool
blockStarted bool
blockIndex int
inputTokens int
@@ -142,6 +144,11 @@ type streamState struct {
}
func (s *streamState) processChunk(resp model.ChatResponse) error {
+ if len(resp.Choices) > 0 && resp.Choices[0].FinishReason() == model.FinishReasonError {
+ s.failed = true
+ return s.sendError()
+ }
+
if !s.started {
s.messageID = resp.ID
@@ -219,6 +226,13 @@ func (s *streamState) processChunk(resp model.ChatResponse) error {
}
func (s *streamState) finish() error {
+ if s.failed {
+ return nil
+ }
+ if !s.started {
+ return errors.New("messages stream ended before message_start")
+ }
+
if s.blockStarted {
if err := s.sendContentBlockStop(); err != nil {
return err
@@ -272,6 +286,16 @@ func (s *streamState) sendEvent(eventType string, data any) error {
return nil
}
+func (s *streamState) sendError() error {
+ return s.sendEvent("error", ErrorResponse{
+ Type: "error",
+ Error: ErrorDetail{
+ Type: "api_error",
+ Message: "Internal Server Error",
+ },
+ })
+}
+
func supportsResponseFlush(w http.ResponseWriter) bool {
for w != nil {
switch v := w.(type) {
diff --git a/cmd/server/app/domain/msgsapp/msgsapp_test.go b/cmd/server/app/domain/msgsapp/msgsapp_test.go
index 777ab7246..c6a97145d 100644
--- a/cmd/server/app/domain/msgsapp/msgsapp_test.go
+++ b/cmd/server/app/domain/msgsapp/msgsapp_test.go
@@ -73,6 +73,39 @@ func TestStreamStateSendEventReportsTransportErrors(t *testing.T) {
}
}
+func TestStreamStateConvertsSDKErrorChunkToAnthropicError(t *testing.T) {
+ rr := httptest.NewRecorder()
+ state := streamState{w: rr}
+ resp := model.ChatResponseErr("request-id", "chat.completion.chunk", "model", 0, errors.New("sensitive internal path"), model.Usage{})
+
+ if err := state.processChunk(resp); err != nil {
+ t.Fatalf("processChunk: %v", err)
+ }
+ if !state.failed {
+ t.Fatal("failed: got false, want true")
+ }
+ if state.started {
+ t.Fatal("started: got true, want false")
+ }
+ if got := rr.Body.String(); !strings.Contains(got, "event: error") || !strings.Contains(got, "Internal Server Error") {
+ t.Errorf("error event: got %q", got)
+ }
+ if strings.Contains(rr.Body.String(), "sensitive internal path") {
+ t.Errorf("error event exposed SDK error: %q", rr.Body.String())
+ }
+ if err := state.finish(); err != nil {
+ t.Fatalf("finish after error: %v", err)
+ }
+}
+
+func TestStreamStateRejectsEmptyStream(t *testing.T) {
+ state := streamState{w: httptest.NewRecorder()}
+
+ if err := state.finish(); err == nil {
+ t.Fatal("finish: got nil, want missing message_start error")
+ }
+}
+
type eventResponseWriter struct {
header http.Header
writeErr error
@@ -104,6 +137,15 @@ func TestToOpenAIMaxTokens(t *testing.T) {
}
}
+func TestToOpenAIForwardsTopK(t *testing.T) {
+ topK := 17
+ d := toOpenAI(MessagesRequest{TopK: &topK})
+
+ if got := d["top_k"]; got != topK {
+ t.Errorf("top_k: got %v, want %d", got, topK)
+ }
+}
+
func TestToMessagesResponseToolInputIsObject(t *testing.T) {
resp := model.ChatResponse{
Choices: []model.Choice{
diff --git a/cmd/server/app/domain/playgroundapp/model.go b/cmd/server/app/domain/playgroundapp/model.go
index 56b3b288c..198f9280c 100644
--- a/cmd/server/app/domain/playgroundapp/model.go
+++ b/cmd/server/app/domain/playgroundapp/model.go
@@ -77,7 +77,6 @@ type SessionConfig struct {
Devices []string `json:"devices"`
MainGPU *int `json:"main_gpu"`
TensorSplit []float32 `json:"tensor_split"`
- OpOffloadMinBatch *int `json:"op_offload_min_batch"`
TensorBuftOverrides []string `json:"tensor_buft_overrides"`
DraftModelID *string `json:"draft_model_id"`
DraftNDraft *int `json:"draft_ndraft"`
@@ -149,9 +148,6 @@ func (sc SessionConfig) ApplyTo(cfg model.Config) model.Config {
if len(sc.TensorSplit) > 0 {
cfg.TensorSplit = sc.TensorSplit
}
- if sc.OpOffloadMinBatch != nil {
- cfg.PtrOpOffloadMinBatch = sc.OpOffloadMinBatch
- }
if len(sc.TensorBuftOverrides) > 0 {
cfg.TensorBuftOverrides = sc.TensorBuftOverrides
}
@@ -200,7 +196,6 @@ func (sc SessionConfig) HasOverrides() bool {
sc.Devices != nil ||
sc.MainGPU != nil ||
sc.TensorSplit != nil ||
- sc.OpOffloadMinBatch != nil ||
sc.DraftModelID != nil ||
sc.DraftNDraft != nil ||
sc.TensorBuftOverrides != nil
@@ -229,10 +224,6 @@ func (sc SessionConfig) Validate() error {
return fmt.Errorf("nseq-max must be between 1 and 64, got %d", *sc.NSeqMax)
}
- if sc.OpOffloadMinBatch != nil && *sc.OpOffloadMinBatch < 0 {
- return fmt.Errorf("op-offload-min-batch must be >= 0, got %d", *sc.OpOffloadMinBatch)
- }
-
// draft_ndraft is valid both with a separate draft model (draft_model_id)
// and on its own as an MTP nDraft override on the target's auto-detected
// MTP head.
diff --git a/cmd/server/app/domain/playgroundapp/playgroundapp.go b/cmd/server/app/domain/playgroundapp/playgroundapp.go
index e187a3fb5..80ab778c6 100644
--- a/cmd/server/app/domain/playgroundapp/playgroundapp.go
+++ b/cmd/server/app/domain/playgroundapp/playgroundapp.go
@@ -9,6 +9,7 @@ import (
"errors"
"fmt"
"net/http"
+ "path/filepath"
"sync"
"time"
@@ -18,6 +19,7 @@ import (
"github.com/ardanlabs/kronk/sdk/kronk"
"github.com/ardanlabs/kronk/sdk/kronk/model"
"github.com/ardanlabs/kronk/sdk/pool"
+ "github.com/ardanlabs/kronk/sdk/tools/defaults"
"github.com/ardanlabs/kronk/sdk/tools/models"
)
@@ -60,7 +62,7 @@ func (a *app) createSession(ctx context.Context, r *http.Request) web.Encoder {
return errs.Errorf(errs.InvalidArgument, "missing model_id")
}
- baseCfg, err := a.models.KronkResolvedConfig(req.ModelID, a.pool.Kronk.ModelConfig())
+ baseCfg, err := a.pool.Kronk.ResolvedKronkConfig(req.ModelID)
if err != nil {
return errs.FromSDK(fmt.Errorf("resolving model config: %w", err))
}
@@ -71,6 +73,14 @@ func (a *app) createSession(ctx context.Context, r *http.Request) web.Encoder {
}
cfg := req.Config.ApplyTo(baseCfg)
+ switch req.TemplateMode {
+ case "custom":
+ cfg.JinjaScript = req.TemplateScript
+ case "builtin":
+ if req.TemplateName != "" {
+ cfg.JinjaFile = filepath.Join(defaults.JinjaDir(a.models.BasePath()), req.TemplateName)
+ }
+ }
// Resolve draft model file paths when the user specifies a draft model ID.
if req.Config.DraftModelID != nil && *req.Config.DraftModelID != "" {
diff --git a/cmd/server/app/domain/toolapp/accuracy.go b/cmd/server/app/domain/toolapp/accuracy.go
index da20a2183..8b129bc6a 100644
--- a/cmd/server/app/domain/toolapp/accuracy.go
+++ b/cmd/server/app/domain/toolapp/accuracy.go
@@ -169,7 +169,7 @@ func (a *app) runAccuracy(ctx context.Context, r *http.Request) web.Encoder {
// Load the model with a large context window and incremental caching
// disabled. Resolve the model's normal config, override those two settings,
// and acquire a dedicated instance.
- cfg, err := a.models.KronkResolvedConfig(req.Model, a.pool.Kronk.ModelConfig())
+ cfg, err := a.pool.Kronk.ResolvedKronkConfig(req.Model)
if err != nil {
return errs.FromSDK(fmt.Errorf("resolving model config: %w", err))
}
@@ -179,7 +179,7 @@ func (a *app) runAccuracy(ctx context.Context, r *http.Request) web.Encoder {
cfg.PtrContextWindow = &cw
cfg.PtrIncrementalCache = &imc
- krn, err := a.pool.Kronk.AquireCustom(ctx, req.Model+"/accuracy", cfg)
+ krn, err := a.pool.Kronk.AquireCustom(ctx, req.Model+"/custom/accuracy", cfg)
if err != nil {
return errs.FromSDK(err)
}
diff --git a/cmd/server/app/domain/toolapp/bucky_libs.go b/cmd/server/app/domain/toolapp/bucky_libs.go
index a9e8bb387..457c19215 100644
--- a/cmd/server/app/domain/toolapp/bucky_libs.go
+++ b/cmd/server/app/domain/toolapp/bucky_libs.go
@@ -113,19 +113,13 @@ func (a *app) pullBuckyLibs(ctx context.Context, r *http.Request) web.Encoder {
status := fmt.Sprintf("%s:%s\n", msg, sb.String())
ver := toAppVersion(status, buckylibs.VersionTag{}, allowUpgrade)
- a.log.Info(ctx, "pull-bucky-libs", "info", ver[:len(ver)-1])
+ a.log.Info(ctx, "pull-bucky-libs", "info", strings.TrimSpace(ver))
fmt.Fprint(w, ver)
f.Flush()
}
- // I know this is a hack and a race condition. I expect this situation
- // to only exist for a few people and in a single tenant mode.
if allowUpgrade && !a.buckyLibs.AllowUpgrade {
a.log.Info(ctx, "pull-bucky-libs", "status", "allowing libs upgrade")
- a.buckyLibs.AllowUpgrade = true
- defer func() {
- a.buckyLibs.AllowUpgrade = false
- }()
}
var (
@@ -141,7 +135,7 @@ func (a *app) pullBuckyLibs(ctx context.Context, r *http.Request) web.Encoder {
// using the libs handle's own triple.
tag, err = a.buckyLibs.DownloadFor(ctx, logger, a.buckyLibs.Arch(), a.buckyLibs.OS(), a.buckyLibs.Processor(), version)
default:
- tag, err = a.buckyLibs.Download(ctx, logger)
+ tag, err = a.buckyLibs.DownloadSelected(ctx, logger, "", allowUpgrade)
}
if err != nil {
ver := toAppVersion(err.Error(), buckylibs.VersionTag{}, allowUpgrade)
@@ -152,7 +146,7 @@ func (a *app) pullBuckyLibs(ctx context.Context, r *http.Request) web.Encoder {
}
ver := toAppVersion("downloaded", tag, allowUpgrade)
- a.log.Info(ctx, "pull-bucky-libs", "info", ver[:len(ver)-1])
+ a.log.Info(ctx, "pull-bucky-libs", "info", strings.TrimSpace(ver))
fmt.Fprint(w, ver)
f.Flush()
diff --git a/cmd/server/app/domain/toolapp/bucky_models.go b/cmd/server/app/domain/toolapp/bucky_models.go
index d3d97865d..ea6434b56 100644
--- a/cmd/server/app/domain/toolapp/bucky_models.go
+++ b/cmd/server/app/domain/toolapp/bucky_models.go
@@ -215,7 +215,7 @@ func (a *app) pullBuckyModel(ctx context.Context, r *http.Request) web.Encoder {
ver = toAppPullResponse(PullResponse{Status: clean})
}
- a.log.Info(ctx, "pull-bucky-model", "info", ver[:len(ver)-1])
+ a.log.Info(ctx, "pull-bucky-model", "info", strings.TrimSpace(ver))
fmt.Fprint(w, ver)
f.Flush()
}
@@ -223,7 +223,7 @@ func (a *app) pullBuckyModel(ctx context.Context, r *http.Request) web.Encoder {
mp, err := a.buckyModels.Download(ctx, logger, source)
if err != nil {
ver := toAppPullResponse(PullResponse{Status: err.Error()})
- a.log.Info(ctx, "pull-bucky-model", "info", ver[:len(ver)-1])
+ a.log.Info(ctx, "pull-bucky-model", "info", strings.TrimSpace(ver))
fmt.Fprint(w, ver)
f.Flush()
return web.NewNoResponse()
diff --git a/cmd/server/app/domain/toolapp/efficiency.go b/cmd/server/app/domain/toolapp/efficiency.go
index 8dc9187d2..40f4c3f78 100644
--- a/cmd/server/app/domain/toolapp/efficiency.go
+++ b/cmd/server/app/domain/toolapp/efficiency.go
@@ -96,7 +96,7 @@ func (a *app) runEfficiency(ctx context.Context, r *http.Request) web.Encoder {
// Resolve the model's normal config and disable incremental caching so each
// prompt is measured from a clean state (no KV reuse skewing the numbers).
- cfg, err := a.models.KronkResolvedConfig(req.Model, a.pool.Kronk.ModelConfig())
+ cfg, err := a.pool.Kronk.ResolvedKronkConfig(req.Model)
if err != nil {
return errs.FromSDK(fmt.Errorf("resolving model config: %w", err))
}
@@ -106,7 +106,7 @@ func (a *app) runEfficiency(ctx context.Context, r *http.Request) web.Encoder {
// Acquire a dedicated instance with a stable per-model key so switching the
// prompt and re-running reuses the loaded model rather than reloading it.
- krn, err := a.pool.Kronk.AquireCustom(ctx, req.Model+"/efficiency", cfg)
+ krn, err := a.pool.Kronk.AquireCustom(ctx, req.Model+"/custom/efficiency", cfg)
if err != nil {
return errs.FromSDK(err)
}
diff --git a/cmd/server/app/domain/toolapp/libs.go b/cmd/server/app/domain/toolapp/libs.go
index 95bb6ac7a..2d6004974 100644
--- a/cmd/server/app/domain/toolapp/libs.go
+++ b/cmd/server/app/domain/toolapp/libs.go
@@ -89,6 +89,8 @@ func (a *app) pullLibs(ctx context.Context, r *http.Request) web.Encoder {
allowUpgrade := a.libs.AllowUpgrade
if tripleAll {
allowUpgrade = true
+ } else if version == "" && q.Get("allow-upgrade") != "" {
+ allowUpgrade = true
}
logger := func(ctx context.Context, msg string, args ...any) {
@@ -102,7 +104,7 @@ func (a *app) pullLibs(ctx context.Context, r *http.Request) web.Encoder {
status := fmt.Sprintf("%s:%s\n", msg, sb.String())
ver := toAppVersion(status, libs.VersionTag{}, allowUpgrade)
- a.log.Info(ctx, "pull-libs", "info", ver[:len(ver)-1])
+ a.log.Info(ctx, "pull-libs", "info", strings.TrimSpace(ver))
fmt.Fprint(w, ver)
f.Flush()
}
@@ -128,31 +130,19 @@ func (a *app) pullLibs(ctx context.Context, r *http.Request) web.Encoder {
a.log.Warn(ctx, "pull-libs", "status", "no installed version found", "warning", err)
}
- // I know this is a hack and a race condition. I expect this situation
- // to only exist for a few people and in a single tenant mode.
- if !a.libs.AllowUpgrade {
- if q.Get("allow-upgrade") != "" {
- a.log.Info(ctx, "pull-libs", "status", "allowing libs upgrade")
- a.libs.AllowUpgrade = true
- defer func() {
- a.libs.AllowUpgrade = false
- }()
- }
+ if allowUpgrade && !a.libs.AllowUpgrade {
+ a.log.Info(ctx, "pull-libs", "status", "allowing libs upgrade")
}
if version != "" {
a.log.Info(ctx, "pull-libs", "status", "using specified version", "version", version)
- a.libs.SetVersion(version)
- defer func() {
- a.libs.SetVersion("")
- }()
}
- vi, err := a.libs.Download(ctx, logger)
+ vi, err := a.libs.DownloadSelected(ctx, logger, version, allowUpgrade)
if err != nil {
- ver := toAppVersion(err.Error(), libs.VersionTag{}, a.libs.AllowUpgrade)
+ ver := toAppVersion(err.Error(), libs.VersionTag{}, allowUpgrade)
- a.log.Info(ctx, "pull-libs", "status", "ERROR", "error", err.Error(), "info", ver[:len(ver)-1])
+ a.log.Info(ctx, "pull-libs", "status", "ERROR", "error", err.Error(), "info", strings.TrimSpace(ver))
fmt.Fprint(w, ver)
f.Flush()
@@ -182,12 +172,12 @@ func (a *app) pullLibs(ctx context.Context, r *http.Request) web.Encoder {
}
var ver string
- ver = toAppVersion("downloaded", vi, a.libs.AllowUpgrade)
+ ver = toAppVersion("downloaded", vi, allowUpgrade)
if instVer.Version == vi.Version {
- ver = toAppVersion("using installed version", vi, a.libs.AllowUpgrade)
+ ver = toAppVersion("using installed version", vi, allowUpgrade)
}
- a.log.Info(ctx, "pull-libs", "info", ver[:len(ver)-1])
+ a.log.Info(ctx, "pull-libs", "info", strings.TrimSpace(ver))
fmt.Fprint(w, ver)
f.Flush()
diff --git a/cmd/server/app/domain/toolapp/malina_libs.go b/cmd/server/app/domain/toolapp/malina_libs.go
index 276c01f4b..c28210e50 100644
--- a/cmd/server/app/domain/toolapp/malina_libs.go
+++ b/cmd/server/app/domain/toolapp/malina_libs.go
@@ -100,17 +100,13 @@ func (a *app) pullMalinaLibs(ctx context.Context, r *http.Request) web.Encoder {
status := fmt.Sprintf("%s:%s\n", msg, sb.String())
ver := toAppVersion(status, malinalibs.VersionTag{}, allowUpgrade)
- a.log.Info(ctx, "pull-malina-libs", "info", ver[:len(ver)-1])
+ a.log.Info(ctx, "pull-malina-libs", "info", strings.TrimSpace(ver))
fmt.Fprint(w, ver)
f.Flush()
}
if allowUpgrade && !a.malinaLibs.AllowUpgrade {
a.log.Info(ctx, "pull-malina-libs", "status", "allowing libs upgrade")
- a.malinaLibs.AllowUpgrade = true
- defer func() {
- a.malinaLibs.AllowUpgrade = false
- }()
}
var (
@@ -123,7 +119,7 @@ func (a *app) pullMalinaLibs(ctx context.Context, r *http.Request) web.Encoder {
case version != "":
tag, err = a.malinaLibs.DownloadFor(ctx, logger, a.malinaLibs.Arch(), a.malinaLibs.OS(), a.malinaLibs.Processor(), version)
default:
- tag, err = a.malinaLibs.Download(ctx, logger)
+ tag, err = a.malinaLibs.DownloadSelected(ctx, logger, "", allowUpgrade)
}
if err != nil {
ver := toAppVersion(err.Error(), malinalibs.VersionTag{}, allowUpgrade)
@@ -134,7 +130,7 @@ func (a *app) pullMalinaLibs(ctx context.Context, r *http.Request) web.Encoder {
}
ver := toAppVersion("downloaded", tag, allowUpgrade)
- a.log.Info(ctx, "pull-malina-libs", "info", ver[:len(ver)-1])
+ a.log.Info(ctx, "pull-malina-libs", "info", strings.TrimSpace(ver))
fmt.Fprint(w, ver)
f.Flush()
diff --git a/cmd/server/app/domain/toolapp/malina_models.go b/cmd/server/app/domain/toolapp/malina_models.go
index ee9fe0cbe..2d4e19ef2 100644
--- a/cmd/server/app/domain/toolapp/malina_models.go
+++ b/cmd/server/app/domain/toolapp/malina_models.go
@@ -179,7 +179,7 @@ func (a *app) pullMalinaModel(ctx context.Context, r *http.Request) web.Encoder
},
}
event := toAppPullResponse(response)
- a.log.Info(ctx, "pull-malina-model", "info", event[:len(event)-1])
+ a.log.Info(ctx, "pull-malina-model", "info", strings.TrimSpace(event))
fmt.Fprint(w, event)
f.Flush()
}
diff --git a/cmd/server/app/domain/toolapp/model.go b/cmd/server/app/domain/toolapp/model.go
index 87535032b..80fa88ca8 100644
--- a/cmd/server/app/domain/toolapp/model.go
+++ b/cmd/server/app/domain/toolapp/model.go
@@ -59,10 +59,10 @@ func toAppVersion(status string, vt libs.VersionTag, allowUpgrade bool) string {
d, err := json.Marshal(vi)
if err != nil {
- return fmt.Sprintf("data: {\"Status\":%q}\n", err.Error())
+ return fmt.Sprintf("data: {\"Status\":%q}\n\n", err.Error())
}
- return fmt.Sprintf("data: %s\n", string(d))
+ return fmt.Sprintf("data: %s\n\n", string(d))
}
// =============================================================================
@@ -539,18 +539,18 @@ func toAppPull(status string, mp models.Path) string {
d, err := json.Marshal(pr)
if err != nil {
- return fmt.Sprintf("data: {\"Status\":%q}\n", err.Error())
+ return fmt.Sprintf("data: {\"Status\":%q}\n\n", err.Error())
}
- return fmt.Sprintf("data: %s\n", string(d))
+ return fmt.Sprintf("data: %s\n\n", string(d))
}
func toAppPullResponse(pr PullResponse) string {
d, err := json.Marshal(pr)
if err != nil {
- return fmt.Sprintf("data: {\"status\":%q}\n", err.Error())
+ return fmt.Sprintf("data: {\"status\":%q}\n\n", err.Error())
}
- return fmt.Sprintf("data: %s\n", string(d))
+ return fmt.Sprintf("data: %s\n\n", string(d))
}
// =============================================================================
diff --git a/cmd/server/app/domain/toolapp/models.go b/cmd/server/app/domain/toolapp/models.go
index ecb22835f..ed8eb9ac3 100644
--- a/cmd/server/app/domain/toolapp/models.go
+++ b/cmd/server/app/domain/toolapp/models.go
@@ -193,7 +193,7 @@ func (a *app) pullModels(ctx context.Context, r *http.Request) web.Encoder {
emit := func(pr PullResponse) {
ver := toAppPullResponse(pr)
- a.log.Info(ctx, "pull-model", "info", ver[:len(ver)-1])
+ a.log.Info(ctx, "pull-model", "info", strings.TrimSpace(ver))
fmt.Fprint(w, ver)
f.Flush()
}
@@ -283,7 +283,7 @@ func (a *app) pullModels(ctx context.Context, r *http.Request) web.Encoder {
if err != nil {
ver := toAppPull(err.Error(), models.Path{})
- a.log.Info(ctx, "pull-model", "info", ver[:len(ver)-1])
+ a.log.Info(ctx, "pull-model", "info", strings.TrimSpace(ver))
fmt.Fprint(w, ver)
f.Flush()
@@ -292,7 +292,7 @@ func (a *app) pullModels(ctx context.Context, r *http.Request) web.Encoder {
ver := toAppPull("downloaded", mp)
- a.log.Info(ctx, "pull-model", "info", ver[:len(ver)-1])
+ a.log.Info(ctx, "pull-model", "info", strings.TrimSpace(ver))
fmt.Fprint(w, ver)
f.Flush()
diff --git a/cmd/server/app/domain/toolapp/models_test.go b/cmd/server/app/domain/toolapp/models_test.go
index e8b4ae181..793e5de1a 100644
--- a/cmd/server/app/domain/toolapp/models_test.go
+++ b/cmd/server/app/domain/toolapp/models_test.go
@@ -1,11 +1,27 @@
package toolapp
import (
+ "strings"
"testing"
+ "github.com/ardanlabs/kronk/sdk/tools/libs"
"github.com/ardanlabs/kronk/sdk/tools/models"
)
+func TestSSEPayloadsEndWithBlankLine(t *testing.T) {
+ events := []string{
+ toAppVersion("downloading", libs.VersionTag{}, false),
+ toAppPull("downloading", models.Path{}),
+ toAppPullResponse(PullResponse{Status: "downloading"}),
+ }
+
+ for i, event := range events {
+ if !strings.HasSuffix(event, "\n\n") {
+ t.Errorf("event %d: got %q, want blank-line terminator", i, event)
+ }
+ }
+}
+
func TestToPullProgress(t *testing.T) {
progress := models.DownloadProgress{
Src: "model.gguf",
diff --git a/cmd/server/app/sdk/authclient/authclient.go b/cmd/server/app/sdk/authclient/authclient.go
index 773fbfcc1..10f091ee5 100644
--- a/cmd/server/app/sdk/authclient/authclient.go
+++ b/cmd/server/app/sdk/authclient/authclient.go
@@ -126,6 +126,7 @@ func (cln *Client) Close() error {
}
const traceIDHeader = "x-trace-id"
+const callTimeout = 5 * time.Second
var errAuthenticationDisabled = errors.New("authentication is disabled by auth service")
@@ -135,6 +136,10 @@ func injectTrace(ctx context.Context) context.Context {
return metadata.AppendToOutgoingContext(ctx, traceIDHeader, traceID)
}
+func callContext(ctx context.Context) (context.Context, context.CancelFunc) {
+ return context.WithTimeout(ctx, callTimeout)
+}
+
// Authenticate calls the auth service to authenticate the user.
func (cln *Client) Authenticate(ctx context.Context, bearerToken string, admin bool, endpoint string) (AuthenticateReponse, error) {
if cln.localAuth && !cln.authEnabled && !(admin && cln.adminAuthEnabled) {
@@ -148,6 +153,8 @@ func (cln *Client) Authenticate(ctx context.Context, bearerToken string, admin b
ctx = injectTrace(ctx)
ctx = metadata.AppendToOutgoingContext(ctx, "authorization", bearerToken)
+ ctx, cancel := callContext(ctx)
+ defer cancel()
req, err := cln.grpc.Authenticate(ctx, arb.Build())
if err != nil {
@@ -189,6 +196,8 @@ func (cln *Client) CreateToken(ctx context.Context, bearerToken string, admin bo
ctx = injectTrace(ctx)
ctx = metadata.AppendToOutgoingContext(ctx, "authorization", bearerToken)
+ ctx, cancel := callContext(ctx)
+ defer cancel()
req, err := cln.grpc.CreateToken(ctx, arb.Build())
if err != nil {
@@ -202,6 +211,8 @@ func (cln *Client) CreateToken(ctx context.Context, bearerToken string, admin bo
func (cln *Client) ListKeys(ctx context.Context, bearerToken string) (ListKeysResponse, error) {
ctx = injectTrace(ctx)
ctx = metadata.AppendToOutgoingContext(ctx, "authorization", bearerToken)
+ ctx, cancel := callContext(ctx)
+ defer cancel()
req, err := cln.grpc.ListKeys(ctx, &authapp.ListKeysRequest{})
if err != nil {
@@ -215,6 +226,8 @@ func (cln *Client) ListKeys(ctx context.Context, bearerToken string) (ListKeysRe
func (cln *Client) AddKey(ctx context.Context, bearerToken string) error {
ctx = injectTrace(ctx)
ctx = metadata.AppendToOutgoingContext(ctx, "authorization", bearerToken)
+ ctx, cancel := callContext(ctx)
+ defer cancel()
_, err := cln.grpc.AddKey(ctx, &authapp.AddKeyRequest{})
return err
@@ -228,6 +241,8 @@ func (cln *Client) RemoveKey(ctx context.Context, bearerToken string, keyID stri
ctx = injectTrace(ctx)
ctx = metadata.AppendToOutgoingContext(ctx, "authorization", bearerToken)
+ ctx, cancel := callContext(ctx)
+ defer cancel()
_, err := cln.grpc.RemoveKey(ctx, rkb.Build())
return err
diff --git a/cmd/server/app/sdk/authclient/authclient_test.go b/cmd/server/app/sdk/authclient/authclient_test.go
index 1c1ff6536..155fe0544 100644
--- a/cmd/server/app/sdk/authclient/authclient_test.go
+++ b/cmd/server/app/sdk/authclient/authclient_test.go
@@ -232,3 +232,36 @@ func TestAuthenticateRequired(t *testing.T) {
})
}
}
+
+func TestCallContextDeadline(t *testing.T) {
+ t.Run("applies call timeout", func(t *testing.T) {
+ start := time.Now()
+ ctx, cancel := callContext(context.Background())
+ defer cancel()
+
+ deadline, ok := ctx.Deadline()
+ if !ok {
+ t.Fatal("Deadline: got no deadline, want call timeout")
+ }
+ if got := deadline.Sub(start); got < callTimeout-time.Second || got > callTimeout+time.Second {
+ t.Errorf("deadline: got %s, want approximately %s", got, callTimeout)
+ }
+ })
+
+ t.Run("preserves earlier parent deadline", func(t *testing.T) {
+ parentDeadline := time.Now().Add(time.Second)
+ parent, parentCancel := context.WithDeadline(context.Background(), parentDeadline)
+ defer parentCancel()
+
+ ctx, cancel := callContext(parent)
+ defer cancel()
+
+ deadline, ok := ctx.Deadline()
+ if !ok {
+ t.Fatal("Deadline: got no deadline, want parent deadline")
+ }
+ if !deadline.Equal(parentDeadline) {
+ t.Errorf("deadline: got %s, want %s", deadline, parentDeadline)
+ }
+ })
+}
diff --git a/cmd/server/app/sdk/mid/errors.go b/cmd/server/app/sdk/mid/errors.go
index 0084c7ea4..e1a148ecc 100644
--- a/cmd/server/app/sdk/mid/errors.go
+++ b/cmd/server/app/sdk/mid/errors.go
@@ -44,7 +44,7 @@ func Errors(log *logger.Logger) web.MidFunc {
return resp
}
- if appErr.Code == errs.InternalOnlyLog {
+ if appErr.Code == errs.Internal || appErr.Code == errs.InternalOnlyLog {
appErr = errs.Errorf(errs.Internal, "Internal Server Error")
}
diff --git a/cmd/server/app/sdk/mid/errors_test.go b/cmd/server/app/sdk/mid/errors_test.go
new file mode 100644
index 000000000..a564d0217
--- /dev/null
+++ b/cmd/server/app/sdk/mid/errors_test.go
@@ -0,0 +1,41 @@
+package mid
+
+import (
+ "context"
+ "io"
+ "net/http"
+ "net/http/httptest"
+ "testing"
+
+ "github.com/ardanlabs/kronk/cmd/server/app/sdk/errs"
+ "github.com/ardanlabs/kronk/cmd/server/foundation/logger"
+ "github.com/ardanlabs/kronk/cmd/server/foundation/web"
+)
+
+func TestErrorsMasksInternalMessages(t *testing.T) {
+ tests := []struct {
+ name string
+ code errs.ErrCode
+ }{
+ {name: "internal", code: errs.Internal},
+ {name: "internal only log", code: errs.InternalOnlyLog},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ log := logger.New(io.Discard, logger.LevelError, "TEST", nil)
+ handler := Errors(log)(func(context.Context, *http.Request) web.Encoder {
+ return errs.Errorf(tt.code, "sensitive /path/to/database")
+ })
+
+ resp := handler(t.Context(), httptest.NewRequest("GET", "/", nil))
+ appErr, ok := resp.(*errs.Error)
+ if !ok {
+ t.Fatalf("response: got %T, want *errs.Error", resp)
+ }
+ if got, want := appErr.Message, "Internal Server Error"; got != want {
+ t.Errorf("message: got %q, want %q", got, want)
+ }
+ })
+ }
+}
diff --git a/cmd/server/app/sdk/mux/admin.go b/cmd/server/app/sdk/mux/admin.go
index 034626a9c..882a2f4c7 100644
--- a/cmd/server/app/sdk/mux/admin.go
+++ b/cmd/server/app/sdk/mux/admin.go
@@ -81,7 +81,7 @@ func remoteHost(remoteAddr string) string {
func registerAdminRoutes(app *web.App, cfg Config) {
limiter := newLoginLimiter()
- app.RawHandlerFunc(http.MethodGet, "", "/", func(w http.ResponseWriter, r *http.Request) {
+ app.RawHandlerFunc(http.MethodGet, "", "/{$}", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/admin/", http.StatusPermanentRedirect)
})
diff --git a/cmd/server/app/sdk/mux/admin_test.go b/cmd/server/app/sdk/mux/admin_test.go
index 1eaa49007..16f82beb7 100644
--- a/cmd/server/app/sdk/mux/admin_test.go
+++ b/cmd/server/app/sdk/mux/admin_test.go
@@ -36,6 +36,13 @@ func TestAdminRedirects(t *testing.T) {
}
})
}
+
+ req := httptest.NewRequest(http.MethodGet, "http://example.test/missing", nil)
+ rr := httptest.NewRecorder()
+ app.ServeHTTP(rr, req)
+ if rr.Code != http.StatusNotFound {
+ t.Errorf("unknown path status: got %d, want %d", rr.Code, http.StatusNotFound)
+ }
}
func TestAdminCookieMiddleware(t *testing.T) {
diff --git a/cmd/server/app/sdk/security/auth/auth_test.go b/cmd/server/app/sdk/security/auth/auth_test.go
index bc54b876d..4ac200b9a 100644
--- a/cmd/server/app/sdk/security/auth/auth_test.go
+++ b/cmd/server/app/sdk/security/auth/auth_test.go
@@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"errors"
+ "strings"
"testing"
"time"
@@ -95,6 +96,111 @@ func TestAuthenticateInvalidToken(t *testing.T) {
}
}
+func TestAuthenticateJWTPolicy(t *testing.T) {
+ ath, err := auth.New(auth.Config{
+ KeyLookup: &keyStore{},
+ Issuer: "service project",
+ })
+ if err != nil {
+ t.Fatalf("construct auth api: %v", err)
+ }
+
+ now := time.Now().UTC()
+ tests := []struct {
+ name string
+ claims auth.Claims
+ mutate func(string) string
+ wantErr bool
+ }{
+ {
+ name: "valid",
+ claims: auth.Claims{
+ Issuer: "service project",
+ Subject: "valid",
+ ExpiresAt: jwt.NewNumericDate(now.Add(time.Hour)),
+ },
+ },
+ {
+ name: "expired",
+ claims: auth.Claims{
+ Issuer: "service project",
+ Subject: "expired",
+ ExpiresAt: jwt.NewNumericDate(now.Add(-time.Hour)),
+ },
+ wantErr: true,
+ },
+ {
+ name: "wrong issuer",
+ claims: auth.Claims{
+ Issuer: "other project",
+ Subject: "wrong-issuer",
+ ExpiresAt: jwt.NewNumericDate(now.Add(time.Hour)),
+ },
+ wantErr: true,
+ },
+ {
+ name: "expired and wrong issuer",
+ claims: auth.Claims{
+ Issuer: "other project",
+ Subject: "expired-wrong-issuer",
+ ExpiresAt: jwt.NewNumericDate(now.Add(-time.Hour)),
+ },
+ wantErr: true,
+ },
+ {
+ name: "missing expiration",
+ claims: auth.Claims{
+ Issuer: "service project",
+ Subject: "missing-expiration",
+ },
+ wantErr: true,
+ },
+ {
+ name: "bad signature",
+ claims: auth.Claims{
+ Issuer: "service project",
+ Subject: "bad-signature",
+ ExpiresAt: jwt.NewNumericDate(now.Add(time.Hour)),
+ },
+ mutate: func(token string) string {
+ signatureStart := strings.LastIndexByte(token, '.') + 1
+ if token[signatureStart] == 'A' {
+ return token[:signatureStart] + "B" + token[signatureStart+1:]
+ }
+ return token[:signatureStart] + "A" + token[signatureStart+1:]
+ },
+ wantErr: true,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ token, err := ath.GenerateToken(tt.claims)
+ if err != nil {
+ t.Fatalf("GenerateToken: %v", err)
+ }
+ if tt.mutate != nil {
+ token = tt.mutate(token)
+ }
+
+ _, err = ath.Authenticate(t.Context(), "Bearer "+token)
+ if tt.wantErr {
+ if !errors.Is(err, auth.ErrInvalidToken) {
+ t.Fatalf("Authenticate: got %v, want ErrInvalidToken", err)
+ }
+ return
+ }
+ if err != nil {
+ t.Fatalf("Authenticate: %v", err)
+ }
+ })
+ }
+
+ if _, err := ath.Authenticate(t.Context(), "Bearer malformed.jwt"); !errors.Is(err, auth.ErrInvalidToken) {
+ t.Fatalf("Authenticate malformed token: got %v, want ErrInvalidToken", err)
+ }
+}
+
func TestAuthenticateSigningMethod(t *testing.T) {
privateKey, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(privateKeyPEM))
if err != nil {
diff --git a/cmd/server/app/sdk/security/auth/rego/authentication.rego b/cmd/server/app/sdk/security/auth/rego/authentication.rego
index b3b8cac24..061ed0917 100644
--- a/cmd/server/app/sdk/security/auth/rego/authentication.rego
+++ b/cmd/server/app/sdk/security/auth/rego/authentication.rego
@@ -4,25 +4,12 @@ import rego.v1
default auth := {"valid": false, "error": "signature_invalid"}
-# Check for token expiration first (before full verification)
-auth := {"valid": false, "error": "token_expired"} if {
- [_, payload, _] := io.jwt.decode(input.Token)
- now := time.now_ns() / 1000000000
- payload.exp < now
-}
-
-# Check for issuer mismatch
-auth := {"valid": false, "error": "issuer_mismatch"} if {
- [_, payload, _] := io.jwt.decode(input.Token)
- payload.iss != input.ISS
-}
-
-# Full verification passes
auth := {"valid": true, "error": ""} if {
- [valid, _, _] := io.jwt.decode_verify(input.Token, {
+ [valid, _, payload] := io.jwt.decode_verify(input.Token, {
"cert": input.Key,
"iss": input.ISS,
"alg": "RS256",
})
- valid == true
+ valid
+ is_number(payload.exp)
}
diff --git a/cmd/server/app/sdk/security/genkey.go b/cmd/server/app/sdk/security/genkey.go
index 9ae4a9fee..3fc2a4672 100644
--- a/cmd/server/app/sdk/security/genkey.go
+++ b/cmd/server/app/sdk/security/genkey.go
@@ -5,6 +5,7 @@ import (
"crypto/rsa"
"crypto/x509"
"encoding/pem"
+ "errors"
"fmt"
"os"
"path/filepath"
@@ -21,12 +22,18 @@ func generatePrivateKey(keysPath string, keyName string) error {
fileName := fmt.Sprintf("%s.pem", keyName)
keyName = filepath.Join(keysPath, fileName)
- // Create a file for the private key information in PEM form.
- privateFile, err := os.OpenFile(keyName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
+ // Create a sibling temporary file so an interrupted write never publishes
+ // a truncated key that prevents the keystore from loading.
+ privateFile, err := os.CreateTemp(keysPath, "."+fileName+".*.tmp")
if err != nil {
- return fmt.Errorf("creating private file: %w", err)
+ return fmt.Errorf("creating temporary private file: %w", err)
+ }
+ tmpName := privateFile.Name()
+ defer os.Remove(tmpName)
+
+ if err := privateFile.Chmod(0600); err != nil {
+ return errors.Join(fmt.Errorf("setting private file permissions: %w", err), privateFile.Close())
}
- defer privateFile.Close()
// Construct a PEM block for the private key.
privateBlock := pem.Block{
@@ -36,7 +43,16 @@ func generatePrivateKey(keysPath string, keyName string) error {
// Write the private key to the private key file.
if err := pem.Encode(privateFile, &privateBlock); err != nil {
- return fmt.Errorf("generate-private-key: unable to encode: %w", err)
+ return errors.Join(fmt.Errorf("generate-private-key: unable to encode: %w", err), privateFile.Close())
+ }
+ if err := privateFile.Sync(); err != nil {
+ return errors.Join(fmt.Errorf("generate-private-key: unable to sync: %w", err), privateFile.Close())
+ }
+ if err := privateFile.Close(); err != nil {
+ return fmt.Errorf("generate-private-key: unable to close: %w", err)
+ }
+ if err := os.Rename(tmpName, keyName); err != nil {
+ return fmt.Errorf("generate-private-key: unable to publish: %w", err)
}
return nil
diff --git a/cmd/server/foundation/web/web.go b/cmd/server/foundation/web/web.go
index 01e9ac0f5..2eb85ae00 100644
--- a/cmd/server/foundation/web/web.go
+++ b/cmd/server/foundation/web/web.go
@@ -82,6 +82,9 @@ func (a *App) ServeHTTP(w http.ResponseWriter, r *http.Request) {
for _, origin := range a.origins {
if origin == "*" || origin == reqOrigin {
w.Header().Set("Access-Control-Allow-Origin", origin)
+ if origin != "*" {
+ w.Header().Add("Vary", "Origin")
+ }
break
}
}
@@ -210,7 +213,14 @@ func (a *App) RawHandlerFunc(method string, group string, path string, rawHandle
otel.GetTextMapPropagator().Inject(ctx, propagation.HeaderCarrier(w.Header()))
- handlerFunc(ctx, r)
+ resp := handlerFunc(ctx, r)
+ if resp == nil {
+ return
+ }
+
+ if err := Respond(ctx, w, resp); err != nil {
+ a.log(ctx, "web-respond", "ERROR", err)
+ }
}
finalPath := path
diff --git a/cmd/server/foundation/web/web_test.go b/cmd/server/foundation/web/web_test.go
index 7df17556e..1980c54e1 100644
--- a/cmd/server/foundation/web/web_test.go
+++ b/cmd/server/foundation/web/web_test.go
@@ -2,11 +2,23 @@ package web
import (
"context"
+ "encoding/json"
"net/http"
"net/http/httptest"
"testing"
)
+type rawErrorResponse struct{}
+
+func (rawErrorResponse) Encode() ([]byte, string, error) {
+ data, err := json.Marshal(map[string]string{"error": "recovered"})
+ return data, "application/json", err
+}
+
+func (rawErrorResponse) HTTPStatus() int {
+ return http.StatusInternalServerError
+}
+
func TestNotFoundHandlerUsesApplicationMiddleware(t *testing.T) {
var middlewareCalls int
var traceID string
@@ -38,3 +50,65 @@ func TestNotFoundHandlerUsesApplicationMiddleware(t *testing.T) {
t.Errorf("trace ID: got %q, want non-default value", traceID)
}
}
+
+func TestRawHandlerFuncWritesMiddlewareResponse(t *testing.T) {
+ recoverPanic := func(next HandlerFunc) HandlerFunc {
+ return func(ctx context.Context, r *http.Request) (resp Encoder) {
+ defer func() {
+ if recover() != nil {
+ resp = rawErrorResponse{}
+ }
+ }()
+ return next(ctx, r)
+ }
+ }
+
+ app := NewApp(func(context.Context, string, ...any) {}, recoverPanic)
+ app.RawHandlerFunc(http.MethodGet, "", "/raw", func(http.ResponseWriter, *http.Request) {
+ panic("boom")
+ })
+
+ rr := httptest.NewRecorder()
+ app.ServeHTTP(rr, httptest.NewRequest(http.MethodGet, "/raw", nil))
+
+ if rr.Code != http.StatusInternalServerError {
+ t.Errorf("status: got %d, want %d", rr.Code, http.StatusInternalServerError)
+ }
+ if got := rr.Body.String(); got != "{\"error\":\"recovered\"}" {
+ t.Errorf("body: got %q, want recovered error", got)
+ }
+}
+
+func TestCORSReflectedOriginVariesByOrigin(t *testing.T) {
+ app := NewApp(func(context.Context, string, ...any) {})
+ app.EnableCORS([]string{"https://console.example"})
+
+ req := httptest.NewRequest(http.MethodOptions, "/v1/models", nil)
+ req.Header.Set("Origin", "https://console.example")
+ rr := httptest.NewRecorder()
+ app.ServeHTTP(rr, req)
+
+ if got := rr.Header().Get("Access-Control-Allow-Origin"); got != "https://console.example" {
+ t.Errorf("Access-Control-Allow-Origin: got %q, want %q", got, "https://console.example")
+ }
+ if got := rr.Header().Get("Vary"); got != "Origin" {
+ t.Errorf("Vary: got %q, want %q", got, "Origin")
+ }
+}
+
+func TestCORSWildcardDoesNotVaryByOrigin(t *testing.T) {
+ app := NewApp(func(context.Context, string, ...any) {})
+ app.EnableCORS([]string{"*"})
+
+ req := httptest.NewRequest(http.MethodOptions, "/v1/models", nil)
+ req.Header.Set("Origin", "https://console.example")
+ rr := httptest.NewRecorder()
+ app.ServeHTTP(rr, req)
+
+ if got := rr.Header().Get("Access-Control-Allow-Origin"); got != "*" {
+ t.Errorf("Access-Control-Allow-Origin: got %q, want %q", got, "*")
+ }
+ if got := rr.Header().Get("Vary"); got != "" {
+ t.Errorf("Vary: got %q, want empty", got)
+ }
+}
diff --git a/sdk/applog/applog.go b/sdk/applog/applog.go
index 3b24beebe..5e28cc55f 100644
--- a/sdk/applog/applog.go
+++ b/sdk/applog/applog.go
@@ -7,6 +7,7 @@ package applog
import (
"context"
"fmt"
+ "strings"
"time"
)
@@ -71,31 +72,34 @@ var DiscardLogger Logger = func(ctx context.Context, msg string, args ...any) {
// shorter updates don't leave trailing garbage from longer prior writes.
var FmtLogger Logger = func(ctx context.Context, msg string, args ...any) {
now := time.Now().Format(time.RFC3339Nano)
+ var line strings.Builder
- cr := ""
+ progress := false
if len(msg) > 0 && msg[0] == '\r' {
- cr = "\r"
+ progress = true
+ line.WriteByte('\r')
msg = msg[1:]
}
if traceID := GetTraceID(ctx); traceID != "" && traceID != NoTraceID {
- fmt.Printf("%sKRONK: %s: INFO: %s: %s:", cr, now, traceID, msg)
+ line.WriteString(fmt.Sprintf("KRONK: %s: INFO: %s: %s:", now, traceID, msg))
} else {
- fmt.Printf("%sKRONK: %s: %s:", cr, now, msg)
+ line.WriteString(fmt.Sprintf("KRONK: %s: %s:", now, msg))
}
for i := 0; i < len(args); i += 2 {
if i+1 < len(args) {
- fmt.Printf(" %v[%v]", args[i], args[i+1])
+ line.WriteString(fmt.Sprintf(" %v[%v]", args[i], args[i+1]))
}
}
- switch cr {
- case "":
- fmt.Println()
- default:
+ if progress {
// Erase from cursor to end of line so a shorter progress update
// doesn't leave stale characters from the previous longer line.
- fmt.Print("\x1b[K")
+ line.WriteString("\x1b[K")
+ } else {
+ line.WriteByte('\n')
}
+
+ fmt.Print(line.String())
}
diff --git a/sdk/bucky/model/stream.go b/sdk/bucky/model/stream.go
index 91f67d3e9..4308b617e 100644
--- a/sdk/bucky/model/stream.go
+++ b/sdk/bucky/model/stream.go
@@ -34,6 +34,10 @@ const (
maxPromptTokens = 64 // tail tokens carried as cross-window prompt context
)
+// ErrStreamStopped indicates that a stream's worker exited after a terminal
+// processing error or close.
+var ErrStreamStopped = errors.New("stream stopped")
+
// =============================================================================
// Events
@@ -618,9 +622,17 @@ func (s *Stream) Feed(ctx context.Context, samples []float32) error {
cp := make([]float32, len(samples))
copy(cp, samples)
+ select {
+ case <-s.doneC:
+ return fmt.Errorf("feed: %w", ErrStreamStopped)
+ default:
+ }
+
select {
case s.inC <- cp:
return nil
+ case <-s.doneC:
+ return fmt.Errorf("feed: %w", ErrStreamStopped)
case <-s.closeC:
return fmt.Errorf("feed: stream closed")
case <-ctx.Done():
@@ -746,8 +758,16 @@ func (s *Stream) Reset(ctx context.Context, opts ...ResetOption) error {
done := make(chan struct{})
+ select {
+ case <-s.doneC:
+ return fmt.Errorf("reset: %w", ErrStreamStopped)
+ default:
+ }
+
select {
case s.resetC <- resetReq{cfg: rc, done: done}:
+ case <-s.doneC:
+ return fmt.Errorf("reset: %w", ErrStreamStopped)
case <-s.closeC:
return fmt.Errorf("reset: stream closed")
case <-ctx.Done():
@@ -757,14 +777,18 @@ func (s *Stream) Reset(ctx context.Context, opts ...ResetOption) error {
select {
case <-done:
return nil
+ case <-s.doneC:
+ return fmt.Errorf("reset: %w", ErrStreamStopped)
case <-ctx.Done():
return ctx.Err()
}
}
-// Close performs one final flush over remaining audio, emits the
-// resulting Final event, closes Events, and returns the whisper.State to
-// the pool. It is idempotent and blocks until the worker has exited.
+// Close performs one final flush over remaining audio, emits the resulting
+// Final event when the Events buffer has room, closes Events, and returns the
+// whisper.State to the pool. If the consumer has abandoned a full Events
+// buffer, cleanup takes priority and the closing event is dropped. Close is
+// idempotent and blocks until the worker has exited.
func (s *Stream) Close() error {
s.closeOnce.Do(func() {
close(s.closeC)
@@ -793,21 +817,21 @@ func (s *Stream) run() {
case rr := <-s.resetC:
if err := s.doReset(rr.cfg); err != nil {
close(rr.done)
- s.events <- Event{Kind: EventError, Err: err}
+ s.emitEvent(Event{Kind: EventError, Err: err})
return
}
close(rr.done)
case <-heartbeat.C:
if err := s.process(); err != nil {
- s.events <- Event{Kind: EventError, Err: err}
+ s.emitEvent(Event{Kind: EventError, Err: err})
return
}
case <-s.closeC:
s.drainInput()
if err := s.finalFlush(); err != nil {
- s.events <- Event{Kind: EventError, Err: err}
+ s.emitEvent(Event{Kind: EventError, Err: err})
}
return
}
@@ -958,7 +982,7 @@ func (s *Stream) doReset(rc ResetConfig) error {
}
if s.cfg.EmitResetEvent {
- s.events <- Event{Kind: EventReset, StartMs: s.baseMs, EndMs: s.baseMs}
+ s.emitEvent(Event{Kind: EventReset, StartMs: s.baseMs, EndMs: s.baseMs})
}
return nil
@@ -991,15 +1015,32 @@ func (s *Stream) emitPartial(tr Transcription) {
}
}
-// emitFinal sends a committed event. Finals are never dropped; the send
-// blocks until the consumer reads it.
+// emitFinal sends a committed event. Finals apply backpressure while the
+// stream is open, but an undrained consumer cannot prevent Close from
+// releasing the worker and its whisper state.
func (s *Stream) emitFinal(tr Transcription) {
- s.events <- Event{
+ s.emitEvent(Event{
Kind: EventFinal,
Text: tr.Text,
Segments: tr.Segments,
StartMs: s.baseMs,
EndMs: s.baseMs + msForSamples(len(s.buf)),
+ })
+}
+
+// emitEvent delivers a non-revisable event with backpressure until shutdown.
+// The first non-blocking attempt preserves a closing Final whenever the buffer
+// still has room; if the buffer is full, Close takes priority over delivery.
+func (s *Stream) emitEvent(event Event) {
+ select {
+ case s.events <- event:
+ return
+ default:
+ }
+
+ select {
+ case s.events <- event:
+ case <-s.closeC:
}
}
diff --git a/sdk/bucky/model/stream_test.go b/sdk/bucky/model/stream_test.go
index d68ea8b30..5a65bcfa7 100644
--- a/sdk/bucky/model/stream_test.go
+++ b/sdk/bucky/model/stream_test.go
@@ -3,6 +3,7 @@ package model
import (
"context"
"encoding/binary"
+ "errors"
"fmt"
"math"
"slices"
@@ -168,6 +169,110 @@ func TestStream_CloseReleasesSlot(t *testing.T) {
}
}
+func TestStream_FeedAndResetReturnAfterWorkerError(t *testing.T) {
+ fd := &fakeDecoder{err: errors.New("decode failed")}
+ s := newStream(StreamConfig{
+ PartialEveryMs: -1,
+ CommitEveryMs: 1,
+ MaxUtteranceMs: 100000,
+ DisableVAD: true,
+ }.withDefaults(), fd.decode, func() {})
+
+ if err := s.Feed(context.Background(), tone(500, 0.5)); err != nil {
+ t.Fatalf("initial Feed: %v", err)
+ }
+ select {
+ case <-s.doneC:
+ case <-time.After(time.Second):
+ t.Fatal("stream worker did not stop after decode error")
+ }
+
+ if err := s.Feed(context.Background(), tone(10, 0.5)); !errors.Is(err, ErrStreamStopped) {
+ t.Errorf("Feed error: got %v, want %v", err, ErrStreamStopped)
+ }
+ if err := s.Reset(context.Background()); !errors.Is(err, ErrStreamStopped) {
+ t.Errorf("Reset error: got %v, want %v", err, ErrStreamStopped)
+ }
+}
+
+func TestStream_CloseReleasesSlotWithFullEventsBuffer(t *testing.T) {
+ fd := &fakeDecoder{text: "flush"}
+ released := make(chan struct{})
+ s := newStream(StreamConfig{
+ PartialEveryMs: -1,
+ CommitEveryMs: 100000,
+ MaxUtteranceMs: 100000,
+ DisableVAD: true,
+ }.withDefaults(), fd.decode, func() { close(released) })
+
+ for range cap(s.events) {
+ s.events <- Event{Kind: EventFinal}
+ }
+ if err := s.Feed(context.Background(), tone(500, 0.5)); err != nil {
+ t.Fatalf("Feed: %v", err)
+ }
+
+ closed := make(chan struct{})
+ go func() {
+ _ = s.Close()
+ close(closed)
+ }()
+
+ select {
+ case <-closed:
+ case <-time.After(time.Second):
+ t.Fatal("Close blocked on a full Events buffer")
+ }
+ select {
+ case <-released:
+ case <-time.After(time.Second):
+ t.Fatal("Close did not release the stream slot")
+ }
+}
+
+func TestStream_CloseUnblocksErrorWithFullEventsBuffer(t *testing.T) {
+ fd := &fakeDecoder{err: errors.New("decode failed")}
+ released := make(chan struct{})
+ s := newStream(StreamConfig{
+ PartialEveryMs: -1,
+ CommitEveryMs: 1,
+ MaxUtteranceMs: 100000,
+ DisableVAD: true,
+ }.withDefaults(), fd.decode, func() { close(released) })
+
+ for range cap(s.events) {
+ s.events <- Event{Kind: EventFinal}
+ }
+ if err := s.Feed(context.Background(), tone(500, 0.5)); err != nil {
+ t.Fatalf("Feed: %v", err)
+ }
+
+ deadline := time.Now().Add(time.Second)
+ for len(fd.promptCalls()) == 0 && time.Now().Before(deadline) {
+ time.Sleep(10 * time.Millisecond)
+ }
+ if len(fd.promptCalls()) == 0 {
+ t.Fatal("decoder was not called")
+ }
+
+ closed := make(chan struct{})
+ go func() {
+ _ = s.Close()
+ close(closed)
+ }()
+
+ select {
+ case <-closed:
+ case <-time.After(time.Second):
+ t.Fatal("Close blocked on a full Events buffer after a decode error")
+ }
+ select {
+ case <-released:
+ case <-time.After(time.Second):
+ t.Fatal("decode error did not release the stream slot")
+ }
+}
+
func TestStream_FinalFlushOnClose(t *testing.T) {
fd := &fakeDecoder{text: "flush"}
cfg := StreamConfig{
diff --git a/sdk/bucky/pool/pool.go b/sdk/bucky/pool/pool.go
index d8d14f002..9bb87ddfe 100644
--- a/sdk/bucky/pool/pool.go
+++ b/sdk/bucky/pool/pool.go
@@ -96,6 +96,7 @@ func New(cfg Config) (*Pool, error) {
Resman: cfg.Resman,
MaxItems: cfg.ModelsInPool,
TTL: cfg.TTL,
+ Backend: "bucky",
}, wl)
if err != nil {
return nil, fmt.Errorf("new: constructing pool core: %w", err)
@@ -143,8 +144,9 @@ func (p *Pool) Invalidate(key string) {
p.engine.Invalidate(key)
}
-// InvalidateSync invalidates a cache entry and waits for the eviction
-// callback to release the underlying resource manager reservation.
+// InvalidateSync invalidates a cache entry and waits for the eviction callback
+// to release the underlying resource manager reservation. If unloading fails,
+// the model and reservation remain in the pool and the error is returned.
func (p *Pool) InvalidateSync(ctx context.Context, key string) error {
return p.engine.InvalidateSync(ctx, key)
}
diff --git a/sdk/kronk/autotune.go b/sdk/kronk/autotune.go
index 093d0b046..ec6529d5c 100644
--- a/sdk/kronk/autotune.go
+++ b/sdk/kronk/autotune.go
@@ -18,6 +18,17 @@ import (
// On any failure the original cfg is returned unchanged so auto-tune never
// blocks a load.
func AutoTuneConfig(ctx context.Context, cfg model.Config) model.Config {
+ return autoTuneConfig(ctx, cfg, nil)
+}
+
+// AutoTuneConfigWithBudget seeds unset settings using a stable memory budget.
+// Pool callers use this so custom loads honor the same resource-manager limits
+// as catalog-driven loads.
+func AutoTuneConfigWithBudget(ctx context.Context, cfg model.Config, budget models.AutoTuneBudget) model.Config {
+ return autoTuneConfig(ctx, cfg, &budget)
+}
+
+func autoTuneConfig(ctx context.Context, cfg model.Config, budget *models.AutoTuneBudget) model.Config {
if len(cfg.ModelFiles) == 0 {
logAutoTune(ctx, cfg.Log, "status", "skipped", "reason", "no model files configured")
return cfg
@@ -45,7 +56,12 @@ func AutoTuneConfig(ctx context.Context, cfg model.Config) model.Config {
if constraints.PtrSWAFull == nil {
constraints.PtrSWAFull = new(llama.ContextDefaultParams().SwaFull != 0)
}
- base, err := models.AutoTuneWithConfig(info, devices.List(), constraints)
+ var base models.ModelConfig
+ if budget == nil {
+ base, err = models.AutoTuneWithConfig(info, devices.List(), constraints)
+ } else {
+ base, err = models.AutoTuneWithConfigAndBudget(info, budget.Devices, constraints, *budget)
+ }
if err != nil {
logAutoTune(ctx, cfg.Log, "status", "skipped", "error", err.Error())
return cfg
diff --git a/sdk/kronk/decision.go b/sdk/kronk/decision.go
index b1b31221b..692402d95 100644
--- a/sdk/kronk/decision.go
+++ b/sdk/kronk/decision.go
@@ -37,7 +37,9 @@ func (krn *Kronk) DecisionHTTP(ctx context.Context, log Logger, w http.ResponseW
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
- w.Write(data)
+ if _, err := w.Write(data); err != nil {
+ return resp, fmt.Errorf("decision-http: %w: write response: %w", ErrResponseCommitted, err)
+ }
return resp, nil
}
diff --git a/sdk/kronk/embedding.go b/sdk/kronk/embedding.go
index 24371ecef..309f69a14 100644
--- a/sdk/kronk/embedding.go
+++ b/sdk/kronk/embedding.go
@@ -47,7 +47,9 @@ func (krn *Kronk) EmbeddingsHTTP(ctx context.Context, log Logger, w http.Respons
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
- w.Write(data)
+ if _, err := w.Write(data); err != nil {
+ return resp, fmt.Errorf("embeddings-http: %w: write response: %w", ErrResponseCommitted, err)
+ }
return resp, nil
}
diff --git a/sdk/kronk/gguf/fetch.go b/sdk/kronk/gguf/fetch.go
index 6b118d901..bce93ac0b 100644
--- a/sdk/kronk/gguf/fetch.go
+++ b/sdk/kronk/gguf/fetch.go
@@ -8,6 +8,8 @@ import (
"net/http"
"os"
"path/filepath"
+
+ "github.com/ardanlabs/kronk/sdk/kronk/hf"
)
// FetchHeaderBytes fetches the first HeaderFetchSize bytes of the GGUF
@@ -109,9 +111,9 @@ func IsValidHeaderBytes(data []byte) bool {
// Returns the requested bytes and the total file size advertised by the
// server (when known).
//
-// When KRONK_HF_TOKEN is set the request carries it as a Bearer
-// Authorization header so gated HuggingFace repos resolve. When the
-// server returns 200 OK (full file) instead of 206 Partial Content —
+// When KRONK_HF_TOKEN is set, requests to Hugging Face carry it as a
+// Bearer Authorization header so gated repos resolve. Other destinations
+// never receive the token. When the server returns 200 OK (full file) —
// which happens for some HuggingFace storage backends like Xet that do
// not honor Range — the function reads only the requested range from
// the response body to avoid downloading the whole file.
@@ -130,7 +132,7 @@ func fetchRangeWithClient(ctx context.Context, client *http.Client, url string,
req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", start, end))
- if token := os.Getenv("KRONK_HF_TOKEN"); token != "" {
+ if token := os.Getenv("KRONK_HF_TOKEN"); token != "" && hf.IsHuggingFaceURL(url) {
req.Header.Set("Authorization", "Bearer "+token)
}
diff --git a/sdk/kronk/gguf/fetch_test.go b/sdk/kronk/gguf/fetch_test.go
index 78210f4de..ad2bfed21 100644
--- a/sdk/kronk/gguf/fetch_test.go
+++ b/sdk/kronk/gguf/fetch_test.go
@@ -3,11 +3,47 @@ package gguf
import (
"context"
"fmt"
+ "io"
"net/http"
"net/http/httptest"
+ "strings"
"testing"
)
+type roundTripFunc func(*http.Request) (*http.Response, error)
+
+func (fn roundTripFunc) RoundTrip(r *http.Request) (*http.Response, error) {
+ return fn(r)
+}
+
+func TestFetchRangeAuthorizesHuggingFace(t *testing.T) {
+ t.Setenv("KRONK_HF_TOKEN", "secret")
+
+ client := http.Client{
+ Transport: roundTripFunc(func(r *http.Request) (*http.Response, error) {
+ if got := r.Header.Get("Authorization"); got != "Bearer secret" {
+ t.Errorf("Authorization: got %q, want %q", got, "Bearer secret")
+ }
+
+ return &http.Response{
+ StatusCode: http.StatusPartialContent,
+ Header: http.Header{"Content-Range": []string{"bytes 0-0/1"}},
+ Body: io.NopCloser(strings.NewReader("x")),
+ ContentLength: 1,
+ Request: r,
+ }, nil
+ }),
+ }
+
+ data, size, err := fetchRangeWithClient(t.Context(), &client, "https://huggingface.co/owner/repo/resolve/main/model.gguf", 0, 0)
+ if err != nil {
+ t.Fatalf("fetchRangeWithClient: %v", err)
+ }
+ if string(data) != "x" || size != 1 {
+ t.Errorf("range result: got data %q and size %d, want data %q and size 1", data, size, "x")
+ }
+}
+
func TestFetchRangeEOFClamped(t *testing.T) {
const fileSize = 7872576
@@ -16,7 +52,11 @@ func TestFetchRangeEOFClamped(t *testing.T) {
body[i] = byte(i % 256)
}
+ t.Setenv("KRONK_HF_TOKEN", "secret")
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if got := r.Header.Get("Authorization"); got != "" {
+ t.Errorf("Authorization: got %q, want empty for non-Hugging Face host", got)
+ }
w.Header().Set("Content-Range", fmt.Sprintf("bytes 0-%d/%d", fileSize-1, fileSize))
w.WriteHeader(http.StatusPartialContent)
w.Write(body)
diff --git a/sdk/kronk/gguf/metadata.go b/sdk/kronk/gguf/metadata.go
index 6be576135..ae521a599 100644
--- a/sdk/kronk/gguf/metadata.go
+++ b/sdk/kronk/gguf/metadata.go
@@ -38,11 +38,22 @@ func ParseInt64WithFallback(metadata map[string]string, key string, suffix strin
return strconv.ParseInt(val, 10, 64)
}
+ var (
+ fallback string
+ found bool
+ )
for k, v := range metadata {
if strings.HasSuffix(k, suffix) {
- return strconv.ParseInt(v, 10, 64)
+ if found {
+ return 0, fmt.Errorf("parse-metadata-int64: metadata suffix %q is ambiguous", suffix)
+ }
+ fallback = v
+ found = true
}
}
+ if found {
+ return strconv.ParseInt(fallback, 10, 64)
+ }
return 0, fmt.Errorf("parse-metadata-int64: metadata key %q not found", key)
}
diff --git a/sdk/kronk/gguf/metadata_test.go b/sdk/kronk/gguf/metadata_test.go
new file mode 100644
index 000000000..8ace359b4
--- /dev/null
+++ b/sdk/kronk/gguf/metadata_test.go
@@ -0,0 +1,18 @@
+package gguf
+
+import (
+ "strings"
+ "testing"
+)
+
+func TestParseInt64WithFallbackRejectsAmbiguousSuffix(t *testing.T) {
+ metadata := map[string]string{
+ "language.block_count": "32",
+ "vision.block_count": "24",
+ }
+
+ _, err := ParseInt64WithFallback(metadata, "missing.block_count", ".block_count")
+ if err == nil || !strings.Contains(err.Error(), "ambiguous") {
+ t.Fatalf("ParseInt64WithFallback: got %v, want ambiguous suffix error", err)
+ }
+}
diff --git a/sdk/kronk/gguf/reader.go b/sdk/kronk/gguf/reader.go
index 0f114023b..f08cbbf90 100644
--- a/sdk/kronk/gguf/reader.go
+++ b/sdk/kronk/gguf/reader.go
@@ -23,11 +23,13 @@ func ParseMetadata(data []byte) (map[string]string, error) {
return nil, fmt.Errorf("parse-metadata: %w", err)
}
- metadata := make(map[string]string, header.MetadataKvCount)
+ // Do not size this map from the untrusted metadata count. Let it grow only
+ // for entries that are actually present in the supplied bytes.
+ metadata := make(map[string]string)
for i := uint64(0); i < header.MetadataKvCount; i++ {
key, value, err := readMetadataKV(reader)
if err != nil {
- break
+ return nil, fmt.Errorf("parse-metadata: read metadata entry %d: %w", i, err)
}
metadata[key] = fmt.Sprintf("%v", value)
}
@@ -180,6 +182,13 @@ func readMetadataValue(r *bytes.Reader, valueType uint32) (any, error) {
return nil, err
}
+ // Every supported array element consumes at least one byte. Reject a
+ // count that cannot fit in the remaining input before using it as a
+ // slice length.
+ if arrayLen > uint64(r.Len()) {
+ return nil, fmt.Errorf("read-metadata-value: array length %d exceeds remaining bytes %d", arrayLen, r.Len())
+ }
+
result := make([]any, arrayLen)
for i := uint64(0); i < arrayLen; i++ {
val, err := readMetadataValue(r, arrayType)
diff --git a/sdk/kronk/gguf/reader_fuzz_test.go b/sdk/kronk/gguf/reader_fuzz_test.go
new file mode 100644
index 000000000..4146f854e
--- /dev/null
+++ b/sdk/kronk/gguf/reader_fuzz_test.go
@@ -0,0 +1,13 @@
+package gguf
+
+import "testing"
+
+func FuzzParsers(f *testing.F) {
+ f.Add([]byte{})
+ f.Add([]byte{'G', 'G', 'U', 'F'})
+
+ f.Fuzz(func(t *testing.T, data []byte) {
+ _, _ = ParseMetadata(data)
+ _, _, _ = ParseHeaderAndTensors(data, int64(len(data)))
+ })
+}
diff --git a/sdk/kronk/gguf/reader_test.go b/sdk/kronk/gguf/reader_test.go
new file mode 100644
index 000000000..6b1c37476
--- /dev/null
+++ b/sdk/kronk/gguf/reader_test.go
@@ -0,0 +1,25 @@
+package gguf
+
+import (
+ "bytes"
+ "encoding/binary"
+ "strings"
+ "testing"
+)
+
+func TestParseMetadataRejectsTruncatedMetadata(t *testing.T) {
+ var data bytes.Buffer
+ header := Header{
+ Magic: Magic,
+ Version: Version,
+ MetadataKvCount: 1,
+ }
+ if err := binary.Write(&data, binary.LittleEndian, header); err != nil {
+ t.Fatalf("write header: %v", err)
+ }
+
+ metadata, err := ParseMetadata(data.Bytes())
+ if err == nil || !strings.Contains(err.Error(), "read metadata entry 0") {
+ t.Fatalf("ParseMetadata: got metadata %v and error %v, want truncated metadata error", metadata, err)
+ }
+}
diff --git a/sdk/kronk/gguf/tensors.go b/sdk/kronk/gguf/tensors.go
index 7c410e3f9..e68e83e57 100644
--- a/sdk/kronk/gguf/tensors.go
+++ b/sdk/kronk/gguf/tensors.go
@@ -130,6 +130,13 @@ func ParseHeaderAndTensors(data []byte, fileSize int64) (metadata map[string]str
// parseTensorTable reads tensor descriptors from a bytes.Reader positioned
// at the start of the tensor table.
func parseTensorTable(r *bytes.Reader, tensorCount uint64) ([]TensorInfo, error) {
+ // Even an empty-name, zero-dimension descriptor consumes 24 bytes: name
+ // length, dimension count, type, and offset. Validate before using the
+ // untrusted count as a slice capacity.
+ if tensorCount > uint64(r.Len()/24) {
+ return nil, fmt.Errorf("parse-tensor-table: tensor count %d exceeds remaining bytes %d", tensorCount, r.Len())
+ }
+
tensors := make([]TensorInfo, 0, tensorCount)
for i := range tensorCount {
@@ -152,6 +159,12 @@ func parseTensorTable(r *bytes.Reader, tensorCount uint64) ([]TensorInfo, error)
return nil, fmt.Errorf("parse-tensor-table: reading n_dims for tensor %d: %w", i, err)
}
+ // Each dimension consumes eight bytes. The later type and offset reads
+ // provide the final structural validation.
+ if uint64(nDims) > uint64(r.Len()/8) {
+ return nil, fmt.Errorf("parse-tensor-table: dimension count %d for tensor %d exceeds remaining bytes %d", nDims, i, r.Len())
+ }
+
dims := make([]int64, nDims)
for d := uint32(0); d < nDims; d++ {
var dim uint64
diff --git a/sdk/kronk/gguf/tensors_test.go b/sdk/kronk/gguf/tensors_test.go
index fa2f66136..c7a505923 100644
--- a/sdk/kronk/gguf/tensors_test.go
+++ b/sdk/kronk/gguf/tensors_test.go
@@ -1,6 +1,51 @@
package gguf
-import "testing"
+import (
+ "bytes"
+ "encoding/binary"
+ "math"
+ "strings"
+ "testing"
+)
+
+func TestReadMetadataValueRejectsImpossibleArrayLength(t *testing.T) {
+ var data bytes.Buffer
+ if err := binary.Write(&data, binary.LittleEndian, uint32(MetadataValueTypeUInt8)); err != nil {
+ t.Fatalf("write array type: %v", err)
+ }
+ if err := binary.Write(&data, binary.LittleEndian, uint64(math.MaxUint64)); err != nil {
+ t.Fatalf("write array length: %v", err)
+ }
+
+ _, err := readMetadataValue(bytes.NewReader(data.Bytes()), MetadataValueTypeArray)
+ if err == nil || !strings.Contains(err.Error(), "array length") {
+ t.Fatalf("readMetadataValue: got %v, want array length error", err)
+ }
+}
+
+func TestParseTensorTableRejectsImpossibleCounts(t *testing.T) {
+ t.Run("tensor count", func(t *testing.T) {
+ _, err := parseTensorTable(bytes.NewReader(nil), math.MaxUint64)
+ if err == nil || !strings.Contains(err.Error(), "tensor count") {
+ t.Fatalf("parseTensorTable: got %v, want tensor count error", err)
+ }
+ })
+
+ t.Run("dimension count", func(t *testing.T) {
+ var data bytes.Buffer
+ for _, value := range []any{uint64(0), uint32(math.MaxUint32)} {
+ if err := binary.Write(&data, binary.LittleEndian, value); err != nil {
+ t.Fatalf("write descriptor: %v", err)
+ }
+ }
+ data.Write(make([]byte, 12))
+
+ _, err := parseTensorTable(bytes.NewReader(data.Bytes()), 1)
+ if err == nil || !strings.Contains(err.Error(), "dimension count") {
+ t.Fatalf("parseTensorTable: got %v, want dimension count error", err)
+ }
+ })
+}
func TestGGMLTypeSizes(t *testing.T) {
tests := []struct {
diff --git a/sdk/kronk/hf/client.go b/sdk/kronk/hf/client.go
index f1ca5804c..4392b9bd7 100644
--- a/sdk/kronk/hf/client.go
+++ b/sdk/kronk/hf/client.go
@@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"fmt"
+ "io"
"net/http"
"net/url"
"os"
@@ -144,14 +145,14 @@ func (c *DefaultClient) httpClient() *http.Client {
return c.HTTP
}
-// do issues a GET request, attaching KRONK_HF_TOKEN when set, and maps
-// HTTP error codes to the resolver's typed errors.
+// do issues a GET request, attaching KRONK_HF_TOKEN to Hugging Face URLs
+// when set, and maps HTTP error codes to the resolver's typed errors.
func (c *DefaultClient) do(ctx context.Context, u string) ([]byte, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil)
if err != nil {
return nil, fmt.Errorf("hf-request: build: %w", err)
}
- if tok := os.Getenv("KRONK_HF_TOKEN"); tok != "" {
+ if tok := os.Getenv("KRONK_HF_TOKEN"); tok != "" && IsHuggingFaceURL(u) {
req.Header.Set("Authorization", "Bearer "+tok)
}
@@ -177,16 +178,9 @@ func (c *DefaultClient) do(ctx context.Context, u string) ([]byte, error) {
return nil, fmt.Errorf("hf-request: unexpected status %d for %s", resp.StatusCode, u)
}
- body := make([]byte, 0, 4096)
- buf := make([]byte, 4096)
- for {
- n, rerr := resp.Body.Read(buf)
- if n > 0 {
- body = append(body, buf[:n]...)
- }
- if rerr != nil {
- break
- }
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return nil, fmt.Errorf("hf-request: read body: %w", err)
}
return body, nil
diff --git a/sdk/kronk/hf/client_test.go b/sdk/kronk/hf/client_test.go
new file mode 100644
index 000000000..51f93dbfd
--- /dev/null
+++ b/sdk/kronk/hf/client_test.go
@@ -0,0 +1,47 @@
+package hf
+
+import (
+ "context"
+ "errors"
+ "io"
+ "net/http"
+ "strings"
+ "testing"
+)
+
+type roundTripFunc func(*http.Request) (*http.Response, error)
+
+func (fn roundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) {
+ return fn(req)
+}
+
+type failingReader struct {
+ read bool
+}
+
+func (fr *failingReader) Read(p []byte) (int, error) {
+ if fr.read {
+ return 0, errors.New("connection reset")
+ }
+
+ fr.read = true
+ return copy(p, "partial"), nil
+}
+
+func TestDefaultClientDoReturnsBodyReadError(t *testing.T) {
+ c := DefaultClient{
+ HTTP: &http.Client{
+ Transport: roundTripFunc(func(*http.Request) (*http.Response, error) {
+ return &http.Response{
+ StatusCode: http.StatusOK,
+ Body: io.NopCloser(&failingReader{}),
+ }, nil
+ }),
+ },
+ }
+
+ _, err := c.do(context.Background(), "https://huggingface.co/api/models/owner/repo")
+ if err == nil || !strings.Contains(err.Error(), "connection reset") {
+ t.Fatalf("do: got %v, want connection reset error", err)
+ }
+}
diff --git a/sdk/kronk/hf/hf.go b/sdk/kronk/hf/hf.go
index 824996c25..cf0811c65 100644
--- a/sdk/kronk/hf/hf.go
+++ b/sdk/kronk/hf/hf.go
@@ -74,29 +74,14 @@ type treeEntry struct {
// repository. When recursive is true the full repo tree is fetched; otherwise
// only the immediate contents of path are listed.
func RepoFiles(ctx context.Context, owner, repo, revision, path string, recursive bool) ([]RepoFile, error) {
- if revision == "" {
- revision = "main"
- }
-
- var apiURL string
- switch {
- case recursive:
- apiURL = fmt.Sprintf("https://huggingface.co/api/models/%s/%s/tree/%s?recursive=true",
- url.PathEscape(owner), url.PathEscape(repo), url.PathEscape(revision))
- case path != "":
- apiURL = fmt.Sprintf("https://huggingface.co/api/models/%s/%s/tree/main/%s",
- url.PathEscape(owner), url.PathEscape(repo), path)
- default:
- apiURL = fmt.Sprintf("https://huggingface.co/api/models/%s/%s/tree/%s",
- url.PathEscape(owner), url.PathEscape(repo), url.PathEscape(revision))
- }
+ apiURL := repoFilesURL(owner, repo, revision, path, recursive)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, apiURL, nil)
if err != nil {
return nil, fmt.Errorf("repo-files: creating request: %w", err)
}
- if token := os.Getenv("KRONK_HF_TOKEN"); token != "" {
+ if token := os.Getenv("KRONK_HF_TOKEN"); token != "" && IsHuggingFaceURL(apiURL) {
req.Header.Set("Authorization", "Bearer "+token)
}
@@ -136,6 +121,27 @@ func RepoFiles(ctx context.Context, owner, repo, revision, path string, recursiv
return files, nil
}
+func repoFilesURL(owner, repo, revision, path string, recursive bool) string {
+ if revision == "" {
+ revision = "main"
+ }
+
+ apiURL := fmt.Sprintf("https://huggingface.co/api/models/%s/%s/tree/%s",
+ url.PathEscape(owner), url.PathEscape(repo), url.PathEscape(revision))
+ if path != "" && !recursive {
+ parts := strings.Split(strings.Trim(path, "/"), "/")
+ for i := range parts {
+ parts[i] = url.PathEscape(parts[i])
+ }
+ apiURL += "/" + strings.Join(parts, "/")
+ }
+ if recursive {
+ apiURL += "?recursive=true"
+ }
+
+ return apiURL
+}
+
// FormatFileSize formats a byte count into a human-readable string using
// SI units (KB, MB, GB).
func FormatFileSize(bytes int64) string {
diff --git a/sdk/kronk/hf/hf_test.go b/sdk/kronk/hf/hf_test.go
new file mode 100644
index 000000000..812011bd8
--- /dev/null
+++ b/sdk/kronk/hf/hf_test.go
@@ -0,0 +1,19 @@
+package hf
+
+import "testing"
+
+func TestRepoFilesURLPreservesRevisionWithPath(t *testing.T) {
+ got := repoFilesURL("owner", "repo", "feature/revision", "quantized/Q4 K", false)
+ want := "https://huggingface.co/api/models/owner/repo/tree/feature%2Frevision/quantized/Q4%20K"
+ if got != want {
+ t.Errorf("repoFilesURL: got %q, want %q", got, want)
+ }
+}
+
+func TestRepoFilesURLRecursiveIgnoresPath(t *testing.T) {
+ got := repoFilesURL("owner", "repo", "branch", "ignored/path", true)
+ want := "https://huggingface.co/api/models/owner/repo/tree/branch?recursive=true"
+ if got != want {
+ t.Errorf("repoFilesURL: got %q, want %q", got, want)
+ }
+}
diff --git a/sdk/kronk/hf/url.go b/sdk/kronk/hf/url.go
index 86b7f6c10..918c55614 100644
--- a/sdk/kronk/hf/url.go
+++ b/sdk/kronk/hf/url.go
@@ -70,6 +70,19 @@ func StripHostPrefix(s string) string {
return s
}
+// IsHuggingFaceURL reports whether rawURL is an HTTPS URL hosted by
+// Hugging Face. Callers use this check before attaching Hugging Face
+// credentials to an outbound request.
+func IsHuggingFaceURL(rawURL string) bool {
+ u, err := url.Parse(rawURL)
+ if err != nil || !strings.EqualFold(u.Scheme, "https") {
+ return false
+ }
+
+ host := u.Hostname()
+ return strings.EqualFold(host, "huggingface.co") || strings.EqualFold(host, "hf.co")
+}
+
// BuildURL composes a HuggingFace resolve URL.
func BuildURL(owner, repo, revision, file string) string {
if revision == "" {
diff --git a/sdk/kronk/hf/url_test.go b/sdk/kronk/hf/url_test.go
index cd40b7e8c..682ed5457 100644
--- a/sdk/kronk/hf/url_test.go
+++ b/sdk/kronk/hf/url_test.go
@@ -34,3 +34,28 @@ func TestNormalizeDownloadURL(t *testing.T) {
})
}
}
+
+func TestIsHuggingFaceURL(t *testing.T) {
+ tests := []struct {
+ name string
+ url string
+ want bool
+ }{
+ {name: "hugging face", url: "https://huggingface.co/owner/repo/resolve/main/model.gguf", want: true},
+ {name: "short host", url: "https://hf.co/owner/repo", want: true},
+ {name: "case and port", url: "HTTPS://HUGGINGFACE.CO:443/owner/repo", want: true},
+ {name: "plaintext", url: "http://huggingface.co/owner/repo"},
+ {name: "host suffix", url: "https://huggingface.co.example.com/owner/repo"},
+ {name: "userinfo", url: "https://huggingface.co@example.com/owner/repo"},
+ {name: "unrelated", url: "https://example.com/model.gguf"},
+ {name: "relative", url: "owner/repo/model.gguf"},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ if got := IsHuggingFaceURL(tt.url); got != tt.want {
+ t.Errorf("IsHuggingFaceURL(%q): got %t, want %t", tt.url, got, tt.want)
+ }
+ })
+ }
+}
diff --git a/sdk/kronk/init.go b/sdk/kronk/init.go
index 6835aeba0..9ff4e3735 100644
--- a/sdk/kronk/init.go
+++ b/sdk/kronk/init.go
@@ -18,9 +18,8 @@ import (
)
var (
- libraryLocation string
- initMu sync.Mutex
- initDone bool
+ initMu sync.Mutex
+ initDone bool
)
type initOptions struct {
@@ -145,8 +144,6 @@ func Init(opts ...InitOption) error {
mtmd.LogSet(llama.LogNormal)
}
- libraryLocation = libPath
-
// Inline of llama.Init so we can gate GGMLBackendLoadAllFromPath on
// the registry being empty. If bucky/whisper was initialized first
// from a sibling lib directory, its libggml-*.{so,dylib,dll} files
diff --git a/sdk/kronk/jsonrepair/jsonrepair.go b/sdk/kronk/jsonrepair/jsonrepair.go
index d46018e10..2abec42b7 100644
--- a/sdk/kronk/jsonrepair/jsonrepair.go
+++ b/sdk/kronk/jsonrepair/jsonrepair.go
@@ -33,10 +33,11 @@ const gemmaToken = "<|\"|>"
// 1. Quick-check: try json.Unmarshal; if valid, return immediately.
// 2. Normalize Gemma4 <|"|> tokens to standard quotes (escaping inner ").
// 3. Normalize backtick delimiters in structural positions to standard quotes.
-// 4. Quote bare JSON keys.
+// 4. Apply structural fixups.
// 5. Re-check: if valid after normalization, return.
// 6. Key-aware repair: walk the JSON structure, find true closing quotes
-// by scanning right-to-left for " followed by } / ] / ,"key": patterns.
+// by scanning right-to-left for " followed by } / ] / ,"key": patterns,
+// then quote bare keys after value boundaries are unambiguous.
// 7. Verify the result with json.Unmarshal.
// 8. If verification fails, try trimming a trailing extra } (Gemma double-brace).
func Repair(s string) (string, error) {
@@ -59,6 +60,7 @@ func Repair(s string) (string, error) {
// Step 6: key-aware repair of unescaped quotes in values.
repaired := repairQuotes(normalized)
+ repaired = quoteBareKeys(repaired)
// Step 7: verify. If the result has a trailing extra } from Gemma's
// double-brace wrapping (call:write{{...}}), try trimming it.
@@ -89,15 +91,13 @@ func Unmarshal(s string, v any) error {
// Normalization
// =============================================================================
-// normalize applies all pre-repair transformations: Gemma <|"|> replacement,
-// backtick delimiter normalization, and bare key quoting. The second return
-// value reports whether any transformation changed the string.
+// normalize applies all pre-repair transformations. The second return value
+// reports whether any transformation changed the string.
func normalize(s string) (string, bool) {
orig := s
s = normalizeGemmaQuotes(s)
s = flattenNestedObject(s)
s = normalizeBacktickDelimiters(s)
- s = quoteBareKeys(s)
s = fixMissingKeyCloseQuote(s)
s = normalizeBackslashControlChars(s)
return s, s != orig
@@ -830,10 +830,20 @@ func quoteBareKeys(s string) string {
continue
}
- // Outside a string: check if this is the start of a bare key.
- // A bare key follows { , [ or is at the start, and is a word
- // followed by a colon.
- if c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_' {
+ // Outside a string: check if this is the start of a bare object key.
+ // Requiring an object-key boundary prevents identifier-like text in
+ // a malformed quoted value from being rewritten before repairQuotes
+ // has restored that value's escaped quotes.
+ keyPosition := true
+ for j := i - 1; j >= 0; j-- {
+ if isWhitespace(s[j]) {
+ continue
+ }
+ keyPosition = s[j] == '{' || s[j] == ','
+ break
+ }
+
+ if keyPosition && (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_') {
// Look ahead to find the colon.
j := i + 1
for j < len(s) && (s[j] >= 'a' && s[j] <= 'z' || s[j] >= 'A' && s[j] <= 'Z' || s[j] >= '0' && s[j] <= '9' || s[j] == '_') {
diff --git a/sdk/kronk/jsonrepair/jsonrepair_test.go b/sdk/kronk/jsonrepair/jsonrepair_test.go
index d70b138da..83c1ec507 100644
--- a/sdk/kronk/jsonrepair/jsonrepair_test.go
+++ b/sdk/kronk/jsonrepair/jsonrepair_test.go
@@ -190,6 +190,11 @@ func TestRepair(t *testing.T) {
input: `{"content":"a "b" c "d" e","filePath":"x.go"}`,
keys: map[string]string{"filePath": "x.go"},
},
+ {
+ name: "identifier colon inside malformed quoted value",
+ input: `{"content":"say "identifier: value" now"}`,
+ wantExact: map[string]string{"content": `say "identifier: value" now`},
+ },
{
name: "bare keys and unescaped quotes",
input: `{content:"say "hello" world",filePath:"test.go"}`,
diff --git a/sdk/kronk/kronk.go b/sdk/kronk/kronk.go
index db59a0882..905df801d 100644
--- a/sdk/kronk/kronk.go
+++ b/sdk/kronk/kronk.go
@@ -41,7 +41,7 @@ func New(opts ...model.Option) (*Kronk, error) {
// NewWithContext provides the ability to use models in a concurrently safe way.
// The context is used to support logging trace ids during model loading.
func NewWithContext(ctx context.Context, opts ...model.Option) (*Kronk, error) {
- if libraryLocation == "" {
+ if !Initialized() {
return nil, fmt.Errorf("new: the Init() function has not been called")
}
diff --git a/sdk/kronk/model/batchgen_finish.go b/sdk/kronk/model/batchgen_finish.go
index 280c2bb09..aecf63f0d 100644
--- a/sdk/kronk/model/batchgen_finish.go
+++ b/sdk/kronk/model/batchgen_finish.go
@@ -293,6 +293,19 @@ func (e *batchEngine) finishSlot(s *slot, err error) {
if outcome.err != nil {
outputTokens := s.reasonTokens + s.completionTokens
usage := Usage{PromptTokens: s.nPrompt, CompletionTokens: outputTokens, TotalTokens: s.nPrompt + outputTokens}
+ status := "error"
+ class := "stop-gate-flush"
+ if errors.Is(outcome.err, context.Canceled) || errors.Is(outcome.err, context.DeadlineExceeded) || ctx.Err() != nil {
+ status = "cancel"
+ class = "context-cancelled"
+ }
+ s.span.RecordError(outcome.err)
+ s.span.SetAttributes(attribute.String("request_status", status))
+ metrics.AddChatRequest(e.model.modelInfo.ID, status)
+ metrics.AddChatError(e.model.modelInfo.ID, class)
+ if !s.job.requestStart.IsZero() {
+ metrics.ObserveChatRequestDuration(e.model.modelInfo.ID, time.Since(s.job.requestStart))
+ }
e.model.sendErrorResponse(ctx, s.job.ch, s.job.id, s.job.object, 0, outcome.err, usage)
return
}
diff --git a/sdk/kronk/model/batchgen_speculative_test.go b/sdk/kronk/model/batchgen_speculative_test.go
index 13cfedd26..955895cd6 100644
--- a/sdk/kronk/model/batchgen_speculative_test.go
+++ b/sdk/kronk/model/batchgen_speculative_test.go
@@ -6,6 +6,8 @@ import (
"testing"
"time"
+ "github.com/ardanlabs/kronk/sdk/kronk/applog"
+ "github.com/ardanlabs/kronk/sdk/kronk/model/internal/speculation"
classicengine "github.com/ardanlabs/kronk/sdk/kronk/model/internal/speculation/classic"
mtpengine "github.com/ardanlabs/kronk/sdk/kronk/model/internal/speculation/mtp"
"github.com/hybridgroup/yzma/pkg/llama"
@@ -75,6 +77,53 @@ func TestNeedsTargetSpecSnapshot(t *testing.T) {
}
}
+func TestClassicSpeculationSupportsOnlyRepresentedSamplingControls(t *testing.T) {
+ tests := []struct {
+ name string
+ params Params
+ want bool
+ }{
+ {name: "ordinary sampling", params: Params{RepeatPenalty: DefRepeatPenalty}, want: true},
+ {name: "grammar", params: Params{RepeatPenalty: DefRepeatPenalty, Grammar: `root ::= "ok"`}},
+ {name: "repeat penalty", params: Params{RepeatPenalty: 1.1}},
+ {name: "frequency penalty", params: Params{RepeatPenalty: DefRepeatPenalty, FrequencyPenalty: 0.2}},
+ {name: "presence penalty", params: Params{RepeatPenalty: DefRepeatPenalty, PresencePenalty: 0.2}},
+ {name: "DRY", params: Params{RepeatPenalty: DefRepeatPenalty, DryMultiplier: 1.0}},
+ {name: "XTC", params: Params{RepeatPenalty: DefRepeatPenalty, XtcProbability: 0.5}},
+ {name: "adaptive P", params: Params{RepeatPenalty: DefRepeatPenalty, AdaptivePTarget: 0.9}},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ if got := classicSpeculationSupports(tt.params); got != tt.want {
+ t.Errorf("classicSpeculationSupports() = %t, want %t", got, tt.want)
+ }
+ })
+ }
+}
+
+func TestCommitSpeculativeReturnsRequiredSnapshotFailure(t *testing.T) {
+ s := &slot{
+ seqID: 7,
+ job: &chatJob{ctx: t.Context()},
+ }
+ e := batchEngine{
+ model: &Model{
+ log: applog.DiscardLogger,
+ modelInfo: ModelInfo{Type: ModelTypeHybrid},
+ },
+ slots: []*slot{s},
+ }
+
+ err := e.CommitSpeculative(0, []llama.Token{1}, speculation.TargetRange{})
+ if err == nil {
+ t.Fatal("CommitSpeculative() error = nil, want snapshot failure")
+ }
+ if len(s.specSnapshot) != 0 {
+ t.Errorf("snapshot length: got %d, want 0", len(s.specSnapshot))
+ }
+}
+
func TestMaxDraftForSlot(t *testing.T) {
e := batchEngine{model: &Model{cfg: Config{PtrContextWindow: new(10)}}}
diff --git a/sdk/kronk/model/caching.go b/sdk/kronk/model/caching.go
index 0e1a7d578..5f23523c0 100644
--- a/sdk/kronk/model/caching.go
+++ b/sdk/kronk/model/caching.go
@@ -3,10 +3,10 @@ package model
import (
"context"
"crypto/sha256"
+ "encoding/binary"
"encoding/hex"
"encoding/json"
"errors"
- "fmt"
"strings"
"github.com/hybridgroup/yzma/pkg/llama"
@@ -114,25 +114,40 @@ func (m *Model) clearCaches(ctx context.Context) error {
// message produced by normalizeMediaMessages / toMediaMessage)
func hashMessages(messages []D) string {
h := sha256.New()
+ var frame [8]byte
+ writeUint64 := func(value uint64) {
+ binary.LittleEndian.PutUint64(frame[:], value)
+ h.Write(frame[:])
+ }
+ writeBytes := func(data []byte) {
+ writeUint64(uint64(len(data)))
+ h.Write(data)
+ }
- for i, msg := range messages {
+ writeUint64(uint64(len(messages)))
+
+ for _, msg := range messages {
role, _ := msg["role"].(string)
content := extractMessageContent(msg)
- fmt.Fprintf(h, "%d:%s:%s|", i, role, content)
+ writeBytes([]byte(role))
+ writeBytes([]byte(content))
+ var media [][]byte
switch c := msg["content"].(type) {
case []byte:
- fmt.Fprintf(h, "media:%d:", len(c))
- h.Write(c)
+ media = append(media, c)
case []any:
for _, part := range c {
if b, ok := part.([]byte); ok {
- fmt.Fprintf(h, "media:%d:", len(b))
- h.Write(b)
+ media = append(media, b)
}
}
}
+ writeUint64(uint64(len(media)))
+ for _, data := range media {
+ writeBytes(data)
+ }
}
return hex.EncodeToString(h.Sum(nil))
diff --git a/sdk/kronk/model/caching_test.go b/sdk/kronk/model/caching_test.go
index 0a2802ca3..d052f5f88 100644
--- a/sdk/kronk/model/caching_test.go
+++ b/sdk/kronk/model/caching_test.go
@@ -69,6 +69,12 @@ func TestHashMessages(t *testing.T) {
msgs2: []D{{"role": "user", "content": "Hello"}, {"role": "assistant", "content": "Hi"}},
wantSame: false,
},
+ {
+ name: "delimiter content cannot impersonate another message",
+ msgs1: []D{{"role": "user", "content": "x|1:assistant:y"}},
+ msgs2: []D{{"role": "user", "content": "x"}, {"role": "assistant", "content": "y"}},
+ wantSame: false,
+ },
}
for _, tt := range tests {
diff --git a/sdk/kronk/model/chat.go b/sdk/kronk/model/chat.go
index 52c4054f2..f141aa516 100644
--- a/sdk/kronk/model/chat.go
+++ b/sdk/kronk/model/chat.go
@@ -277,16 +277,31 @@ func (m *Model) wrapChannelForLogging(ctx context.Context, returnCh chan ChatRes
go func() {
var srl StreamingResponseLogger
+ canceled := false
for resp := range ch {
srl.Capture(resp)
+ if canceled {
+ if len(resp.Choices) > 0 && resp.Choices[0].FinishReason() != "" {
+ select {
+ case returnCh <- resp:
+ default:
+ }
+ }
+ continue
+ }
+
select {
case returnCh <- resp:
case <-ctx.Done():
- m.log(ctx, "chat-streaming", "OUT-MESSAGES", srl.String())
- close(returnCh)
- return
+ canceled = true
+ if len(resp.Choices) > 0 && resp.Choices[0].FinishReason() != "" {
+ select {
+ case returnCh <- resp:
+ default:
+ }
+ }
}
}
diff --git a/sdk/kronk/model/chat_test.go b/sdk/kronk/model/chat_test.go
index 74097f451..56487f4e6 100644
--- a/sdk/kronk/model/chat_test.go
+++ b/sdk/kronk/model/chat_test.go
@@ -382,6 +382,7 @@ func TestChatPreservesValidationError(t *testing.T) {
{name: "invalid float parameter", field: "temperature", value: D{"invalid": true}},
{name: "invalid integer parameter", field: "max_tokens", value: D{"invalid": true}},
{name: "invalid boolean parameter", field: "logprobs", value: "invalid"},
+ {name: "numeric boolean parameter", field: "stream", value: 0},
{name: "invalid reasoning parameter type", field: "reasoning_effort", value: 1},
{name: "unsupported choice count", field: "n", value: 4},
}
@@ -1325,6 +1326,33 @@ func TestSendFinalResponseReturnsCancellation(t *testing.T) {
}
}
+func TestLoggingWrapperDrainsAndPreservesTerminalResponseAfterCancellation(t *testing.T) {
+ ctx, cancel := context.WithCancel(t.Context())
+ cancel()
+
+ insecureLogging := true
+ m := Model{
+ cfg: Config{PtrInsecureLogging: &insecureLogging},
+ log: applog.DiscardLogger,
+ }
+ returnCh := make(chan ChatResponse, streamChBuffer)
+ producerCh := m.wrapChannelForLogging(ctx, returnCh)
+ producerCh <- chatResponseDelta("id", ObjectChatText, "model", 0, "ignored", false, nil)
+ terminal := chatResponseFinal("id", ObjectChatText, "model", 0, "done", "", nil, nil, FinishReasonStop, false, Usage{})
+ producerCh <- terminal
+ close(producerCh)
+
+ var gotTerminal bool
+ for resp := range returnCh {
+ if len(resp.Choices) > 0 && resp.Choices[0].FinishReason() == FinishReasonStop {
+ gotTerminal = true
+ }
+ }
+ if !gotTerminal {
+ t.Fatal("terminal response was dropped after cancellation")
+ }
+}
+
func TestUsageCachedTokensJSON(t *testing.T) {
tests := []struct {
name string
diff --git a/sdk/kronk/model/config.go b/sdk/kronk/model/config.go
index 3c9befba5..1e0e0ea0d 100644
--- a/sdk/kronk/model/config.go
+++ b/sdk/kronk/model/config.go
@@ -225,6 +225,9 @@ type AdapterConfig struct {
// JinjaFile is the path to the jinja file. This is not required and can be
// used if you want to override the templated provided by the model metadata.
//
+// JinjaScript is an in-memory jinja template override. It takes precedence
+// over JinjaFile and is intended for request-scoped model configurations.
+//
// LoadMode controls how model weights are loaded. The default is LoadModeAuto,
// which uses mmap when every selected device supports it and otherwise uses
// ordinary loading. LoadModeNone disables mmap, which can improve tensor
@@ -283,9 +286,6 @@ type AdapterConfig struct {
// (GPU). When nil or true, operations are offloaded (default behavior). Set to
// false to keep operations on the CPU.
//
-// OpOffloadMinBatch sets the minimum batch size at which host tensor operations
-// are offloaded to the device. When unset or 0, llama.cpp's default is used.
-//
// ProjFile is the path to the projection files. This is mandatory for media
// based models like vision and audio.
//
@@ -405,6 +405,7 @@ type Config struct {
PtrIncrementalCache *bool
PtrInsecureLogging *bool
JinjaFile string
+ JinjaScript string
LoadMode LoadMode
Log applog.Logger
PtrMainGPU *int
@@ -418,7 +419,6 @@ type Config struct {
NUMA string
PtrOffloadKQV *bool
PtrOpOffload *bool
- PtrOpOffloadMinBatch *int
ProjFile string
MTPDrafterFile string
PtrProjOnCPU *bool
@@ -466,7 +466,6 @@ func (cfg Config) NSeqMax() int { return intOr(cfg.PtrNSeqMax, 0) }
func (cfg Config) NThreads() int { return intOr(cfg.PtrNThreads, 0) }
func (cfg Config) NThreadsBatch() int { return intOr(cfg.PtrNThreadsBatch, 0) }
func (cfg Config) CacheMinTokens() int { return intOr(cfg.PtrCacheMinTokens, 0) }
-func (cfg Config) OpOffloadMinBatch() int { return intOr(cfg.PtrOpOffloadMinBatch, 0) }
func (cfg Config) MainGPU() int { return intOr(cfg.PtrMainGPU, 0) }
func (cfg Config) NGpuLayers() int { return intOr(cfg.PtrNGpuLayers, 0) }
func (cfg Config) RopeFreqBase() float32 { return float32Or(cfg.PtrRopeFreqBase, 0) }
@@ -546,14 +545,14 @@ func (cfg Config) String() string {
return fmt.Sprintf("{mode:%s top_n:%s}", m.Mode, topN)
}
- return fmt.Sprintf("\nAdapters[%v]\nAdmissionTimeout[%s]\nAutoTune[%t]\nCacheMinTokens[%s]\nCacheTypeK[%s]\nCacheTypeV[%s]\nContextWindow[%s]\nDefaultParams[%s]\nDecisionProtocol[%s]\nChatTemplateKwargs[%s]\nDevices[%v]\nFlashAttention[%s]\nIMCSessionCapacity[%d]\nIncrementalCache[%s]\nInsecureLogging[%s]\nJinjaFile[%s]\nLoadMode[%s]\nMainGPU[%s]\nMoE[%s]\nModelFiles[%v]\nNGpuLayers[%s]\nNSeqMax[%s]\nNThreads[%s]\nNThreadsBatch[%s]\nPrefillBatchSize[%s]\nEffectiveNBatch[%d]\nEffectiveNUBatch[%d]\nNUMA[%s]\nOffloadKQV[%s]\nOpOffload[%s]\nOpOffloadMinBatch[%s]\nProjFile[%s]\nMTPDrafterFile[%s]\nProjOnCPU[%s]\nProjDevice[%s]\nQueueDepth[%d]\nRopeFreqBase[%s]\nRopeFreqScale[%s]\nRopeScaling[%s]\nSessionStoreFactory[%t]\nSpeculation[%s]\nSplitMode[%s]\nSWAFull[%s]\nTensorBuftOverrides[%v]\nTensorSplit[%v]\nYarnAttnFactor[%s]\nYarnBetaFast[%s]\nYarnBetaSlow[%s]\nYarnExtFactor[%s]\nYarnOrigCtx[%s]\nDraftModel[%v]\n",
+ return fmt.Sprintf("\nAdapters[%v]\nAdmissionTimeout[%s]\nAutoTune[%t]\nCacheMinTokens[%s]\nCacheTypeK[%s]\nCacheTypeV[%s]\nContextWindow[%s]\nDefaultParams[%s]\nDecisionProtocol[%s]\nChatTemplateKwargs[%s]\nDevices[%v]\nFlashAttention[%s]\nIMCSessionCapacity[%d]\nIncrementalCache[%s]\nInsecureLogging[%s]\nJinjaFile[%s]\nLoadMode[%s]\nMainGPU[%s]\nMoE[%s]\nModelFiles[%v]\nNGpuLayers[%s]\nNSeqMax[%s]\nNThreads[%s]\nNThreadsBatch[%s]\nPrefillBatchSize[%s]\nEffectiveNBatch[%d]\nEffectiveNUBatch[%d]\nNUMA[%s]\nOffloadKQV[%s]\nOpOffload[%s]\nProjFile[%s]\nMTPDrafterFile[%s]\nProjOnCPU[%s]\nProjDevice[%s]\nQueueDepth[%d]\nRopeFreqBase[%s]\nRopeFreqScale[%s]\nRopeScaling[%s]\nSessionStoreFactory[%t]\nSpeculation[%s]\nSplitMode[%s]\nSWAFull[%s]\nTensorBuftOverrides[%v]\nTensorSplit[%v]\nYarnAttnFactor[%s]\nYarnBetaFast[%s]\nYarnBetaSlow[%s]\nYarnExtFactor[%s]\nYarnOrigCtx[%s]\nDraftModel[%v]\n",
cfg.Adapters, formatDurationPtr(cfg.PtrAdmissionTimeout), cfg.AutoTune, formatIntPtr(cfg.PtrCacheMinTokens), cfg.CacheTypeK, cfg.CacheTypeV,
formatIntPtr(cfg.PtrContextWindow), cfg.DefaultParams.String(), cfg.DecisionProtocol, chatTemplateKwargsSummary(cfg.ChatTemplateKwargs), cfg.Devices, cfg.FlashAttention(),
cfg.IMCSessionCapacity(), formatBoolPtr(cfg.PtrIncrementalCache), formatBoolPtr(cfg.PtrInsecureLogging), cfg.JinjaFile,
cfg.LoadMode, formatIntPtr(cfg.PtrMainGPU), formatMoEPtr(cfg.PtrMoE), cfg.ModelFiles,
formatIntPtr(cfg.PtrNGpuLayers), formatIntPtr(cfg.PtrNSeqMax), formatIntPtr(cfg.PtrNThreads), formatIntPtr(cfg.PtrNThreadsBatch), formatIntPtr(cfg.PtrPrefillBatchSize), cfg.EffectiveNBatch(), cfg.EffectiveNUBatch(),
cfg.NUMA,
- formatBoolPtr(cfg.PtrOffloadKQV), formatBoolPtr(cfg.PtrOpOffload), formatIntPtr(cfg.PtrOpOffloadMinBatch), cfg.ProjFile, cfg.MTPDrafterFile, formatBoolPtr(cfg.PtrProjOnCPU), cfg.ProjDevice, cfg.QueueDepth(),
+ formatBoolPtr(cfg.PtrOffloadKQV), formatBoolPtr(cfg.PtrOpOffload), cfg.ProjFile, cfg.MTPDrafterFile, formatBoolPtr(cfg.PtrProjOnCPU), cfg.ProjDevice, cfg.QueueDepth(),
formatFloat32Ptr(cfg.PtrRopeFreqBase), formatFloat32Ptr(cfg.PtrRopeFreqScale), cfg.RopeScaling,
cfg.SessionStoreFactory != nil, cfg.SpeculationMode(),
formatSplitModePtr(cfg.PtrSplitMode),
@@ -727,10 +726,6 @@ func validateConfig(ctx context.Context, cfg Config, log applog.Logger) error {
}
}
- if cfg.OpOffloadMinBatch() < 0 {
- return fmt.Errorf("validate-config: OpOffloadMinBatch must be >= 0, got %d", cfg.OpOffloadMinBatch())
- }
-
for _, modelFile := range cfg.ModelFiles {
log(ctx, "validate-config", "model-file", modelFile)
@@ -862,6 +857,8 @@ func adjustConfig(cfg Config, model llama.Model) Config {
}
if cfg.PtrDraftModel != nil && cfg.PtrDraftModel.NDraft <= 0 {
+ draft := *cfg.PtrDraftModel
+ cfg.PtrDraftModel = &draft
// Separate-GGUF drafts default to defNDraft; MTP nDraft overrides
// (no model files) default to defMTPNDraft.
if cfg.PtrDraftModel.IsSeparate() {
@@ -875,10 +872,6 @@ func adjustConfig(cfg Config, model llama.Model) Config {
if cfg.PtrInsecureLogging == nil {
cfg.PtrInsecureLogging = new(false)
}
- if cfg.PtrOpOffloadMinBatch == nil {
- cfg.PtrOpOffloadMinBatch = new(0)
- }
-
return cfg
}
@@ -1994,6 +1987,7 @@ func WithIMCSessionCapacity(v int) Option {
func WithIncrementalCache(v bool) Option { return func(c *Config) { c.PtrIncrementalCache = new(v) } }
func WithInsecureLogging(v bool) Option { return func(c *Config) { c.PtrInsecureLogging = new(v) } }
func WithJinjaFile(v string) Option { return func(c *Config) { c.JinjaFile = v } }
+func WithJinjaScript(v string) Option { return func(c *Config) { c.JinjaScript = v } }
func WithLoadMode(v LoadMode) Option { return func(c *Config) { c.LoadMode = v } }
func WithLog(v applog.Logger) Option { return func(c *Config) { c.Log = v } }
func WithMainGPU(v int) Option { return func(c *Config) { c.PtrMainGPU = new(v) } }
@@ -2007,7 +2001,6 @@ func WithPrefillBatchSize(v int) Option { return func(c *Config) { c.PtrP
func WithNUMA(v string) Option { return func(c *Config) { c.NUMA = v } }
func WithOffloadKQV(v bool) Option { return func(c *Config) { c.PtrOffloadKQV = new(v) } }
func WithOpOffload(v bool) Option { return func(c *Config) { c.PtrOpOffload = new(v) } }
-func WithOpOffloadMinBatch(v int) Option { return func(c *Config) { c.PtrOpOffloadMinBatch = new(v) } }
func WithProjFile(v string) Option { return func(c *Config) { c.ProjFile = v } }
func WithMTPDrafterFile(v string) Option { return func(c *Config) { c.MTPDrafterFile = v } }
func WithProjOnCPU(v bool) Option { return func(c *Config) { c.PtrProjOnCPU = new(v) } }
diff --git a/sdk/kronk/model/config_test.go b/sdk/kronk/model/config_test.go
index 94eaf9782..d443b7b8a 100644
--- a/sdk/kronk/model/config_test.go
+++ b/sdk/kronk/model/config_test.go
@@ -419,6 +419,21 @@ func TestAdjustConfigUsesConfiguredPrefillBatchSize(t *testing.T) {
}
}
+func TestAdjustConfigDoesNotMutateDraftModelConfig(t *testing.T) {
+ draft := &DraftModelConfig{ModelFiles: []string{"draft.gguf"}}
+ cfg := adjustConfig(Config{PtrDraftModel: draft}, 0)
+
+ if draft.NDraft != 0 {
+ t.Errorf("caller draft NDraft: got %d, want 0", draft.NDraft)
+ }
+ if cfg.PtrDraftModel == draft {
+ t.Fatal("adjusted config retained caller-owned draft pointer")
+ }
+ if cfg.PtrDraftModel.NDraft != defNDraft {
+ t.Errorf("adjusted draft NDraft: got %d, want %d", cfg.PtrDraftModel.NDraft, defNDraft)
+ }
+}
+
func TestAdjustConfigUsesKronkThreadDefault(t *testing.T) {
defaultThreads := max(defNThreads, runtime.NumCPU())
tests := []struct {
diff --git a/sdk/kronk/model/decision_engine.go b/sdk/kronk/model/decision_engine.go
index 50006bca5..12488230a 100644
--- a/sdk/kronk/model/decision_engine.go
+++ b/sdk/kronk/model/decision_engine.go
@@ -167,34 +167,34 @@ type decisionPart struct {
readouts []decisionReadout
}
-func (e *decisionEngine) decode(parts ...decisionPart) ([][][]float32, error) {
+func (e *decisionEngine) decode(parts ...decisionPart) ([][][]float32, bool, error) {
var total int
for _, part := range parts {
total += len(part.tokens)
}
if total == 0 {
- return make([][][]float32, len(parts)), nil
+ return make([][][]float32, len(parts)), false, nil
}
indices, err := stageDecisionParts(e.batch, parts)
if err != nil {
- return nil, fmt.Errorf("decision stage batch: %w", err)
+ return nil, true, fmt.Errorf("decision stage batch: %w", err)
}
code, err := e.batch.process(llama.ProcessTypeDecode)
if err != nil {
- return nil, fmt.Errorf("decision process: %w", err)
+ return nil, true, fmt.Errorf("decision process: %w", err)
}
if code != 0 {
- return nil, fmt.Errorf("decision process returned %d", code)
+ return nil, code < 0, fmt.Errorf("decision process returned %d", code)
}
result := make([][][]float32, len(parts))
for partIndex, part := range parts {
if len(indices[partIndex]) != len(part.readouts) {
- return nil, fmt.Errorf("decision produced %d readout rows, want %d", len(indices[partIndex]), len(part.readouts))
+ return nil, true, fmt.Errorf("decision produced %d readout rows, want %d", len(indices[partIndex]), len(part.readouts))
}
result[partIndex] = make([][]float32, len(part.readouts))
@@ -202,11 +202,11 @@ func (e *decisionEngine) decode(parts ...decisionPart) ([][][]float32, error) {
for readoutIndex, batchIndex := range indices[partIndex] {
allLogits, err := llama.GetLogitsIth(e.lctx, batchIndex, e.nVocab)
if err != nil {
- return nil, fmt.Errorf("decision get logits at batch index %d: %w", batchIndex, err)
+ return nil, true, fmt.Errorf("decision get logits at batch index %d: %w", batchIndex, err)
}
if allLogits == nil {
- return nil, fmt.Errorf("decision has no logits at batch index %d", batchIndex)
+ return nil, true, fmt.Errorf("decision has no logits at batch index %d", batchIndex)
}
candidates := part.readouts[readoutIndex].candidates
@@ -218,7 +218,7 @@ func (e *decisionEngine) decode(parts ...decisionPart) ([][][]float32, error) {
}
}
- return result, nil
+ return result, false, nil
}
func stageDecisionParts(batch *extendedBatch, parts []decisionPart) ([][]int32, error) {
@@ -252,7 +252,7 @@ func stageDecisionParts(batch *extendedBatch, parts []decisionPart) ([][]int32,
return indices, nil
}
-func (e *decisionEngine) evaluate(entries []decisionScheduledEntry) ([][][]float32, error) {
+func (e *decisionEngine) evaluate(entries []decisionScheduledEntry) ([][][]float32, bool, error) {
parts := make([]decisionPart, len(entries))
for i, entry := range entries {
parts[i] = decisionPart{
@@ -262,16 +262,17 @@ func (e *decisionEngine) evaluate(entries []decisionScheduledEntry) ([][][]float
}
}
- outputs, err := e.decode(parts...)
+ outputs, fatal, err := e.decode(parts...)
if err != nil {
- return nil, errors.Join(err, e.clear())
+ clearErr := e.clear()
+ return nil, fatal || clearErr != nil, errors.Join(err, clearErr)
}
for i := range entries {
if _, err := llama.MemorySeqRm(e.mem, llama.SeqId(i), -1, -1); err != nil {
- return nil, errors.Join(fmt.Errorf("decision remove sequence %d: %w", i, err), e.clear())
+ return nil, true, errors.Join(fmt.Errorf("decision remove sequence %d: %w", i, err), e.clear())
}
}
- return outputs, nil
+ return outputs, false, nil
}
diff --git a/sdk/kronk/model/decision_openjev.go b/sdk/kronk/model/decision_openjev.go
index ef8380a84..0e429fb44 100644
--- a/sdk/kronk/model/decision_openjev.go
+++ b/sdk/kronk/model/decision_openjev.go
@@ -203,6 +203,9 @@ func (p *openJEVProtocol) work(ctx context.Context, state string, instructions s
if len(tokens) == 0 {
return decisionWork{}, fmt.Errorf("tokenize prompt: no tokens")
}
+ if len(tokens) > p.model.decision.contextWindow {
+ return decisionWork{}, fmt.Errorf("%w: input needs %d tokens, limit is %d", ErrDecisionBudget, len(tokens), p.model.decision.contextWindow)
+ }
candidates := append([]llama.Token(nil), p.letterTokens[:len(options)]...)
return decisionWork{
tokens: tokens,
diff --git a/sdk/kronk/model/decision_schedule_test.go b/sdk/kronk/model/decision_schedule_test.go
index 86d568a2b..09d88b0d8 100644
--- a/sdk/kronk/model/decision_schedule_test.go
+++ b/sdk/kronk/model/decision_schedule_test.go
@@ -73,13 +73,13 @@ func TestDecisionSchedulerCoalescesQueuedJobs(t *testing.T) {
scheduler := newDecisionScheduler(&engine, 1)
batchWidths := make(chan int, 1)
- scheduler.evaluate = func(entries []decisionScheduledEntry) ([][][]float32, error) {
+ scheduler.evaluate = func(entries []decisionScheduledEntry) ([][][]float32, bool, error) {
batchWidths <- len(entries)
outputs := make([][][]float32, len(entries))
for i, entry := range entries {
outputs[i] = make([][]float32, len(entry.work.readouts))
}
- return outputs, nil
+ return outputs, false, nil
}
jobs := []*decisionJob{
@@ -116,10 +116,10 @@ func TestDecisionSchedulerStopDrainsQueuedJobs(t *testing.T) {
evaluating := make(chan struct{})
release := make(chan struct{})
- scheduler.evaluate = func(entries []decisionScheduledEntry) ([][][]float32, error) {
+ scheduler.evaluate = func(entries []decisionScheduledEntry) ([][][]float32, bool, error) {
close(evaluating)
<-release
- return make([][][]float32, len(entries)), nil
+ return make([][][]float32, len(entries)), false, nil
}
first := newDecisionJob(context.Background(), []decisionWork{decisionTestWork(2, 1)})
@@ -149,6 +149,46 @@ func TestDecisionSchedulerStopDrainsQueuedJobs(t *testing.T) {
}
}
+func TestDecisionSchedulerContinuesAfterRecoverableEvaluationError(t *testing.T) {
+ engine := decisionEngine{
+ maxSequences: 1,
+ maxTokens: 100,
+ maxOutputs: 10,
+ }
+ scheduler := newDecisionScheduler(&engine, 2)
+
+ recoverableErr := errors.New("no KV slot")
+ evaluations := 0
+ scheduler.evaluate = func(entries []decisionScheduledEntry) ([][][]float32, bool, error) {
+ evaluations++
+ if evaluations == 1 {
+ return nil, false, recoverableErr
+ }
+ outputs := make([][][]float32, len(entries))
+ for i, entry := range entries {
+ outputs[i] = make([][]float32, len(entry.work.readouts))
+ }
+ return outputs, false, nil
+ }
+
+ first := newDecisionJob(context.Background(), []decisionWork{decisionTestWork(2, 1)})
+ second := newDecisionJob(context.Background(), []decisionWork{decisionTestWork(2, 1)})
+ scheduler.requestQ <- first
+ scheduler.requestQ <- second
+ scheduler.start()
+ t.Cleanup(scheduler.stop)
+
+ if result := <-first.resultCh; !errors.Is(result.err, recoverableErr) {
+ t.Fatalf("first job: got %v, want %v", result.err, recoverableErr)
+ }
+ if result := <-second.resultCh; result.err != nil {
+ t.Fatalf("second job: got %v, want success", result.err)
+ }
+ if scheduler.stopped.Load() {
+ t.Fatal("scheduler stopped after recoverable error")
+ }
+}
+
func decisionTestWork(tokens, readouts int) decisionWork {
work := decisionWork{
tokens: make([]llama.Token, tokens),
diff --git a/sdk/kronk/model/decision_scheduler.go b/sdk/kronk/model/decision_scheduler.go
index db23869cf..3b7332756 100644
--- a/sdk/kronk/model/decision_scheduler.go
+++ b/sdk/kronk/model/decision_scheduler.go
@@ -10,7 +10,7 @@ import (
var errDecisionEngineStopped = errors.New("decision engine stopped")
-type decisionEvaluateFunc func(entries []decisionScheduledEntry) ([][][]float32, error)
+type decisionEvaluateFunc func(entries []decisionScheduledEntry) (outputs [][][]float32, fatal bool, err error)
type decisionJobResult struct {
outputs [][][]float32
@@ -195,13 +195,17 @@ func (s *decisionScheduler) processLoop() {
return
}
- outputs, err := s.evaluate(schedule.entries)
+ outputs, fatal, err := s.evaluate(schedule.entries)
if err != nil {
affected := decisionScheduleJobs(schedule)
completeDecisionJobs(affected, err)
- completeDecisionJobs(active, err)
- s.terminate(err)
- return
+ active = removeDecisionJobs(active, affected)
+ if fatal {
+ completeDecisionJobs(active, err)
+ s.terminate(err)
+ return
+ }
+ continue
}
if len(outputs) != len(schedule.entries) {
err := fmt.Errorf("decision scheduler returned %d outputs for %d work items", len(outputs), len(schedule.entries))
@@ -269,6 +273,22 @@ func decisionScheduleJobs(schedule decisionSchedule) []*decisionJob {
return jobs
}
+func removeDecisionJobs(jobs, removedJobs []*decisionJob) []*decisionJob {
+ removed := make(map[*decisionJob]struct{}, len(removedJobs))
+ for _, job := range removedJobs {
+ removed[job] = struct{}{}
+ }
+
+ remaining := jobs[:0]
+ for _, job := range jobs {
+ if _, exists := removed[job]; !exists {
+ remaining = append(remaining, job)
+ }
+ }
+
+ return remaining
+}
+
func (s *decisionScheduler) drain(err error) {
for {
select {
diff --git a/sdk/kronk/model/draft_mtp.go b/sdk/kronk/model/draft_mtp.go
index 9c219d83f..112b9bfce 100644
--- a/sdk/kronk/model/draft_mtp.go
+++ b/sdk/kronk/model/draft_mtp.go
@@ -331,7 +331,6 @@ func loadDraftModelMTPSeparate(ctx context.Context, log applog.Logger, cfg Confi
}
params := embeddedMTPContextParams(llama.ContextDefaultParams(), targetCtxParams)
- params.CtxOther = targetCtx
lctx, err := llama.InitFromModel(draftModel, params)
if err != nil {
llama.ModelFree(draftModel)
diff --git a/sdk/kronk/model/draft_mtp_backend.go b/sdk/kronk/model/draft_mtp_backend.go
index ef91746bc..4f3b044f5 100644
--- a/sdk/kronk/model/draft_mtp_backend.go
+++ b/sdk/kronk/model/draft_mtp_backend.go
@@ -3,7 +3,6 @@ package model
import (
"context"
"fmt"
- "os"
"github.com/ardanlabs/kronk/sdk/kronk/applog"
yzmaspec "github.com/hybridgroup/yzma/exp/speculative"
@@ -57,7 +56,6 @@ func (b qwen35OwnKVBackend) load(req mtpLoadRequest) (drafter, error) {
const reason = "target GGUF declares MTP (nextn_predict_layers>0) but the loaded llama library does not export the NextN hidden-state APIs required by Yzma. MTP speculative decoding is DISABLED for this model. Install the llama.cpp version pinned for this Kronk release."
req.log(req.ctx, "draft-model-mtp", "status", "DISABLED",
"backend", b.name(), "nextn-layers", nLayers, "reason", reason)
- fmt.Fprintf(os.Stderr, "WARN: MTP DISABLED for this model: %s\n", reason)
return nil, nil
}
@@ -80,7 +78,6 @@ func (b qwen35OwnKVBackend) load(req mtpLoadRequest) (drafter, error) {
if !yzmaspec.Available() {
const reason = "MTPDrafterFile is a Qwen own-KV MTP head but the loaded llama library does not export the NextN hidden-state APIs required by Yzma. MTP speculative decoding is DISABLED for this model."
req.log(req.ctx, "draft-model-mtp-separate", "status", "DISABLED", "backend", b.name(), "reason", reason)
- fmt.Fprintf(os.Stderr, "WARN: MTP DISABLED for this model: %s\n", reason)
return nil, nil
}
@@ -107,7 +104,6 @@ func (b gemmaSharedKVBackend) load(req mtpLoadRequest) (drafter, error) {
if !yzmaspec.Available() {
const reason = "MTPDrafterFile is a gemma4-assistant MTP head but the loaded llama library does not export the NextN hidden-state APIs required by Yzma. MTP speculative decoding is DISABLED for this model."
req.log(req.ctx, "draft-model-mtp-shared", "status", "DISABLED", "backend", b.name(), "reason", reason)
- fmt.Fprintf(os.Stderr, "WARN: MTP DISABLED for this model: %s\n", reason)
return nil, nil
}
diff --git a/sdk/kronk/model/embed.go b/sdk/kronk/model/embed.go
index edb7bf873..14721a8e8 100644
--- a/sdk/kronk/model/embed.go
+++ b/sdk/kronk/model/embed.go
@@ -26,6 +26,10 @@ func (m *Model) Embeddings(ctx context.Context, d D) (response EmbedReponse, err
if !m.modelInfo.IsEmbedModel {
return EmbedReponse{}, fmt.Errorf("embeddings: model doesn't support embedding")
}
+ if err := m.beginActiveOperation(); err != nil {
+ return EmbedReponse{}, fmt.Errorf("embeddings: %w", err)
+ }
+ defer m.endActiveOperation()
started := time.Now()
runtimeName := "context_pool"
diff --git a/sdk/kronk/model/embed_test.go b/sdk/kronk/model/embed_test.go
index d8607e3ec..4974314f2 100644
--- a/sdk/kronk/model/embed_test.go
+++ b/sdk/kronk/model/embed_test.go
@@ -24,3 +24,15 @@ func TestEmbeddingVector(t *testing.T) {
t.Errorf("raw vector: got %v, want [3 4 12]", raw)
}
}
+
+func TestEmbeddingsRejectsOperationDuringUnload(t *testing.T) {
+ m := Model{modelInfo: ModelInfo{IsEmbedModel: true}}
+ m.unloaded.Store(true)
+
+ if _, err := m.Embeddings(t.Context(), D{"input": "hello"}); err == nil {
+ t.Fatal("Embeddings() error = nil, want unloading error")
+ }
+ if got := m.activeStreams.Load(); got != 0 {
+ t.Errorf("active streams: got %d, want 0", got)
+ }
+}
diff --git a/sdk/kronk/model/grammar.go b/sdk/kronk/model/grammar.go
index 0f80c9d53..324d16267 100644
--- a/sdk/kronk/model/grammar.go
+++ b/sdk/kronk/model/grammar.go
@@ -65,7 +65,7 @@ func fromJSONSchema(schema any) (string, error) {
rules: make(map[string]string),
}
- rootRule, err := gb.schemaToRule("root", schemaMap)
+ rootRule, err := gb.schemaToRule(schemaMap)
if err != nil {
return "", fmt.Errorf("from-json-schema: %w", err)
}
@@ -134,10 +134,16 @@ func fromResponseFormat(rf any) (string, error) {
// Grammar builder for JSON Schema conversion.
type grammarBuilder struct {
- rules map[string]string
+ rules map[string]string
+ nextRuleID int
}
-func (gb *grammarBuilder) schemaToRule(name string, schema map[string]any) (string, error) {
+func (gb *grammarBuilder) nextRuleName() string {
+ gb.nextRuleID++
+ return fmt.Sprintf("rule-%d", gb.nextRuleID)
+}
+
+func (gb *grammarBuilder) schemaToRule(schema map[string]any) (string, error) {
schemaType, _ := schema["type"].(string)
if enum, ok := schema["enum"].([]any); ok {
@@ -146,10 +152,10 @@ func (gb *grammarBuilder) schemaToRule(name string, schema map[string]any) (stri
switch schemaType {
case "object":
- return gb.objectToRule(name, schema)
+ return gb.objectToRule(schema)
case "array":
- return gb.arrayToRule(name, schema)
+ return gb.arrayToRule(schema)
case "string":
return gb.stringToRule(schema)
@@ -171,7 +177,7 @@ func (gb *grammarBuilder) schemaToRule(name string, schema map[string]any) (stri
}
}
-func (gb *grammarBuilder) objectToRule(name string, schema map[string]any) (string, error) {
+func (gb *grammarBuilder) objectToRule(schema map[string]any) (string, error) {
props, _ := schema["properties"].(map[string]any)
if props == nil {
if propsD, ok := schema["properties"].(D); ok {
@@ -217,8 +223,8 @@ func (gb *grammarBuilder) objectToRule(name string, schema map[string]any) (stri
continue
}
- propRuleName := fmt.Sprintf("%s-%s", name, key)
- propRule, err := gb.schemaToRule(propRuleName, propSchema)
+ propRuleName := gb.nextRuleName()
+ propRule, err := gb.schemaToRule(propSchema)
if err != nil {
return "", err
}
@@ -228,7 +234,12 @@ func (gb *grammarBuilder) objectToRule(name string, schema map[string]any) (stri
propRule = propRuleName
}
- pair := fmt.Sprintf(`"\"" "%s" "\"" ws ":" ws %s`, key, propRule)
+ keyRule, err := jsonValueToRule(key)
+ if err != nil {
+ return "", fmt.Errorf("property %q: %w", key, err)
+ }
+
+ pair := fmt.Sprintf(`%s ws ":" ws %s`, keyRule, propRule)
if !required[key] {
pair = fmt.Sprintf("( %s )?", pair)
}
@@ -242,7 +253,7 @@ func (gb *grammarBuilder) objectToRule(name string, schema map[string]any) (stri
return fmt.Sprintf(`"{" ws %s ws "}"`, strings.Join(pairs, ` ws "," ws `)), nil
}
-func (gb *grammarBuilder) arrayToRule(name string, schema map[string]any) (string, error) {
+func (gb *grammarBuilder) arrayToRule(schema map[string]any) (string, error) {
items, _ := schema["items"].(map[string]any)
if items == nil {
if itemsD, ok := schema["items"].(D); ok {
@@ -254,8 +265,8 @@ func (gb *grammarBuilder) arrayToRule(name string, schema map[string]any) (strin
return "array", nil
}
- itemRuleName := fmt.Sprintf("%s-item", name)
- itemRule, err := gb.schemaToRule(itemRuleName, items)
+ itemRuleName := gb.nextRuleName()
+ itemRule, err := gb.schemaToRule(items)
if err != nil {
return "", err
}
@@ -273,8 +284,8 @@ func (gb *grammarBuilder) stringToRule(schema map[string]any) (string, error) {
return gb.enumToRule(enum)
}
- if pattern, ok := schema["pattern"].(string); ok {
- return fmt.Sprintf(`"\"" %s "\""`, pattern), nil
+ if _, ok := schema["pattern"].(string); ok {
+ return "", fmt.Errorf("%w: json schema pattern is not supported", ErrInvalidRequest)
}
return "string", nil
@@ -283,24 +294,11 @@ func (gb *grammarBuilder) stringToRule(schema map[string]any) (string, error) {
func (gb *grammarBuilder) enumToRule(values []any) (string, error) {
var options []string
for _, v := range values {
- switch val := v.(type) {
- case string:
- options = append(options, fmt.Sprintf(`"\"" "%s" "\""`, val))
-
- case float64:
- switch {
- case val == float64(int(val)):
- options = append(options, fmt.Sprintf(`"%d"`, int(val)))
- default:
- options = append(options, fmt.Sprintf(`"%v"`, val))
- }
-
- case bool:
- options = append(options, fmt.Sprintf(`"%t"`, val))
-
- default:
- options = append(options, fmt.Sprintf(`"%v"`, val))
+ option, err := jsonValueToRule(v)
+ if err != nil {
+ return "", fmt.Errorf("enum value: %w", err)
}
+ options = append(options, option)
}
if len(options) == 0 {
@@ -314,6 +312,37 @@ func (gb *grammarBuilder) enumToRule(values []any) (string, error) {
return fmt.Sprintf("( %s )", strings.Join(options, " | ")), nil
}
+func jsonValueToRule(value any) (string, error) {
+ data, err := json.Marshal(value)
+ if err != nil {
+ return "", fmt.Errorf("marshal JSON value: %w", err)
+ }
+ return gbnfLiteral(string(data)), nil
+}
+
+func gbnfLiteral(value string) string {
+ var b strings.Builder
+ b.Grow(len(value) + 2)
+ b.WriteByte('"')
+ for _, r := range value {
+ switch r {
+ case '"', '\\':
+ b.WriteByte('\\')
+ b.WriteRune(r)
+ case '\n':
+ b.WriteString(`\n`)
+ case '\r':
+ b.WriteString(`\r`)
+ case '\t':
+ b.WriteString(`\t`)
+ default:
+ b.WriteRune(r)
+ }
+ }
+ b.WriteByte('"')
+ return b.String()
+}
+
func (gb *grammarBuilder) addCommonRules() {
for name, rule := range commonRules {
if _, exists := gb.rules[name]; !exists {
diff --git a/sdk/kronk/model/grammar_test.go b/sdk/kronk/model/grammar_test.go
index 2a9965643..71a4d4005 100644
--- a/sdk/kronk/model/grammar_test.go
+++ b/sdk/kronk/model/grammar_test.go
@@ -49,11 +49,11 @@ func TestFromJSONSchema_SimpleObject(t *testing.T) {
if !strings.Contains(grammar, "root ::=") {
t.Error("grammar should contain root rule")
}
- if !strings.Contains(grammar, `"name"`) {
- t.Error("grammar should contain name property")
+ if !strings.Contains(grammar, `"\"name\""`) {
+ t.Errorf("grammar missing name property:\n%s", grammar)
}
- if !strings.Contains(grammar, `"age"`) {
- t.Error("grammar should contain age property")
+ if !strings.Contains(grammar, `"\"age\""`) {
+ t.Errorf("grammar missing age property:\n%s", grammar)
}
}
@@ -77,8 +77,8 @@ func TestFromJSONSchema_WithEnum(t *testing.T) {
"required": []string{"verdict"},
},
wantRules: []string{
- `root ::= "{" ws "\"" "verdict" "\"" ws ":" ws root-verdict ws "}"`,
- `root-verdict ::= ( "\"" "yes" "\"" | "\"" "no" "\"" | "\"" "maybe" "\"" )`,
+ `root ::= "{" ws "\"verdict\"" ws ":" ws rule-1 ws "}"`,
+ `rule-1 ::= ( "\"yes\"" | "\"no\"" | "\"maybe\"" )`,
},
},
{
@@ -91,8 +91,8 @@ func TestFromJSONSchema_WithEnum(t *testing.T) {
},
},
wantRules: []string{
- `root ::= "[" ws ( root-item ( ws "," ws root-item )* )? ws "]"`,
- `root-item ::= ( "\"" "yes" "\"" | "\"" "no" "\"" )`,
+ `root ::= "[" ws ( rule-1 ( ws "," ws rule-1 )* )? ws "]"`,
+ `rule-1 ::= ( "\"yes\"" | "\"no\"" )`,
},
},
{
@@ -102,7 +102,7 @@ func TestFromJSONSchema_WithEnum(t *testing.T) {
"enum": []any{"yes", "no"},
},
wantRules: []string{
- `root ::= ( "\"" "yes" "\"" | "\"" "no" "\"" )`,
+ `root ::= ( "\"yes\"" | "\"no\"" )`,
},
rootHasAlt: true,
},
@@ -129,16 +129,69 @@ func TestFromJSONSchema_WithEnum(t *testing.T) {
}
}
+func TestJSONValueToRuleEscapesString(t *testing.T) {
+ got, err := jsonValueToRule("a\"b\\c\n雪")
+ if err != nil {
+ t.Fatalf("jsonValueToRule: %v", err)
+ }
+
+ want := `"\"a\\\"b\\\\c\\n雪\""`
+ if got != want {
+ t.Errorf("jsonValueToRule: got %q, want %q", got, want)
+ }
+}
+
+func TestFromJSONSchema_PropertyNamesAreNotRuleNames(t *testing.T) {
+ schema := D{
+ "type": "object",
+ "properties": D{
+ "bad name_\"": D{
+ "type": "string",
+ "enum": []any{"a\"b\\c\n雪", "no"},
+ },
+ },
+ }
+
+ grammar, err := fromJSONSchema(schema)
+ if err != nil {
+ t.Fatalf("fromJSONSchema: %v", err)
+ }
+
+ if !strings.Contains(grammar, `"\"bad name_\\\"\""`) {
+ t.Errorf("grammar missing escaped property name:\n%s", grammar)
+ }
+ if !strings.Contains(grammar, `"\"a\\\"b\\\\c\\n雪\""`) {
+ t.Errorf("grammar missing escaped enum value:\n%s", grammar)
+ }
+ if strings.Contains(grammar, "root-bad name") {
+ t.Errorf("grammar used property text as a rule name:\n%s", grammar)
+ }
+ if !strings.Contains(grammar, "rule-1 ::=") {
+ t.Errorf("grammar missing generated rule name:\n%s", grammar)
+ }
+}
+
+func TestFromJSONSchema_PatternUnsupported(t *testing.T) {
+ schema := D{
+ "type": "string",
+ "pattern": `^[a-z]+$`,
+ }
+
+ if _, err := fromJSONSchema(schema); !errors.Is(err, ErrInvalidRequest) {
+ t.Errorf("fromJSONSchema: got %v, want ErrInvalidRequest", err)
+ }
+}
+
func TestFromJSONSchema_EnumGrammarInitializes(t *testing.T) {
schema := D{
"type": "object",
"properties": D{
- "verdict": D{
+ "verdict\"\\\n雪": D{
"type": "string",
- "enum": []any{"yes", "no", "maybe"},
+ "enum": []any{"yes\"\\\n雪", "no", "maybe"},
},
},
- "required": []string{"verdict"},
+ "required": []string{"verdict\"\\\n雪"},
}
grammar, err := fromJSONSchema(schema)
@@ -225,7 +278,7 @@ func TestFromJSONSchema_NestedObject(t *testing.T) {
if !strings.Contains(grammar, "root ::=") {
t.Error("grammar should contain root rule")
}
- if !strings.Contains(grammar, `"user"`) {
+ if !strings.Contains(grammar, `"\"user\""`) {
t.Error("grammar should contain user property")
}
}
@@ -330,10 +383,10 @@ func TestFromResponseFormat_JSONSchema_OpenAIWrapped(t *testing.T) {
if !strings.Contains(grammar, "root ::=") {
t.Error("grammar should contain root rule")
}
- if !strings.Contains(grammar, `"name"`) {
+ if !strings.Contains(grammar, `"\"name\""`) {
t.Error("grammar should contain name property")
}
- if !strings.Contains(grammar, `"age"`) {
+ if !strings.Contains(grammar, `"\"age\""`) {
t.Error("grammar should contain age property")
}
}
@@ -356,7 +409,7 @@ func TestFromResponseFormat_JSONSchema_DirectSchema(t *testing.T) {
if !strings.Contains(grammar, "root ::=") {
t.Error("grammar should contain root rule")
}
- if !strings.Contains(grammar, `"id"`) {
+ if !strings.Contains(grammar, `"\"id\""`) {
t.Error("grammar should contain id property")
}
}
@@ -394,7 +447,7 @@ func TestFromResponseFormat_MapStringAny(t *testing.T) {
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
- if !strings.Contains(grammar, `"flag"`) {
+ if !strings.Contains(grammar, `"\"flag\""`) {
t.Error("grammar should contain flag property")
}
}
diff --git a/sdk/kronk/model/internal/speculation/speculation.go b/sdk/kronk/model/internal/speculation/speculation.go
index a78971f99..5f31404d7 100644
--- a/sdk/kronk/model/internal/speculation/speculation.go
+++ b/sdk/kronk/model/internal/speculation/speculation.go
@@ -145,7 +145,7 @@ func Resolve(cfg Config) (Plan, error) {
plan.Source = SourceMTP
plan.MTPArchitecture = MTPArchitectureQwen35OwnKV
plan.MTPArtifact = MTPArtifactEmbedded
- plan.LoadMTP = true
+ plan.LoadMTP = plan.Available
case cfg.Mode == ModeMTP:
return Plan{}, fmt.Errorf("speculation mode %q requested but the model has no companion or embedded MTP implementation", cfg.Mode)
}
diff --git a/sdk/kronk/model/internal/speculation/speculation_test.go b/sdk/kronk/model/internal/speculation/speculation_test.go
index d0eb54b98..e243186ba 100644
--- a/sdk/kronk/model/internal/speculation/speculation_test.go
+++ b/sdk/kronk/model/internal/speculation/speculation_test.go
@@ -18,6 +18,7 @@ func TestResolve(t *testing.T) {
{"auto prefers companion MTP", Config{Mode: ModeAuto, CompanionMTP: true, EmbeddedMTP: true, MTPNDraft: 3, MTPAvailable: true}, SourceMTP, MTPArchitectureGemmaSharedKV, MTPArtifactCompanion, false, false},
{"auto selects own-KV companion MTP", Config{Mode: ModeAuto, OwnKVCompanionMTP: true, EmbeddedMTP: true, MTPNDraft: 3, MTPAvailable: true}, SourceMTP, MTPArchitectureQwen35OwnKV, MTPArtifactCompanion, false, false},
{"auto selects embedded MTP", Config{Mode: ModeAuto, EmbeddedMTP: true, MTPNDraft: 3, MTPAvailable: true}, SourceMTP, MTPArchitectureQwen35OwnKV, MTPArtifactEmbedded, true, false},
+ {"auto does not load unavailable embedded MTP", Config{Mode: ModeAuto, EmbeddedMTP: true}, SourceMTP, MTPArchitectureQwen35OwnKV, MTPArtifactEmbedded, false, false},
{"classic requires model", Config{Mode: ModeClassic}, SourceNone, MTPArchitectureNone, MTPArtifactNone, false, true},
{"MTP rejects classic model", Config{Mode: ModeMTP, ClassicConfigured: true}, SourceNone, MTPArchitectureNone, MTPArtifactNone, false, true},
{"MTP requires source", Config{Mode: ModeMTP, MTPAvailable: true}, SourceNone, MTPArchitectureNone, MTPArtifactNone, false, true},
diff --git a/sdk/kronk/model/model.go b/sdk/kronk/model/model.go
index 415b27b4e..24e3d61e0 100644
--- a/sdk/kronk/model/model.go
+++ b/sdk/kronk/model/model.go
@@ -7,7 +7,6 @@ import (
"context"
"errors"
"fmt"
- "os"
"path"
"path/filepath"
"runtime"
@@ -31,10 +30,6 @@ import (
"go.opentelemetry.io/otel/attribute"
)
-// modelLoadMu serializes model loading to prevent concurrent mutation of
-// process-level environment variables (e.g., GGML_OP_OFFLOAD_MIN_BATCH).
-var modelLoadMu sync.Mutex
-
// compiledTemplate holds a pre-compiled Jinja template. Compiled once per
// Model via Model.templateOnce / Model.compiledTmpl in applyJinjaTemplate.
type compiledTemplate struct {
@@ -224,8 +219,7 @@ type Model struct {
// NewModel loads a model from the GGUF files specified in cfg and returns
// a *Model ready to serve requests. It validates the configuration, builds
// llama.cpp model parameters, applies NUMA settings, performs the actual
-// GGUF load (serialized via a process-wide mutex to guard the
-// GGML_OP_OFFLOAD_MIN_BATCH env var), computes VRAM/KV diagnostics,
+// GGUF load, computes VRAM/KV diagnostics,
// retrieves the chat template, and initializes the per-model runtime —
// either the sequence-batch runtime or context-pool fallback for embed/rerank
// models, or a batch engine plus parser plugin and optional draft model for
@@ -276,7 +270,7 @@ func NewModel(ctx context.Context, cfg Config) (*Model, error) {
// -------------------------------------------------------------------------
- mdl, loadDuration, err := loadModelWithEnvGuard(ctx, l, cfg, mParams, ka)
+ mdl, loadDuration, err := loadModel(ctx, l, cfg.ModelFiles, mParams, ka)
if err != nil {
return nil, err
}
@@ -515,7 +509,7 @@ func validateGenerationBatchCapacity(nBatch, generationReserve int) error {
// modelParamsKeepalive holds backing buffers that the C side of llama.cpp
// reads via pointer during ModelLoadFromFile. They must outlive the load
-// call; the caller passes this to loadModelWithEnvGuard which holds the
+// call; the caller passes this to loadModel which holds the
// references via runtime.KeepAlive across the load.
type modelParamsKeepalive struct {
devices []llama.GGMLBackendDevice
@@ -658,32 +652,11 @@ func applyNUMA(ctx context.Context, cfg Config, l applog.Logger) {
l(ctx, "NUMA", "strategy", cfg.NUMA)
}
-// loadModelWithEnvGuard performs the actual GGUF load while serializing the
-// process-level GGML_OP_OFFLOAD_MIN_BATCH env var so concurrent loads (e.g.
-// target + draft) do not race. The previous env value is saved and restored
-// so unrelated callers are unaffected. The keepalive struct keeps the
-// param-backing buffers alive across the C call.
-func loadModelWithEnvGuard(ctx context.Context, l applog.Logger, cfg Config, mParams llama.ModelParams, ka modelParamsKeepalive) (llama.Model, time.Duration, error) {
- modelLoadMu.Lock()
- defer modelLoadMu.Unlock()
-
- prevOffloadMinBatch, hadOffloadMinBatch := os.LookupEnv("GGML_OP_OFFLOAD_MIN_BATCH")
- if cfg.OpOffloadMinBatch() > 0 {
- os.Setenv("GGML_OP_OFFLOAD_MIN_BATCH", strconv.Itoa(*cfg.PtrOpOffloadMinBatch))
- l(ctx, "OP-OFFLOAD-MIN-BATCH", "value", *cfg.PtrOpOffloadMinBatch)
- } else {
- os.Unsetenv("GGML_OP_OFFLOAD_MIN_BATCH")
- }
- defer func() {
- if hadOffloadMinBatch {
- os.Setenv("GGML_OP_OFFLOAD_MIN_BATCH", prevOffloadMinBatch)
- } else {
- os.Unsetenv("GGML_OP_OFFLOAD_MIN_BATCH")
- }
- }()
-
+// loadModel performs the actual GGUF load. The keepalive struct keeps the
+// parameter-backing buffers alive across the C call.
+func loadModel(ctx context.Context, l applog.Logger, modelFiles []string, mParams llama.ModelParams, ka modelParamsKeepalive) (llama.Model, time.Duration, error) {
loadStart := time.Now()
- mdl, err := loadModelFromFiles(ctx, l, cfg.ModelFiles, mParams)
+ mdl, err := loadModelFromFiles(ctx, l, modelFiles, mParams)
runtime.KeepAlive(ka.devices)
runtime.KeepAlive(ka.tensorSplit)
runtime.KeepAlive(ka.tensorBuft)
@@ -1147,19 +1120,27 @@ func loadModeName(loadMode llama.LoadMode) string {
// retrieveTemplate resolves the Jinja chat template for a model. The
// resolution order, from highest to lowest priority:
//
-// 1. cfg.JinjaFile — explicit "template:" entry in model_config.yaml.
-// 2. /.jinja — exact match on the model id (e.g.
+// 1. cfg.JinjaScript — request-scoped in-memory template override.
+// 2. cfg.JinjaFile — explicit "template:" entry in model_config.yaml.
+// 3. /.jinja — exact match on the model id (e.g.
// "Qwopus3.5-4B-Coder.Q8_0.jinja"), letting operators target a
// specific quant.
-// 3. /.jinja — match against the
+// 4. /.jinja — match against the
// base model name with any trailing quant tag removed (e.g.
// "Qwopus3.5-4B-Coder.jinja"), so one file covers every quant of
// the same model.
-// 4. The GGUF-embedded "tokenizer.chat_template" — original fallback.
+// 5. The GGUF-embedded "tokenizer.chat_template" — original fallback.
//
-// Auto-discovery (steps 2-3) lets users drop a .jinja file into
+// Auto-discovery (steps 3-4) lets users drop a .jinja file into
// /jinja/ and have it applied without editing model_config.yaml.
func retrieveTemplate(cfg Config, modelID string, mdl llama.Model) (Template, error) {
+ if cfg.JinjaScript != "" {
+ return Template{
+ FileName: "playground-custom",
+ Script: cfg.JinjaScript,
+ }, nil
+ }
+
if cfg.JinjaFile != "" {
data, err := readJinjaTemplate(cfg.JinjaFile)
if err != nil {
@@ -1224,6 +1205,26 @@ func autoDiscoverTemplate(modelID string) (Template, bool) {
return Template{}, false
}
+func (m *Model) beginActiveOperation() error {
+ if m.unloaded.Load() {
+ return errors.New("model is unloading")
+ }
+
+ m.activeStreams.Add(1)
+ if m.unloaded.Load() {
+ m.activeStreams.Add(-1)
+ return errors.New("model is unloading")
+ }
+ metrics.AddPoolActiveStreams(m.modelInfo.ID, 1)
+
+ return nil
+}
+
+func (m *Model) endActiveOperation() {
+ m.activeStreams.Add(-1)
+ metrics.AddPoolActiveStreams(m.modelInfo.ID, -1)
+}
+
func (m *Model) Unload(ctx context.Context) error {
if !m.unloaded.CompareAndSwap(false, true) {
return nil // Already unloaded
diff --git a/sdk/kronk/model/params.go b/sdk/kronk/model/params.go
index 5e92d7339..da2156c6f 100644
--- a/sdk/kronk/model/params.go
+++ b/sdk/kronk/model/params.go
@@ -1153,7 +1153,7 @@ func parseBool(fieldName string, val any) (bool, error) {
return b, nil
}
- return true, nil
+ return false, fmt.Errorf("%w: parse-bool: field-name[%s] must be a boolean or boolean string", ErrInvalidRequest, fieldName)
}
func parseReasoningString(fieldName string, val any) (string, error) {
diff --git a/sdk/kronk/model/parser.go b/sdk/kronk/model/parser.go
index 3dc4e7529..e2403fde2 100644
--- a/sdk/kronk/model/parser.go
+++ b/sdk/kronk/model/parser.go
@@ -94,6 +94,11 @@ type Result struct {
// instance is created per slot via Parser.NewStateMachine and reused
// across requests on that slot via Reset.
//
+// Implementations may consume protocol framing. Once content has been
+// recognized as answer, reasoning, or tool payload, unexpected non-whitespace
+// continuations must be returned on an appropriate channel so final parsing can
+// reject malformed output atomically.
+//
// Behavior is undefined if Classify is called after a previous call returned
// eog=true. Callers must invoke Reset before reusing the state machine.
type StateMachine interface {
diff --git a/sdk/kronk/model/rerank.go b/sdk/kronk/model/rerank.go
index 8c68b0f65..d27a2731f 100644
--- a/sdk/kronk/model/rerank.go
+++ b/sdk/kronk/model/rerank.go
@@ -28,6 +28,10 @@ func (m *Model) Rerank(ctx context.Context, d D) (response RerankResponse, err e
if !m.modelInfo.IsRerankModel {
return RerankResponse{}, fmt.Errorf("rerank: model doesn't support reranking")
}
+ if err := m.beginActiveOperation(); err != nil {
+ return RerankResponse{}, fmt.Errorf("rerank: %w", err)
+ }
+ defer m.endActiveOperation()
started := time.Now()
runtimeName := "context_pool"
diff --git a/sdk/kronk/model/rerank_test.go b/sdk/kronk/model/rerank_test.go
index 6c113fdc0..643d9501c 100644
--- a/sdk/kronk/model/rerank_test.go
+++ b/sdk/kronk/model/rerank_test.go
@@ -23,3 +23,15 @@ func TestRerankTokenLimit(t *testing.T) {
})
}
}
+
+func TestRerankRejectsOperationDuringUnload(t *testing.T) {
+ m := Model{modelInfo: ModelInfo{IsRerankModel: true}}
+ m.unloaded.Store(true)
+
+ if _, err := m.Rerank(t.Context(), D{"query": "hello", "documents": []string{"world"}}); err == nil {
+ t.Fatal("Rerank() error = nil, want unloading error")
+ }
+ if got := m.activeStreams.Load(); got != 0 {
+ t.Errorf("active streams: got %d, want 0", got)
+ }
+}
diff --git a/sdk/kronk/model/speculation_runtime.go b/sdk/kronk/model/speculation_runtime.go
index 6cbb8e52e..ba0a92e8a 100644
--- a/sdk/kronk/model/speculation_runtime.go
+++ b/sdk/kronk/model/speculation_runtime.go
@@ -45,9 +45,22 @@ func (e *batchEngine) PrefillDraft(slotID int) error {
func (e *batchEngine) CanSpeculate(slotID int) bool {
s := e.slots[slotID]
+ if e.model.cfg.speculationPlan.Source == speculationSourceClassic && !classicSpeculationSupports(s.job.params) {
+ return false
+ }
return e.model.draft != nil && !s.draftPrefillNeeded && s.draftNPast > 0 && (!e.model.cfg.speculationPlan.MTP() || !s.mtp.Disabled)
}
+func classicSpeculationSupports(p Params) bool {
+ return p.Grammar == "" &&
+ p.AdaptivePTarget == 0 &&
+ p.DryMultiplier == 0 &&
+ p.FrequencyPenalty == 0 &&
+ p.PresencePenalty == 0 &&
+ p.RepeatPenalty == DefRepeatPenalty &&
+ p.XtcProbability == 0
+}
+
func (e *batchEngine) ClassicGenerationInput(slotID int) (classicengine.GenerationInput, error) {
if _, ok := e.model.draft.(*classicDrafter); !ok {
return classicengine.GenerationInput{}, fmt.Errorf("classic controller requires a classic drafter")
@@ -96,6 +109,7 @@ func (e *batchEngine) CommitSpeculative(slotID int, candidates []llama.Token, ta
if err := e.captureTargetSpecSnapshot(s); err != nil {
e.model.log(s.job.ctx, "speculative", "status", "snapshot-error", "slot", s.id, "err", err)
s.specSnapshot = s.specSnapshot[:0]
+ return fmt.Errorf("capture target state for speculative decoding: %w", err)
}
}
diff --git a/sdk/kronk/model/template_resolve_test.go b/sdk/kronk/model/template_resolve_test.go
index 0eaac03a2..a3fd7c540 100644
--- a/sdk/kronk/model/template_resolve_test.go
+++ b/sdk/kronk/model/template_resolve_test.go
@@ -136,3 +136,21 @@ func TestAutoDiscoverTemplate(t *testing.T) {
}
})
}
+
+func TestRetrieveTemplateInlineScriptWins(t *testing.T) {
+ const script = `{{ messages | length }}`
+
+ tmpl, err := retrieveTemplate(Config{
+ JinjaFile: filepath.Join(t.TempDir(), "missing.jinja"),
+ JinjaScript: script,
+ }, "model", 0)
+ if err != nil {
+ t.Fatalf("retrieveTemplate: %v", err)
+ }
+ if tmpl.FileName != "playground-custom" {
+ t.Errorf("FileName: got %q, want playground-custom", tmpl.FileName)
+ }
+ if tmpl.Script != script {
+ t.Errorf("Script: got %q, want %q", tmpl.Script, script)
+ }
+}
diff --git a/sdk/kronk/observ/metrics/metrics.go b/sdk/kronk/observ/metrics/metrics.go
index ff72f4563..fd65f243a 100644
--- a/sdk/kronk/observ/metrics/metrics.go
+++ b/sdk/kronk/observ/metrics/metrics.go
@@ -115,10 +115,10 @@ type promMetrics struct {
poolSingleflightWait prometheus.Histogram
poolEvictWaitSeconds prometheus.Histogram
poolUnloadDuration *prometheus.HistogramVec // labels: model_id.
- poolItemsInPool prometheus.Gauge
- poolMaxItemsInPool prometheus.Gauge
- poolActiveStreams *prometheus.GaugeVec // labels: model_id.
- poolInflightLoads prometheus.Gauge
+ poolItemsInPool *prometheus.GaugeVec // labels: backend.
+ poolMaxItemsInPool *prometheus.GaugeVec // labels: backend.
+ poolActiveStreams *prometheus.GaugeVec // labels: model_id.
+ poolInflightLoads *prometheus.GaugeVec // labels: backend.
// -------------------------------------------------------------------------
// Resource manager metrics (sdk/pool/resman).
@@ -251,22 +251,22 @@ func init() {
Help: "Model unload duration in seconds.",
Buckets: subSecondBuckets,
}, []string{"model_id"}),
- poolItemsInPool: auto.NewGauge(prometheus.GaugeOpts{
+ poolItemsInPool: auto.NewGaugeVec(prometheus.GaugeOpts{
Name: "pool_items_in_pool",
- Help: "Number of distinct model entries currently in the pool cache.",
- }),
- poolMaxItemsInPool: auto.NewGauge(prometheus.GaugeOpts{
+ Help: "Number of distinct model entries currently in the pool cache, by backend.",
+ }, []string{"backend"}),
+ poolMaxItemsInPool: auto.NewGaugeVec(prometheus.GaugeOpts{
Name: "pool_max_items_in_pool",
- Help: "Maximum number of model entries the pool will keep before TTL/cap eviction.",
- }),
+ Help: "Maximum number of model entries each backend pool will keep before TTL/cap eviction.",
+ }, []string{"backend"}),
poolActiveStreams: auto.NewGaugeVec(prometheus.GaugeOpts{
Name: "pool_active_streams",
Help: "Active streaming requests per model.",
}, []string{"model_id"}),
- poolInflightLoads: auto.NewGauge(prometheus.GaugeOpts{
+ poolInflightLoads: auto.NewGaugeVec(prometheus.GaugeOpts{
Name: "pool_inflight_loads",
- Help: "Number of model loads currently in progress (reservation held but not yet in cache).",
- }),
+ Help: "Number of model loads currently in progress by backend (reservation held but not yet in cache).",
+ }, []string{"backend"}),
// Resource manager.
resmanBudgetPercent: auto.NewGauge(prometheus.GaugeOpts{
@@ -575,14 +575,14 @@ func ObservePoolUnloadDuration(modelID string, d time.Duration) {
m.poolUnloadDuration.WithLabelValues(normalizeModelID(modelID)).Observe(d.Seconds())
}
-// SetPoolItemsInPool updates the gauge of items currently in the pool.
-func SetPoolItemsInPool(n int) {
- m.poolItemsInPool.Set(float64(n))
+// SetPoolItemsInPool updates the gauge of items currently in a backend pool.
+func SetPoolItemsInPool(backend string, n int) {
+ m.poolItemsInPool.WithLabelValues(backend).Set(float64(n))
}
-// SetPoolMaxItemsInPool updates the gauge of the configured cache cap.
-func SetPoolMaxItemsInPool(n int) {
- m.poolMaxItemsInPool.Set(float64(n))
+// SetPoolMaxItemsInPool updates the gauge of a backend's configured cache cap.
+func SetPoolMaxItemsInPool(backend string, n int) {
+ m.poolMaxItemsInPool.WithLabelValues(backend).Set(float64(n))
}
// SetPoolActiveStreams updates the active streams gauge for a model.
@@ -600,9 +600,9 @@ func ClearPoolActiveStreams(modelID string) {
m.poolActiveStreams.DeleteLabelValues(normalizeModelID(modelID))
}
-// SetPoolInflightLoads updates the gauge of in-progress loads.
-func SetPoolInflightLoads(n int) {
- m.poolInflightLoads.Set(float64(n))
+// SetPoolInflightLoads updates the gauge of in-progress loads for a backend.
+func SetPoolInflightLoads(backend string, n int) {
+ m.poolInflightLoads.WithLabelValues(backend).Set(float64(n))
}
// =============================================================================
diff --git a/sdk/kronk/observ/metrics/metrics_test.go b/sdk/kronk/observ/metrics/metrics_test.go
index 5c5d465bb..a169b2652 100644
--- a/sdk/kronk/observ/metrics/metrics_test.go
+++ b/sdk/kronk/observ/metrics/metrics_test.go
@@ -83,6 +83,44 @@ func TestInferenceAndBatchSeqMetrics(t *testing.T) {
}
}
+func TestPoolGaugesAreSeparatedByBackend(t *testing.T) {
+ SetPoolItemsInPool("kronk-test", 2)
+ SetPoolItemsInPool("bucky-test", 3)
+ SetPoolMaxItemsInPool("kronk-test", 4)
+ SetPoolMaxItemsInPool("bucky-test", 5)
+ SetPoolInflightLoads("kronk-test", 6)
+ SetPoolInflightLoads("bucky-test", 7)
+
+ tests := []struct {
+ name string
+ backend string
+ want float64
+ }{
+ {name: "pool_items_in_pool", backend: "kronk-test", want: 2},
+ {name: "pool_items_in_pool", backend: "bucky-test", want: 3},
+ {name: "pool_max_items_in_pool", backend: "kronk-test", want: 4},
+ {name: "pool_max_items_in_pool", backend: "bucky-test", want: 5},
+ {name: "pool_inflight_loads", backend: "kronk-test", want: 6},
+ {name: "pool_inflight_loads", backend: "bucky-test", want: 7},
+ }
+
+ families, err := Gatherer().Gather()
+ if err != nil {
+ t.Fatalf("Gather: unexpected error: %v", err)
+ }
+ for _, tt := range tests {
+ t.Run(tt.name+"/"+tt.backend, func(t *testing.T) {
+ metric := findMetric(families, tt.name, map[string]string{"backend": tt.backend})
+ if metric == nil {
+ t.Fatalf("metric %q with backend %q not found", tt.name, tt.backend)
+ }
+ if got := metric.GetGauge().GetValue(); got != tt.want {
+ t.Errorf("value: got %v, want %v", got, tt.want)
+ }
+ })
+ }
+}
+
func findMetric(families []*dto.MetricFamily, name string, labels map[string]string) *dto.Metric {
for _, family := range families {
if family.GetName() != name {
diff --git a/sdk/kronk/observ/otel/otel.go b/sdk/kronk/observ/otel/otel.go
index 557a604b9..e9be16f1c 100644
--- a/sdk/kronk/observ/otel/otel.go
+++ b/sdk/kronk/observ/otel/otel.go
@@ -21,6 +21,7 @@ import (
sdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
"go.opentelemetry.io/otel/trace"
+ "go.opentelemetry.io/otel/trace/noop"
)
const defaultTraceID = "00000000000000000000000000000000"
@@ -188,7 +189,7 @@ func InjectTracing(ctx context.Context, tracer trace.Tracer) context.Context {
func AddSpan(ctx context.Context, spanName string, keyValues ...attribute.KeyValue) (context.Context, trace.Span) {
tracer, ok := ctx.Value(tracerKey).(trace.Tracer)
if !ok || tracer == nil {
- return ctx, trace.SpanFromContext(ctx)
+ return noop.NewTracerProvider().Tracer("kronk").Start(ctx, spanName)
}
ctx, span := tracer.Start(ctx, spanName)
diff --git a/sdk/kronk/observ/otel/otel_test.go b/sdk/kronk/observ/otel/otel_test.go
index 57b2beb86..c18a25f8f 100644
--- a/sdk/kronk/observ/otel/otel_test.go
+++ b/sdk/kronk/observ/otel/otel_test.go
@@ -67,3 +67,33 @@ func testInitTracingPreservesGlobalDelegation(t *testing.T) {
t.Errorf("span name: got %q, want %q", got, "after-activation")
}
}
+
+func TestAddSpanWithoutTracerDoesNotEndParent(t *testing.T) {
+ recorder := tracetest.NewSpanRecorder()
+ provider := sdktrace.NewTracerProvider(
+ sdktrace.WithSampler(sdktrace.AlwaysSample()),
+ sdktrace.WithSpanProcessor(recorder),
+ )
+ t.Cleanup(func() {
+ if err := provider.Shutdown(context.Background()); err != nil {
+ t.Errorf("shutdown tracer provider: %v", err)
+ }
+ })
+
+ ctx, parent := provider.Tracer("test").Start(context.Background(), "parent")
+ _, child := AddSpan(ctx, "child")
+ child.End()
+
+ if got := len(recorder.Ended()); got != 0 {
+ t.Fatalf("ended spans after child.End: got %d, want 0", got)
+ }
+
+ parent.End()
+ ended := recorder.Ended()
+ if got := len(ended); got != 1 {
+ t.Fatalf("ended spans after parent.End: got %d, want 1", got)
+ }
+ if got := ended[0].Name(); got != "parent" {
+ t.Errorf("ended span: got %q, want %q", got, "parent")
+ }
+}
diff --git a/sdk/kronk/parsers/deepseek/deepseek_test.go b/sdk/kronk/parsers/deepseek/deepseek_test.go
index a20db29bc..1e9ae648e 100644
--- a/sdk/kronk/parsers/deepseek/deepseek_test.go
+++ b/sdk/kronk/parsers/deepseek/deepseek_test.go
@@ -85,6 +85,17 @@ func TestStateMachineSingleChunkDSMLBlock(t *testing.T) {
assertResult(t, sm, block, model.ChannelTool, block, false)
}
+func TestStateMachinePreservesAnswerBeforeCompleteToolBlock(t *testing.T) {
+ sm := Parser{}.NewStateMachine()
+ block := toolCallsOpen + invokeOpen + ` name="ping">` + invokeClose + toolCallsClose
+
+ assertResult(t, sm, "answer"+block, model.ChannelAnswer, "answer", false)
+ got := sm.(model.StateMachineFlusher).Flush()
+ if got.Channel != model.ChannelTool || got.Content != block {
+ t.Errorf("Flush: got {%v %q}, want {%v %q}", got.Channel, got.Content, model.ChannelTool, block)
+ }
+}
+
func TestStateMachineMultipleToolBlocks(t *testing.T) {
first := toolCallsOpen + invokeOpen + ` name="first">` + invokeClose + toolCallsClose
second := toolCallsOpen + invokeOpen + ` name="second">` + invokeClose + toolCallsClose
diff --git a/sdk/kronk/parsers/deepseek/state_machine.go b/sdk/kronk/parsers/deepseek/state_machine.go
index b0a1cf9a6..1e8712fd7 100644
--- a/sdk/kronk/parsers/deepseek/state_machine.go
+++ b/sdk/kronk/parsers/deepseek/state_machine.go
@@ -22,6 +22,7 @@ type stateMachine struct {
toolCallDeltas []model.ResponseToolCallDelta
startedCalls []model.ResponseToolCallDelta
detectedCalls int
+ output []model.Result
}
// Reset returns the stateMachine to its initial state for reuse.
@@ -36,10 +37,18 @@ func (sm *stateMachine) Reset() {
sm.toolCallDeltas = nil
sm.startedCalls = nil
sm.detectedCalls = 0
+ sm.output = nil
}
// Classify classifies one decoded token's content.
func (sm *stateMachine) Classify(content string) (model.Result, bool) {
+ result, eog := sm.classify(content)
+ sm.enqueue(result)
+
+ return sm.popOutput(), eog
+}
+
+func (sm *stateMachine) classify(content string) (model.Result, bool) {
if sm.malformedTool {
return model.Result{Channel: model.ChannelTool, Content: content}, false
}
@@ -92,6 +101,10 @@ func (sm *stateMachine) Classify(content string) (model.Result, bool) {
// Flush drains an unresolved DSML opener prefix or an incomplete tools block.
func (sm *stateMachine) Flush() model.Result {
+ if result := sm.popOutput(); result != (model.Result{}) {
+ return result
+ }
+
if sm.inToolCall {
content := sm.toolCallBuf.String()
sm.toolCallBuf.Reset()
@@ -140,8 +153,14 @@ func (sm *stateMachine) classifyContent(content string) (model.Result, bool) {
if openerAt := strings.Index(content, toolCallsOpen); openerAt != -1 {
sm.startToolCall(content[openerAt:])
result := sm.completeBufferedTool()
- if openerAt > 0 && result.Content == "" {
- return model.Result{Channel: sm.status, Content: content[:openerAt]}, false
+ if openerAt > 0 {
+ prefix := model.Result{Channel: sm.status, Content: content[:openerAt]}
+ if result.Content == "" {
+ return prefix, false
+ }
+ sm.enqueue(prefix)
+ sm.enqueue(result)
+ return model.Result{}, false
}
return result, false
}
@@ -158,6 +177,22 @@ func (sm *stateMachine) classifyContent(content string) (model.Result, bool) {
return model.Result{Channel: sm.status, Content: content}, false
}
+func (sm *stateMachine) enqueue(result model.Result) {
+ if result != (model.Result{}) {
+ sm.output = append(sm.output, result)
+ }
+}
+
+func (sm *stateMachine) popOutput() model.Result {
+ if len(sm.output) == 0 {
+ return model.Result{}
+ }
+
+ result := sm.output[0]
+ sm.output = sm.output[1:]
+ return result
+}
+
func (sm *stateMachine) startToolCall(content string) {
sm.inToolCall = true
sm.afterToolCall = false
diff --git a/sdk/kronk/parsers/deepseek/toolparse.go b/sdk/kronk/parsers/deepseek/toolparse.go
index bca36012f..e6a76316d 100644
--- a/sdk/kronk/parsers/deepseek/toolparse.go
+++ b/sdk/kronk/parsers/deepseek/toolparse.go
@@ -180,6 +180,7 @@ func skipDSMLSpace(content string, offset int) int {
func decodeUniqueDSMLJSON(raw string) (any, error) {
decoder := json.NewDecoder(strings.NewReader(raw))
+ decoder.UseNumber()
value, err := decodeUniqueDSMLJSONValue(decoder)
if err != nil {
return nil, err
diff --git a/sdk/kronk/parsers/deepseek/toolparse_test.go b/sdk/kronk/parsers/deepseek/toolparse_test.go
index 47a7b61fd..d9a051f61 100644
--- a/sdk/kronk/parsers/deepseek/toolparse_test.go
+++ b/sdk/kronk/parsers/deepseek/toolparse_test.go
@@ -85,7 +85,7 @@ func TestToolCallWeatherTemplateRoundTrip(t *testing.T) {
func TestToolCallTypedParametersAndParallelInvocations(t *testing.T) {
content := toolCallsOpen +
invokeOpen + ` name="first">` +
- parameterOpen + ` name="count" string="false">42` + parameterClose +
+ parameterOpen + ` name="count" string="false">9007199254740993` + parameterClose +
parameterOpen + ` name="enabled" string="false">true` + parameterClose +
parameterOpen + ` name="items" string="false">["a","b"]` + parameterClose +
parameterOpen + ` name="options" string="false">{"unit":"c"}` + parameterClose +
@@ -103,7 +103,7 @@ func TestToolCallTypedParametersAndParallelInvocations(t *testing.T) {
}
want := map[string]any{
- "count": float64(42),
+ "count": json.Number("9007199254740993"),
"enabled": true,
"items": []any{"a", "b"},
"options": map[string]any{"unit": "c"},
diff --git a/sdk/kronk/parsers/fallback/fallback_test.go b/sdk/kronk/parsers/fallback/fallback_test.go
index 5f0d4b5cb..df19a7a91 100644
--- a/sdk/kronk/parsers/fallback/fallback_test.go
+++ b/sdk/kronk/parsers/fallback/fallback_test.go
@@ -44,3 +44,43 @@ func TestParserReasoningThenAnswer(t *testing.T) {
t.Errorf("answer: got %+v", got)
}
}
+
+func TestParserReasoningMarkersAtEverySplit(t *testing.T) {
+ const stream = "reasonanswer"
+ for split := range len(stream) + 1 {
+ sm := Parser{}.NewStateMachine()
+ var reasoning, answer string
+ for _, fragment := range []string{stream[:split], stream[split:]} {
+ result, _ := sm.Classify(fragment)
+ switch result.Channel {
+ case model.ChannelReasoning:
+ reasoning += result.Content
+ case model.ChannelAnswer:
+ answer += result.Content
+ }
+ }
+ flusher := sm.(model.StateMachineFlusher)
+ for result := flusher.Flush(); result != (model.Result{}); result = flusher.Flush() {
+ switch result.Channel {
+ case model.ChannelReasoning:
+ reasoning += result.Content
+ case model.ChannelAnswer:
+ answer += result.Content
+ }
+ }
+ if reasoning != "reason" || answer != "answer" {
+ t.Errorf("split %d: got reasoning %q answer %q", split, reasoning, answer)
+ }
+ }
+}
+
+func TestParserFlushesIncompleteReasoningMarker(t *testing.T) {
+ sm := Parser{}.NewStateMachine()
+ if result, _ := sm.Classify("answer":
- sm.status = model.ChannelReasoning
- return model.Result{}, false
+ sm.pending += content
+ for sm.pending != "" {
+ at, marker := nextReasoningMarker(sm.pending)
+ if at >= 0 {
+ sm.enqueue(sm.status, sm.pending[:at])
+ sm.pending = sm.pending[at+len(marker):]
+ if marker == thinkOpen {
+ sm.status = model.ChannelReasoning
+ } else {
+ sm.status = model.ChannelAnswer
+ }
+ continue
+ }
+
+ keep := partialReasoningMarkerSuffix(sm.pending)
+ sm.enqueue(sm.status, sm.pending[:len(sm.pending)-keep])
+ sm.pending = sm.pending[len(sm.pending)-keep:]
+ break
+ }
+
+ return sm.dequeue(), false
+}
- case "":
- sm.status = model.ChannelAnswer
- return model.Result{}, false
+func nextReasoningMarker(content string) (int, string) {
+ best := -1
+ var marker string
+ for _, candidate := range [...]string{thinkOpen, thinkClose} {
+ if at := strings.Index(content, candidate); at >= 0 && (best == -1 || at < best) {
+ best = at
+ marker = candidate
+ }
+ }
+ return best, marker
+}
- default:
- return model.Result{Channel: sm.status, Content: content}, false
+func partialReasoningMarkerSuffix(content string) int {
+ best := 0
+ for _, marker := range [...]string{thinkOpen, thinkClose} {
+ for size := 1; size < len(marker) && size <= len(content); size++ {
+ if strings.HasSuffix(content, marker[:size]) {
+ best = max(best, size)
+ }
+ }
+ }
+ return best
+}
+
+func (sm *stateMachine) enqueue(channel model.Channel, content string) {
+ if content == "" {
+ return
+ }
+ if len(sm.queue) > 0 && sm.queue[len(sm.queue)-1].Channel == channel {
+ sm.queue[len(sm.queue)-1].Content += content
+ return
+ }
+ sm.queue = append(sm.queue, model.Result{Channel: channel, Content: content})
+}
+
+func (sm *stateMachine) dequeue() model.Result {
+ if len(sm.queue) == 0 {
+ return model.Result{}
+ }
+ result := sm.queue[0]
+ sm.queue = sm.queue[1:]
+ return result
+}
+
+// Flush drains queued content and incomplete reasoning markers.
+func (sm *stateMachine) Flush() model.Result {
+ if len(sm.queue) > 0 {
+ return sm.dequeue()
+ }
+ if sm.pending == "" {
+ return model.Result{}
}
+ result := model.Result{Channel: sm.status, Content: sm.pending}
+ sm.pending = ""
+ return result
}
diff --git a/sdk/kronk/parsers/glm/glm.go b/sdk/kronk/parsers/glm/glm.go
index 5e23b9ef2..5c408095e 100644
--- a/sdk/kronk/parsers/glm/glm.go
+++ b/sdk/kronk/parsers/glm/glm.go
@@ -58,6 +58,15 @@ func (Parser) ToolCall(_ context.Context, _ applog.Logger, buf string) []model.R
return parseGLM(buf)
}
+// ToolCallWithSchema parses GLM tool calls and uses the declared tool schema
+// to recover argument types from the otherwise untyped argument tags.
+func (Parser) ToolCallWithSchema(_ context.Context, _ applog.Logger, buf string, tools []model.D) []model.ResponseToolCall {
+ toolCalls := parseGLM(buf)
+ normalizeGLMArguments(toolCalls, tools)
+
+ return toolCalls
+}
+
// containsGLMMarkers reports whether a chat template carries distinctive
// GLM tool-call tokens. The / pair is unique to GLM's
// tool-call format and unlikely to appear in any other lineage's template.
diff --git a/sdk/kronk/parsers/glm/toolparse.go b/sdk/kronk/parsers/glm/toolparse.go
index 70dfdb776..d811e9e09 100644
--- a/sdk/kronk/parsers/glm/toolparse.go
+++ b/sdk/kronk/parsers/glm/toolparse.go
@@ -1,8 +1,10 @@
package glm
import (
+ "encoding/json"
"errors"
"fmt"
+ "math/big"
"strings"
"uuid"
@@ -111,6 +113,137 @@ func failedGLMToolCall(raw string, err error) model.ResponseToolCall {
}
}
+func normalizeGLMArguments(toolCalls []model.ResponseToolCall, tools []model.D) {
+ for i := range toolCalls {
+ properties := glmToolProperties(tools, toolCalls[i].Function.Name)
+ if properties == nil {
+ continue
+ }
+
+ for name, value := range toolCalls[i].Function.Arguments {
+ raw, ok := value.(string)
+ if !ok {
+ continue
+ }
+
+ property, ok := properties[name].(model.D)
+ if !ok {
+ continue
+ }
+ schemaType, ok := glmSchemaType(property["type"])
+ if !ok || schemaType == "string" {
+ continue
+ }
+
+ if schemaType == "boolean" {
+ switch strings.ToLower(strings.TrimSpace(raw)) {
+ case "true":
+ toolCalls[i].Function.Arguments[name] = true
+ case "false":
+ toolCalls[i].Function.Arguments[name] = false
+ }
+ continue
+ }
+
+ parsed, ok := decodeGLMJSONValue(raw)
+ if !ok {
+ continue
+ }
+
+ switch schemaType {
+ case "object":
+ if _, ok := parsed.(map[string]any); ok {
+ toolCalls[i].Function.Arguments[name] = parsed
+ }
+
+ case "array":
+ if _, ok := parsed.([]any); ok {
+ toolCalls[i].Function.Arguments[name] = parsed
+ }
+
+ case "number":
+ if _, ok := parsed.(json.Number); ok {
+ toolCalls[i].Function.Arguments[name] = parsed
+ }
+
+ case "integer":
+ if number, ok := parsed.(json.Number); ok && glmJSONInteger(number) {
+ toolCalls[i].Function.Arguments[name] = parsed
+ }
+
+ case "null":
+ if parsed == nil {
+ toolCalls[i].Function.Arguments[name] = nil
+ }
+ }
+ }
+ }
+}
+
+func glmToolProperties(tools []model.D, name string) model.D {
+ var properties model.D
+ for _, tool := range tools {
+ if tool["type"] != "function" {
+ continue
+ }
+ function, ok := tool["function"].(model.D)
+ if !ok || function["name"] != name {
+ continue
+ }
+ if properties != nil {
+ return nil
+ }
+ parameters, ok := function["parameters"].(model.D)
+ if !ok {
+ return nil
+ }
+ properties, ok = parameters["properties"].(model.D)
+ if !ok {
+ return nil
+ }
+ }
+
+ return properties
+}
+
+func glmSchemaType(value any) (string, bool) {
+ switch value := value.(type) {
+ case string:
+ return value, true
+ case []any:
+ if len(value) == 1 {
+ schemaType, ok := value[0].(string)
+ return schemaType, ok
+ }
+ case []string:
+ if len(value) == 1 {
+ return value[0], true
+ }
+ }
+
+ return "", false
+}
+
+func decodeGLMJSONValue(raw string) (any, bool) {
+ if !json.Valid([]byte(raw)) {
+ return nil, false
+ }
+
+ decoder := json.NewDecoder(strings.NewReader(raw))
+ decoder.UseNumber()
+ var value any
+ if err := decoder.Decode(&value); err != nil {
+ return nil, false
+ }
+
+ return value, true
+}
+
+func glmJSONInteger(number json.Number) bool {
+ value, ok := new(big.Rat).SetString(number.String())
+ return ok && value.IsInt()
+}
+
func newToolCallID() string {
return "call_" + uuid.New().String()
}
diff --git a/sdk/kronk/parsers/glm/toolparse_test.go b/sdk/kronk/parsers/glm/toolparse_test.go
index 8028c1e26..310aa61ba 100644
--- a/sdk/kronk/parsers/glm/toolparse_test.go
+++ b/sdk/kronk/parsers/glm/toolparse_test.go
@@ -2,9 +2,12 @@ package glm
import (
"context"
+ "encoding/json"
+ "reflect"
"testing"
"github.com/ardanlabs/kronk/sdk/kronk/applog"
+ "github.com/ardanlabs/kronk/sdk/kronk/model"
)
var noopLog applog.Logger = func(context.Context, string, ...any) {}
@@ -50,6 +53,49 @@ func TestParseGLM_MultipleArgs(t *testing.T) {
}
}
+func TestToolCallWithSchema(t *testing.T) {
+ tools := []model.D{{
+ "type": "function",
+ "function": model.D{
+ "name": "convert",
+ "parameters": model.D{
+ "properties": model.D{
+ "text": model.D{"type": "string"},
+ "enabled": model.D{"type": "boolean"},
+ "count": model.D{"type": "integer"},
+ "ratio": model.D{"type": "number"},
+ "items": model.D{"type": "array"},
+ "options": model.D{"type": "object"},
+ },
+ },
+ },
+ }}
+
+ content := "convert" +
+ "texttrue" +
+ "enabledtrue" +
+ "count9007199254740993" +
+ "ratio1.5" +
+ "items[1,2]" +
+ "options{\"unit\":\"c\"}"
+ calls := Parser{}.ToolCallWithSchema(context.Background(), noopLog, content, tools)
+ if len(calls) != 1 || calls[0].Status != 0 {
+ t.Fatalf("ToolCallWithSchema: got %+v, want one successful call", calls)
+ }
+
+ want := model.ToolCallArguments{
+ "text": "true",
+ "enabled": true,
+ "count": json.Number("9007199254740993"),
+ "ratio": json.Number("1.5"),
+ "items": []any{json.Number("1"), json.Number("2")},
+ "options": map[string]any{"unit": "c"},
+ }
+ if got := calls[0].Function.Arguments; !reflect.DeepEqual(got, want) {
+ t.Errorf("Arguments: got %#v, want %#v", got, want)
+ }
+}
+
func TestParseGLM_StructuralWhitespace(t *testing.T) {
calls := parseGLM("get_weathercity \t\nNYC \r\nunitsC")
if len(calls) != 1 || calls[0].Status != 0 {
diff --git a/sdk/kronk/parsers/lfm/lfm_test.go b/sdk/kronk/parsers/lfm/lfm_test.go
index c71bb03f6..2572a91ea 100644
--- a/sdk/kronk/parsers/lfm/lfm_test.go
+++ b/sdk/kronk/parsers/lfm/lfm_test.go
@@ -61,6 +61,16 @@ func TestPythonToolCalls(t *testing.T) {
}
}
+func TestUnbracketedCommaSeparatedPythonToolCalls(t *testing.T) {
+ calls := Parser{}.ToolCall(context.Background(), nil, `first(x=1), second(y=2)`)
+ if len(calls) != 2 || calls[0].Status != 0 || calls[1].Status != 0 {
+ t.Fatalf("calls: got %#v, want two successful calls", calls)
+ }
+ if calls[0].Function.Name != "first" || calls[1].Function.Name != "second" {
+ t.Errorf("names: got %q and %q, want first and second", calls[0].Function.Name, calls[1].Function.Name)
+ }
+}
+
func TestJSONToolCallsAndSerialization(t *testing.T) {
input := `[{"name":"one","arguments":{"number":9007199254740993,"text":"42","object":{"x":true}}},{"name":"two","arguments":{"nil":null}}]`
calls := Parser{}.ToolCall(context.Background(), nil, input)
diff --git a/sdk/kronk/parsers/lfm/toolparse.go b/sdk/kronk/parsers/lfm/toolparse.go
index 8c44c3d1a..05bbc01e6 100644
--- a/sdk/kronk/parsers/lfm/toolparse.go
+++ b/sdk/kronk/parsers/lfm/toolparse.go
@@ -129,6 +129,12 @@ func splitPayloads(content string) []string {
end := pos + 1
payloads = append(payloads, strings.TrimSpace(content[start:end]))
start = skipWhitespace(content, end)
+ if start < len(content) && content[start] == ',' {
+ start = skipWhitespace(content, start+1)
+ if start == len(content) {
+ return nil
+ }
+ }
pos = start - 1
}
}
diff --git a/sdk/kronk/parsers/qwen/qwen_test.go b/sdk/kronk/parsers/qwen/qwen_test.go
index 660c167cf..a44a12e56 100644
--- a/sdk/kronk/parsers/qwen/qwen_test.go
+++ b/sdk/kronk/parsers/qwen/qwen_test.go
@@ -89,15 +89,22 @@ func TestParser_ReasoningThenAnswer(t *testing.T) {
func TestParser_JSONToolCall(t *testing.T) {
c := Parser{}.NewStateMachine()
+ var tooling strings.Builder
runSteps(t, "json-tool-call", c, []step{
{token: "", channel: model.ChannelTool},
{token: `{"name":"a","arguments":{}}`, channel: model.ChannelNone},
{token: "", channel: model.ChannelTool,
content: `{"name":"a","arguments":{}}` + "\n"},
})
- _, eog := c.Classify("done")
- if !eog {
- t.Errorf("expected EOG after tool call closed")
+ tooling.WriteString(`{"name":"a","arguments":{}}` + "\n")
+ result, eog := c.Classify("done")
+ if eog || result.Channel != model.ChannelTool || result.Content != "done" {
+ t.Fatalf("unexpected continuation: got (%+v, %v), want preserved tool content", result, eog)
+ }
+ tooling.WriteString(result.Content)
+ calls := Parser{}.ToolCall(t.Context(), nil, tooling.String())
+ if len(calls) != 1 || calls[0].Status == 0 || calls[0].Function.Name != "" {
+ t.Fatalf("ToolCall: got %+v, want one non-executable failed call", calls)
}
}
diff --git a/sdk/kronk/parsers/qwen/state_machine.go b/sdk/kronk/parsers/qwen/state_machine.go
index 515057bb1..36ec8deb6 100644
--- a/sdk/kronk/parsers/qwen/state_machine.go
+++ b/sdk/kronk/parsers/qwen/state_machine.go
@@ -151,17 +151,12 @@ func (sm *stateMachine) Classify(content string) (model.Result, bool) {
return model.Result{}, false
}
}
- if sm.directToolCallDone {
- // Preserve every unexpected continuation after direct XML for the
- // final parser. If it were discarded here, token boundaries could
- // turn malformed nested delimiter text into valid-looking calls.
- sm.toolCallDone = false
- sm.directToolCallDone = false
- return model.Result{Channel: model.ChannelTool, Content: content}, false
- }
+ // Preserve every unexpected continuation for the final parser. If it
+ // were discarded here, malformed output could leave an executable
+ // valid-looking call prefix.
sm.toolCallDone = false
sm.directToolCallDone = false
- return model.Result{}, true
+ return model.Result{Channel: model.ChannelTool, Content: content}, false
}
}
diff --git a/sdk/kronk/parsers/qwen/toolparse.go b/sdk/kronk/parsers/qwen/toolparse.go
index a6af2f1bb..8df3ca904 100644
--- a/sdk/kronk/parsers/qwen/toolparse.go
+++ b/sdk/kronk/parsers/qwen/toolparse.go
@@ -5,6 +5,7 @@ import (
"encoding/json"
"errors"
"fmt"
+ "io"
"math/big"
"strings"
@@ -275,54 +276,187 @@ func isJSONInteger(number json.Number) bool {
// parseJSON parses tool calls in the OpenAI JSON envelope format used inside
// Qwen's … wrappers.
func parseJSON(ctx context.Context, log applog.Logger, content string) []model.ResponseToolCall {
- var toolCalls []model.ResponseToolCall
-
- remaining := content
- for len(remaining) > 0 {
- remaining = strings.TrimLeft(remaining, " \t\n\r")
- if len(remaining) == 0 {
- break
- }
+ raw := content
+ remaining := strings.TrimLeft(content, " \t\n\r")
+ if remaining == "" {
+ return []model.ResponseToolCall{failedJSONToolCall(raw, errors.New("parse qwen JSON: tool call is empty"))}
+ }
+ var toolCalls []model.ResponseToolCall
+ for remaining != "" {
if remaining[0] != '{' {
- idx := strings.Index(remaining, "{")
- if idx == -1 {
- break
- }
- remaining = remaining[idx:]
+ return []model.ResponseToolCall{failedJSONToolCall(raw, errors.New("parse qwen JSON: unexpected content outside tool call object"))}
}
- jsonEnd := findJSONObjectEnd(remaining)
- if jsonEnd == -1 {
- jsonEnd = len(remaining)
+ end := findJSONObjectEnd(remaining)
+ if end < 0 {
+ return []model.ResponseToolCall{failedJSONToolCall(raw, errors.New("parse qwen JSON: incomplete tool call object"))}
}
- call := remaining[:jsonEnd]
- remaining = remaining[jsonEnd:]
-
- toolCall := model.ResponseToolCall{
- ID: newToolCallID(),
- Type: "function",
+ call := remaining[:end]
+ function, err := decodeQwenFunction(call)
+ if err != nil {
+ function, err = repairQwenFunction(call, err)
}
-
- if err := jsonrepair.Unmarshal(call, &toolCall.Function); err != nil {
+ if err != nil {
if log != nil {
log(ctx, "jsonrepair", "status", "unmarshal-failed",
"format", "json", "error", err, "json", call)
}
- toolCall.Status = 2
- toolCall.Error = err.Error()
- toolCall.Raw = call
+ return []model.ResponseToolCall{failedJSONToolCall(raw, err)}
}
- toolCall.Function.Name = strings.TrimPrefix(toolCall.Function.Name, ".")
+ function.Name = strings.TrimPrefix(function.Name, ".")
+ if function.Name == "" {
+ return []model.ResponseToolCall{failedJSONToolCall(raw, errors.New("parse qwen JSON: tool call name is empty"))}
+ }
- toolCalls = append(toolCalls, toolCall)
+ toolCalls = append(toolCalls, model.ResponseToolCall{
+ ID: newToolCallID(),
+ Type: "function",
+ Function: function,
+ })
+ remaining = strings.TrimLeft(remaining[end:], " \t\n\r")
}
return toolCalls
}
+func failedJSONToolCall(raw string, err error) model.ResponseToolCall {
+ return model.ResponseToolCall{ID: newToolCallID(), Type: "function", Status: 2, Raw: raw, Error: err.Error()}
+}
+
+func repairQwenFunction(raw string, original error) (model.ResponseToolCallFunction, error) {
+ repaired, err := jsonrepair.Repair(raw)
+ if err != nil || !qwenRepairOnlyAddsEscapes(raw, repaired) {
+ return model.ResponseToolCallFunction{}, original
+ }
+
+ return decodeQwenFunction(repaired)
+}
+
+func qwenRepairOnlyAddsEscapes(raw, repaired string) bool {
+ for rawPos, repairedPos := 0, 0; rawPos < len(raw) || repairedPos < len(repaired); {
+ if rawPos < len(raw) && repairedPos < len(repaired) && raw[rawPos] == repaired[repairedPos] {
+ rawPos++
+ repairedPos++
+ continue
+ }
+ if repairedPos < len(repaired) && repaired[repairedPos] == '\\' {
+ repairedPos++
+ continue
+ }
+ return false
+ }
+
+ return true
+}
+
+func decodeQwenFunction(raw string) (model.ResponseToolCallFunction, error) {
+ value, err := decodeUniqueQwenJSON(raw)
+ if err != nil {
+ return model.ResponseToolCallFunction{}, err
+ }
+
+ envelope, ok := value.(map[string]any)
+ if !ok {
+ return model.ResponseToolCallFunction{}, errors.New("parse qwen JSON: tool call must be an object")
+ }
+ name, ok := envelope["name"].(string)
+ if !ok || name == "" {
+ return model.ResponseToolCallFunction{}, errors.New("parse qwen JSON: tool call name is empty")
+ }
+
+ argumentValue, ok := envelope["arguments"]
+ if !ok {
+ return model.ResponseToolCallFunction{}, errors.New("parse qwen JSON: tool call arguments must be an object")
+ }
+ if encoded, ok := argumentValue.(string); ok {
+ argumentValue, err = decodeUniqueQwenJSON(encoded)
+ if err != nil {
+ return model.ResponseToolCallFunction{}, fmt.Errorf("parse qwen JSON: invalid tool arguments: %w", err)
+ }
+ }
+ arguments, ok := argumentValue.(map[string]any)
+ if !ok {
+ return model.ResponseToolCallFunction{}, errors.New("parse qwen JSON: tool call arguments must be an object")
+ }
+
+ return model.ResponseToolCallFunction{Name: name, Arguments: model.ToolCallArguments(arguments)}, nil
+}
+
+func decodeUniqueQwenJSON(raw string) (any, error) {
+ decoder := json.NewDecoder(strings.NewReader(raw))
+ decoder.UseNumber()
+
+ value, err := decodeUniqueQwenJSONValue(decoder)
+ if err != nil {
+ return nil, err
+ }
+ if _, err := decoder.Token(); !errors.Is(err, io.EOF) {
+ if err == nil {
+ return nil, errors.New("parse qwen JSON: unexpected data after JSON value")
+ }
+ return nil, err
+ }
+
+ return value, nil
+}
+
+func decodeUniqueQwenJSONValue(decoder *json.Decoder) (any, error) {
+ token, err := decoder.Token()
+ if err != nil {
+ return nil, err
+ }
+ delim, ok := token.(json.Delim)
+ if !ok {
+ return token, nil
+ }
+
+ switch delim {
+ case '{':
+ object := make(map[string]any)
+ for decoder.More() {
+ keyToken, err := decoder.Token()
+ if err != nil {
+ return nil, err
+ }
+ key, ok := keyToken.(string)
+ if !ok {
+ return nil, errors.New("parse qwen JSON: object key is not a string")
+ }
+ if _, exists := object[key]; exists {
+ return nil, fmt.Errorf("parse qwen JSON: duplicate key %q", key)
+ }
+ value, err := decodeUniqueQwenJSONValue(decoder)
+ if err != nil {
+ return nil, err
+ }
+ object[key] = value
+ }
+ if token, err := decoder.Token(); err != nil || token != json.Delim('}') {
+ return nil, errors.New("parse qwen JSON: object is not closed")
+ }
+ return object, nil
+
+ case '[':
+ var array []any
+ for decoder.More() {
+ value, err := decodeUniqueQwenJSONValue(decoder)
+ if err != nil {
+ return nil, err
+ }
+ array = append(array, value)
+ }
+ if token, err := decoder.Token(); err != nil || token != json.Delim(']') {
+ return nil, errors.New("parse qwen JSON: array is not closed")
+ }
+ return array, nil
+ }
+
+ return nil, fmt.Errorf("parse qwen JSON: unexpected delimiter %q", delim)
+}
+
func findJSONObjectEnd(s string) int {
if len(s) == 0 || s[0] != '{' {
idx := strings.Index(s, "{")
diff --git a/sdk/kronk/parsers/qwen/toolparse_test.go b/sdk/kronk/parsers/qwen/toolparse_test.go
index 7382e124c..38d79f93c 100644
--- a/sdk/kronk/parsers/qwen/toolparse_test.go
+++ b/sdk/kronk/parsers/qwen/toolparse_test.go
@@ -315,3 +315,30 @@ func TestParseJSON_Multiple(t *testing.T) {
t.Errorf("names = %v, want [a, b]", names)
}
}
+
+func TestParseJSON_RejectsMalformedOutputAtomically(t *testing.T) {
+ tests := []struct {
+ name string
+ content string
+ }{
+ {name: "leading garbage", content: `junk{"name":"safe","arguments":{}}`},
+ {name: "trailing garbage", content: `{"name":"safe","arguments":{}}junk`},
+ {name: "empty name", content: `{"name":"","arguments":{}}`},
+ {name: "duplicate name", content: `{"name":"safe","name":"unsafe","arguments":{}}`},
+ {name: "duplicate argument", content: `{"name":"safe","arguments":{"command":"echo safe","command":"id"}}`},
+ {name: "escaped duplicate argument", content: `{"name":"safe","arguments":{"command":"echo safe","\u0063ommand":"id"}}`},
+ {name: "non-object arguments", content: `{"name":"safe","arguments":[]}`},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ calls := parseJSON(context.Background(), noopLog, tt.content)
+ if len(calls) != 1 || calls[0].Status == 0 || calls[0].Function.Name != "" {
+ t.Fatalf("parseJSON: got %+v, want one non-executable failed call", calls)
+ }
+ if calls[0].Raw != tt.content {
+ t.Errorf("Raw: got %q, want %q", calls[0].Raw, tt.content)
+ }
+ })
+ }
+}
diff --git a/sdk/kronk/pool/config_test.go b/sdk/kronk/pool/config_test.go
index 8b5ac6ae2..405a77d76 100644
--- a/sdk/kronk/pool/config_test.go
+++ b/sdk/kronk/pool/config_test.go
@@ -9,6 +9,26 @@ import (
"github.com/ardanlabs/kronk/sdk/tools/models"
)
+func TestCatalogModelID(t *testing.T) {
+ tests := []struct {
+ name string
+ key string
+ want string
+ }{
+ {name: "catalog model", key: "provider/model", want: "provider/model"},
+ {name: "profile", key: "provider/model/agent", want: "provider/model/agent"},
+ {name: "playground", key: "provider/model/playground/session-1", want: "provider/model"},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ if got := catalogModelID(tt.key); got != tt.want {
+ t.Errorf("catalogModelID(%q): got %q, want %q", tt.key, got, tt.want)
+ }
+ })
+ }
+}
+
func TestValidateConfigTTL(t *testing.T) {
tests := []struct {
name string
diff --git a/sdk/kronk/pool/llama.go b/sdk/kronk/pool/llama.go
index fba26336c..7ae8916ff 100644
--- a/sdk/kronk/pool/llama.go
+++ b/sdk/kronk/pool/llama.go
@@ -82,6 +82,17 @@ func (l *Llama) ResolvedModelConfig(modelID string) (models.ModelConfig, error)
)
}
+// ResolvedKronkConfig returns the same budgeted runtime configuration used to
+// prepare a model for planning and loading.
+func (l *Llama) ResolvedKronkConfig(modelID string) (model.Config, error) {
+ return l.models.KronkResolvedConfigWithBudget(
+ modelID,
+ l.modelConfig,
+ l.autoTuneBudget(modelID),
+ effectiveSWAFull(model.Config{}),
+ )
+}
+
// Prepare resolves the model configuration once for both planning and loading.
func (l *Llama) Prepare(_ context.Context, req loader.LoadRequest) (any, error) {
return l.resolveConfig(req)
@@ -608,60 +619,18 @@ func nGpuLayersName(p *int) string {
// Display implements loader.Loader.Display for the llama backend.
//
// It returns the KV cache and total VRAM values to surface in
-// BUI/observability output for a loaded model. Both this path and the
-// SDK-internal calculateVRAMDiag route through vram.FromFiles, so the
-// two computations are byte-identical for any well-formed local model.
-// The dedicated lookup is retained so a hypothetical resman-side
-// failure (e.g. an index miss) cleanly falls back to the values the
-// SDK stored at load time rather than zeroing out the BUI display.
-func (l *Llama) Display(krn *kronk.Kronk, modelID string) loader.Display {
+// BUI/observability output for a loaded model. The SDK calculated and stored
+// these values while loading the model, so status queries do not need to read
+// and parse the GGUF header again.
+func (l *Llama) Display(krn *kronk.Kronk, _ string) loader.Display {
cfg := krn.ModelConfig()
mi := krn.ModelInfo()
- ctxWin := int64(cfg.ContextWindow())
- if ctxWin <= 0 {
- ctxWin = int64(vram.ContextWindow8K)
- }
-
- nseq := int64(cfg.NSeqMax())
- if nseq <= 0 {
- nseq = 1
+ return loader.Display{
+ KVCache: mi.SlotMemory,
+ VRAMTotal: mi.VRAMTotal,
+ Slots: max(int(cfg.NSeqMax()), 1),
}
-
- vramCfg := vram.Config{
- ContextWindow: ctxWin,
- BytesPerElement: bytesPerElement(cfg.CacheTypeK, cfg.CacheTypeV),
- TypeK: int32(cfg.CacheTypeK),
- TypeV: int32(cfg.CacheTypeV),
- Slots: nseq,
- NUBatch: effectivePrefillBatchSize(cfg),
- ExpertLayersOnGPU: cfg.ExpertLayersOnGPU(),
- GPULayers: int64(cfg.NGpuLayers()),
- KVCacheOnCPU: cfg.PtrOffloadKQV != nil && !*cfg.PtrOffloadKQV,
- SWAFull: effectiveSWAFull(cfg),
- VTransposed: cfg.FlashAttention() == model.FlashAttentionDisabled,
- RecurrentStateCopies: model.RecurrentStateCopies(cfg, false),
- EmbeddedMTPStateCopies: model.RecurrentStateCopies(cfg, true),
- ComputeContexts: model.SpeculativeContextCount(cfg),
- }
-
- out := loader.Display{
- Slots: max(int(cfg.NSeqMax()), 1),
- }
-
- if v, err := l.models.CalculateVRAM(modelID, vramCfg); err == nil {
- out.KVCache = v.SlotMemory
- if l.resman.UnifiedMemory() {
- out.VRAMTotal = v.UnifiedFootprint()
- } else {
- out.VRAMTotal = v.TotalVRAM
- }
- return out
- }
-
- out.KVCache = mi.SlotMemory
- out.VRAMTotal = mi.VRAMTotal
- return out
}
// effectiveSWAFull mirrors modelCtxParams without mutating the user config:
diff --git a/sdk/kronk/pool/pool.go b/sdk/kronk/pool/pool.go
index 36e8ff033..ca36ddf6e 100644
--- a/sdk/kronk/pool/pool.go
+++ b/sdk/kronk/pool/pool.go
@@ -156,6 +156,7 @@ func New(cfg Config) (*Pool, error) {
Resman: cfg.Resman,
MaxItems: cfg.ModelsInPool,
TTL: cfg.TTL,
+ Backend: "kronk",
}, llama)
if err != nil {
return nil, fmt.Errorf("new: constructing pool core: %w", err)
@@ -214,20 +215,13 @@ func (p *Pool) AquireModel(ctx context.Context, modelID string) (*kronk.Kronk, e
// This bypasses the normal catalog resolution path. The key includes the
// canonical model ID followed by the custom workload name.
func (p *Pool) AquireCustom(ctx context.Context, key string, cfg model.Config) (*kronk.Kronk, error) {
- modelID := strings.TrimSuffix(key, "/accuracy")
- modelID = strings.TrimSuffix(modelID, "/efficiency")
- if before, _, found := strings.Cut(modelID, "/playground/"); found {
- modelID = before
- }
- if modelID == key {
- return nil, fmt.Errorf("acquire-custom: invalid key %q", key)
- }
- if _, err := models.ParseModelID(modelID); err != nil {
- return nil, fmt.Errorf("acquire-custom: %w", err)
+ modelID, err := customModelID(key)
+ if err != nil {
+ return nil, err
}
cfg.ResponseModelID = modelID
if cfg.AutoTune && !cfg.AutoTuned {
- cfg = kronk.AutoTuneConfig(ctx, cfg)
+ cfg = kronk.AutoTuneConfigWithBudget(ctx, cfg, p.llama.autoTuneBudget(modelID))
}
krn, err := p.engine.Acquire(ctx, loader.LoadRequest{
ModelID: modelID,
@@ -237,6 +231,26 @@ func (p *Pool) AquireCustom(ctx context.Context, key string, cfg model.Config) (
return krn, translateCapacityError(err)
}
+func customModelID(key string) (string, error) {
+ if _, err := models.ParseModelID(key); err == nil {
+ return "", fmt.Errorf("acquire-custom: key %q collides with a catalog model id", key)
+ }
+
+ modelID := strings.TrimSuffix(key, "/custom/accuracy")
+ modelID = strings.TrimSuffix(modelID, "/custom/efficiency")
+ if before, _, found := strings.Cut(modelID, "/playground/"); found {
+ modelID = before
+ }
+ if modelID == key {
+ return "", fmt.Errorf("acquire-custom: invalid key %q", key)
+ }
+ if _, err := models.ParseModelID(modelID); err != nil {
+ return "", fmt.Errorf("acquire-custom: %w", err)
+ }
+
+ return modelID, nil
+}
+
// translateCapacityError exposes resource-manager capacity failures through
// this package's public sentinel while preserving the detailed original error.
func translateCapacityError(err error) error {
@@ -257,6 +271,12 @@ func (p *Pool) ResolvedModelConfig(modelID string) (models.ModelConfig, error) {
return p.llama.ResolvedModelConfig(modelID)
}
+// ResolvedKronkConfig returns the same budgeted runtime configuration used to
+// prepare a model for planning and loading.
+func (p *Pool) ResolvedKronkConfig(modelID string) (model.Config, error) {
+ return p.llama.ResolvedKronkConfig(modelID)
+}
+
// GetExisting returns a pooled model if it exists, without creating
// one.
func (p *Pool) GetExisting(key string) (*kronk.Kronk, bool) {
@@ -273,8 +293,9 @@ func (p *Pool) Invalidate(key string) {
p.engine.Invalidate(key)
}
-// InvalidateSync invalidates a cache entry and waits for the eviction
-// callback to release the underlying resource manager reservation.
+// InvalidateSync invalidates a cache entry and waits for the eviction callback
+// to release the underlying resource manager reservation. If unloading fails,
+// the model and reservation remain in the pool and the error is returned.
func (p *Pool) InvalidateSync(ctx context.Context, key string) error {
return p.engine.InvalidateSync(ctx, key)
}
@@ -295,15 +316,42 @@ func (p *Pool) InvalidateSync(ctx context.Context, key string) error {
func (p *Pool) ModelStatus() ([]ModelDetail, error) {
ps := make([]ModelDetail, 0)
loadedKeys := make(map[string]struct{})
+ entries := slices.Collect(p.engine.Coldest())
+ usage := p.resman.Usage()
+
+ // Build the catalog view once per status request. Looking it up for every
+ // loaded key rereads and decodes the index and stats every installed model.
+ filesByID := make(map[string]models.File)
+ if files, err := p.models.Files(); err == nil {
+ for _, file := range files {
+ filesByID[file.OwnedBy+"/"+file.ID] = file
+ }
+ }
+
+ reservationBytes := make(map[string]int64, len(usage.Reservations))
+ for _, reservation := range usage.Reservations {
+ reservationBytes[reservation.Key] = reservation.VRAMBytes + reservation.RAMBytes
+ }
- for entry := range p.engine.Coldest() {
- mi, ok := p.models.LookupFile(entry.Key)
+ for _, entry := range entries {
+ modelID, err := models.ParseModelID(catalogModelID(entry.Key))
+ if err != nil {
+ continue
+ }
+
+ mi, ok := filesByID[modelID.Base()]
if !ok {
continue
}
krn := entry.Value
- disp := p.llama.Display(krn, mi.ID)
+ disp := p.llama.Display(krn, modelID.Base())
+
+ if usage.UnifiedMemory {
+ if bytes, exists := reservationBytes[entry.Key]; exists {
+ disp.VRAMTotal = bytes
+ }
+ }
ps = append(ps, ModelDetail{
ID: entry.Key,
@@ -331,7 +379,7 @@ func (p *Pool) ModelStatus() ([]ModelDetail, error) {
// p.engine.HasTicket to only surface kronk's own in-flight loads.
// Without this guard, bucky reservations leak in as fake "loading"
// kronk entries with no size/owner/family populated.
- for _, r := range p.resman.Usage().Reservations {
+ for _, r := range usage.Reservations {
if _, ok := loadedKeys[r.Key]; ok {
continue
}
@@ -341,10 +389,12 @@ func (p *Pool) ModelStatus() ([]ModelDetail, error) {
var ownedBy, modelFamily string
var size int64
- if mi, ok := p.models.LookupFile(r.Key); ok {
- ownedBy = mi.OwnedBy
- modelFamily = mi.ModelFamily
- size = mi.Size
+ if modelID, err := models.ParseModelID(catalogModelID(r.Key)); err == nil {
+ if mi, ok := filesByID[modelID.Base()]; ok {
+ ownedBy = mi.OwnedBy
+ modelFamily = mi.ModelFamily
+ size = mi.Size
+ }
}
ps = append(ps, ModelDetail{
@@ -361,6 +411,13 @@ func (p *Pool) ModelStatus() ([]ModelDetail, error) {
return ps, nil
}
+func catalogModelID(key string) string {
+ if modelID, _, found := strings.Cut(key, "/playground/"); found {
+ return modelID
+ }
+ return key
+}
+
// IMCSessions returns the current IMC cache entries for loaded models. It does
// not load models or retain session history.
func (p *Pool) IMCSessions() []IMCSessionDetail {
diff --git a/sdk/kronk/pool/pool_key_test.go b/sdk/kronk/pool/pool_key_test.go
new file mode 100644
index 000000000..820c8874e
--- /dev/null
+++ b/sdk/kronk/pool/pool_key_test.go
@@ -0,0 +1,39 @@
+package pool
+
+import (
+ "strings"
+ "testing"
+)
+
+func TestCustomModelID(t *testing.T) {
+ tests := []struct {
+ name string
+ key string
+ want string
+ wantErr string
+ }{
+ {name: "accuracy", key: "owner/model/custom/accuracy", want: "owner/model"},
+ {name: "efficiency profile", key: "owner/model/profile/custom/efficiency", want: "owner/model/profile"},
+ {name: "playground", key: "owner/model/playground/session", want: "owner/model"},
+ {name: "catalog collision", key: "owner/model/accuracy", wantErr: "collides"},
+ {name: "unknown workload", key: "owner/model/custom/unknown", wantErr: "invalid key"},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got, err := customModelID(tt.key)
+ if tt.wantErr != "" {
+ if err == nil || !strings.Contains(err.Error(), tt.wantErr) {
+ t.Fatalf("customModelID: got %q, %v, want error containing %q", got, err, tt.wantErr)
+ }
+ return
+ }
+ if err != nil {
+ t.Fatalf("customModelID: %v", err)
+ }
+ if got != tt.want {
+ t.Errorf("customModelID: got %q, want %q", got, tt.want)
+ }
+ })
+ }
+}
diff --git a/sdk/kronk/rerank.go b/sdk/kronk/rerank.go
index e07fb627a..0182afde0 100644
--- a/sdk/kronk/rerank.go
+++ b/sdk/kronk/rerank.go
@@ -47,7 +47,9 @@ func (krn *Kronk) RerankHTTP(ctx context.Context, log Logger, w http.ResponseWri
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
- w.Write(data)
+ if _, err := w.Write(data); err != nil {
+ return resp, fmt.Errorf("rerank-http: %w: write response: %w", ErrResponseCommitted, err)
+ }
return resp, nil
}
diff --git a/sdk/kronk/response.go b/sdk/kronk/response.go
index cc263b4d0..9189ad469 100644
--- a/sdk/kronk/response.go
+++ b/sdk/kronk/response.go
@@ -283,14 +283,15 @@ type streamState struct {
params inputParams
d model.D
seq int
- outputIndex int
- contentIndex int
+ nextOutputIndex int
+ msgOutputIndex int
msgID string
msgItemEmitted bool
fullText string
fullReasoning string
fcItems []ResponseOutputItem
fcIDs []string
+ fcOutputIndexes []int
fcArgsAccum []string
toolCallsSeenID map[string]int
lastChatResp model.ChatResponse
@@ -454,12 +455,14 @@ func (ss *streamState) handleTextDelta(delta string) []ResponseStreamEvent {
}
ss.fullText += delta
+ outputIndex := ss.msgOutputIndex
+ contentIndex := 0
events = append(events, ResponseStreamEvent{
Type: "response.output_text.delta",
SequenceNumber: ss.seq,
ItemID: ss.msgID,
- OutputIndex: &ss.outputIndex,
- ContentIndex: &ss.contentIndex,
+ OutputIndex: &outputIndex,
+ ContentIndex: &contentIndex,
Delta: delta,
})
ss.seq++
@@ -470,6 +473,8 @@ func (ss *streamState) handleTextDelta(delta string) []ResponseStreamEvent {
func (ss *streamState) emitMessageItemAdded() []ResponseStreamEvent {
ss.msgID = "msg_" + uuid.New().String()
ss.msgItemEmitted = true
+ ss.msgOutputIndex = ss.nextOutputIndex
+ ss.nextOutputIndex++
outputItem := ResponseOutputItem{
Type: "message",
@@ -480,12 +485,14 @@ func (ss *streamState) emitMessageItemAdded() []ResponseStreamEvent {
{Type: "output_text", Text: "", Annotations: []string{}},
},
}
+ outputIndex := ss.msgOutputIndex
+ contentIndex := 0
events := []ResponseStreamEvent{
{
Type: "response.output_item.added",
SequenceNumber: ss.seq,
- OutputIndex: &ss.outputIndex,
+ OutputIndex: &outputIndex,
Item: &outputItem,
},
}
@@ -496,8 +503,8 @@ func (ss *streamState) emitMessageItemAdded() []ResponseStreamEvent {
Type: "response.content_part.added",
SequenceNumber: ss.seq,
ItemID: ss.msgID,
- OutputIndex: &ss.outputIndex,
- ContentIndex: &ss.contentIndex,
+ OutputIndex: &outputIndex,
+ ContentIndex: &contentIndex,
Part: &contentPart,
})
ss.seq++
@@ -518,13 +525,11 @@ func (ss *streamState) handleToolCalls(toolCalls []model.ResponseToolCall) []Res
idx = len(ss.fcItems)
ss.toolCallsSeenID[tc.ID] = idx
- if ss.msgItemEmitted {
- ss.outputIndex++
- }
-
fcID := fmt.Sprintf("call_%s", uuid.New().String())
ss.fcIDs = append(ss.fcIDs, fcID)
ss.fcArgsAccum = append(ss.fcArgsAccum, "")
+ ss.fcOutputIndexes = append(ss.fcOutputIndexes, ss.nextOutputIndex)
+ ss.nextOutputIndex++
emptyArgs := ""
fcItem := ResponseOutputItem{
@@ -537,7 +542,7 @@ func (ss *streamState) handleToolCalls(toolCalls []model.ResponseToolCall) []Res
}
ss.fcItems = append(ss.fcItems, fcItem)
- outIdx := ss.outputIndex + idx
+ outIdx := ss.fcOutputIndexes[idx]
events = append(events, ResponseStreamEvent{
Type: "response.output_item.added",
SequenceNumber: ss.seq,
@@ -552,7 +557,7 @@ func (ss *streamState) handleToolCalls(toolCalls []model.ResponseToolCall) []Res
ss.fcArgsAccum[idx] = argsDelta
- outIdx := ss.outputIndex + idx
+ outIdx := ss.fcOutputIndexes[idx]
events = append(events, ResponseStreamEvent{
Type: "response.function_call_arguments.delta",
SequenceNumber: ss.seq,
@@ -567,13 +572,15 @@ func (ss *streamState) handleToolCalls(toolCalls []model.ResponseToolCall) []Res
}
func (ss *streamState) finalizeMessageItem() []ResponseStreamEvent {
+ outputIndex := ss.msgOutputIndex
+ contentIndex := 0
events := []ResponseStreamEvent{
{
Type: "response.output_text.done",
SequenceNumber: ss.seq,
ItemID: ss.msgID,
- OutputIndex: &ss.outputIndex,
- ContentIndex: &ss.contentIndex,
+ OutputIndex: &outputIndex,
+ ContentIndex: &contentIndex,
Text: ss.fullText,
},
}
@@ -584,8 +591,8 @@ func (ss *streamState) finalizeMessageItem() []ResponseStreamEvent {
Type: "response.content_part.done",
SequenceNumber: ss.seq,
ItemID: ss.msgID,
- OutputIndex: &ss.outputIndex,
- ContentIndex: &ss.contentIndex,
+ OutputIndex: &outputIndex,
+ ContentIndex: &contentIndex,
Part: &contentPart,
})
ss.seq++
@@ -602,7 +609,7 @@ func (ss *streamState) finalizeMessageItem() []ResponseStreamEvent {
events = append(events, ResponseStreamEvent{
Type: "response.output_item.done",
SequenceNumber: ss.seq,
- OutputIndex: &ss.outputIndex,
+ OutputIndex: &outputIndex,
Item: &outputItem,
})
ss.seq++
@@ -614,10 +621,7 @@ func (ss *streamState) finalizeToolCalls() []ResponseStreamEvent {
var events []ResponseStreamEvent
for i, fcItem := range ss.fcItems {
- outIdx := ss.outputIndex + i
- if ss.msgItemEmitted {
- outIdx = ss.outputIndex + i + 1
- }
+ outIdx := ss.fcOutputIndexes[i]
events = append(events, ResponseStreamEvent{
Type: "response.function_call_arguments.done",
diff --git a/sdk/kronk/response_test.go b/sdk/kronk/response_test.go
index 07acd86dd..0e4dd3705 100644
--- a/sdk/kronk/response_test.go
+++ b/sdk/kronk/response_test.go
@@ -34,6 +34,52 @@ func TestStreamStateErrorEvent(t *testing.T) {
}
}
+func TestStreamStateOutputIndexesRemainStable(t *testing.T) {
+ ss := streamState{}
+ messageEvents := ss.handleTextDelta("hello")
+
+ firstToolEvents := ss.handleToolCalls([]model.ResponseToolCall{{
+ ID: "tool-1",
+ Function: model.ResponseToolCallFunction{Name: "first"},
+ }})
+ secondToolEvents := ss.handleToolCalls([]model.ResponseToolCall{{
+ ID: "tool-2",
+ Function: model.ResponseToolCallFunction{Name: "second"},
+ }})
+ doneEvents := ss.finalizeToolCalls()
+
+ assertEventIndexes(t, messageEvents, 0)
+ assertEventIndexes(t, firstToolEvents, 1)
+ assertEventIndexes(t, secondToolEvents, 2)
+ assertEventIndexes(t, doneEvents[:2], 1)
+ assertEventIndexes(t, doneEvents[2:], 2)
+}
+
+func TestStreamStateIndexesMessageAfterTool(t *testing.T) {
+ ss := streamState{}
+ toolEvents := ss.handleToolCalls([]model.ResponseToolCall{{
+ ID: "tool-1",
+ Function: model.ResponseToolCallFunction{Name: "first"},
+ }})
+ messageEvents := ss.handleTextDelta("hello")
+
+ assertEventIndexes(t, toolEvents, 0)
+ assertEventIndexes(t, messageEvents, 1)
+}
+
+func assertEventIndexes(t *testing.T, events []ResponseStreamEvent, want int) {
+ t.Helper()
+
+ for _, event := range events {
+ if event.OutputIndex == nil {
+ t.Fatalf("%s: OutputIndex is nil", event.Type)
+ }
+ if got := *event.OutputIndex; got != want {
+ t.Errorf("%s: OutputIndex got %d, want %d", event.Type, got, want)
+ }
+ }
+}
+
func TestResponseValidatesMessagesBeforeAdmission(t *testing.T) {
tests := []struct {
name string
diff --git a/sdk/kronk/tokenize.go b/sdk/kronk/tokenize.go
index b17b3349a..a9319d5b9 100644
--- a/sdk/kronk/tokenize.go
+++ b/sdk/kronk/tokenize.go
@@ -43,7 +43,9 @@ func (krn *Kronk) TokenizeHTTP(ctx context.Context, log Logger, w http.ResponseW
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
- w.Write(data)
+ if _, err := w.Write(data); err != nil {
+ return resp, fmt.Errorf("tokenize-http: %w: write response: %w", ErrResponseCommitted, err)
+ }
return resp, nil
}
diff --git a/sdk/kronk/vram/http.go b/sdk/kronk/vram/http.go
index e8a178312..50c7af768 100644
--- a/sdk/kronk/vram/http.go
+++ b/sdk/kronk/vram/http.go
@@ -246,12 +246,12 @@ func isFolderURL(modelURL string) bool {
// fetchFolderFiles lists GGUF files in a HuggingFace folder and returns
// their download URLs (sorted) and total size.
func fetchFolderFiles(ctx context.Context, folderURL string) ([]string, int64, error) {
- owner, repo, folderPath, err := parseFolderURL(folderURL)
+ owner, repo, revision, folderPath, err := parseFolderURL(folderURL)
if err != nil {
return nil, 0, err
}
- repoFiles, err := hf.RepoFiles(ctx, owner, repo, "main", folderPath, false)
+ repoFiles, err := hf.RepoFiles(ctx, owner, repo, revision, folderPath, false)
if err != nil {
return nil, 0, fmt.Errorf("fetch-folder-files: %w", err)
}
@@ -264,7 +264,7 @@ func fetchFolderFiles(ctx context.Context, folderURL string) ([]string, int64, e
continue
}
- downloadURL := fmt.Sprintf("https://huggingface.co/%s/%s/resolve/main/%s", owner, repo, f.Filename)
+ downloadURL := hf.BuildURL(owner, repo, revision, f.Filename)
fileURLs = append(fileURLs, downloadURL)
totalSize += f.Size
}
@@ -278,37 +278,46 @@ func fetchFolderFiles(ctx context.Context, folderURL string) ([]string, int64, e
return fileURLs, totalSize, nil
}
-// parseFolderURL extracts owner, repo, and folder path from a HuggingFace
-// folder URL.
+// parseFolderURL extracts owner, repo, revision, and folder path from a
+// HuggingFace folder URL.
//
// Supported formats:
//
// https://huggingface.co/owner/repo/tree/main/subfolder
// owner/repo/tree/main/subfolder
// owner/repo/subfolder (no /tree/main/ prefix)
-func parseFolderURL(folderURL string) (owner, repo, folderPath string, err error) {
- raw := folderURL
- raw = strings.TrimPrefix(raw, "https://huggingface.co/")
- raw = strings.TrimPrefix(raw, "http://huggingface.co/")
+func parseFolderURL(folderURL string) (owner, repo, revision, folderPath string, err error) {
+ raw := strings.TrimSpace(folderURL)
+ for _, prefix := range []string{
+ "https://huggingface.co/",
+ "http://huggingface.co/",
+ "https://hf.co/",
+ "http://hf.co/",
+ } {
+ if strings.HasPrefix(strings.ToLower(raw), prefix) {
+ raw = raw[len(prefix):]
+ break
+ }
+ }
+ raw = hf.StripHostPrefix(raw)
- parts := strings.SplitN(raw, "/", 3)
+ parts := strings.Split(strings.Trim(raw, "/"), "/")
if len(parts) < 3 {
- return "", "", "", fmt.Errorf("parse-folder-url: invalid folder URL: %s", folderURL)
+ return "", "", "", "", fmt.Errorf("parse-folder-url: invalid folder URL: %s", folderURL)
}
owner = parts[0]
repo = parts[1]
- rest := parts[2]
-
- // Strip tree/main/ prefix if present.
- rest = strings.TrimPrefix(rest, "tree/main/")
-
- // Strip blob/main/ prefix if present.
- rest = strings.TrimPrefix(rest, "blob/main/")
-
- if rest == "" {
- return "", "", "", fmt.Errorf("parse-folder-url: missing folder path in URL: %s", folderURL)
+ revision = "main"
+ rest := parts[2:]
+ if rest[0] == "tree" || rest[0] == "blob" {
+ if len(rest) < 3 {
+ return "", "", "", "", fmt.Errorf("parse-folder-url: missing folder path in URL: %s", folderURL)
+ }
+ revision = rest[1]
+ rest = rest[2:]
}
+ folderPath = strings.Join(rest, "/")
- return owner, repo, rest, nil
+ return owner, repo, revision, folderPath, nil
}
diff --git a/sdk/kronk/vram/http_test.go b/sdk/kronk/vram/http_test.go
index 7b9195f7c..cea25677a 100644
--- a/sdk/kronk/vram/http_test.go
+++ b/sdk/kronk/vram/http_test.go
@@ -215,3 +215,44 @@ func TestIsFolderURL(t *testing.T) {
})
}
}
+
+func TestParseFolderURL(t *testing.T) {
+ tests := []struct {
+ name string
+ url string
+ wantOwner string
+ wantRepo string
+ wantRevision string
+ wantPath string
+ }{
+ {
+ name: "hf short host and branch",
+ url: "https://hf.co/owner/repo/tree/feature-branch/quantized/Q4_K_M",
+ wantOwner: "owner",
+ wantRepo: "repo",
+ wantRevision: "feature-branch",
+ wantPath: "quantized/Q4_K_M",
+ },
+ {
+ name: "shorthand defaults to main",
+ url: "owner/repo/quantized/Q4_K_M",
+ wantOwner: "owner",
+ wantRepo: "repo",
+ wantRevision: "main",
+ wantPath: "quantized/Q4_K_M",
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ owner, repo, revision, path, err := parseFolderURL(tt.url)
+ if err != nil {
+ t.Fatalf("parseFolderURL: %v", err)
+ }
+ if owner != tt.wantOwner || repo != tt.wantRepo || revision != tt.wantRevision || path != tt.wantPath {
+ t.Errorf("parseFolderURL: got %q/%q/%q/%q, want %q/%q/%q/%q",
+ owner, repo, revision, path, tt.wantOwner, tt.wantRepo, tt.wantRevision, tt.wantPath)
+ }
+ })
+ }
+}
diff --git a/sdk/malina/pool/pool.go b/sdk/malina/pool/pool.go
index 8a6c395d8..37fd661b7 100644
--- a/sdk/malina/pool/pool.go
+++ b/sdk/malina/pool/pool.go
@@ -65,6 +65,7 @@ func New(cfg Config) (*Pool, error) {
Resman: cfg.Resman,
MaxItems: cfg.ModelsInPool,
TTL: cfg.TTL,
+ Backend: "malina",
}, ml)
if err != nil {
return nil, fmt.Errorf("new: constructing pool engine: %w", err)
@@ -114,6 +115,8 @@ func (p *Pool) Invalidate(key string) {
}
// InvalidateSync removes a model and waits for its reservation to be released.
+// If unloading fails, the model and reservation remain in the pool and the
+// error is returned.
func (p *Pool) InvalidateSync(ctx context.Context, key string) error {
return p.engine.InvalidateSync(ctx, key)
}
diff --git a/sdk/malina/pool/status.go b/sdk/malina/pool/status.go
index ec2301b15..92c23470e 100644
--- a/sdk/malina/pool/status.go
+++ b/sdk/malina/pool/status.go
@@ -1,6 +1,9 @@
package pool
-import "fmt"
+import (
+ "context"
+ "fmt"
+)
// ModelStatus returns loaded and in-flight Malina models.
func (p *Pool) ModelStatus() ([]ModelDetail, error) {
@@ -18,7 +21,11 @@ func (p *Pool) ModelStatus() ([]ModelDetail, error) {
display := p.loader.Display(handle, entry.Key)
size, err := p.modelSize(entry.Key)
if err != nil {
- return nil, fmt.Errorf("model-status: %w", err)
+ p.loader.log(context.Background(), "malina-model-status",
+ "status", "model-size-unavailable",
+ "model-id", entry.Key,
+ "ERROR", err,
+ )
}
details = append(details, ModelDetail{
@@ -42,7 +49,11 @@ func (p *Pool) ModelStatus() ([]ModelDetail, error) {
size, err := p.modelSize(reservation.Key)
if err != nil {
- return nil, fmt.Errorf("model-status: %w", err)
+ p.loader.log(context.Background(), "malina-model-status",
+ "status", "model-size-unavailable",
+ "model-id", reservation.Key,
+ "ERROR", err,
+ )
}
details = append(details, ModelDetail{
diff --git a/sdk/pool/engine/acquire.go b/sdk/pool/engine/acquire.go
index c8f04b73d..e2958c8b7 100644
--- a/sdk/pool/engine/acquire.go
+++ b/sdk/pool/engine/acquire.go
@@ -28,7 +28,15 @@ func (c *Pool[H]) Acquire(ctx context.Context, req loader.LoadRequest) (H, error
ctx, span := otel.AddSpan(ctx, "pool-acquire")
defer span.End()
- if entry, exists := c.cache.GetEntry(req.Key); exists {
+ c.lifecycleMu.Lock()
+ if c.shuttingDown {
+ c.lifecycleMu.Unlock()
+ return zero, ErrPoolClosed
+ }
+ entry, exists := c.cache.GetEntry(req.Key)
+ c.lifecycleMu.Unlock()
+
+ if exists {
c.log(ctx, "acquire",
"status", "cache-hit",
"key", req.Key,
@@ -47,9 +55,16 @@ func (c *Pool[H]) Acquire(ctx context.Context, req loader.LoadRequest) (H, error
"key", req.Key,
)
- // Use singleflight to prevent concurrent loads of the same key.
+ // Use singleflight to prevent concurrent loads of the same key. The shared
+ // load has a pool-owned lifetime; each caller independently stops waiting
+ // when its request context is canceled.
sfStart := time.Now()
- result, err, shared := c.loadGroup.Do(req.Key, func() (any, error) {
+ resultC := c.loadGroup.DoChan(req.Key, func() (any, error) {
+ loadCtx, finishLoad, err := c.beginLoad(ctx)
+ if err != nil {
+ return zero, err
+ }
+ defer finishLoad()
// Double-check pool after acquiring the singleflight lock.
if h, exists := c.cache.GetIfPresent(req.Key); exists {
@@ -57,7 +72,7 @@ func (c *Pool[H]) Acquire(ctx context.Context, req loader.LoadRequest) (H, error
}
if preparer, ok := c.loader.(loader.Preparer); ok {
- prepared, err := preparer.Prepare(ctx, req)
+ prepared, err := preparer.Prepare(loadCtx, req)
if err != nil {
metrics.AddPoolLoadFailure("plan")
return zero, fmt.Errorf("acquire: prepare: %w", err)
@@ -65,13 +80,13 @@ func (c *Pool[H]) Acquire(ctx context.Context, req loader.LoadRequest) (H, error
req.Prepared = prepared
}
- planReq, err := c.loader.Plan(ctx, req)
+ planReq, err := c.loader.Plan(loadCtx, req)
if err != nil {
metrics.AddPoolLoadFailure("plan")
return zero, fmt.Errorf("acquire: plan: %w", err)
}
- ticket, plan, err := c.reserveWithEviction(ctx, req.Key, planReq)
+ ticket, plan, err := c.reserveWithEviction(loadCtx, req.Key, planReq)
if err != nil {
return zero, fmt.Errorf("acquire: %w", err)
}
@@ -80,33 +95,33 @@ func (c *Pool[H]) Acquire(ctx context.Context, req loader.LoadRequest) (H, error
"status", "reserved",
"key", req.Key,
}, describePlan(plan)...)
- c.log(ctx, "acquire", reservedArgs...)
- c.LogResmanUsage(ctx, "post-reserve", "key", req.Key)
+ c.log(loadCtx, "acquire", reservedArgs...)
+ c.LogResmanUsage(loadCtx, "post-reserve", "key", req.Key)
- h, err := c.loader.Load(ctx, req)
+ h, err := c.loader.Load(loadCtx, req)
if err != nil {
c.resman.Release(ticket)
- c.log(ctx, "acquire",
+ c.log(loadCtx, "acquire",
"status", "load-failed-reservation-released",
"key", req.Key,
"ERROR", err,
)
- c.LogResmanUsage(ctx, "post-failed-load", "key", req.Key)
+ c.LogResmanUsage(loadCtx, "post-failed-load", "key", req.Key)
metrics.AddPoolLoadFailure("load")
return zero, fmt.Errorf("acquire: %w", err)
}
if validator, ok := c.loader.(loader.Validator[H]); ok {
- if err := validator.Validate(ctx, req, h); err != nil {
- unloadErr := h.Unload(context.WithoutCancel(ctx))
+ if err := validator.Validate(loadCtx, req, h); err != nil {
+ unloadErr := h.Unload(context.WithoutCancel(loadCtx))
c.resman.Release(ticket)
- c.log(ctx, "acquire",
+ c.log(loadCtx, "acquire",
"status", "validation-failed-reservation-released",
"key", req.Key,
"ERROR", err,
"unload-error", unloadErr,
)
- c.LogResmanUsage(ctx, "post-failed-validation", "key", req.Key)
+ c.LogResmanUsage(loadCtx, "post-failed-validation", "key", req.Key)
metrics.AddPoolLoadFailure("validate")
if unloadErr != nil {
return zero, fmt.Errorf("acquire: validate loaded handle: %w", errors.Join(err, fmt.Errorf("unload: %w", unloadErr)))
@@ -115,12 +130,13 @@ func (c *Pool[H]) Acquire(ctx context.Context, req loader.LoadRequest) (H, error
}
}
- c.storeTicket(req.Key, ticket)
- c.cache.Set(req.Key, h)
- c.itemsInPool.Add(1)
+ if accepted := c.storeLoaded(req.Key, ticket, h); !accepted {
+ c.cache.Invalidate(req.Key)
+ return zero, ErrPoolClosed
+ }
if entry, ok := c.cache.GetEntryQuietly(req.Key); ok {
- c.log(ctx, "acquire",
+ c.log(loadCtx, "acquire",
"status", "cache-set",
"key", req.Key,
"expires-at", c.EntryExpiresAt(entry),
@@ -131,6 +147,18 @@ func (c *Pool[H]) Acquire(ctx context.Context, req loader.LoadRequest) (H, error
return h, nil
})
+ var result any
+ var err error
+ var shared bool
+ select {
+ case <-ctx.Done():
+ err = ctx.Err()
+ case sfResult := <-resultC:
+ result = sfResult.Val
+ err = sfResult.Err
+ shared = sfResult.Shared
+ }
+
if shared {
metrics.ObservePoolSingleflightWait(time.Since(sfStart))
}
diff --git a/sdk/pool/engine/acquire_test.go b/sdk/pool/engine/acquire_test.go
index 8266b298f..2e279f58c 100644
--- a/sdk/pool/engine/acquire_test.go
+++ b/sdk/pool/engine/acquire_test.go
@@ -12,12 +12,13 @@ import (
)
type preparedHandle struct {
- unloadCalls atomic.Int32
- unloadErr error
+ activeStreams atomic.Int32
+ unloadCalls atomic.Int32
+ unloadErr error
}
-func (*preparedHandle) ActiveStreams() int {
- return 0
+func (h *preparedHandle) ActiveStreams() int {
+ return int(h.activeStreams.Load())
}
func (h *preparedHandle) Unload(context.Context) error {
@@ -31,6 +32,9 @@ type preparedLoader struct {
loadPrepared any
handles map[string]*preparedHandle
validateErr error
+ loadStarted chan struct{}
+ releaseLoad chan struct{}
+ ignoreCancel bool
}
func (pl *preparedLoader) Prepare(context.Context, loader.LoadRequest) (any, error) {
@@ -43,8 +47,22 @@ func (pl *preparedLoader) Plan(_ context.Context, req loader.LoadRequest) (resma
return resman.PlanRequest{Key: req.Key, RAMBytes: 1}, nil
}
-func (pl *preparedLoader) Load(_ context.Context, req loader.LoadRequest) (*preparedHandle, error) {
+func (pl *preparedLoader) Load(ctx context.Context, req loader.LoadRequest) (*preparedHandle, error) {
pl.loadPrepared = req.Prepared
+ if pl.loadStarted != nil {
+ close(pl.loadStarted)
+ }
+ if pl.releaseLoad != nil {
+ if pl.ignoreCancel {
+ <-pl.releaseLoad
+ } else {
+ select {
+ case <-pl.releaseLoad:
+ case <-ctx.Done():
+ return nil, ctx.Err()
+ }
+ }
+ }
h := &preparedHandle{}
if pl.handles != nil {
@@ -135,6 +153,192 @@ func TestAcquireValidationFailureUnloadsAndReleases(t *testing.T) {
}
}
+func TestAcquireCallerCancellationDoesNotCancelSharedLoad(t *testing.T) {
+ pl := &preparedLoader{
+ loadStarted: make(chan struct{}),
+ releaseLoad: make(chan struct{}),
+ }
+ p, err := New(Config{
+ Log: func(context.Context, string, ...any) {},
+ Resman: newTestResourceManager(t),
+ MaxItems: 1,
+ }, pl)
+ if err != nil {
+ t.Fatalf("New: %v", err)
+ }
+
+ ctx, cancel := context.WithCancel(context.Background())
+ first := make(chan error, 1)
+ go func() {
+ _, err := p.Acquire(ctx, loader.LoadRequest{ModelID: "model", Key: "model"})
+ first <- err
+ }()
+ <-pl.loadStarted
+
+ cancel()
+ if err := <-first; !errors.Is(err, context.Canceled) {
+ t.Fatalf("first Acquire error: got %v, want %v", err, context.Canceled)
+ }
+
+ second := make(chan error, 1)
+ go func() {
+ _, err := p.Acquire(context.Background(), loader.LoadRequest{ModelID: "model", Key: "model"})
+ second <- err
+ }()
+ close(pl.releaseLoad)
+
+ if err := <-second; err != nil {
+ t.Fatalf("second Acquire: %v", err)
+ }
+}
+
+func TestShutdownRejectsLoadCompletingAfterShutdown(t *testing.T) {
+ pl := &preparedLoader{
+ handles: make(map[string]*preparedHandle),
+ loadStarted: make(chan struct{}),
+ releaseLoad: make(chan struct{}),
+ ignoreCancel: true,
+ }
+ rm := newTestResourceManager(t)
+ p, err := New(Config{
+ Log: func(context.Context, string, ...any) {},
+ Resman: rm,
+ MaxItems: 1,
+ }, pl)
+ if err != nil {
+ t.Fatalf("New: %v", err)
+ }
+
+ acquired := make(chan error, 1)
+ go func() {
+ _, err := p.Acquire(context.Background(), loader.LoadRequest{ModelID: "model", Key: "model"})
+ acquired <- err
+ }()
+ <-pl.loadStarted
+
+ shutdown := make(chan error, 1)
+ go func() {
+ shutdown <- p.Shutdown(context.Background())
+ }()
+
+ for {
+ p.lifecycleMu.Lock()
+ stopping := p.shuttingDown
+ p.lifecycleMu.Unlock()
+ if stopping {
+ break
+ }
+ }
+ close(pl.releaseLoad)
+
+ if err := <-acquired; !errors.Is(err, ErrPoolClosed) {
+ t.Fatalf("Acquire error: got %v, want %v", err, ErrPoolClosed)
+ }
+ if err := <-shutdown; err != nil {
+ t.Fatalf("Shutdown: %v", err)
+ }
+ if got := p.ItemsInPool(); got != 0 {
+ t.Errorf("ItemsInPool: got %d, want 0", got)
+ }
+ if got := len(rm.Usage().Reservations); got != 0 {
+ t.Errorf("Reservations: got %d, want 0", got)
+ }
+ if got := pl.handles["model"].unloadCalls.Load(); got != 1 {
+ t.Errorf("Unload calls: got %d, want 1", got)
+ }
+ if _, err := p.Acquire(context.Background(), loader.LoadRequest{ModelID: "other", Key: "other"}); !errors.Is(err, ErrPoolClosed) {
+ t.Fatalf("Acquire after Shutdown error: got %v, want %v", err, ErrPoolClosed)
+ }
+}
+
+func TestInvalidateSyncRestoresHandleWhenUnloadFails(t *testing.T) {
+ wantErr := errors.New("unload failed")
+ pl := &preparedLoader{handles: make(map[string]*preparedHandle)}
+ rm := newTestResourceManager(t)
+ p, err := New(Config{
+ Log: func(context.Context, string, ...any) {},
+ Resman: rm,
+ MaxItems: 1,
+ }, pl)
+ if err != nil {
+ t.Fatalf("New: %v", err)
+ }
+
+ const key = "model"
+ if _, err := p.Acquire(context.Background(), loader.LoadRequest{ModelID: key, Key: key}); err != nil {
+ t.Fatalf("Acquire: %v", err)
+ }
+ pl.handles[key].unloadErr = wantErr
+
+ ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
+ defer cancel()
+ if err := p.InvalidateSync(ctx, key); !errors.Is(err, wantErr) {
+ t.Fatalf("InvalidateSync error: got %v, want %v", err, wantErr)
+ }
+ if _, exists := p.GetExisting(key); !exists {
+ t.Error("cache entry: got missing after unload failure, want restored")
+ }
+ if got := p.ItemsInPool(); got != 1 {
+ t.Errorf("ItemsInPool: got %d, want 1", got)
+ }
+ if got := len(rm.Usage().Reservations); got != 1 {
+ t.Errorf("Reservations: got %d, want 1", got)
+ }
+
+ pl.handles[key].unloadErr = nil
+ if err := p.InvalidateSync(ctx, key); err != nil {
+ t.Fatalf("second InvalidateSync: %v", err)
+ }
+ if got := p.ItemsInPool(); got != 0 {
+ t.Errorf("ItemsInPool after successful retry: got %d, want 0", got)
+ }
+ if got := len(rm.Usage().Reservations); got != 0 {
+ t.Errorf("Reservations after successful retry: got %d, want 0", got)
+ }
+}
+
+func TestInvalidateSyncRestoresActiveHandle(t *testing.T) {
+ pl := &preparedLoader{handles: make(map[string]*preparedHandle)}
+ rm := newTestResourceManager(t)
+ p, err := New(Config{
+ Log: func(context.Context, string, ...any) {},
+ Resman: rm,
+ MaxItems: 1,
+ }, pl)
+ if err != nil {
+ t.Fatalf("New: %v", err)
+ }
+
+ const key = "model"
+ if _, err := p.Acquire(context.Background(), loader.LoadRequest{ModelID: key, Key: key}); err != nil {
+ t.Fatalf("Acquire: %v", err)
+ }
+ pl.handles[key].activeStreams.Store(1)
+
+ ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
+ defer cancel()
+ if err := p.InvalidateSync(ctx, key); !errors.Is(err, ErrModelInUse) {
+ t.Fatalf("InvalidateSync error: got %v, want %v", err, ErrModelInUse)
+ }
+ if got := pl.handles[key].unloadCalls.Load(); got != 0 {
+ t.Errorf("Unload calls: got %d, want 0", got)
+ }
+ if _, exists := p.GetExisting(key); !exists {
+ t.Error("cache entry: got missing while active, want restored")
+ }
+ if got := p.ItemsInPool(); got != 1 {
+ t.Errorf("ItemsInPool: got %d, want 1", got)
+ }
+ if got := len(rm.Usage().Reservations); got != 1 {
+ t.Errorf("Reservations: got %d, want 1", got)
+ }
+
+ pl.handles[key].activeStreams.Store(0)
+ if err := p.InvalidateSync(ctx, key); err != nil {
+ t.Fatalf("second InvalidateSync: %v", err)
+ }
+}
+
func TestNewTTL(t *testing.T) {
tests := []struct {
name string
@@ -221,3 +425,39 @@ func TestTTLDisabledStillAllowsCapacityEviction(t *testing.T) {
t.Errorf("model-a unload calls: got %d, want 1", got)
}
}
+
+func TestCapacityEvictionRetainsModelWhenUnloadFails(t *testing.T) {
+ wantErr := errors.New("unload failed")
+ pl := &preparedLoader{handles: make(map[string]*preparedHandle)}
+ rm := newTestResourceManager(t)
+ p, err := New(Config{
+ Log: func(context.Context, string, ...any) {},
+ Resman: rm,
+ MaxItems: 1,
+ }, pl)
+ if err != nil {
+ t.Fatalf("New: %v", err)
+ }
+
+ ctx := context.Background()
+ if _, err := p.Acquire(ctx, loader.LoadRequest{ModelID: "model-a", Key: "model-a"}); err != nil {
+ t.Fatalf("Acquire model-a: %v", err)
+ }
+ pl.handles["model-a"].unloadErr = wantErr
+
+ if _, err := p.Acquire(ctx, loader.LoadRequest{ModelID: "model-b", Key: "model-b"}); !errors.Is(err, wantErr) {
+ t.Fatalf("Acquire model-b error: got %v, want %v", err, wantErr)
+ }
+ if _, exists := p.GetExisting("model-a"); !exists {
+ t.Error("model-a: got missing after unload failure, want restored")
+ }
+ if _, exists := p.GetExisting("model-b"); exists {
+ t.Error("model-b: got resident after failed eviction, want missing")
+ }
+ if got := p.ItemsInPool(); got != 1 {
+ t.Errorf("ItemsInPool: got %d, want 1", got)
+ }
+ if got := len(rm.Usage().Reservations); got != 1 {
+ t.Errorf("Reservations: got %d, want 1", got)
+ }
+}
diff --git a/sdk/pool/engine/eviction.go b/sdk/pool/engine/eviction.go
index f5168bce3..337576e16 100644
--- a/sdk/pool/engine/eviction.go
+++ b/sdk/pool/engine/eviction.go
@@ -123,10 +123,14 @@ func (c *Pool[H]) evictOneIdle(ctx context.Context, newKey, reason string, req r
metrics.AddPoolEviction(reason, victimSelectionMode)
evictStart := time.Now()
+ c.clearEvictionError(victim)
c.cache.Invalidate(victim)
deadline := time.Now().Add(maxWait)
for {
+ if err := c.evictionError(victim); err != nil {
+ return fmt.Errorf("evict-one-idle: unload victim[%s]: %w", victim, err)
+ }
if !c.hasTicket(victim) && int(c.itemsInPool.Load()) < c.maxItems+1 {
// The eviction callback has run (ticket released) and the
// counter has been decremented or is at its previous level.
@@ -166,37 +170,39 @@ func (c *Pool[H]) eviction(event otter.DeletionEvent[string, H]) {
ctx, cancel := context.WithTimeout(context.Background(), unloadTimeout)
defer cancel()
- c.log(ctx, "pool eviction", "key", event.Key, "cause", event.Cause.String(), "cause-code", int(event.Cause), "was-evicted", event.WasEvicted(), "active-streams", event.Value.ActiveStreams())
+ activeStreams := event.Value.ActiveStreams()
+ c.log(ctx, "pool eviction", "key", event.Key, "cause", event.Cause.String(), "cause-code", int(event.Cause), "was-evicted", event.WasEvicted(), "active-streams", activeStreams)
- // If there are active streams and this was an automatic eviction
- // (not a replacement from our own Set call below), re-insert the
- // model to prevent eviction. WasEvicted() returns false for
- // CauseReplacement and CauseInvalidation.
- if event.Value.ActiveStreams() > 0 && event.WasEvicted() {
- c.log(ctx, "pool eviction prevented", "key", event.Key, "active-streams", event.Value.ActiveStreams())
- c.cache.Set(event.Key, event.Value)
+ // A replacement event means this handle was already restored by an
+ // earlier deletion callback and remains represented in the cache.
+ if activeStreams > 0 && event.Cause == otter.CauseReplacement {
+ c.log(ctx, "pool eviction skipped (replacement with active streams)", "key", event.Key, "active-streams", activeStreams)
return
}
- // If this is a replacement event (from our Set above) and there
- // are still active streams, just return without unloading - the
- // handle is still in the pool. For invalidation (shutdown), we
- // still need to unload since the pool is being cleared.
- if event.Value.ActiveStreams() > 0 && event.Cause != otter.CauseInvalidation {
- c.log(ctx, "pool eviction skipped (replacement with active streams)", "key", event.Key, "active-streams", event.Value.ActiveStreams())
+ // ActiveStreams can change after a caller selects an idle victim. Recheck
+ // in the callback so explicit invalidation has the same protection as
+ // automatic eviction. Unload performs the authoritative final check for
+ // the smaller race between this read and its shutdown lock.
+ if activeStreams > 0 {
+ err := fmt.Errorf("%w: key[%s] active-streams[%d]", ErrModelInUse, event.Key, activeStreams)
+ c.restoreAfterFailedEviction(ctx, event, err)
return
}
- c.log(ctx, "pool eviction", "key", event.Key, "status", "unload-started", "active-streams", event.Value.ActiveStreams())
+ c.log(ctx, "pool eviction", "key", event.Key, "status", "unload-started", "active-streams", activeStreams)
unloadStart := time.Now()
if err := event.Value.Unload(ctx); err != nil {
- c.log(ctx, "pool eviction", "key", event.Key, "ERROR", err)
+ metrics.ObservePoolUnloadDuration(event.Key, time.Since(unloadStart))
+ c.restoreAfterFailedEviction(ctx, event, err)
+ return
}
unloadDur := time.Since(unloadStart)
metrics.ObservePoolUnloadDuration(event.Key, unloadDur)
+ c.clearEvictionError(event.Key)
// Track the eviction reason as observed by the otter cache. The
// "evict-before-load" path also fires this callback (via
@@ -230,6 +236,21 @@ func (c *Pool[H]) eviction(event otter.DeletionEvent[string, H]) {
c.PublishMetrics()
}
+// restoreAfterFailedEviction puts a handle back in the cache while retaining
+// its item count and resource reservation. Unload errors mean the engine must
+// conservatively continue treating the model as resident.
+func (c *Pool[H]) restoreAfterFailedEviction(ctx context.Context, event otter.DeletionEvent[string, H], err error) {
+ _, restored := c.cache.Set(event.Key, event.Value)
+ c.setEvictionError(event.Key, err)
+ c.log(ctx, "pool eviction",
+ "key", event.Key,
+ "status", "unload-failed-restored",
+ "restored", restored,
+ "ERROR", err,
+ )
+ c.PublishMetrics()
+}
+
// otterCauseLabel maps the otter eviction cause to a metrics label.
func otterCauseLabel(cause otter.DeletionCause) string {
switch cause {
diff --git a/sdk/pool/engine/logging.go b/sdk/pool/engine/logging.go
index bb9437da0..f9621df23 100644
--- a/sdk/pool/engine/logging.go
+++ b/sdk/pool/engine/logging.go
@@ -145,9 +145,9 @@ func (c *Pool[H]) PublishMetrics() {
metrics.PublishResmanUsage(pu)
items := int(c.itemsInPool.Load())
- metrics.SetPoolItemsInPool(items)
+ metrics.SetPoolItemsInPool(c.backend, items)
// Inflight = tickets held but not yet visible in the cache.
inflight := max(c.activeTicketCount()-items, 0)
- metrics.SetPoolInflightLoads(inflight)
+ metrics.SetPoolInflightLoads(c.backend, inflight)
}
diff --git a/sdk/pool/engine/pool.go b/sdk/pool/engine/pool.go
index af398e1b0..e8932edeb 100644
--- a/sdk/pool/engine/pool.go
+++ b/sdk/pool/engine/pool.go
@@ -34,11 +34,20 @@ import (
"golang.org/x/sync/singleflight"
)
-// ErrServerBusy is returned when the pool cannot make room for a new
-// entry because no idle pool entry is available to evict — either
-// every cached entry has active streams, or the cache is empty/in flux
-// and there is nothing to reclaim.
-var ErrServerBusy = errors.New("server busy: no idle pool entry available to evict")
+var (
+ // ErrServerBusy is returned when the pool cannot make room for a new
+ // entry because no idle pool entry is available to evict — either
+ // every cached entry has active streams, or the cache is empty/in flux
+ // and there is nothing to reclaim.
+ ErrServerBusy = errors.New("server busy: no idle pool entry available to evict")
+
+ // ErrModelInUse is returned when invalidation races with a request that
+ // begins using the selected model.
+ ErrModelInUse = errors.New("model has active streams")
+
+ // ErrPoolClosed is returned when an acquisition begins after pool shutdown.
+ ErrPoolClosed = errors.New("pool is shutting down")
+)
// Config carries the non-generic settings used to construct a Pool.
//
@@ -60,20 +69,30 @@ type Config struct {
// TTL is the duration an entry can live in the cache without being
// accessed before the cache evicts it. Zero disables idle expiration.
TTL time.Duration
+
+ // Backend identifies this pool in metrics. Empty defaults to "unknown".
+ Backend string
}
// Pool is the generic pool engine.
type Pool[H loader.Handle] struct {
- log applog.Logger
- loader loader.Loader[H]
- cache *otter.Cache[string, H]
- itemsInPool atomic.Int32
- maxItems int
- ttl time.Duration
- loadGroup singleflight.Group
- resman *resman.Manager
- ticketsMu sync.Mutex
- tickets map[string]resman.Ticket
+ log applog.Logger
+ loader loader.Loader[H]
+ cache *otter.Cache[string, H]
+ itemsInPool atomic.Int32
+ maxItems int
+ ttl time.Duration
+ backend string
+ loadGroup singleflight.Group
+ resman *resman.Manager
+ lifecycleMu sync.Mutex
+ loadsCtx context.Context
+ cancelLoads context.CancelFunc
+ loads sync.WaitGroup
+ shuttingDown bool
+ ticketsMu sync.Mutex
+ tickets map[string]resman.Ticket
+ evictionErrs map[string]error
}
// New constructs a Pool wired to the supplied loader. The caller owns
@@ -96,13 +115,22 @@ func New[H loader.Handle](cfg Config, l loader.Loader[H]) (*Pool[H], error) {
return nil, errors.New("engine: new: ttl must be >= 0")
}
+ loadsCtx, cancelLoads := context.WithCancel(context.Background())
+ if cfg.Backend == "" {
+ cfg.Backend = "unknown"
+ }
+
c := Pool[H]{
- log: cfg.Log,
- loader: l,
- maxItems: cfg.MaxItems,
- ttl: cfg.TTL,
- resman: cfg.Resman,
- tickets: make(map[string]resman.Ticket),
+ log: cfg.Log,
+ loader: l,
+ maxItems: cfg.MaxItems,
+ ttl: cfg.TTL,
+ backend: cfg.Backend,
+ resman: cfg.Resman,
+ loadsCtx: loadsCtx,
+ cancelLoads: cancelLoads,
+ tickets: make(map[string]resman.Ticket),
+ evictionErrs: make(map[string]error),
}
opt := otter.Options[string, H]{
@@ -120,7 +148,7 @@ func New[H loader.Handle](cfg Config, l loader.Loader[H]) (*Pool[H], error) {
c.cache = cache
- metrics.SetPoolMaxItemsInPool(cfg.MaxItems)
+ metrics.SetPoolMaxItemsInPool(cfg.Backend, cfg.MaxItems)
c.PublishMetrics()
return &c, nil
@@ -152,19 +180,26 @@ func (c *Pool[H]) GetExisting(key string) (H, bool) {
// reservation may not be released by the time this returns; use
// InvalidateSync when a consistent post-eviction view is required.
func (c *Pool[H]) Invalidate(key string) {
+ c.clearEvictionError(key)
c.cache.Invalidate(key)
}
-// InvalidateSync invalidates a cache entry and waits for the eviction
-// callback to release the underlying resource manager reservation.
+// InvalidateSync invalidates a cache entry and waits for the eviction callback
+// to release the underlying resource manager reservation. If the model becomes
+// active or unloading fails, the entry and reservation are restored and the
+// unload error is returned.
func (c *Pool[H]) InvalidateSync(ctx context.Context, key string) error {
const pollInterval = 25 * time.Millisecond
const maxWait = 60 * time.Second
+ c.clearEvictionError(key)
c.cache.Invalidate(key)
deadline := time.Now().Add(maxWait)
for {
+ if err := c.evictionError(key); err != nil {
+ return fmt.Errorf("invalidate-sync: unload key[%s]: %w", key, err)
+ }
if !c.hasTicket(key) {
return nil
}
@@ -190,9 +225,35 @@ func (c *Pool[H]) Shutdown(ctx context.Context) error {
defer cancel()
}
+ c.lifecycleMu.Lock()
+ c.shuttingDown = true
+ c.cancelLoads()
+ c.lifecycleMu.Unlock()
+
+ c.clearEvictionErrors()
+ c.cache.InvalidateAll()
+
+ loadsDone := make(chan struct{})
+ go func() {
+ c.loads.Wait()
+ close(loadsDone)
+ }()
+
+ select {
+ case <-loadsDone:
+ case <-ctx.Done():
+ return ctx.Err()
+ }
+
+ // Catch handles that completed loading as shutdown began. Such loads are
+ // never returned to callers, but are briefly cached so normal eviction owns
+ // their unload and reservation cleanup.
c.cache.InvalidateAll()
for c.itemsInPool.Load() > 0 {
+ if key, err := c.firstEvictionError(); err != nil {
+ return fmt.Errorf("shutdown: unload key[%s]: %w", key, err)
+ }
select {
case <-ctx.Done():
return ctx.Err()
@@ -203,6 +264,44 @@ func (c *Pool[H]) Shutdown(ctx context.Context) error {
return nil
}
+// beginLoad creates a context whose values come from the singleflight leader
+// but whose cancellation is owned by the pool lifecycle. Callers may stop
+// waiting without canceling a load shared by other callers.
+func (c *Pool[H]) beginLoad(parent context.Context) (context.Context, func(), error) {
+ c.lifecycleMu.Lock()
+ defer c.lifecycleMu.Unlock()
+
+ if c.shuttingDown {
+ return nil, nil, ErrPoolClosed
+ }
+
+ ctx, cancel := context.WithCancel(context.WithoutCancel(parent))
+ stop := context.AfterFunc(c.loadsCtx, cancel)
+ c.loads.Add(1)
+
+ done := func() {
+ stop()
+ cancel()
+ c.loads.Done()
+ }
+
+ return ctx, done, nil
+}
+
+// storeLoaded commits a newly loaded handle and reports whether the pool is
+// still accepting acquisitions. During shutdown the handle is stored only so
+// the regular eviction path can unload it and release its reservation.
+func (c *Pool[H]) storeLoaded(key string, ticket resman.Ticket, h H) bool {
+ c.lifecycleMu.Lock()
+ defer c.lifecycleMu.Unlock()
+
+ c.storeTicket(key, ticket)
+ c.cache.Set(key, h)
+ c.itemsInPool.Add(1)
+
+ return !c.shuttingDown
+}
+
// Coldest returns an iterator that yields cached entries in LRU
// (coldest-first) order. Used by wrappers for ModelStatus listings.
func (c *Pool[H]) Coldest() iter.Seq[otter.Entry[string, H]] {
@@ -261,6 +360,39 @@ func (c *Pool[H]) hasTicket(key string) bool {
return ok
}
+func (c *Pool[H]) setEvictionError(key string, err error) {
+ c.ticketsMu.Lock()
+ defer c.ticketsMu.Unlock()
+ c.evictionErrs[key] = err
+}
+
+func (c *Pool[H]) clearEvictionError(key string) {
+ c.ticketsMu.Lock()
+ defer c.ticketsMu.Unlock()
+ delete(c.evictionErrs, key)
+}
+
+func (c *Pool[H]) clearEvictionErrors() {
+ c.ticketsMu.Lock()
+ defer c.ticketsMu.Unlock()
+ clear(c.evictionErrs)
+}
+
+func (c *Pool[H]) evictionError(key string) error {
+ c.ticketsMu.Lock()
+ defer c.ticketsMu.Unlock()
+ return c.evictionErrs[key]
+}
+
+func (c *Pool[H]) firstEvictionError() (string, error) {
+ c.ticketsMu.Lock()
+ defer c.ticketsMu.Unlock()
+ for key, err := range c.evictionErrs {
+ return key, err
+ }
+ return "", nil
+}
+
// HasTicket reports whether this engine currently owns a reservation
// for key. Backend wrappers use this to filter the shared resman's
// Reservations slice down to entries that belong to this pool so they
diff --git a/sdk/tools/bucky/libs/libs.go b/sdk/tools/bucky/libs/libs.go
index 61dae5d24..3f0b80a22 100644
--- a/sdk/tools/bucky/libs/libs.go
+++ b/sdk/tools/bucky/libs/libs.go
@@ -425,6 +425,13 @@ func (lib *Libs) List() ([]VersionTag, error) {
// - WithValidation(true) verifies the selected installed bundle before
// Download reports success.
func (lib *Libs) Download(ctx context.Context, log Logger) (tag VersionTag, retErr error) {
+ return lib.DownloadSelected(ctx, log, lib.version, lib.AllowUpgrade)
+}
+
+// DownloadSelected performs the Download workflow with request-scoped version
+// and upgrade settings instead of mutating the Libs configuration.
+func (lib *Libs) DownloadSelected(ctx context.Context, log Logger, versionOverride string, allowUpgrade bool) (tag VersionTag, retErr error) {
+ log = normalizeLogger(log)
defer func() {
if retErr == nil && lib.validation {
retErr = lib.validateDownload(ctx, tag)
@@ -455,7 +462,7 @@ func (lib *Libs) Download(ctx context.Context, log Logger) (tag VersionTag, retE
// bucky-builder. For all other rows the network lookup is
// unnecessary, so skip it.
var latest string
- if lib.version == "" && lib.AllowUpgrade {
+ if versionOverride == "" && allowUpgrade {
v, err := download.WhisperLatestVersion()
if err != nil {
if installed.Version == "" {
@@ -468,7 +475,7 @@ func (lib *Libs) Download(ctx context.Context, log Logger) (tag VersionTag, retE
latest = v
}
- version := chooseVersion(lib.version, lib.AllowUpgrade, installed.Version, latest, defaultVersion)
+ version := chooseVersion(versionOverride, allowUpgrade, installed.Version, latest, defaultVersion)
log(ctx, "download-libraries: check whisper.cpp installation", "arch", lib.arch, "os", lib.os, "processor", lib.processor, "requested", version, "current", installed.Version)
@@ -553,14 +560,22 @@ func (lib *Libs) Remove(arch string, opSys string, processor string) error {
// alongside so subsequent InstalledVersion calls can report the
// installed metadata.
func (lib *Libs) downloadInto(ctx context.Context, log Logger, path string, arch string, opSys string, processor string, version string) (VersionTag, error) {
- if err := os.MkdirAll(path, 0o755); err != nil {
- return VersionTag{}, fmt.Errorf("download-into: unable to create destination: %w", err)
+ log = normalizeLogger(log)
+ parent := filepath.Dir(path)
+ if err := os.MkdirAll(parent, 0o755); err != nil {
+ return VersionTag{}, fmt.Errorf("download-into: unable to create parent: %w", err)
}
- tempPath := filepath.Join(path, "temp")
- if err := os.MkdirAll(tempPath, 0o755); err != nil {
- return VersionTag{}, fmt.Errorf("download-into: unable to create temp: %w", err)
+ stagePath, err := os.MkdirTemp(parent, "."+filepath.Base(path)+".stage-")
+ if err != nil {
+ return VersionTag{}, fmt.Errorf("download-into: unable to create staging directory: %w", err)
}
+ preserveStage := false
+ defer func() {
+ if !preserveStage {
+ _ = os.RemoveAll(stagePath)
+ }
+ }()
progress := func(src string, currentSize int64, totalSize int64, mbPerSec float64, complete bool) {
log(ctx, fmt.Sprintf("\r\x1b[Kdownload-libraries: Downloading %s... %d MB of %d MB (%.2f MB/s)", src, currentSize/(1000*1000), totalSize/(1000*1000), mbPerSec))
@@ -568,53 +583,59 @@ func (lib *Libs) downloadInto(ctx context.Context, log Logger, path string, arch
pr := downloader.NewProgressReader(progress, downloader.SizeIntervalMB10)
- if err := download.GetWithContext(ctx, arch, opSys, processor, version, tempPath, getter.ProgressTracker(pr)); err != nil {
- os.RemoveAll(tempPath)
+ if err := download.GetWithContext(ctx, arch, opSys, processor, version, stagePath, getter.ProgressTracker(pr)); err != nil {
return VersionTag{}, fmt.Errorf("download-into: unable to install whisper.cpp: %w", err)
}
- if err := swapTempForLibAt(path, tempPath); err != nil {
- os.RemoveAll(tempPath)
- return VersionTag{}, fmt.Errorf("download-into: unable to swap temp for lib: %w", err)
+ if err := writeVersionFile(stagePath, version, arch, opSys, processor); err != nil {
+ return VersionTag{}, fmt.Errorf("download-into: unable to create version file: %w", err)
+ }
+ if err := ctx.Err(); err != nil {
+ return VersionTag{}, fmt.Errorf("download-into: activate libraries: %w", err)
}
- if err := writeVersionFile(path, version, arch, opSys, processor); err != nil {
- return VersionTag{}, fmt.Errorf("download-into: unable to create version file: %w", err)
+ preserveStage, err = swapInstall(path, stagePath)
+ if err != nil {
+ return VersionTag{}, fmt.Errorf("download-into: unable to install staged libraries: %w", err)
}
return readVersionFile(path)
}
-func swapTempForLibAt(path string, tempPath string) error {
- entries, err := os.ReadDir(path)
- if err != nil {
- return fmt.Errorf("swap-temp-for-lib: unable to read libPath: %w", err)
- }
-
- for _, entry := range entries {
- if entry.Name() == "temp" {
- continue
+func swapInstall(path string, stagePath string) (bool, error) {
+ backupPath := ""
+ if _, err := os.Stat(path); err == nil {
+ backup, err := os.MkdirTemp(filepath.Dir(path), "."+filepath.Base(path)+".backup-")
+ if err != nil {
+ return false, fmt.Errorf("swap-install: create backup path: %w", err)
}
- os.RemoveAll(filepath.Join(path, entry.Name()))
- }
-
- tempEntries, err := os.ReadDir(tempPath)
- if err != nil {
- return fmt.Errorf("swap-temp-for-lib: unable to read temp: %w", err)
+ if err := os.Remove(backup); err != nil {
+ return false, fmt.Errorf("swap-install: prepare backup path: %w", err)
+ }
+ backupPath = backup
+ if err := os.Rename(path, backupPath); err != nil {
+ return false, fmt.Errorf("swap-install: preserve current install: %w", err)
+ }
+ } else if !os.IsNotExist(err) {
+ return false, fmt.Errorf("swap-install: inspect current install: %w", err)
}
- for _, entry := range tempEntries {
- src := filepath.Join(tempPath, entry.Name())
- dst := filepath.Join(path, entry.Name())
- os.RemoveAll(dst)
- if err := os.Rename(src, dst); err != nil {
- return fmt.Errorf("swap-temp-for-lib: unable to move %s: %w", entry.Name(), err)
+ if err := os.Rename(stagePath, path); err != nil {
+ if backupPath != "" {
+ if rollbackErr := os.Rename(backupPath, path); rollbackErr != nil {
+ return true, errors.Join(
+ fmt.Errorf("swap-install: activate staged install %q: %w", stagePath, err),
+ fmt.Errorf("swap-install: restore backup %q: %w", backupPath, rollbackErr),
+ )
+ }
}
+ return false, fmt.Errorf("swap-install: activate staged install: %w", err)
}
- os.RemoveAll(tempPath)
-
- return nil
+ if backupPath != "" {
+ _ = os.RemoveAll(backupPath)
+ }
+ return false, nil
}
func writeVersionFile(path string, version string, arch string, opSys string, processor string) error {
@@ -830,6 +851,13 @@ func bareVersion(version string) string {
return version
}
+func normalizeLogger(log Logger) Logger {
+ if log == nil {
+ return applog.DiscardLogger
+ }
+ return log
+}
+
// hasNetwork reports whether Kronk can reach the internet. It issues a real
// HTTP request through a client that honors HTTP_PROXY/HTTPS_PROXY, so the
// probe succeeds in proxy-only environments where a raw outbound TCP dial is
diff --git a/sdk/tools/bucky/libs/libs_test.go b/sdk/tools/bucky/libs/libs_test.go
index 46a6855b0..1c137a816 100644
--- a/sdk/tools/bucky/libs/libs_test.go
+++ b/sdk/tools/bucky/libs/libs_test.go
@@ -1,6 +1,11 @@
package libs
-import "testing"
+import (
+ "context"
+ "os"
+ "path/filepath"
+ "testing"
+)
func TestWithValidation(t *testing.T) {
var options Options
@@ -11,6 +16,42 @@ func TestWithValidation(t *testing.T) {
}
}
+func TestDownloadAcceptsNilLogger(t *testing.T) {
+ root := t.TempDir()
+ if err := writeVersionFile(root, defaultVersion, "arm64", "darwin", "metal"); err != nil {
+ t.Fatalf("writeVersionFile: %v", err)
+ }
+
+ lib := Libs{path: root, readOnly: true}
+ if _, err := lib.Download(context.Background(), nil); err != nil {
+ t.Fatalf("Download: %v", err)
+ }
+}
+
+func TestSwapInstallRestoresExistingInstallWhenActivationFails(t *testing.T) {
+ root := t.TempDir()
+ path := filepath.Join(root, "cpu")
+ if err := os.Mkdir(path, 0o755); err != nil {
+ t.Fatalf("Mkdir: %v", err)
+ }
+ existing := filepath.Join(path, "libwhisper.dylib")
+ if err := os.WriteFile(existing, []byte("working"), 0o644); err != nil {
+ t.Fatalf("WriteFile: %v", err)
+ }
+
+ if _, err := swapInstall(path, filepath.Join(root, "missing-stage")); err == nil {
+ t.Fatal("swapInstall: got nil error, want activation failure")
+ }
+
+ data, err := os.ReadFile(existing)
+ if err != nil {
+ t.Fatalf("ReadFile existing install: %v", err)
+ }
+ if string(data) != "working" {
+ t.Errorf("existing install: got %q, want working", data)
+ }
+}
+
func TestVersionGreater(t *testing.T) {
tests := []struct {
name string
diff --git a/sdk/tools/bucky/models/models.go b/sdk/tools/bucky/models/models.go
index b8777fb16..c0948ed0e 100644
--- a/sdk/tools/bucky/models/models.go
+++ b/sdk/tools/bucky/models/models.go
@@ -31,6 +31,7 @@ var (
localFolder = "bucky-models"
indexFile = ".index.yaml"
+ partialDir = ".partial"
)
// Path returns file path information about a whisper model. It is an
@@ -153,8 +154,8 @@ func (m *Models) BuildIndex(log applog.Logger, checkSHA bool) error {
// - A full ggml filename ("ggml-tiny.bin").
// - A fully qualified download URL accepted by hashicorp/go-getter.
//
-// Models already present on disk for the resolved short name are
-// returned without a network round-trip.
+// Existing files are passed through the downloader so it can compare their
+// size with the server and resume an interrupted transfer when necessary.
func (m *Models) Download(ctx context.Context, log applog.Logger, source string) (Path, error) {
source = strings.TrimSpace(source)
if source == "" {
@@ -185,22 +186,11 @@ func (m *Models) Download(ctx context.Context, log applog.Logger, source string)
}
dest := filepath.Join(m.modelsPath, fileName)
- if info, err := os.Stat(dest); err == nil && info.Size() > 0 {
- log(ctx, "download-model: already installed", "file", fileName)
- mp := Path{
- ModelFiles: []string{dest},
- Downloaded: true,
- Validated: true,
- FileSizes: []int64{info.Size()},
- }
- if err := m.refreshIndex(log); err != nil {
- log(ctx, "download-model: refresh index", "ERROR", err)
- }
- if err := m.cacheHeaderFromFile(extractModelID(fileName), dest); err != nil {
- log(ctx, "download-model: cache header", "ERROR", err)
- }
- return mp, nil
+ stagingDir := filepath.Join(m.modelsPath, partialDir)
+ if err := os.MkdirAll(stagingDir, 0o755); err != nil {
+ return Path{}, fmt.Errorf("download: create staging directory: %w", err)
}
+ staged := filepath.Join(stagingDir, fileName)
progress := func(src string, currentSize int64, totalSize int64, mbPerSec float64, complete bool) {
log(ctx, fmt.Sprintf("\r\x1b[Kdownload-model: Downloading %s... %d MB of %d MB (%.2f MB/s)", src, currentSize/(1000*1000), totalSize/(1000*1000), mbPerSec))
@@ -208,14 +198,22 @@ func (m *Models) Download(ctx context.Context, log applog.Logger, source string)
pr := downloader.NewProgressReader(progress, downloader.SizeIntervalMB10)
- if err := download.GetModelWithContext(ctx, downloadURL, m.modelsPath, getter.ProgressTracker(pr)); err != nil {
+ if err := download.GetModelWithContext(ctx, downloadURL, stagingDir, getter.ProgressTracker(pr)); err != nil {
return Path{}, fmt.Errorf("download: %w", err)
}
- info, err := os.Stat(dest)
+ info, err := os.Stat(staged)
if err != nil {
- return Path{}, fmt.Errorf("download: stat installed model: %w", err)
+ return Path{}, fmt.Errorf("download: stat staged model: %w", err)
}
+ if info.Size() == 0 {
+ return Path{}, fmt.Errorf("download: staged model is empty")
+ }
+
+ if err := activateModelFile(staged, dest); err != nil {
+ return Path{}, fmt.Errorf("download: activate model: %w", err)
+ }
+ _ = os.Remove(stagingDir)
if err := m.refreshIndex(log); err != nil {
log(ctx, "download-model: refresh index", "ERROR", err)
@@ -350,6 +348,48 @@ func parseURLPath(raw string) string {
// =============================================================================
+func activateModelFile(staged string, dest string) error {
+ backup := ""
+ if _, err := os.Stat(dest); err == nil {
+ file, err := os.CreateTemp(filepath.Dir(dest), "."+filepath.Base(dest)+".backup-*")
+ if err != nil {
+ return fmt.Errorf("create backup path: %w", err)
+ }
+ backup = file.Name()
+ if err := file.Close(); err != nil {
+ os.Remove(backup)
+ return fmt.Errorf("close backup path: %w", err)
+ }
+ if err := os.Remove(backup); err != nil {
+ return fmt.Errorf("prepare backup path: %w", err)
+ }
+ if err := os.Rename(dest, backup); err != nil {
+ return fmt.Errorf("preserve installed model: %w", err)
+ }
+ } else if !errors.Is(err, os.ErrNotExist) {
+ return fmt.Errorf("inspect installed model: %w", err)
+ }
+
+ if err := os.Rename(staged, dest); err != nil {
+ if backup != "" {
+ if rollbackErr := os.Rename(backup, dest); rollbackErr != nil {
+ return errors.Join(
+ fmt.Errorf("activate staged model: %w", err),
+ fmt.Errorf("restore installed model: %w", rollbackErr),
+ )
+ }
+ }
+ return fmt.Errorf("activate staged model: %w", err)
+ }
+
+ if backup != "" {
+ _ = os.Remove(backup)
+ }
+ return nil
+}
+
+// =============================================================================
+
// catalog is the curated set of well-known whisper models. URLs are
// pinned to the upstream HuggingFace mirror. The set mirrors the
// table maintained in github.com/ardanlabs/bucky/cmd/model.go so
diff --git a/sdk/tools/bucky/models/models_test.go b/sdk/tools/bucky/models/models_test.go
index 73ddd3263..77c703009 100644
--- a/sdk/tools/bucky/models/models_test.go
+++ b/sdk/tools/bucky/models/models_test.go
@@ -4,6 +4,9 @@ import (
"context"
"encoding/binary"
"errors"
+ "fmt"
+ "net/http"
+ "net/http/httptest"
"os"
"path/filepath"
"testing"
@@ -71,3 +74,90 @@ func TestCatalogHeaderInstalledModelOutsideCatalog(t *testing.T) {
t.Error("IsMultilingual: got true, want false")
}
}
+
+func TestDownloadResumesPartialModel(t *testing.T) {
+ contents := []byte("complete whisper model contents")
+
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Accept-Ranges", "bytes")
+ if r.Method == http.MethodHead {
+ w.Header().Set("Content-Length", fmt.Sprint(len(contents)))
+ return
+ }
+
+ start := 0
+ if value := r.Header.Get("Range"); value != "" {
+ if _, err := fmt.Sscanf(value, "bytes=%d-", &start); err != nil {
+ t.Errorf("Range header: %q", value)
+ http.Error(w, "bad range", http.StatusBadRequest)
+ return
+ }
+ w.Header().Set("Content-Length", fmt.Sprint(len(contents)-start))
+ w.Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", start, len(contents)-1, len(contents)))
+ w.WriteHeader(http.StatusPartialContent)
+ } else {
+ w.Header().Set("Content-Length", fmt.Sprint(len(contents)))
+ }
+ _, _ = w.Write(contents[start:])
+ }))
+ defer server.Close()
+
+ m, err := NewWithPaths(t.TempDir())
+ if err != nil {
+ t.Fatalf("NewWithPaths: %v", err)
+ }
+
+ stagingDir := filepath.Join(m.Path(), partialDir)
+ if err := os.MkdirAll(stagingDir, 0o755); err != nil {
+ t.Fatalf("MkdirAll staging: %v", err)
+ }
+ if err := os.WriteFile(filepath.Join(stagingDir, "ggml-resume.bin"), contents[:7], 0o644); err != nil {
+ t.Fatalf("WriteFile: %v", err)
+ }
+
+ if _, err := m.Download(t.Context(), func(context.Context, string, ...any) {}, server.URL+"/ggml-resume.bin"); err != nil {
+ t.Fatalf("Download: %v", err)
+ }
+
+ got, err := os.ReadFile(filepath.Join(m.Path(), "ggml-resume.bin"))
+ if err != nil {
+ t.Fatalf("ReadFile: %v", err)
+ }
+ if string(got) != string(contents) {
+ t.Fatalf("downloaded contents: got %q, want %q", got, contents)
+ }
+}
+
+func TestInterruptedDownloadIsNotInstalled(t *testing.T) {
+ contents := []byte("partial whisper model")
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Content-Length", fmt.Sprint(len(contents)*2))
+ if r.Method == http.MethodHead {
+ return
+ }
+ _, _ = w.Write(contents)
+ }))
+ defer server.Close()
+
+ m, err := NewWithPaths(t.TempDir())
+ if err != nil {
+ t.Fatalf("NewWithPaths: %v", err)
+ }
+ log := func(context.Context, string, ...any) {}
+
+ if _, err := m.Download(t.Context(), log, server.URL+"/ggml-interrupted.bin"); err == nil {
+ t.Fatal("Download: got nil error, want interrupted download error")
+ }
+ if _, err := os.Stat(filepath.Join(m.Path(), "ggml-interrupted.bin")); !errors.Is(err, os.ErrNotExist) {
+ t.Fatalf("installed model: got %v, want os.ErrNotExist", err)
+ }
+ if _, err := os.Stat(filepath.Join(m.Path(), partialDir, "ggml-interrupted.bin")); err != nil {
+ t.Fatalf("partial model was not retained for resume: %v", err)
+ }
+ if err := m.BuildIndex(log, false); err != nil {
+ t.Fatalf("BuildIndex: %v", err)
+ }
+ if _, err := m.FullPath("interrupted"); !errors.Is(err, ErrModelNotFound) {
+ t.Fatalf("FullPath: got %v, want ErrModelNotFound", err)
+ }
+}
diff --git a/sdk/tools/defaults/yaml/model_config.yaml b/sdk/tools/defaults/yaml/model_config.yaml
index 68fb6ce62..111ce45ec 100644
--- a/sdk/tools/defaults/yaml/model_config.yaml
+++ b/sdk/tools/defaults/yaml/model_config.yaml
@@ -96,7 +96,6 @@ version: 1
# numa: distribute # NUMA strategy: "" (off), distribute, isolate, numactl, mirror
# offload-kqv: true # Offload KV cache to GPU (false = keep on CPU)
# op-offload: true # Offload tensor operations to GPU (false = keep on CPU)
-# op-offload-min-batch: 0 # Min batch size before host tensor ops are offloaded (0 = default)
# proj-on-cpu: true # Force multimodal projector (mmproj) onto CPU
# proj-device: CUDA1 # Explicit mmproj device; omit for automatic (conflicts with proj-on-cpu: true)
# rope-freq-base: 1000000 # RoPE base frequency (nil = from model, e.g., 10000 Llama, 1000000 Qwen)
diff --git a/sdk/tools/devices/gpu_detect_linux.go b/sdk/tools/devices/gpu_detect_linux.go
index 1d09b20e8..bac03e6b5 100644
--- a/sdk/tools/devices/gpu_detect_linux.go
+++ b/sdk/tools/devices/gpu_detect_linux.go
@@ -3,8 +3,10 @@
package devices
import (
+ "context"
"os/exec"
"strings"
+ "time"
"github.com/hybridgroup/yzma/pkg/download"
)
@@ -35,7 +37,10 @@ func hasVulkan() bool {
return false
}
- out, err := exec.Command("vulkaninfo", "--summary").CombinedOutput()
+ ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
+ defer cancel()
+
+ out, err := exec.CommandContext(ctx, "vulkaninfo", "--summary").CombinedOutput()
if err != nil {
return false
}
diff --git a/sdk/tools/devices/gpu_detect_windows.go b/sdk/tools/devices/gpu_detect_windows.go
index 8d15de001..24c16356d 100644
--- a/sdk/tools/devices/gpu_detect_windows.go
+++ b/sdk/tools/devices/gpu_detect_windows.go
@@ -3,8 +3,10 @@
package devices
import (
+ "context"
"os/exec"
"strings"
+ "time"
"github.com/hybridgroup/yzma/pkg/download"
)
@@ -30,7 +32,10 @@ func DetectGPU() download.Processor {
// vulkaninfo utility on PATH or the Vulkan runtime DLL in System32.
func hasVulkan() bool {
if _, err := exec.LookPath("vulkaninfo"); err == nil {
- out, err := exec.Command("vulkaninfo", "--summary").CombinedOutput()
+ ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
+ defer cancel()
+
+ out, err := exec.CommandContext(ctx, "vulkaninfo", "--summary").CombinedOutput()
if err == nil && strings.Contains(string(out), "Vulkan Instance") {
return true
}
diff --git a/sdk/tools/diagnose/diagnose.go b/sdk/tools/diagnose/diagnose.go
index f088bb976..0b35d7294 100644
--- a/sdk/tools/diagnose/diagnose.go
+++ b/sdk/tools/diagnose/diagnose.go
@@ -35,6 +35,10 @@ const installTimeout = 15 * time.Minute
// resolveTimeout bounds the inspect-only model lookup (no download).
const resolveTimeout = 10 * time.Second
+// commandTimeout prevents a wedged driver utility or llama-bench process from
+// blocking a diagnostic report indefinitely.
+const commandTimeout = 2 * time.Minute
+
// =============================================================================
// Report model
@@ -255,7 +259,7 @@ func Collect(ctx context.Context, log applog.Logger, opts ...Option) (Report, er
r := Report{
Versions: collectVersions(o.kronkVersion),
- System: collectSystem(),
+ System: collectSystem(ctx),
}
backends, root, err := resolveBackends(ctx, log, o.install)
@@ -333,7 +337,7 @@ func Collect(ctx context.Context, log applog.Logger, opts ...Option) (Report, er
benchProc = "cpu"
}
- r.Bench = collectBench(benchProc, b.BinDir, modelPath, forceCPU)
+ r.Bench = collectBench(ctx, benchProc, b.BinDir, modelPath, forceCPU)
}
}
@@ -350,7 +354,7 @@ func collectVersions(kronkVersion string) Versions {
}
}
-func collectSystem() System {
+func collectSystem(ctx context.Context) System {
s := System{
OS: runtime.GOOS,
Arch: runtime.GOARCH,
@@ -358,7 +362,7 @@ func collectSystem() System {
}
for _, spec := range systemCommandSpecs() {
- s.Commands = append(s.Commands, capture(spec))
+ s.Commands = append(s.Commands, capture(ctx, spec))
}
s.CPUModel, s.RAMBytes = parseSystem(s.Commands)
@@ -366,14 +370,14 @@ func collectSystem() System {
return s
}
-func llamaCommands(binDir string) []Command {
+func llamaCommands(ctx context.Context, binDir string) []Command {
return []Command{
- capture(commandSpec{bin(binDir, "llama-cli"), []string{"--version"}}),
- capture(commandSpec{bin(binDir, "llama-bench"), []string{"--list-devices"}}),
+ capture(ctx, commandSpec{bin(binDir, "llama-cli"), []string{"--version"}}),
+ capture(ctx, commandSpec{bin(binDir, "llama-bench"), []string{"--list-devices"}}),
}
}
-func collectBench(processor, binDir, modelPath string, forceCPU bool) Bench {
+func collectBench(ctx context.Context, processor, binDir, modelPath string, forceCPU bool) Bench {
args := []string{"-m", modelPath}
// Force CPU-only execution only when reusing a GPU bundle's binary for a
@@ -390,7 +394,7 @@ func collectBench(processor, binDir, modelPath string, forceCPU bool) Bench {
Processor: processor,
Model: modelPath,
Commands: []Command{
- capture(commandSpec{bin(binDir, "llama-bench"), args}),
+ capture(ctx, commandSpec{bin(binDir, "llama-bench"), args}),
},
}
}
@@ -543,7 +547,7 @@ func resolveBackends(ctx context.Context, log applog.Logger, install bool) ([]Ba
}
binDir := filepath.Join(root, tag.OS, tag.Arch, tag.Processor)
- cmds := llamaCommands(binDir)
+ cmds := llamaCommands(ctx, binDir)
backends = append(backends, Backend{
Processor: tag.Processor,
@@ -612,10 +616,13 @@ type commandSpec struct {
}
// capture runs a command and returns its combined output as a Command.
-func capture(spec commandSpec) Command {
+func capture(ctx context.Context, spec commandSpec) Command {
cmd := Command{Cmd: strings.TrimSpace(spec.name + " " + strings.Join(spec.args, " "))}
- out, err := exec.Command(spec.name, spec.args...).CombinedOutput()
+ commandCtx, cancel := context.WithTimeout(ctx, commandTimeout)
+ defer cancel()
+
+ out, err := exec.CommandContext(commandCtx, spec.name, spec.args...).CombinedOutput()
cmd.Output = expandTabs(string(out))
if err != nil {
cmd.Err = err.Error()
diff --git a/sdk/tools/diagnose/diagnose_test.go b/sdk/tools/diagnose/diagnose_test.go
new file mode 100644
index 000000000..2b506c167
--- /dev/null
+++ b/sdk/tools/diagnose/diagnose_test.go
@@ -0,0 +1,18 @@
+package diagnose
+
+import (
+ "context"
+ "os"
+ "strings"
+ "testing"
+)
+
+func TestCaptureHonorsCanceledContext(t *testing.T) {
+ ctx, cancel := context.WithCancel(t.Context())
+ cancel()
+
+ cmd := capture(ctx, commandSpec{name: os.Args[0], args: []string{"-test.run=^$"}})
+ if !strings.Contains(cmd.Err, context.Canceled.Error()) {
+ t.Fatalf("capture error: got %q, want context cancellation", cmd.Err)
+ }
+}
diff --git a/sdk/tools/downloader/downloader.go b/sdk/tools/downloader/downloader.go
index 6c07d85cd..672197a02 100644
--- a/sdk/tools/downloader/downloader.go
+++ b/sdk/tools/downloader/downloader.go
@@ -10,6 +10,7 @@ import (
"os"
"time"
+ "github.com/ardanlabs/kronk/sdk/kronk/hf"
"github.com/hashicorp/go-getter"
)
@@ -40,7 +41,7 @@ func Download(ctx context.Context, src string, dest string, progress ProgressFun
httpGetter := &getter.HttpGetter{}
- if os.Getenv("KRONK_HF_TOKEN") != "" {
+ if os.Getenv("KRONK_HF_TOKEN") != "" && hf.IsHuggingFaceURL(src) {
httpGetter.Header = map[string][]string{
"Authorization": {"Bearer " + os.Getenv("KRONK_HF_TOKEN")},
}
diff --git a/sdk/tools/downloader/downloader_test.go b/sdk/tools/downloader/downloader_test.go
index c6816463a..77baa3abd 100644
--- a/sdk/tools/downloader/downloader_test.go
+++ b/sdk/tools/downloader/downloader_test.go
@@ -17,6 +17,9 @@ func TestDownloadResumesPartialFile(t *testing.T) {
rangeCh := make(chan string, 1)
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if got := r.Header.Get("Authorization"); got != "" {
+ t.Errorf("Authorization: got %q, want empty for non-Hugging Face host", got)
+ }
w.Header().Set("Accept-Ranges", "bytes")
w.Header().Set("Content-Length", fmt.Sprint(len(content)))
if r.Method == http.MethodHead {
@@ -40,6 +43,7 @@ func TestDownloadResumesPartialFile(t *testing.T) {
}))
defer srv.Close()
+ t.Setenv("KRONK_HF_TOKEN", "secret")
t.Setenv("KRONK_SKIP_NETWORK_CHECK", "yes")
dest := t.TempDir()
modelFile := filepath.Join(dest, "model.gguf")
diff --git a/sdk/tools/libs/bundle.go b/sdk/tools/libs/bundle.go
index 5b62014fe..0d53d9816 100644
--- a/sdk/tools/libs/bundle.go
+++ b/sdk/tools/libs/bundle.go
@@ -356,15 +356,21 @@ func (lib *Libs) PullBundleFromPeer(ctx context.Context, host string, arch strin
}
dest := installPathFor(lib.root, a, o, p)
- if err := os.MkdirAll(dest, 0o755); err != nil {
- return VersionTag{}, fmt.Errorf("libs: pull-bundle-from-peer: mkdir dest: %w", err)
+ parent := filepath.Dir(dest)
+ if err := os.MkdirAll(parent, 0o755); err != nil {
+ return VersionTag{}, fmt.Errorf("libs: pull-bundle-from-peer: mkdir parent: %w", err)
}
- tempPath := filepath.Join(dest, "temp")
- os.RemoveAll(tempPath)
- if err := os.MkdirAll(tempPath, 0o755); err != nil {
- return VersionTag{}, fmt.Errorf("libs: pull-bundle-from-peer: mkdir temp: %w", err)
+ tempPath, err := os.MkdirTemp(parent, "."+filepath.Base(dest)+".stage-")
+ if err != nil {
+ return VersionTag{}, fmt.Errorf("libs: pull-bundle-from-peer: mkdir stage: %w", err)
}
+ preserveStage := false
+ defer func() {
+ if !preserveStage {
+ _ = os.RemoveAll(tempPath)
+ }
+ }()
tmpZip := filepath.Join(tempPath, BundleZipFile)
@@ -465,24 +471,24 @@ func (lib *Libs) PullBundleFromPeer(ctx context.Context, host string, arch strin
// downstream peer.
os.Remove(tmpZip)
- if progress != nil {
- progress(PullBundleProgress{Phase: "swapping"})
+ // Read the version.json that came across in the bundle. If absent,
+ // synthesize one from the requested triple before activation so the
+ // staged directory is a complete installation.
+ tag, err := readVersionFile(tempPath)
+ if err != nil {
+ if err := writeVersionFile(tempPath, "", a, o, p); err != nil {
+ return VersionTag{}, fmt.Errorf("libs: pull-bundle-from-peer: write version.json: %w", err)
+ }
+ tag, _ = readVersionFile(tempPath)
}
- if err := swapTempForLibAt(dest, tempPath); err != nil {
- os.RemoveAll(tempPath)
- return VersionTag{}, fmt.Errorf("libs: pull-bundle-from-peer: swap: %w", err)
+ if progress != nil {
+ progress(PullBundleProgress{Phase: "swapping"})
}
- // Read the version.json that came across in the bundle. If absent,
- // synthesize one from the requested triple so that List/InstalledFor
- // continue to work.
- tag, err := readVersionFile(dest)
+ preserveStage, err = swapInstall(dest, tempPath)
if err != nil {
- if err := writeVersionFile(dest, "", a, o, p); err != nil {
- return VersionTag{}, fmt.Errorf("libs: pull-bundle-from-peer: write version.json: %w", err)
- }
- tag, _ = readVersionFile(dest)
+ return VersionTag{}, fmt.Errorf("libs: pull-bundle-from-peer: swap: %w", err)
}
if progress != nil {
diff --git a/sdk/tools/libs/libs.go b/sdk/tools/libs/libs.go
index 5b4b4d0a4..f4fb8b870 100644
--- a/sdk/tools/libs/libs.go
+++ b/sdk/tools/libs/libs.go
@@ -314,6 +314,13 @@ func (lib *Libs) SetVersion(version string) {
// - WithValidation(true) verifies the selected installed bundle before
// Download reports success.
func (lib *Libs) Download(ctx context.Context, log Logger) (tag VersionTag, retErr error) {
+ return lib.DownloadSelected(ctx, log, lib.version, lib.AllowUpgrade)
+}
+
+// DownloadSelected performs the Download workflow with request-scoped version
+// and upgrade settings instead of mutating the Libs configuration.
+func (lib *Libs) DownloadSelected(ctx context.Context, log Logger, versionOverride string, allowUpgrade bool) (tag VersionTag, retErr error) {
+ log = normalizeLogger(log)
defer func() {
if retErr == nil && lib.validation {
retErr = lib.validateDownload(ctx, log, tag)
@@ -346,7 +353,7 @@ func (lib *Libs) Download(ctx context.Context, log Logger) (tag VersionTag, retE
// For matrix row 2 we need the latest version published by llama.cpp.
// For all other rows the network lookup is unnecessary, so skip it.
var latest string
- if lib.version == "" && lib.AllowUpgrade {
+ if versionOverride == "" && allowUpgrade {
info, err := lib.VersionInformation()
if err != nil {
if installed.Version == "" {
@@ -359,7 +366,7 @@ func (lib *Libs) Download(ctx context.Context, log Logger) (tag VersionTag, retE
latest = info.Latest
}
- version := chooseVersion(lib.version, lib.AllowUpgrade, installed.Version, latest, defaultVersion)
+ version := chooseVersion(versionOverride, allowUpgrade, installed.Version, latest, defaultVersion)
log(ctx, "download-libraries: check llama.cpp installation", "arch", lib.arch, "os", lib.os, "processor", lib.processor, "requested", version, "current", installed.Version)
@@ -450,11 +457,22 @@ func (lib *Libs) DownloadInto(ctx context.Context, log Logger, path string, arch
// download.* values. Internal callers that have already parsed a triple use
// this directly to avoid re-parsing.
func (lib *Libs) downloadInto(ctx context.Context, log Logger, path string, arch download.Arch, opSys download.OS, processor download.Processor, version string) (VersionTag, error) {
- if err := os.MkdirAll(path, 0o755); err != nil {
- return VersionTag{}, fmt.Errorf("download-into: unable to create destination: %w", err)
+ log = normalizeLogger(log)
+ parent := filepath.Dir(path)
+ if err := os.MkdirAll(parent, 0o755); err != nil {
+ return VersionTag{}, fmt.Errorf("download-into: unable to create parent: %w", err)
}
- tempPath := filepath.Join(path, "temp")
+ stagePath, err := os.MkdirTemp(parent, "."+filepath.Base(path)+".stage-")
+ if err != nil {
+ return VersionTag{}, fmt.Errorf("download-into: unable to create staging directory: %w", err)
+ }
+ preserveStage := false
+ defer func() {
+ if !preserveStage {
+ _ = os.RemoveAll(stagePath)
+ }
+ }()
progress := func(src string, currentSize int64, totalSize int64, mbPerSec float64, complete bool) {
log(ctx, fmt.Sprintf("\r\x1b[Kdownload-libraries: Downloading %s... %d MB of %d MB (%.2f MB/s)", src, currentSize/(1000*1000), totalSize/(1000*1000), mbPerSec))
@@ -469,25 +487,26 @@ func (lib *Libs) downloadInto(ctx context.Context, log Logger, path string, arch
Version: version,
}
- err := download.Install(ctx, target, tempPath, pr, nil)
+ err = download.Install(ctx, target, stagePath, pr, nil)
if err != nil {
- os.RemoveAll(tempPath)
return VersionTag{}, fmt.Errorf("download-into: unable to install llama.cpp: %w", err)
}
- record, err := download.ReadInstallRecord(tempPath)
+ record, err := download.ReadInstallRecord(stagePath)
if err != nil {
- os.RemoveAll(tempPath)
return VersionTag{}, fmt.Errorf("download-into: unable to read install record: %w", err)
}
- if err := swapTempForLibAt(path, tempPath); err != nil {
- os.RemoveAll(tempPath)
- return VersionTag{}, fmt.Errorf("download-into: unable to swap temp for lib: %w", err)
+ if err := writeVersionFile(stagePath, record.Tag, arch, opSys, processor); err != nil {
+ return VersionTag{}, fmt.Errorf("download-into: unable to create version file: %w", err)
+ }
+ if err := ctx.Err(); err != nil {
+ return VersionTag{}, fmt.Errorf("download-into: activate libraries: %w", err)
}
- if err := writeVersionFile(path, record.Tag, arch, opSys, processor); err != nil {
- return VersionTag{}, fmt.Errorf("download-into: unable to create version file: %w", err)
+ preserveStage, err = swapInstall(path, stagePath)
+ if err != nil {
+ return VersionTag{}, fmt.Errorf("download-into: unable to install staged libraries: %w", err)
}
return readVersionFile(path)
@@ -696,37 +715,40 @@ func parseTriple(arch string, opSys string, processor string) (download.Arch, do
// =============================================================================
-func swapTempForLibAt(path string, tempPath string) error {
- entries, err := os.ReadDir(path)
- if err != nil {
- return fmt.Errorf("swap-temp-for-lib: unable to read libPath: %w", err)
- }
-
- for _, entry := range entries {
- if entry.Name() == "temp" {
- continue
+func swapInstall(path string, stagePath string) (bool, error) {
+ backupPath := ""
+ if _, err := os.Stat(path); err == nil {
+ backup, err := os.MkdirTemp(filepath.Dir(path), "."+filepath.Base(path)+".backup-")
+ if err != nil {
+ return false, fmt.Errorf("swap-install: create backup path: %w", err)
}
-
- os.RemoveAll(filepath.Join(path, entry.Name()))
- }
-
- tempEntries, err := os.ReadDir(tempPath)
- if err != nil {
- return fmt.Errorf("swap-temp-for-lib: unable to read temp: %w", err)
+ if err := os.Remove(backup); err != nil {
+ return false, fmt.Errorf("swap-install: prepare backup path: %w", err)
+ }
+ backupPath = backup
+ if err := os.Rename(path, backupPath); err != nil {
+ return false, fmt.Errorf("swap-install: preserve current install: %w", err)
+ }
+ } else if !os.IsNotExist(err) {
+ return false, fmt.Errorf("swap-install: inspect current install: %w", err)
}
- for _, entry := range tempEntries {
- src := filepath.Join(tempPath, entry.Name())
- dst := filepath.Join(path, entry.Name())
- os.RemoveAll(dst)
- if err := os.Rename(src, dst); err != nil {
- return fmt.Errorf("swap-temp-for-lib: unable to move %s: %w", entry.Name(), err)
+ if err := os.Rename(stagePath, path); err != nil {
+ if backupPath != "" {
+ if rollbackErr := os.Rename(backupPath, path); rollbackErr != nil {
+ return true, errors.Join(
+ fmt.Errorf("swap-install: activate staged install %q: %w", stagePath, err),
+ fmt.Errorf("swap-install: restore backup %q: %w", backupPath, rollbackErr),
+ )
+ }
}
+ return false, fmt.Errorf("swap-install: activate staged install: %w", err)
}
- os.RemoveAll(tempPath)
-
- return nil
+ if backupPath != "" {
+ _ = os.RemoveAll(backupPath)
+ }
+ return false, nil
}
func writeVersionFile(path string, version string, arch download.Arch, opSys download.OS, processor download.Processor) error {
@@ -919,6 +941,13 @@ func versionTag(value string) string {
return tag
}
+func normalizeLogger(log Logger) Logger {
+ if log == nil {
+ return applog.DiscardLogger
+ }
+ return log
+}
+
// hasNetwork reports whether Kronk can reach the internet. It issues a real
// HTTP request through a client that honors HTTP_PROXY/HTTPS_PROXY, so the
// probe succeeds in proxy-only environments where a raw outbound TCP dial is
diff --git a/sdk/tools/libs/libs_test.go b/sdk/tools/libs/libs_test.go
index bc6e39282..fe1514036 100644
--- a/sdk/tools/libs/libs_test.go
+++ b/sdk/tools/libs/libs_test.go
@@ -24,6 +24,43 @@ func TestWithValidation(t *testing.T) {
}
}
+func TestDownloadAcceptsNilLogger(t *testing.T) {
+ root := t.TempDir()
+ a, o, p := mustParseTriple(t)
+ if err := writeVersionFile(root, "b100", a, o, p); err != nil {
+ t.Fatalf("writeVersionFile: %v", err)
+ }
+
+ lib := Libs{path: root, readOnly: true}
+ if _, err := lib.Download(t.Context(), nil); err != nil {
+ t.Fatalf("Download: %v", err)
+ }
+}
+
+func TestSwapInstallRestoresExistingInstallWhenActivationFails(t *testing.T) {
+ root := t.TempDir()
+ path := filepath.Join(root, "cpu")
+ if err := os.Mkdir(path, 0o755); err != nil {
+ t.Fatalf("Mkdir: %v", err)
+ }
+ existing := filepath.Join(path, "libllama.dylib")
+ if err := os.WriteFile(existing, []byte("working"), 0o644); err != nil {
+ t.Fatalf("WriteFile: %v", err)
+ }
+
+ if _, err := swapInstall(path, filepath.Join(root, "missing-stage")); err == nil {
+ t.Fatal("swapInstall: got nil error, want activation failure")
+ }
+
+ data, err := os.ReadFile(existing)
+ if err != nil {
+ t.Fatalf("ReadFile existing install: %v", err)
+ }
+ if string(data) != "working" {
+ t.Errorf("existing install: got %q, want working", data)
+ }
+}
+
func TestAllowUnavailableFileValidation(t *testing.T) {
var logged bool
log := func(_ context.Context, _ string, _ ...any) {
diff --git a/sdk/tools/malina/libs/libs.go b/sdk/tools/malina/libs/libs.go
index d9e0687fb..b6bf9af6e 100644
--- a/sdk/tools/malina/libs/libs.go
+++ b/sdk/tools/malina/libs/libs.go
@@ -433,6 +433,12 @@ func (lib *Libs) List() ([]VersionTag, error) {
// - WithValidation(true) verifies the selected installed bundle against
// Malina's embedded manifest before Download reports success.
func (lib *Libs) Download(ctx context.Context, log Logger) (tag VersionTag, retErr error) {
+ return lib.DownloadSelected(ctx, log, lib.version, lib.AllowUpgrade)
+}
+
+// DownloadSelected performs the Download workflow with request-scoped version
+// and upgrade settings instead of mutating the Libs configuration.
+func (lib *Libs) DownloadSelected(ctx context.Context, log Logger, versionOverride string, allowUpgrade bool) (tag VersionTag, retErr error) {
defer func() {
if retErr == nil && lib.validation {
retErr = lib.validateDownload(ctx, tag)
@@ -459,8 +465,8 @@ func (lib *Libs) Download(ctx context.Context, log Logger) (tag VersionTag, retE
return VersionTag{}, fmt.Errorf("download-libraries: network check: %w", err)
}
- required := lib.version
- if required == "" && !lib.AllowUpgrade {
+ required := versionOverride
+ if required == "" && !allowUpgrade {
required = defaultVersion
}
if installed.Version == "" {
@@ -481,7 +487,7 @@ func (lib *Libs) Download(ctx context.Context, log Logger) (tag VersionTag, retE
// leejet stable-diffusion.cpp releases. For all other rows the network lookup is
// unnecessary, so skip it.
var latest string
- if lib.version == "" && lib.AllowUpgrade {
+ if versionOverride == "" && allowUpgrade {
v, err := latestVersion()
if ctxErr := ctx.Err(); ctxErr != nil {
return VersionTag{}, fmt.Errorf("download-libraries: retrieve latest version: %w", ctxErr)
@@ -497,7 +503,7 @@ func (lib *Libs) Download(ctx context.Context, log Logger) (tag VersionTag, retE
latest = v
}
- version := chooseVersion(lib.version, lib.AllowUpgrade, latest, defaultVersion)
+ version := chooseVersion(versionOverride, allowUpgrade, latest, defaultVersion)
log(ctx, "download-libraries: check stable-diffusion.cpp installation", "arch", lib.arch, "os", lib.os, "processor", lib.processor, "requested", version, "current", installed.Version)
diff --git a/sdk/tools/malina/models/models.go b/sdk/tools/malina/models/models.go
index 524884d01..bf64b9154 100644
--- a/sdk/tools/malina/models/models.go
+++ b/sdk/tools/malina/models/models.go
@@ -15,6 +15,7 @@ import (
"sync"
"github.com/ardanlabs/kronk/sdk/applog"
+ "github.com/ardanlabs/kronk/sdk/kronk/hf"
"github.com/ardanlabs/kronk/sdk/tools/backend"
"github.com/ardanlabs/kronk/sdk/tools/defaults"
"github.com/ardanlabs/malina/pkg/download"
@@ -115,12 +116,7 @@ func (m *Models) downloadBundle(ctx context.Context, log applog.Logger, bundle B
dir := filepath.Join(m.modelsPath, bundle.Name.String())
manifest := Manifest{Bundle: bundle.Name, License: bundle.License, Gated: bundle.Gated, Files: make(map[string]string, len(bundle.Files))}
for _, file := range bundle.Files {
- finalTarget := filepath.Join(dir, file.Filename)
- absoluteTarget, err := filepath.Abs(finalTarget)
- if err != nil {
- return Manifest{}, fmt.Errorf("download-bundle: resolve target: %w", err)
- }
- manifest.Files[string(file.Role)] = absoluteTarget
+ manifest.Files[string(file.Role)] = file.Filename
if err := downloadModelFile(ctx, file.URL, filepath.Join(stageDir, file.Filename), progress); err != nil {
return Manifest{}, bundleDownloadError(bundle, file, err)
}
@@ -186,7 +182,7 @@ func downloadFile(ctx context.Context, source string, target string, progress ge
if token == "" {
token = os.Getenv("HF_TOKEN")
}
- if token != "" {
+ if token != "" && hf.IsHuggingFaceURL(source) {
header.Set("Authorization", "Bearer "+token)
}
client := getter.Client{
@@ -234,6 +230,14 @@ func (m *Models) loadManifestLocked(bundle Bundle) (Manifest, error) {
if !m.validManifest(bundle, manifest) {
return Manifest{}, fmt.Errorf("load-manifest: invalid manifest for bundle %q", bundle.Name)
}
+ dir := filepath.Join(m.modelsPath, bundle.Name.String())
+ for _, file := range bundle.Files {
+ resolved, err := filepath.Abs(filepath.Join(dir, file.Filename))
+ if err != nil {
+ return Manifest{}, fmt.Errorf("load-manifest: resolve %q: %w", file.Filename, err)
+ }
+ manifest.Files[string(file.Role)] = resolved
+ }
return manifest, nil
}
@@ -333,7 +337,14 @@ func (m *Models) validManifest(bundle Bundle, manifest Manifest) bool {
}
expected := filepath.Join(dir, file.Filename)
path := manifest.Files[string(file.Role)]
- if path == "" || !samePath(path, expected) {
+ if path == "" {
+ return false
+ }
+ if filepath.IsAbs(path) {
+ if filepath.Base(path) != file.Filename {
+ return false
+ }
+ } else if path != file.Filename {
return false
}
info, err := os.Lstat(expected)
@@ -344,12 +355,6 @@ func (m *Models) validManifest(bundle Bundle, manifest Manifest) bool {
return true
}
-func samePath(left string, right string) bool {
- leftAbs, leftErr := filepath.Abs(left)
- rightAbs, rightErr := filepath.Abs(right)
- return leftErr == nil && rightErr == nil && filepath.Clean(leftAbs) == filepath.Clean(rightAbs)
-}
-
// Download downloads source as a curated bundle name.
func (m *Models) Download(ctx context.Context, log applog.Logger, source string) (Path, error) {
name, err := ParseBundleName(source)
diff --git a/sdk/tools/malina/models/models_test.go b/sdk/tools/malina/models/models_test.go
index 1a7b83f0b..59695fbe6 100644
--- a/sdk/tools/malina/models/models_test.go
+++ b/sdk/tools/malina/models/models_test.go
@@ -188,15 +188,14 @@ func TestBundleBasicTextToImage(t *testing.T) {
}
}
-func TestDownloadFileAuthorization(t *testing.T) {
+func TestDownloadFileDoesNotAuthorizeOtherHosts(t *testing.T) {
tests := []struct {
name string
kronkToken string
hfToken string
- want string
}{
- {name: "kronk token takes precedence", kronkToken: "kronk", hfToken: "hf", want: "Bearer kronk"},
- {name: "HF token fallback", hfToken: "hf", want: "Bearer hf"},
+ {name: "Kronk token", kronkToken: "kronk"},
+ {name: "HF token fallback", hfToken: "hf"},
}
for _, tt := range tests {
@@ -214,8 +213,8 @@ func TestDownloadFileAuthorization(t *testing.T) {
if err := downloadFile(t.Context(), server.URL+"/model.gguf", target, nil); err != nil {
t.Fatalf("downloadFile() error = %v", err)
}
- if authorization != tt.want {
- t.Errorf("Authorization: got %q, want %q", authorization, tt.want)
+ if authorization != "" {
+ t.Errorf("Authorization: got %q, want empty for non-Hugging Face host", authorization)
}
})
}
@@ -278,6 +277,40 @@ func TestDownloadBundleWritesManifestAfterCompletion(t *testing.T) {
}
}
+func TestDownloadBundlePersistsRelativePaths(t *testing.T) {
+ originalDownload := downloadModelFile
+ t.Cleanup(func() { downloadModelFile = originalDownload })
+ downloadModelFile = func(ctx context.Context, source string, target string, progress getter.ProgressTracker) error {
+ return os.WriteFile(target, []byte("model"), 0o644)
+ }
+
+ m, err := NewWithPaths(t.TempDir())
+ if err != nil {
+ t.Fatalf("NewWithPaths() error = %v", err)
+ }
+ bundle, _ := BundleByName(BundleSD15)
+ manifest, err := m.downloadBundle(t.Context(), applog.DiscardLogger, bundle, nil)
+ if err != nil {
+ t.Fatalf("downloadBundle() error = %v", err)
+ }
+ wantPath := filepath.Join(m.Path(), bundle.Name.String(), bundle.Files[0].Filename)
+ if got := manifest.Files[string(RoleModel)]; got != wantPath {
+ t.Errorf("returned model path = %q, want %q", got, wantPath)
+ }
+
+ data, err := os.ReadFile(filepath.Join(m.Path(), bundle.Name.String(), ManifestFilename))
+ if err != nil {
+ t.Fatalf("ReadFile() error = %v", err)
+ }
+ var stored Manifest
+ if err := json.Unmarshal(data, &stored); err != nil {
+ t.Fatalf("Unmarshal() error = %v", err)
+ }
+ if got := stored.Files[string(RoleModel)]; got != bundle.Files[0].Filename {
+ t.Errorf("stored model path = %q, want relative filename %q", got, bundle.Files[0].Filename)
+ }
+}
+
func TestDownloadBundleRejectsEmptyStagedFile(t *testing.T) {
originalDownload := downloadModelFile
t.Cleanup(func() { downloadModelFile = originalDownload })
@@ -350,6 +383,40 @@ func TestLoadManifestRoundTrip(t *testing.T) {
}
}
+func TestLoadManifestRelocatesLegacyAbsolutePath(t *testing.T) {
+ m, err := NewWithPaths(t.TempDir())
+ if err != nil {
+ t.Fatalf("NewWithPaths() error = %v", err)
+ }
+ bundle, _ := BundleByName(BundleSD15)
+ dir := filepath.Join(m.Path(), bundle.Name.String())
+ if err := os.MkdirAll(dir, 0o755); err != nil {
+ t.Fatal(err)
+ }
+ current := filepath.Join(dir, bundle.Files[0].Filename)
+ if err := os.WriteFile(current, []byte("model"), 0o644); err != nil {
+ t.Fatal(err)
+ }
+ legacy := Manifest{Bundle: bundle.Name, Files: map[string]string{
+ string(RoleModel): filepath.Join(t.TempDir(), bundle.Files[0].Filename),
+ }}
+ data, err := json.Marshal(legacy)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err := os.WriteFile(filepath.Join(dir, ManifestFilename), data, 0o644); err != nil {
+ t.Fatal(err)
+ }
+
+ manifest, err := m.LoadManifest(BundleSD15)
+ if err != nil {
+ t.Fatalf("LoadManifest() error = %v", err)
+ }
+ if got := manifest.Files[string(RoleModel)]; got != current {
+ t.Errorf("model path = %q, want relocated path %q", got, current)
+ }
+}
+
func TestIndexFullPathRemoveLifecycle(t *testing.T) {
m, err := NewWithPaths(t.TempDir())
if err != nil {
diff --git a/sdk/tools/models/catalog.go b/sdk/tools/models/catalog.go
index bf91a77df..7957edb3d 100644
--- a/sdk/tools/models/catalog.go
+++ b/sdk/tools/models/catalog.go
@@ -118,11 +118,23 @@ func (r Resolution) VerifyLocal() error {
// previously-seen IDs and falls back to the HuggingFace API for new ones.
type Resolver struct {
filePath string
- mu sync.Mutex
+ mu *sync.Mutex
hfClient hf.Client
models *Models
}
+var resolverLocks sync.Map
+
+func resolverLock(filePath string) *sync.Mutex {
+ key, err := filepath.Abs(filePath)
+ if err != nil {
+ key = filepath.Clean(filePath)
+ }
+
+ lock, _ := resolverLocks.LoadOrStore(key, &sync.Mutex{})
+ return lock.(*sync.Mutex)
+}
+
// NewResolver constructs a Resolver using the default HuggingFace client.
// filePath is the location of catalog.yaml on disk.
func NewResolver(m *Models, filePath string) *Resolver {
@@ -134,6 +146,7 @@ func NewResolver(m *Models, filePath string) *Resolver {
func NewResolverWithClient(m *Models, filePath string, client hf.Client) *Resolver {
return &Resolver{
filePath: filePath,
+ mu: resolverLock(filePath),
hfClient: client,
models: m,
}
@@ -184,6 +197,37 @@ func (r *Resolver) Save(rm Catalog) error {
return r.saveLocked(rm)
}
+func (r *Resolver) update(updateFn func(*Catalog) error) error {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+
+ rm, err := r.loadLocked()
+ if err != nil {
+ return err
+ }
+
+ if err := updateFn(&rm); err != nil {
+ return err
+ }
+
+ return r.saveLocked(rm)
+}
+
+func (r *Resolver) saveEntry(canonical string, entry CatalogEntry) error {
+ return r.update(func(rm *Catalog) error {
+ rm.Models[canonical] = entry
+ return nil
+ })
+}
+
+// Delete removes one catalog entry in a single read-modify-write transaction.
+func (r *Resolver) Delete(canonical string) error {
+ return r.update(func(rm *Catalog) error {
+ delete(rm.Models, canonical)
+ return nil
+ })
+}
+
func (r *Resolver) saveLocked(rm Catalog) error {
if rm.Models == nil {
rm.Models = map[string]CatalogEntry{}
@@ -198,8 +242,26 @@ func (r *Resolver) saveLocked(rm Catalog) error {
return fmt.Errorf("resolver-save: mkdir: %w", err)
}
- if err := os.WriteFile(r.filePath, data, 0644); err != nil {
- return fmt.Errorf("resolver-save: write: %w", err)
+ tmp, err := os.CreateTemp(filepath.Dir(r.filePath), filepath.Base(r.filePath)+".*.tmp")
+ if err != nil {
+ return fmt.Errorf("resolver-save: create temp: %w", err)
+ }
+ tmpPath := tmp.Name()
+ defer os.Remove(tmpPath)
+
+ if _, err := tmp.Write(data); err != nil {
+ tmp.Close()
+ return fmt.Errorf("resolver-save: write temp: %w", err)
+ }
+ if err := tmp.Chmod(0644); err != nil {
+ tmp.Close()
+ return fmt.Errorf("resolver-save: chmod temp: %w", err)
+ }
+ if err := tmp.Close(); err != nil {
+ return fmt.Errorf("resolver-save: close temp: %w", err)
+ }
+ if err := os.Rename(tmpPath, r.filePath); err != nil {
+ return fmt.Errorf("resolver-save: rename temp: %w", err)
}
return nil
@@ -284,8 +346,7 @@ func (r *Resolver) Resolve(ctx context.Context, id string) (Resolution, error) {
entry.MMProjOrig = res.MMProjOrig
entry.MTPOrig = res.MTPOrig
entry.MTPChecked = true
- rm.Models[res.CanonicalID] = entry
- if err := r.Save(rm); err != nil {
+ if err := r.saveEntry(res.CanonicalID, entry); err != nil {
return Resolution{}, fmt.Errorf("resolve: persist: %w", err)
}
@@ -307,8 +368,7 @@ func (r *Resolver) Resolve(ctx context.Context, id string) (Resolution, error) {
entry := r.buildEntry(local.Provider, local.Family, local.Revision, local.Files, local.MMProj, local.MTP)
entry.MMProjOrig = local.MMProjOrig
entry.MTPOrig = local.MTPOrig
- rm.Models[local.CanonicalID] = entry
- if err := r.Save(rm); err != nil {
+ if err := r.saveEntry(local.CanonicalID, entry); err != nil {
return Resolution{}, fmt.Errorf("resolve: persist local: %w", err)
}
@@ -390,11 +450,7 @@ func (r *Resolver) resolvePinned(ctx context.Context, provider, repo, modelID st
entry.MMProjOrig = mmproj
entry.MTPOrig = mtp
entry.MTPChecked = true
- if rm.Models == nil {
- rm.Models = map[string]CatalogEntry{}
- }
- rm.Models[canonical] = entry
- if err := r.Save(rm); err != nil {
+ if err := r.saveEntry(canonical, entry); err != nil {
return Resolution{}, fmt.Errorf("resolve: persist: %w", err)
}
@@ -473,12 +529,7 @@ func (r *Resolver) resolveByTag(ctx context.Context, provider, repo, tag string)
entry.MTPOrig = mtp
entry.MTPChecked = true
- if rm.Models == nil {
- rm.Models = map[string]CatalogEntry{}
- }
- rm.Models[canonical] = entry
-
- if err := r.Save(rm); err != nil {
+ if err := r.saveEntry(canonical, entry); err != nil {
return Resolution{}, fmt.Errorf("resolve: persist: %w", err)
}
@@ -623,28 +674,22 @@ func (r *Resolver) enrichCatalogEntry(ctx context.Context, canonical string, log
return nil
}
- rm, err := r.Load()
- if err != nil {
- return fmt.Errorf("enrich-catalog-entry: load: %w", err)
- }
-
- entry, ok := rm.Models[canonical]
- if !ok {
- return nil
- }
+ if err := r.update(func(rm *Catalog) error {
+ entry, ok := rm.Models[canonical]
+ if !ok {
+ return nil
+ }
- updated, changed, err := r.models.enrichEntry(ctx, entry)
- if err != nil {
- log(ctx, "enrich-catalog-entry", "id", canonical, "ERROR", err)
- return nil
- }
- if !changed {
+ updated, changed, err := r.models.enrichEntry(ctx, entry)
+ if err != nil {
+ log(ctx, "enrich-catalog-entry", "id", canonical, "ERROR", err)
+ return nil
+ }
+ if changed {
+ rm.Models[canonical] = updated
+ }
return nil
- }
-
- rm.Models[canonical] = updated
-
- if err := r.Save(rm); err != nil {
+ }); err != nil {
return fmt.Errorf("enrich-catalog-entry: save: %w", err)
}
@@ -655,32 +700,28 @@ func (r *Resolver) enrichCatalogEntry(ctx context.Context, canonical string, log
// the updated FileSizes/MMProjSize back to catalog.yaml. Used after a
// fresh download so the persisted entry reflects actual byte counts.
func (r *Resolver) refreshSizes(canonical string) error {
- rm, err := r.Load()
- if err != nil {
- return fmt.Errorf("refresh-sizes: load: %w", err)
- }
-
- entry, ok := rm.Models[canonical]
- if !ok {
- return nil
- }
-
- updated := r.buildEntry(entry.Provider, entry.Family, entry.Revision, entry.Files, entry.MMProj, entry.MTP)
+ if err := r.update(func(rm *Catalog) error {
+ entry, ok := rm.Models[canonical]
+ if !ok {
+ return nil
+ }
- // Preserve fields buildEntry does not repopulate so a size refresh
- // never drops the HF source names, enrichment, or the resolution
- // timestamp.
- updated.MMProjOrig = entry.MMProjOrig
- updated.MTPOrig = entry.MTPOrig
- updated.MTPChecked = entry.MTPChecked
- updated.MTPSource = entry.MTPSource
- updated.ModelType = entry.ModelType
- updated.Capabilities = entry.Capabilities
- updated.ResolvedAt = entry.ResolvedAt
+ updated := r.buildEntry(entry.Provider, entry.Family, entry.Revision, entry.Files, entry.MMProj, entry.MTP)
- rm.Models[canonical] = updated
+ // Preserve fields buildEntry does not repopulate so a size refresh
+ // never drops the HF source names, enrichment, or the resolution
+ // timestamp.
+ updated.MMProjOrig = entry.MMProjOrig
+ updated.MTPOrig = entry.MTPOrig
+ updated.MTPChecked = entry.MTPChecked
+ updated.MTPSource = entry.MTPSource
+ updated.ModelType = entry.ModelType
+ updated.Capabilities = entry.Capabilities
+ updated.ResolvedAt = entry.ResolvedAt
- if err := r.Save(rm); err != nil {
+ rm.Models[canonical] = updated
+ return nil
+ }); err != nil {
return fmt.Errorf("refresh-sizes: save: %w", err)
}
@@ -1126,15 +1167,6 @@ func (m *Models) persistURLResolution(modelURLs []string, projURL, mtpURL string
r := NewResolver(m, rfile)
- rm, err := r.Load()
- if err != nil {
- return fmt.Errorf("persist-url: load: %w", err)
- }
-
- if rm.Models == nil {
- rm.Models = map[string]CatalogEntry{}
- }
-
modelID := catalogModelID(repo, files[0])
canonical := canonicalID(provider, modelID)
@@ -1145,28 +1177,27 @@ func (m *Models) persistURLResolution(modelURLs []string, projURL, mtpURL string
entry.MTPChecked = true
}
- // A URL-based download only carries the companions it was asked to
- // fetch. Preserve any companion already recorded for this model when
- // the current call did not supply it, so pulling just the MTP drafter
- // (projURL == "") does not clobber a previously resolved mmproj, and a
- // projection-only pull does not wipe a tracked MTP companion.
- if prev, ok := rm.Models[canonical]; ok {
- if projURL == "" {
- entry.MMProj = prev.MMProj
- entry.MMProjOrig = prev.MMProjOrig
- entry.MMProjSize = prev.MMProjSize
- }
- if mtpURL == "" {
- entry.MTP = prev.MTP
- entry.MTPOrig = prev.MTPOrig
- entry.MTPSize = prev.MTPSize
- entry.MTPChecked = prev.MTPChecked
+ if err := r.update(func(rm *Catalog) error {
+ // A URL-based download only carries the companions it was asked to
+ // fetch. Preserve any companion already recorded for this model when
+ // the current call did not supply it.
+ if prev, ok := rm.Models[canonical]; ok {
+ if projURL == "" {
+ entry.MMProj = prev.MMProj
+ entry.MMProjOrig = prev.MMProjOrig
+ entry.MMProjSize = prev.MMProjSize
+ }
+ if mtpURL == "" {
+ entry.MTP = prev.MTP
+ entry.MTPOrig = prev.MTPOrig
+ entry.MTPSize = prev.MTPSize
+ entry.MTPChecked = prev.MTPChecked
+ }
}
- }
- rm.Models[canonical] = entry
-
- if err := r.Save(rm); err != nil {
+ rm.Models[canonical] = entry
+ return nil
+ }); err != nil {
return fmt.Errorf("persist-url: save: %w", err)
}
diff --git a/sdk/tools/models/catalog_api.go b/sdk/tools/models/catalog_api.go
index 68ce1296c..9c6b15184 100644
--- a/sdk/tools/models/catalog_api.go
+++ b/sdk/tools/models/catalog_api.go
@@ -201,7 +201,10 @@ func (m *Models) ReconcileCatalog(ctx context.Context, log applog.Logger) error
r := NewResolver(m, rfile)
- cat, err := r.Load()
+ r.mu.Lock()
+ defer r.mu.Unlock()
+
+ cat, err := r.loadLocked()
if err != nil {
return fmt.Errorf("reconcile-catalog: load: %w", err)
}
@@ -257,7 +260,7 @@ func (m *Models) ReconcileCatalog(ctx context.Context, log applog.Logger) error
return nil
}
- if err := r.Save(cat); err != nil {
+ if err := r.saveLocked(cat); err != nil {
return fmt.Errorf("reconcile-catalog: save: %w", err)
}
@@ -382,10 +385,9 @@ func (m *Models) RemoveCatalogEntry(ctx context.Context, canonicalID string, log
}
}
- // 3. Remove the entry itself and persist.
- delete(cat.Models, canonicalID)
-
- if err := r.Save(cat); err != nil {
+ // 3. Remove the entry itself and persist without replacing concurrent
+ // additions made after this operation loaded the catalog.
+ if err := r.Delete(canonicalID); err != nil {
return fmt.Errorf("remove-catalog-entry: save: %w", err)
}
diff --git a/sdk/tools/models/catalog_test.go b/sdk/tools/models/catalog_test.go
index 82d7d867b..b7f8f2b62 100644
--- a/sdk/tools/models/catalog_test.go
+++ b/sdk/tools/models/catalog_test.go
@@ -5,11 +5,13 @@ import (
"context"
"encoding/binary"
"errors"
+ "fmt"
"os"
"path/filepath"
"reflect"
"sort"
"strings"
+ "sync"
"testing"
"github.com/ardanlabs/kronk/sdk/kronk/gguf"
@@ -1634,6 +1636,43 @@ func TestResolver_AllInputForms_ProduceSameDownloadURL(t *testing.T) {
}
}
+func TestResolverConcurrentUpdatesPreserveEntries(t *testing.T) {
+ const count = 16
+
+ filePath := filepath.Join(t.TempDir(), "catalog.yaml")
+ errCh := make(chan error, count)
+
+ var wg sync.WaitGroup
+ for i := range count {
+ wg.Go(func() {
+
+ resolver := NewResolver(nil, filePath)
+ id := fmt.Sprintf("owner/model-%02d", i)
+ errCh <- resolver.saveEntry(id, CatalogEntry{
+ Provider: "owner",
+ Family: fmt.Sprintf("repo-%02d", i),
+ Files: []string{fmt.Sprintf("model-%02d.gguf", i)},
+ })
+ })
+ }
+
+ wg.Wait()
+ close(errCh)
+ for err := range errCh {
+ if err != nil {
+ t.Fatalf("saveEntry: %v", err)
+ }
+ }
+
+ catalog, err := NewResolver(nil, filePath).Load()
+ if err != nil {
+ t.Fatalf("Load: %v", err)
+ }
+ if len(catalog.Models) != count {
+ t.Fatalf("catalog entries: got %d, want %d", len(catalog.Models), count)
+ }
+}
+
// =============================================================================
func mustWriteFile(t *testing.T, path, content string) {
diff --git a/sdk/tools/models/download.go b/sdk/tools/models/download.go
index 6468de5e7..07d461a46 100644
--- a/sdk/tools/models/download.go
+++ b/sdk/tools/models/download.go
@@ -631,7 +631,7 @@ func (m *Models) downloadCompanion(ctx context.Context, log applog.Logger, loc L
// existing local file's sha and skip the body download on a match.
shaFileName := filepath.Join(filepath.Dir(dstFileName), "sha", filepath.Base(dstFileName))
- orgShaFileName, _, err := m.pull(context.Background(), loc, pullSha, progress)
+ orgShaFileName, _, err := m.pull(ctx, loc, pullSha, progress)
if err != nil {
return "", false, fmt.Errorf("download-model: unable to download sha file: %w", err)
}
@@ -732,7 +732,7 @@ func (m *Models) checkValidatedIndex(ctx context.Context, log applog.Logger, mLo
// when the getter no-op'd because the file already existed at the expected
// size).
func (m *Models) downloadModelFile(ctx context.Context, mLoc Locator, progress downloader.ProgressFunc) (string, bool, error) {
- if _, _, err := m.pull(context.Background(), mLoc, pullSha, progress); err != nil {
+ if _, _, err := m.pull(ctx, mLoc, pullSha, progress); err != nil {
return "", false, fmt.Errorf("download-model: unable to download sha file: %w", err)
}
@@ -763,6 +763,13 @@ func (m *Models) tryReuseCompanionFromURLName(ctx context.Context, log applog.Lo
if _, err := os.Stat(urlFilePath); err != nil {
return "", false, nil
}
+ if filepath.Clean(urlFilePath) == filepath.Clean(dstFileName) {
+ if err := checkModelStrict(dstFileName); err != nil {
+ return "", false, nil
+ }
+ log(ctx, "download-model: companion already present under canonical URL name, reusing in place", "kind", kind.label, "file", filepath.Base(dstFileName))
+ return dstFileName, true, nil
+ }
log(ctx, "download-model: found existing companion file by URL name, copying", "kind", kind.label, "src", urlFileName, "dst", filepath.Base(dstFileName))
@@ -984,6 +991,10 @@ func newLocator(rawURL string) (Locator, error) {
// empty segment, owner=parts[1], repo=parts[2], file=path.Base.
owner := parts[1]
repo := parts[2]
+ modelDir := filepath.Join(owner, repo)
+ if !filepath.IsLocal(modelDir) {
+ return Locator{}, fmt.Errorf("locator: invalid model directory: %q", modelDir)
+ }
upstream := path.Base(u.Path)
disk := applyRenamePrefix(repo, upstream)
diff --git a/sdk/tools/models/download_test.go b/sdk/tools/models/download_test.go
index 2d6cd9f2f..6cf54f770 100644
--- a/sdk/tools/models/download_test.go
+++ b/sdk/tools/models/download_test.go
@@ -599,6 +599,26 @@ func TestPullBody_RemovesOversizedDestination(t *testing.T) {
}
}
+func TestNewLocatorRejectsModelDirectoryTraversal(t *testing.T) {
+ tests := []string{
+ "https://huggingface.co/../../resolve/main/model.gguf",
+ "https://huggingface.co/%2e%2e/%2e%2e/resolve/main/model.gguf",
+ }
+
+ for _, rawURL := range tests {
+ t.Run(rawURL, func(t *testing.T) {
+ if _, err := newLocator(rawURL); err == nil {
+ t.Fatalf("newLocator(%q): expected invalid model directory error", rawURL)
+ }
+ })
+ }
+
+ const mirrorURL = "http://kronk-peer.local/download/owner/repo/resolve/main/model.gguf"
+ if _, err := newLocator(mirrorURL); err != nil {
+ t.Fatalf("newLocator(%q): %v", mirrorURL, err)
+ }
+}
+
// TestRemoveOversizedBody_KeepsEverythingElse pins the states that survive: a
// short file is what resume is for, and no readable pointer means no size.
func TestRemoveOversizedBody_KeepsEverythingElse(t *testing.T) {
@@ -948,3 +968,70 @@ func TestDownloadCompanion_ReuseBySHAStillShortCircuits(t *testing.T) {
})
}
}
+
+func TestTryReuseCompanionFromURLNameAdoptsDestinationInPlace(t *testing.T) {
+ body := []byte("projection")
+ m := newTestModels(t)
+ dir := filepath.Join(m.modelsPath, "provider", "family")
+ if err := os.MkdirAll(filepath.Join(dir, "sha"), 0o755); err != nil {
+ t.Fatalf("MkdirAll: %v", err)
+ }
+
+ const rawURL = "https://huggingface.co/provider/family/resolve/main/mmproj-model.gguf"
+ loc, err := newLocator(rawURL)
+ if err != nil {
+ t.Fatalf("newLocator: %v", err)
+ }
+ dest := filepath.Join(dir, "mmproj-model.gguf")
+ if err := os.WriteFile(dest, body, 0o644); err != nil {
+ t.Fatalf("WriteFile companion: %v", err)
+ }
+ if err := os.WriteFile(filepath.Join(dir, "sha", filepath.Base(dest)), makeShaPointer(body), 0o644); err != nil {
+ t.Fatalf("WriteFile pointer: %v", err)
+ }
+
+ got, hit, err := m.tryReuseCompanionFromURLName(t.Context(), testLog, companionProj, loc, dest)
+ if err != nil {
+ t.Fatalf("tryReuseCompanionFromURLName: %v", err)
+ }
+ if !hit || got != dest {
+ t.Fatalf("reuse result: got path %q hit %t, want path %q hit true", got, hit, dest)
+ }
+ content, err := os.ReadFile(dest)
+ if err != nil {
+ t.Fatalf("ReadFile companion: %v", err)
+ }
+ if !bytes.Equal(content, body) {
+ t.Errorf("companion: got %q, want %q", content, body)
+ }
+}
+
+func TestSHAPointerDownloadsUseRequestContext(t *testing.T) {
+ const rawURL = "https://huggingface.co/provider/family/resolve/main/model.gguf"
+ loc, err := newLocator(rawURL)
+ if err != nil {
+ t.Fatalf("newLocator: %v", err)
+ }
+
+ prevD, prevN := downloadFn, hasNetworkFn
+ hasNetworkFn = func() bool { return true }
+ downloadFn = func(ctx context.Context, _ string, _ string, _ downloader.ProgressFunc, _ int64) (bool, error) {
+ return false, ctx.Err()
+ }
+ t.Cleanup(func() {
+ downloadFn = prevD
+ hasNetworkFn = prevN
+ })
+
+ ctx, cancel := context.WithCancel(t.Context())
+ cancel()
+ m := newTestModels(t)
+
+ if _, _, err := m.downloadModelFile(ctx, loc, nil); !errors.Is(err, context.Canceled) {
+ t.Errorf("downloadModelFile: got %v, want context.Canceled", err)
+ }
+ modelFile := filepath.Join(m.modelsPath, "provider", "family", "model.gguf")
+ if _, _, err := m.downloadCompanion(ctx, testLog, loc, modelFile, companionProj, nil); !errors.Is(err, context.Canceled) {
+ t.Errorf("downloadCompanion: got %v, want context.Canceled", err)
+ }
+}
diff --git a/sdk/tools/models/kronkconfig.go b/sdk/tools/models/kronkconfig.go
index 1e54df836..90269d7a7 100644
--- a/sdk/tools/models/kronkconfig.go
+++ b/sdk/tools/models/kronkconfig.go
@@ -366,7 +366,6 @@ type ModelConfig struct {
NUMA string `yaml:"numa,omitempty"`
PtrOffloadKQV *bool `yaml:"offload-kqv,omitempty"`
PtrOpOffload *bool `yaml:"op-offload,omitempty"`
- PtrOpOffloadMinBatch *int `yaml:"op-offload-min-batch,omitempty"`
PtrProjOnCPU *bool `yaml:"proj-on-cpu,omitempty"`
ProjDevice string `yaml:"proj-device,omitempty"`
PtrQueueDepth *int `yaml:"queue-depth,omitempty"`
@@ -438,7 +437,6 @@ func (mc ModelConfig) ToKronkConfig() model.Config {
NUMA: mc.NUMA,
PtrOffloadKQV: mc.PtrOffloadKQV,
PtrOpOffload: mc.PtrOpOffload,
- PtrOpOffloadMinBatch: mc.PtrOpOffloadMinBatch,
PtrProjOnCPU: mc.PtrProjOnCPU,
ProjDevice: mc.ProjDevice,
PtrQueueDepth: mc.PtrQueueDepth,
diff --git a/sdk/tools/models/kronkresolve.go b/sdk/tools/models/kronkresolve.go
index 0ab467e73..48e650cfa 100644
--- a/sdk/tools/models/kronkresolve.go
+++ b/sdk/tools/models/kronkresolve.go
@@ -281,6 +281,12 @@ func AutoTuneWithConfig(info ModelInfo, devs devices.Devices, constraints ModelC
return autoTuneWithConfigAndBudget(info, devs, constraints, nil)
}
+// AutoTuneWithConfigAndBudget returns hardware-aware defaults constrained by
+// the supplied stable memory budget.
+func AutoTuneWithConfigAndBudget(info ModelInfo, devs devices.Devices, constraints ModelConfig, budget AutoTuneBudget) (ModelConfig, error) {
+ return autoTuneWithConfigAndBudget(info, devs, constraints, &budget)
+}
+
func autoTuneWithConfigAndBudget(info ModelInfo, devs devices.Devices, constraints ModelConfig, budget *AutoTuneBudget) (ModelConfig, error) {
analysis, err := analyzeModelWithConfigAndBudget(info, devs, constraints, budget)
if err != nil {
@@ -431,9 +437,6 @@ func MergeModelConfig(dst *ModelConfig, src ModelConfig) {
if src.PtrOpOffload != nil {
dst.PtrOpOffload = src.PtrOpOffload
}
- if src.PtrOpOffloadMinBatch != nil {
- dst.PtrOpOffloadMinBatch = src.PtrOpOffloadMinBatch
- }
if src.PtrProjOnCPU != nil {
dst.PtrProjOnCPU = src.PtrProjOnCPU
}
diff --git a/sdk/tools/models/models.go b/sdk/tools/models/models.go
index c69b59ec8..7327cecb1 100644
--- a/sdk/tools/models/models.go
+++ b/sdk/tools/models/models.go
@@ -239,7 +239,7 @@ func (m *Models) BuildIndex(log applog.Logger, checkSHA bool) error {
}
indexPath := filepath.Join(m.modelsPath, indexFile)
- if err := os.WriteFile(indexPath, indexData, 0644); err != nil {
+ if err := writeIndexFile(indexPath, indexData); err != nil {
return fmt.Errorf("write index file: %w", err)
}
@@ -313,7 +313,7 @@ func (m *Models) MarkValidated(modelID string) error {
return fmt.Errorf("mark-validated: marshal index: %w", err)
}
- if err := os.WriteFile(indexPath, out, 0644); err != nil {
+ if err := writeIndexFile(indexPath, out); err != nil {
return fmt.Errorf("mark-validated: write index: %w", err)
}
@@ -322,6 +322,34 @@ func (m *Models) MarkValidated(modelID string) error {
// =============================================================================
+func writeIndexFile(indexPath string, data []byte) error {
+ tmp, err := os.CreateTemp(filepath.Dir(indexPath), filepath.Base(indexPath)+".*.tmp")
+ if err != nil {
+ return fmt.Errorf("create temp: %w", err)
+ }
+ tmpPath := tmp.Name()
+ defer os.Remove(tmpPath)
+
+ if _, err := tmp.Write(data); err != nil {
+ tmp.Close()
+ return fmt.Errorf("write temp: %w", err)
+ }
+ if err := tmp.Chmod(0o644); err != nil {
+ tmp.Close()
+ return fmt.Errorf("chmod temp: %w", err)
+ }
+ if err := tmp.Close(); err != nil {
+ return fmt.Errorf("close temp: %w", err)
+ }
+ if err := os.Rename(tmpPath, indexPath); err != nil {
+ return fmt.Errorf("rename temp: %w", err)
+ }
+
+ return nil
+}
+
+// =============================================================================
+
func (m *Models) removeEmptyDirs() error {
var dirs []string
diff --git a/sdk/tools/models/remove.go b/sdk/tools/models/remove.go
index cda00c55c..efae631f3 100644
--- a/sdk/tools/models/remove.go
+++ b/sdk/tools/models/remove.go
@@ -26,7 +26,7 @@ func (m *Models) Remove(mp Path, log applog.Logger) (err error) {
base := filepath.Base(modelFile)
shaFile := filepath.Join(dir, "sha", base)
- if err := os.Remove(shaFile); err != nil {
+ if err := os.Remove(shaFile); err != nil && !errors.Is(err, os.ErrNotExist) {
return fmt.Errorf("remove: unable to remove model: %q", shaFile)
}
@@ -47,7 +47,7 @@ func (m *Models) Remove(mp Path, log applog.Logger) (err error) {
base := filepath.Base(mp.ProjFile)
shaFile := filepath.Join(dir, "sha", base)
- if err := os.Remove(shaFile); err != nil {
+ if err := os.Remove(shaFile); err != nil && !errors.Is(err, os.ErrNotExist) {
return fmt.Errorf("remove: unable to remove model: %q", shaFile)
}
@@ -65,7 +65,7 @@ func (m *Models) Remove(mp Path, log applog.Logger) (err error) {
base := filepath.Base(mp.MTPFile)
shaFile := filepath.Join(dir, "sha", base)
- if err := os.Remove(shaFile); err != nil {
+ if err := os.Remove(shaFile); err != nil && !errors.Is(err, os.ErrNotExist) {
return fmt.Errorf("remove: unable to remove model: %q", shaFile)
}
diff --git a/sdk/tools/models/remove_test.go b/sdk/tools/models/remove_test.go
index 3ed46851c..170700cc0 100644
--- a/sdk/tools/models/remove_test.go
+++ b/sdk/tools/models/remove_test.go
@@ -1,6 +1,7 @@
package models
import (
+ "os"
"path/filepath"
"testing"
)
@@ -16,3 +17,26 @@ func TestRemove_ErrorOnFailedDelete(t *testing.T) {
t.Fatal("Remove returned nil error after a failed deletion; want non-nil error")
}
}
+
+func TestRemoveAllowsMissingSHAPointers(t *testing.T) {
+ m := newTestModels(t)
+ dir := filepath.Join(m.Path(), "provider", "family")
+ if err := os.MkdirAll(dir, 0o755); err != nil {
+ t.Fatalf("MkdirAll: %v", err)
+ }
+
+ mp := Path{
+ ModelFiles: []string{filepath.Join(dir, "model.gguf")},
+ ProjFile: filepath.Join(dir, "mmproj-model.gguf"),
+ MTPFile: filepath.Join(dir, "mtp-model.gguf"),
+ }
+ for _, file := range []string{mp.ModelFiles[0], mp.ProjFile, mp.MTPFile} {
+ if err := os.WriteFile(file, []byte("data"), 0o644); err != nil {
+ t.Fatalf("WriteFile %s: %v", file, err)
+ }
+ }
+
+ if err := m.Remove(mp, testLog); err != nil {
+ t.Fatalf("Remove: %v", err)
+ }
+}
diff --git a/sdk/tools/models/retrieve.go b/sdk/tools/models/retrieve.go
index cf9435d3c..78eb9dae0 100644
--- a/sdk/tools/models/retrieve.go
+++ b/sdk/tools/models/retrieve.go
@@ -42,10 +42,15 @@ func (m *Models) Files() ([]File, error) {
var totalSize int64
var modified time.Time
+ missing := false
for _, f := range mp.ModelFiles {
info, err := os.Stat(f)
if err != nil {
+ if errors.Is(err, os.ErrNotExist) {
+ missing = true
+ break
+ }
return nil, fmt.Errorf("stat: %w", err)
}
@@ -54,6 +59,9 @@ func (m *Models) Files() ([]File, error) {
modified = info.ModTime()
}
}
+ if missing {
+ continue
+ }
modelPath := strings.TrimPrefix(mp.ModelFiles[0], m.modelsPath)
modelPath = strings.TrimPrefix(modelPath, string(filepath.Separator))
diff --git a/sdk/tools/models/retrieve_lookup_test.go b/sdk/tools/models/retrieve_lookup_test.go
index 303bdd7c9..8a4389143 100644
--- a/sdk/tools/models/retrieve_lookup_test.go
+++ b/sdk/tools/models/retrieve_lookup_test.go
@@ -110,3 +110,42 @@ func TestFilesPreservesPublicFileContract(t *testing.T) {
t.Errorf("FullPath bare model: got %v, want ErrInvalidModelID", err)
}
}
+
+func TestFilesSkipsModelWithMissingShard(t *testing.T) {
+ m, err := NewWithPaths(t.TempDir())
+ if err != nil {
+ t.Fatalf("NewWithPaths: %v", err)
+ }
+
+ healthy := filepath.Join(m.Path(), "provider", "healthy-family", "healthy.gguf")
+ if err := os.MkdirAll(filepath.Dir(healthy), 0o755); err != nil {
+ t.Fatalf("MkdirAll: %v", err)
+ }
+ if err := os.WriteFile(healthy, []byte("healthy"), 0o644); err != nil {
+ t.Fatalf("WriteFile healthy model: %v", err)
+ }
+
+ index, err := yaml.Marshal(map[string]Path{
+ "provider/healthy": {ModelFiles: []string{healthy}},
+ "provider/stale": {
+ ModelFiles: []string{
+ filepath.Join(m.Path(), "provider", "stale-family", "part-1.gguf"),
+ filepath.Join(m.Path(), "provider", "stale-family", "part-2.gguf"),
+ },
+ },
+ })
+ if err != nil {
+ t.Fatalf("Marshal index: %v", err)
+ }
+ if err := os.WriteFile(filepath.Join(m.Path(), indexFile), index, 0o644); err != nil {
+ t.Fatalf("WriteFile index: %v", err)
+ }
+
+ files, err := m.Files()
+ if err != nil {
+ t.Fatalf("Files: %v", err)
+ }
+ if len(files) != 1 || files[0].ID != "healthy" {
+ t.Fatalf("Files: got %+v, want only healthy model", files)
+ }
+}
diff --git a/zarf/kms/model_config.yaml b/zarf/kms/model_config.yaml
index 791a3b014..a1a4c4207 100644
--- a/zarf/kms/model_config.yaml
+++ b/zarf/kms/model_config.yaml
@@ -96,7 +96,6 @@ version: 1
# numa: distribute # NUMA strategy: "" (off), distribute, isolate, numactl, mirror
# offload-kqv: true # Offload KV cache to GPU (false = keep on CPU)
# op-offload: true # Offload tensor operations to GPU (false = keep on CPU)
-# op-offload-min-batch: 0 # Min batch size before host tensor ops are offloaded (0 = default)
# proj-on-cpu: true # Force multimodal projector (mmproj) onto CPU
# proj-device: CUDA1 # Explicit mmproj device; omit for automatic (conflicts with proj-on-cpu: true)
# rope-freq-base: 1000000 # RoPE base frequency (nil = from model, e.g., 10000 Llama, 1000000 Qwen)