+189
-17
@@ -1404,6 +1404,64 @@ function bareAgentTrimMessages(msgs, maxBytes) {
|
||||
return out
|
||||
}
|
||||
|
||||
/**
|
||||
* Rough token estimate (chars/4). Good enough for local ctx budgeting.
|
||||
* @param {unknown} value
|
||||
*/
|
||||
function bareAgentEstimateTokens(value) {
|
||||
try {
|
||||
const n = JSON.stringify(value == null ? '' : value).length
|
||||
return Math.max(0, Math.ceil(n / 4))
|
||||
} catch {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim history + shrink system content so prompt fits a QVAC ctx window.
|
||||
* Reserves room for completion and optional tools JSON.
|
||||
* @param {unknown[]} msgs
|
||||
* @param {number} ctxSize
|
||||
* @param {{ tools?: unknown[], reserveCompletion?: number }} [opts]
|
||||
*/
|
||||
function bareAgentTrimMessagesForCtx(msgs, ctxSize, opts) {
|
||||
const ctx = Math.max(2048, Math.floor(Number(ctxSize) || 4096))
|
||||
const reserve =
|
||||
opts && Number.isFinite(Number(opts.reserveCompletion))
|
||||
? Math.max(256, Math.floor(Number(opts.reserveCompletion)))
|
||||
: Math.min(1024, Math.max(256, Math.floor(ctx * 0.15)))
|
||||
const toolsTok = bareAgentEstimateTokens(
|
||||
opts && Array.isArray(opts.tools) && opts.tools.length ? opts.tools : []
|
||||
)
|
||||
const budget = Math.max(512, ctx - reserve - toolsTok)
|
||||
|
||||
/** @type {unknown[]} */
|
||||
let out = Array.isArray(msgs) ? msgs.slice() : []
|
||||
// Drop middle turns first (keep system + recent).
|
||||
while (bareAgentEstimateTokens(out) > budget && out.length > 3) {
|
||||
out.splice(2, 1)
|
||||
}
|
||||
// Shrink system blob if still over (workspace/man/skills dominate).
|
||||
if (bareAgentEstimateTokens(out) > budget && out[0] && typeof out[0] === 'object') {
|
||||
const sys = /** @type {Record<string, unknown>} */ (out[0])
|
||||
if (sys.role === 'system' && typeof sys.content === 'string') {
|
||||
let content = sys.content
|
||||
let guard = 0
|
||||
while (
|
||||
bareAgentEstimateTokens(out) > budget &&
|
||||
content.length > 800 &&
|
||||
guard < 24
|
||||
) {
|
||||
content =
|
||||
content.slice(0, Math.floor(content.length * 0.82)) + '\n… truncated'
|
||||
out[0] = { ...sys, content }
|
||||
guard++
|
||||
}
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
/**
|
||||
* Best-effort load instruction files.
|
||||
* @param {Record<string, unknown>} ctx
|
||||
@@ -1597,6 +1655,16 @@ async function bareAgentResetChatSession(ctx, paths, argv0) {
|
||||
|
||||
/** @typedef {'lite'|'recommended'|'strong'|'tool-tiny'} BareAgentQvacProfileId */
|
||||
|
||||
/**
|
||||
* Native context windows from upstream model cards (not conservative laptop defaults).
|
||||
* Qwen3 dense (0.6B/1.7B/4B): https://huggingface.co/Qwen/Qwen3-0.6B — 32,768
|
||||
* Llama 3.2 1B (tool-calling finetune base): Meta Llama 3.2 — 128,000
|
||||
* Absolute ceiling for overrides / host clamp.
|
||||
*/
|
||||
const BARE_AGENT_QVAC_CTX_QWEN3 = 32768
|
||||
const BARE_AGENT_QVAC_CTX_LLAMA32_1B = 131072
|
||||
const BARE_AGENT_QVAC_CTX_ABSOLUTE_MAX = 131072
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* id: BareAgentQvacProfileId,
|
||||
@@ -1617,50 +1685,69 @@ const BARE_AGENT_QVAC_PROFILES = {
|
||||
id: 'lite',
|
||||
label: 'Lite',
|
||||
description:
|
||||
'Smallest download. Good for weak machines / ~4 GB VRAM; limited tool use.',
|
||||
'Smallest download (Qwen3-0.6B). Model-card context 32k; limited tool use.',
|
||||
chatModel: 'QWEN3_600M_INST_Q4',
|
||||
tools: false,
|
||||
minRamGb: 4,
|
||||
minDiskGb: 2,
|
||||
approxDownloadGb: 0.5,
|
||||
ctxSize: 4096
|
||||
ctxSize: BARE_AGENT_QVAC_CTX_QWEN3
|
||||
},
|
||||
recommended: {
|
||||
id: 'recommended',
|
||||
label: 'Recommended',
|
||||
description:
|
||||
'Best balance for Bare OS agent tool calling (fits ~4–8 GB VRAM at ctx 8k).',
|
||||
'Best balance for Bare OS agent tool calling (Qwen3-1.7B, model-card context 32k).',
|
||||
chatModel: 'QWEN3_1_7B_INST_Q4',
|
||||
tools: true,
|
||||
minRamGb: 8,
|
||||
minDiskGb: 5,
|
||||
approxDownloadGb: 2.5,
|
||||
ctxSize: 8192
|
||||
ctxSize: BARE_AGENT_QVAC_CTX_QWEN3
|
||||
},
|
||||
strong: {
|
||||
id: 'strong',
|
||||
label: 'Strong',
|
||||
description: 'Better reasoning. Needs more RAM/VRAM/disk.',
|
||||
description:
|
||||
'Better reasoning (Qwen3-4B). Model-card context 32k (131k with YaRN not enabled).',
|
||||
chatModel: 'QWEN3_4B_INST_Q4_K_M',
|
||||
tools: true,
|
||||
minRamGb: 16,
|
||||
minDiskGb: 8,
|
||||
approxDownloadGb: 3.5,
|
||||
ctxSize: 8192
|
||||
ctxSize: BARE_AGENT_QVAC_CTX_QWEN3
|
||||
},
|
||||
'tool-tiny': {
|
||||
id: 'tool-tiny',
|
||||
label: 'Tool-tiny',
|
||||
description: 'Llama tool-calling 1B fallback if Qwen tools misbehave.',
|
||||
description:
|
||||
'Llama 3.2 1B tool-calling fallback (model-card context 128k).',
|
||||
chatModel: 'LLAMA_TOOL_CALLING_1B_INST_Q4_K',
|
||||
tools: true,
|
||||
minRamGb: 6,
|
||||
minDiskGb: 3,
|
||||
approxDownloadGb: 1,
|
||||
ctxSize: 4096
|
||||
ctxSize: BARE_AGENT_QVAC_CTX_LLAMA32_1B
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Model-card / train context for a QVAC registry id (fallback 32k).
|
||||
* @param {string} [modelId]
|
||||
* @returns {number}
|
||||
*/
|
||||
function bareAgentQvacModelCardCtxSize(modelId) {
|
||||
const id = String(modelId || '')
|
||||
.trim()
|
||||
.toUpperCase()
|
||||
if (!id) return BARE_AGENT_QVAC_CTX_QWEN3
|
||||
if (id.includes('LLAMA') || id.includes('LLAMA_TOOL')) {
|
||||
return BARE_AGENT_QVAC_CTX_LLAMA32_1B
|
||||
}
|
||||
if (id.includes('QWEN3')) return BARE_AGENT_QVAC_CTX_QWEN3
|
||||
return BARE_AGENT_QVAC_CTX_QWEN3
|
||||
}
|
||||
|
||||
/** @returns {BareAgentQvacProfile[]} */
|
||||
function bareAgentQvacProfileList() {
|
||||
return Object.values(BARE_AGENT_QVAC_PROFILES)
|
||||
@@ -1749,17 +1836,33 @@ function bareAgentResolveBackend(config) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve context window for QVAC load (profile default or config override).
|
||||
* Resolve context window for QVAC load (profile/model-card default or config override).
|
||||
* Tool schemas alone are ~4.5k tokens, so tool-enabled profiles need ≥8192.
|
||||
* @param {Record<string, unknown>} config
|
||||
* @param {BareAgentQvacProfile} profile
|
||||
*/
|
||||
function bareAgentQvacResolveCtxSize(config, profile) {
|
||||
const modelId = String(
|
||||
(config && (config.qvac_model || config.model)) ||
|
||||
(profile && profile.chatModel) ||
|
||||
''
|
||||
)
|
||||
const cardCtx = bareAgentQvacModelCardCtxSize(modelId)
|
||||
const profileCtx = Math.max(
|
||||
2048,
|
||||
Number(profile && profile.ctxSize) || cardCtx
|
||||
)
|
||||
const raw = Number(config && config.qvac_ctx_size)
|
||||
let ctx
|
||||
if (Number.isFinite(raw) && raw >= 2048) {
|
||||
// Cap high overrides; 32k+ KV often OOMs laptop GPUs (~4 GB VRAM).
|
||||
return Math.min(32768, Math.floor(raw))
|
||||
ctx = Math.min(BARE_AGENT_QVAC_CTX_ABSOLUTE_MAX, Math.floor(raw))
|
||||
} else {
|
||||
// Prefer explicit profile ctx (already model-card sized); else card for model id.
|
||||
ctx = Math.min(BARE_AGENT_QVAC_CTX_ABSOLUTE_MAX, Math.max(profileCtx, cardCtx))
|
||||
}
|
||||
return Math.max(2048, Number(profile.ctxSize) || 8192)
|
||||
// Full Bare OS tool list ≈ 4.5k tokens; leave room for system + reply.
|
||||
if (profile && profile.tools !== false && ctx < 8192) ctx = 8192
|
||||
return ctx
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -6846,11 +6949,36 @@ async function bareOsRunAgentSession(ctx, argv0, task, runOpts) {
|
||||
if (needWizard) await bareAgentSyncWorkspaceFromConfig(ctx, paths, config)
|
||||
|
||||
const backendForPrompt = bareAgentResolveBackend(config)
|
||||
const promptProfile = bareAgentQvacGetProfile(
|
||||
String(config.qvac_profile || config.profile || '')
|
||||
)
|
||||
const promptCtxSize =
|
||||
backendForPrompt === 'qvac'
|
||||
? bareAgentQvacResolveCtxSize(config, promptProfile)
|
||||
: 32768
|
||||
// Local QVAC models have a hard ctx window; keep the system prompt lean.
|
||||
const workspaceBudget = backendForPrompt === 'qvac' ? 8000 : 24000
|
||||
const manBudget = backendForPrompt === 'qvac' ? 4000 : 12000
|
||||
const instructionsBudget = backendForPrompt === 'qvac' ? 3000 : 8000
|
||||
const skillsBudget = backendForPrompt === 'qvac' ? 2000 : 4000
|
||||
// Scale char budgets from ctx (chars ≈ tokens*4); leave room for tools/reply.
|
||||
const toolsOn = backendForPrompt === 'qvac' && promptProfile.tools !== false
|
||||
const promptCharBudget = Math.max(
|
||||
4000,
|
||||
Math.floor(promptCtxSize * 4 * (toolsOn ? 0.35 : 0.7))
|
||||
)
|
||||
const workspaceBudget =
|
||||
backendForPrompt === 'qvac'
|
||||
? Math.min(8000, Math.floor(promptCharBudget * 0.35))
|
||||
: 24000
|
||||
const manBudget =
|
||||
backendForPrompt === 'qvac'
|
||||
? Math.min(4000, Math.floor(promptCharBudget * 0.2))
|
||||
: 12000
|
||||
const instructionsBudget =
|
||||
backendForPrompt === 'qvac'
|
||||
? Math.min(3000, Math.floor(promptCharBudget * 0.2))
|
||||
: 8000
|
||||
const skillsBudget =
|
||||
backendForPrompt === 'qvac'
|
||||
? Math.min(2000, Math.floor(promptCharBudget * 0.15))
|
||||
: 4000
|
||||
|
||||
const workspacePromptBlock = await bareAgentLoadWorkspacePrompt(
|
||||
ctx,
|
||||
@@ -7005,6 +7133,27 @@ async function bareOsRunAgentSession(ctx, argv0, task, runOpts) {
|
||||
const backendIter = bareAgentResolveBackend(configRef.current)
|
||||
/** @type {Record<string, unknown>} */
|
||||
const providerNow = String(configRef.current.provider || '').trim().toLowerCase()
|
||||
let qvacToolsForTurn = /** @type {unknown[]} */ ([])
|
||||
if (backendIter === 'qvac') {
|
||||
const profileEarly = bareAgentQvacGetProfile(
|
||||
String(configRef.current.qvac_profile || 'recommended')
|
||||
)
|
||||
const ctxEarly = bareAgentQvacResolveCtxSize(
|
||||
configRef.current,
|
||||
profileEarly
|
||||
)
|
||||
qvacToolsForTurn =
|
||||
profileEarly.tools !== false
|
||||
? bareAgentFlattenToolsForQvac(tools)
|
||||
: []
|
||||
messages = bareAgentTrimMessagesForCtx(messages, ctxEarly, {
|
||||
tools: qvacToolsForTurn,
|
||||
reserveCompletion: Math.min(
|
||||
1024,
|
||||
Number(configRef.current.max_tokens) || 512
|
||||
)
|
||||
})
|
||||
}
|
||||
if (reasoningSettings.enabled && reasoningSettings.mode === 'trace') {
|
||||
bareAgentWriteOut(
|
||||
ctx,
|
||||
@@ -7095,6 +7244,29 @@ async function bareOsRunAgentSession(ctx, argv0, task, runOpts) {
|
||||
EDIT_ANSI_RESET +
|
||||
'\n'
|
||||
)
|
||||
try {
|
||||
const st =
|
||||
typeof ctx.bareOsQvacStatus === 'function'
|
||||
? ctx.bareOsQvacStatus()
|
||||
: null
|
||||
if (st && (st.cacheDir || st.hdmsPath || st.backendsDir)) {
|
||||
bareAgentWriteOut(
|
||||
ctx,
|
||||
stdout,
|
||||
bareEditSgr('dim', useColor) +
|
||||
'[qvac] cache=' +
|
||||
String(st.cacheDir || '') +
|
||||
' hdms=' +
|
||||
String(st.hdmsPath || '/mnt/models') +
|
||||
' backends=' +
|
||||
String(st.backendsDir || '(unresolved)') +
|
||||
EDIT_ANSI_RESET +
|
||||
'\n'
|
||||
)
|
||||
}
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
if (typeof ctx.bareOsQvacLoadModel === 'function') {
|
||||
const loaded = await ctx.bareOsQvacLoadModel({
|
||||
modelSrc,
|
||||
@@ -7145,7 +7317,7 @@ async function bareOsRunAgentSession(ctx, argv0, task, runOpts) {
|
||||
}
|
||||
await ctx.bareOsQvacComplete({
|
||||
history: messages,
|
||||
tools: bareAgentFlattenToolsForQvac(tools),
|
||||
tools: qvacToolsForTurn,
|
||||
stream: Boolean(configRef.current.stream !== false),
|
||||
captureThinking: reasoningSettings.enabled,
|
||||
modelSrc,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"schema": 2,
|
||||
"profileId": "bare-os-posix-like",
|
||||
"generatedAt": "2026-07-31T21:35:54.625Z",
|
||||
"generatedAt": "2026-07-31T23:16:21.588Z",
|
||||
"note": "Sparse POSIX Issue 7 coverage hints; commandIndex is generated each coreutils build.",
|
||||
"commandIndex": [
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema": 1,
|
||||
"atMs": 1785533754625,
|
||||
"atMs": 1785539781587,
|
||||
"commands": [
|
||||
"agent",
|
||||
"appctl",
|
||||
|
||||
@@ -30,10 +30,17 @@ After **`agent --config`** / **`--setup`** (or changing **`owner_name`** / **`ag
|
||||
|
||||
Default backend is **QVAC** (QuantumVerse Automatic Computer) — local in-process LLM via the booter **`ctx.bareOsQvac*`** bridge (`@qvac/sdk`). Weights download on first use after you pick a profile in **`agent --config`**.
|
||||
|
||||
Models are stored for durability on HDMS label **`models`** (guest path **`/mnt/models/`**) and materialize into a host cache for llama.cpp load:
|
||||
|
||||
- Host cache: **`$BARE_OS_HOST_DATA/qvac/models`** (default **`~/.bare-os/qvac/models`**)
|
||||
- Runtime config: **`$BARE_OS_HOST_DATA/qvac/qvac.config.json`** (`QVAC_CONFIG_PATH`, absolute `cacheDirectory`)
|
||||
|
||||
First load downloads via the QVAC registry into the **host cache**, then mirrors into HDMS. If HDMS already has the GGUF, Bare OS materializes it to the host cache before load. If auto-create fails, run **`hdms create models`** after unlock.
|
||||
|
||||
- `backend` — `qvac` (default) or `rest`
|
||||
- `qvac_profile` — `lite` / `recommended` / `strong` / `tool-tiny`
|
||||
- `qvac_model` — registry id (e.g. `QWEN3_1_7B_INST_Q4`)
|
||||
- `qvac_ctx_size` — optional context window override (profile defaults: lite/tool-tiny 4096, recommended/strong 8192; max 32768)
|
||||
- `qvac_ctx_size` — optional context window override. Profile defaults match model cards: Qwen3 profiles **32768**, tool-tiny (Llama 3.2 1B) **131072** (max override 131072). Tool-enabled profiles floor at 8192 (tool schemas alone are ~4.5k tokens). Cap further with host env `BARE_OS_QVAC_MAX_CTX` if VRAM is tight.
|
||||
- `qvac_device` — `gpu` (default) or `cpu` (bypass Vulkan; slower)
|
||||
- `qvac_main_gpu` — `auto` (default: pick highest-VRAM Vulkan GPU, else CPU), `dedicated`, `integrated`, or device index (`0`, `1`, …)
|
||||
- `qvac_gpu_layers` — optional layer offload count (`0` = CPU weights)
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -491,13 +491,14 @@ export function createBareOsQvacBridge(opts = {}) {
|
||||
if (!key) throw new Error('bareOsQvacLoadModel: modelSrc required')
|
||||
|
||||
const toolsEnabled = o.tools !== false
|
||||
// Respect caller/profile ctx; clamp default max to 8k (old agents sent 16k/32k).
|
||||
// Allow model-card windows (Qwen3 32k, Llama 3.2 1B 128k). Override with
|
||||
// BARE_OS_QVAC_MAX_CTX to cap KV on small GPUs.
|
||||
const maxCtxRaw = Number(env.BARE_OS_QVAC_MAX_CTX)
|
||||
const maxCtx =
|
||||
Number.isFinite(maxCtxRaw) && maxCtxRaw >= 2048
|
||||
? Math.min(32768, Math.floor(maxCtxRaw))
|
||||
: 8192
|
||||
const ctxSize = Math.max(2048, Math.min(maxCtx, Number(o.ctxSize) || 4096))
|
||||
? Math.min(131072, Math.floor(maxCtxRaw))
|
||||
: 131072
|
||||
const ctxSize = Math.max(2048, Math.min(maxCtx, Number(o.ctxSize) || 32768))
|
||||
const resolved = bareOsQvacResolveDeviceConfig(o, env)
|
||||
const verbEnv = Number(env.BARE_OS_QVAC_VERBOSITY)
|
||||
const verbosity =
|
||||
@@ -847,7 +848,10 @@ export function createBareOsQvacBridge(opts = {}) {
|
||||
const s = await ensureApi()
|
||||
const onEvent =
|
||||
typeof o.onEvent === 'function' ? o.onEvent : () => {}
|
||||
const flatTools = bareOsQvacFlattenTools(o.tools || [])
|
||||
const toolsEnabled = o.toolsEnabled !== false
|
||||
const flatTools = toolsEnabled
|
||||
? bareOsQvacFlattenTools(o.tools || [])
|
||||
: []
|
||||
const history = Array.isArray(o.history) ? o.history : []
|
||||
|
||||
const run = s.completion({
|
||||
|
||||
@@ -4,6 +4,16 @@
|
||||
|
||||
/** @typedef {'lite'|'recommended'|'strong'|'tool-tiny'} BareAgentQvacProfileId */
|
||||
|
||||
/**
|
||||
* Native context windows from upstream model cards (not conservative laptop defaults).
|
||||
* Qwen3 dense (0.6B/1.7B/4B): https://huggingface.co/Qwen/Qwen3-0.6B — 32,768
|
||||
* Llama 3.2 1B (tool-calling finetune base): Meta Llama 3.2 — 128,000
|
||||
* Absolute ceiling for overrides / host clamp.
|
||||
*/
|
||||
const BARE_AGENT_QVAC_CTX_QWEN3 = 32768
|
||||
const BARE_AGENT_QVAC_CTX_LLAMA32_1B = 131072
|
||||
const BARE_AGENT_QVAC_CTX_ABSOLUTE_MAX = 131072
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* id: BareAgentQvacProfileId,
|
||||
@@ -24,50 +34,69 @@ const BARE_AGENT_QVAC_PROFILES = {
|
||||
id: 'lite',
|
||||
label: 'Lite',
|
||||
description:
|
||||
'Smallest download. Good for weak machines / ~4 GB VRAM; limited tool use.',
|
||||
'Smallest download (Qwen3-0.6B). Model-card context 32k; limited tool use.',
|
||||
chatModel: 'QWEN3_600M_INST_Q4',
|
||||
tools: false,
|
||||
minRamGb: 4,
|
||||
minDiskGb: 2,
|
||||
approxDownloadGb: 0.5,
|
||||
ctxSize: 4096
|
||||
ctxSize: BARE_AGENT_QVAC_CTX_QWEN3
|
||||
},
|
||||
recommended: {
|
||||
id: 'recommended',
|
||||
label: 'Recommended',
|
||||
description:
|
||||
'Best balance for Bare OS agent tool calling (fits ~4–8 GB VRAM at ctx 8k).',
|
||||
'Best balance for Bare OS agent tool calling (Qwen3-1.7B, model-card context 32k).',
|
||||
chatModel: 'QWEN3_1_7B_INST_Q4',
|
||||
tools: true,
|
||||
minRamGb: 8,
|
||||
minDiskGb: 5,
|
||||
approxDownloadGb: 2.5,
|
||||
ctxSize: 8192
|
||||
ctxSize: BARE_AGENT_QVAC_CTX_QWEN3
|
||||
},
|
||||
strong: {
|
||||
id: 'strong',
|
||||
label: 'Strong',
|
||||
description: 'Better reasoning. Needs more RAM/VRAM/disk.',
|
||||
description:
|
||||
'Better reasoning (Qwen3-4B). Model-card context 32k (131k with YaRN not enabled).',
|
||||
chatModel: 'QWEN3_4B_INST_Q4_K_M',
|
||||
tools: true,
|
||||
minRamGb: 16,
|
||||
minDiskGb: 8,
|
||||
approxDownloadGb: 3.5,
|
||||
ctxSize: 8192
|
||||
ctxSize: BARE_AGENT_QVAC_CTX_QWEN3
|
||||
},
|
||||
'tool-tiny': {
|
||||
id: 'tool-tiny',
|
||||
label: 'Tool-tiny',
|
||||
description: 'Llama tool-calling 1B fallback if Qwen tools misbehave.',
|
||||
description:
|
||||
'Llama 3.2 1B tool-calling fallback (model-card context 128k).',
|
||||
chatModel: 'LLAMA_TOOL_CALLING_1B_INST_Q4_K',
|
||||
tools: true,
|
||||
minRamGb: 6,
|
||||
minDiskGb: 3,
|
||||
approxDownloadGb: 1,
|
||||
ctxSize: 4096
|
||||
ctxSize: BARE_AGENT_QVAC_CTX_LLAMA32_1B
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Model-card / train context for a QVAC registry id (fallback 32k).
|
||||
* @param {string} [modelId]
|
||||
* @returns {number}
|
||||
*/
|
||||
function bareAgentQvacModelCardCtxSize(modelId) {
|
||||
const id = String(modelId || '')
|
||||
.trim()
|
||||
.toUpperCase()
|
||||
if (!id) return BARE_AGENT_QVAC_CTX_QWEN3
|
||||
if (id.includes('LLAMA') || id.includes('LLAMA_TOOL')) {
|
||||
return BARE_AGENT_QVAC_CTX_LLAMA32_1B
|
||||
}
|
||||
if (id.includes('QWEN3')) return BARE_AGENT_QVAC_CTX_QWEN3
|
||||
return BARE_AGENT_QVAC_CTX_QWEN3
|
||||
}
|
||||
|
||||
/** @returns {BareAgentQvacProfile[]} */
|
||||
function bareAgentQvacProfileList() {
|
||||
return Object.values(BARE_AGENT_QVAC_PROFILES)
|
||||
@@ -156,17 +185,33 @@ function bareAgentResolveBackend(config) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve context window for QVAC load (profile default or config override).
|
||||
* Resolve context window for QVAC load (profile/model-card default or config override).
|
||||
* Tool schemas alone are ~4.5k tokens, so tool-enabled profiles need ≥8192.
|
||||
* @param {Record<string, unknown>} config
|
||||
* @param {BareAgentQvacProfile} profile
|
||||
*/
|
||||
function bareAgentQvacResolveCtxSize(config, profile) {
|
||||
const modelId = String(
|
||||
(config && (config.qvac_model || config.model)) ||
|
||||
(profile && profile.chatModel) ||
|
||||
''
|
||||
)
|
||||
const cardCtx = bareAgentQvacModelCardCtxSize(modelId)
|
||||
const profileCtx = Math.max(
|
||||
2048,
|
||||
Number(profile && profile.ctxSize) || cardCtx
|
||||
)
|
||||
const raw = Number(config && config.qvac_ctx_size)
|
||||
let ctx
|
||||
if (Number.isFinite(raw) && raw >= 2048) {
|
||||
// Cap high overrides; 32k+ KV often OOMs laptop GPUs (~4 GB VRAM).
|
||||
return Math.min(32768, Math.floor(raw))
|
||||
ctx = Math.min(BARE_AGENT_QVAC_CTX_ABSOLUTE_MAX, Math.floor(raw))
|
||||
} else {
|
||||
// Prefer explicit profile ctx (already model-card sized); else card for model id.
|
||||
ctx = Math.min(BARE_AGENT_QVAC_CTX_ABSOLUTE_MAX, Math.max(profileCtx, cardCtx))
|
||||
}
|
||||
return Math.max(2048, Number(profile.ctxSize) || 8192)
|
||||
// Full Bare OS tool list ≈ 4.5k tokens; leave room for system + reply.
|
||||
if (profile && profile.tools !== false && ctx < 8192) ctx = 8192
|
||||
return ctx
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -369,6 +369,64 @@ function bareAgentTrimMessages(msgs, maxBytes) {
|
||||
return out
|
||||
}
|
||||
|
||||
/**
|
||||
* Rough token estimate (chars/4). Good enough for local ctx budgeting.
|
||||
* @param {unknown} value
|
||||
*/
|
||||
function bareAgentEstimateTokens(value) {
|
||||
try {
|
||||
const n = JSON.stringify(value == null ? '' : value).length
|
||||
return Math.max(0, Math.ceil(n / 4))
|
||||
} catch {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim history + shrink system content so prompt fits a QVAC ctx window.
|
||||
* Reserves room for completion and optional tools JSON.
|
||||
* @param {unknown[]} msgs
|
||||
* @param {number} ctxSize
|
||||
* @param {{ tools?: unknown[], reserveCompletion?: number }} [opts]
|
||||
*/
|
||||
function bareAgentTrimMessagesForCtx(msgs, ctxSize, opts) {
|
||||
const ctx = Math.max(2048, Math.floor(Number(ctxSize) || 4096))
|
||||
const reserve =
|
||||
opts && Number.isFinite(Number(opts.reserveCompletion))
|
||||
? Math.max(256, Math.floor(Number(opts.reserveCompletion)))
|
||||
: Math.min(1024, Math.max(256, Math.floor(ctx * 0.15)))
|
||||
const toolsTok = bareAgentEstimateTokens(
|
||||
opts && Array.isArray(opts.tools) && opts.tools.length ? opts.tools : []
|
||||
)
|
||||
const budget = Math.max(512, ctx - reserve - toolsTok)
|
||||
|
||||
/** @type {unknown[]} */
|
||||
let out = Array.isArray(msgs) ? msgs.slice() : []
|
||||
// Drop middle turns first (keep system + recent).
|
||||
while (bareAgentEstimateTokens(out) > budget && out.length > 3) {
|
||||
out.splice(2, 1)
|
||||
}
|
||||
// Shrink system blob if still over (workspace/man/skills dominate).
|
||||
if (bareAgentEstimateTokens(out) > budget && out[0] && typeof out[0] === 'object') {
|
||||
const sys = /** @type {Record<string, unknown>} */ (out[0])
|
||||
if (sys.role === 'system' && typeof sys.content === 'string') {
|
||||
let content = sys.content
|
||||
let guard = 0
|
||||
while (
|
||||
bareAgentEstimateTokens(out) > budget &&
|
||||
content.length > 800 &&
|
||||
guard < 24
|
||||
) {
|
||||
content =
|
||||
content.slice(0, Math.floor(content.length * 0.82)) + '\n… truncated'
|
||||
out[0] = { ...sys, content }
|
||||
guard++
|
||||
}
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
/**
|
||||
* Best-effort load instruction files.
|
||||
* @param {Record<string, unknown>} ctx
|
||||
|
||||
@@ -900,11 +900,36 @@ async function bareOsRunAgentSession(ctx, argv0, task, runOpts) {
|
||||
if (needWizard) await bareAgentSyncWorkspaceFromConfig(ctx, paths, config)
|
||||
|
||||
const backendForPrompt = bareAgentResolveBackend(config)
|
||||
const promptProfile = bareAgentQvacGetProfile(
|
||||
String(config.qvac_profile || config.profile || '')
|
||||
)
|
||||
const promptCtxSize =
|
||||
backendForPrompt === 'qvac'
|
||||
? bareAgentQvacResolveCtxSize(config, promptProfile)
|
||||
: 32768
|
||||
// Local QVAC models have a hard ctx window; keep the system prompt lean.
|
||||
const workspaceBudget = backendForPrompt === 'qvac' ? 8000 : 24000
|
||||
const manBudget = backendForPrompt === 'qvac' ? 4000 : 12000
|
||||
const instructionsBudget = backendForPrompt === 'qvac' ? 3000 : 8000
|
||||
const skillsBudget = backendForPrompt === 'qvac' ? 2000 : 4000
|
||||
// Scale char budgets from ctx (chars ≈ tokens*4); leave room for tools/reply.
|
||||
const toolsOn = backendForPrompt === 'qvac' && promptProfile.tools !== false
|
||||
const promptCharBudget = Math.max(
|
||||
4000,
|
||||
Math.floor(promptCtxSize * 4 * (toolsOn ? 0.35 : 0.7))
|
||||
)
|
||||
const workspaceBudget =
|
||||
backendForPrompt === 'qvac'
|
||||
? Math.min(8000, Math.floor(promptCharBudget * 0.35))
|
||||
: 24000
|
||||
const manBudget =
|
||||
backendForPrompt === 'qvac'
|
||||
? Math.min(4000, Math.floor(promptCharBudget * 0.2))
|
||||
: 12000
|
||||
const instructionsBudget =
|
||||
backendForPrompt === 'qvac'
|
||||
? Math.min(3000, Math.floor(promptCharBudget * 0.2))
|
||||
: 8000
|
||||
const skillsBudget =
|
||||
backendForPrompt === 'qvac'
|
||||
? Math.min(2000, Math.floor(promptCharBudget * 0.15))
|
||||
: 4000
|
||||
|
||||
const workspacePromptBlock = await bareAgentLoadWorkspacePrompt(
|
||||
ctx,
|
||||
@@ -1059,6 +1084,27 @@ async function bareOsRunAgentSession(ctx, argv0, task, runOpts) {
|
||||
const backendIter = bareAgentResolveBackend(configRef.current)
|
||||
/** @type {Record<string, unknown>} */
|
||||
const providerNow = String(configRef.current.provider || '').trim().toLowerCase()
|
||||
let qvacToolsForTurn = /** @type {unknown[]} */ ([])
|
||||
if (backendIter === 'qvac') {
|
||||
const profileEarly = bareAgentQvacGetProfile(
|
||||
String(configRef.current.qvac_profile || 'recommended')
|
||||
)
|
||||
const ctxEarly = bareAgentQvacResolveCtxSize(
|
||||
configRef.current,
|
||||
profileEarly
|
||||
)
|
||||
qvacToolsForTurn =
|
||||
profileEarly.tools !== false
|
||||
? bareAgentFlattenToolsForQvac(tools)
|
||||
: []
|
||||
messages = bareAgentTrimMessagesForCtx(messages, ctxEarly, {
|
||||
tools: qvacToolsForTurn,
|
||||
reserveCompletion: Math.min(
|
||||
1024,
|
||||
Number(configRef.current.max_tokens) || 512
|
||||
)
|
||||
})
|
||||
}
|
||||
if (reasoningSettings.enabled && reasoningSettings.mode === 'trace') {
|
||||
bareAgentWriteOut(
|
||||
ctx,
|
||||
@@ -1222,7 +1268,7 @@ async function bareOsRunAgentSession(ctx, argv0, task, runOpts) {
|
||||
}
|
||||
await ctx.bareOsQvacComplete({
|
||||
history: messages,
|
||||
tools: bareAgentFlattenToolsForQvac(tools),
|
||||
tools: qvacToolsForTurn,
|
||||
stream: Boolean(configRef.current.stream !== false),
|
||||
captureThinking: reasoningSettings.enabled,
|
||||
modelSrc,
|
||||
|
||||
@@ -40,7 +40,7 @@ First load downloads via the QVAC registry into the **host cache**, then mirrors
|
||||
- `backend` — `qvac` (default) or `rest`
|
||||
- `qvac_profile` — `lite` / `recommended` / `strong` / `tool-tiny`
|
||||
- `qvac_model` — registry id (e.g. `QWEN3_1_7B_INST_Q4`)
|
||||
- `qvac_ctx_size` — optional context window override (profile defaults: lite/tool-tiny 4096, recommended/strong 8192; max 32768)
|
||||
- `qvac_ctx_size` — optional context window override. Profile defaults match model cards: Qwen3 profiles **32768**, tool-tiny (Llama 3.2 1B) **131072** (max override 131072). Tool-enabled profiles floor at 8192 (tool schemas alone are ~4.5k tokens). Cap further with host env `BARE_OS_QVAC_MAX_CTX` if VRAM is tight.
|
||||
- `qvac_device` — `gpu` (default) or `cpu` (bypass Vulkan; slower)
|
||||
- `qvac_main_gpu` — `auto` (default: pick highest-VRAM Vulkan GPU, else CPU), `dedicated`, `integrated`, or device index (`0`, `1`, …)
|
||||
- `qvac_gpu_layers` — optional layer offload count (`0` = CPU weights)
|
||||
|
||||
@@ -10,7 +10,7 @@ function loadAgentQvacHelpers() {
|
||||
vm.createContext(sandbox)
|
||||
vm.runInContext(
|
||||
QVAC_SRC +
|
||||
'\n;this.__exports = { bareAgentFlattenToolsForQvac, bareAgentQvacGetProfile, bareAgentQvacProfileList, bareAgentResolveBackend, bareAgentQvacBridgeAvailable, bareAgentQvacResolveCtxSize, bareAgentQvacResolveDeviceOpts }',
|
||||
'\n;this.__exports = { bareAgentFlattenToolsForQvac, bareAgentQvacGetProfile, bareAgentQvacProfileList, bareAgentResolveBackend, bareAgentQvacBridgeAvailable, bareAgentQvacResolveCtxSize, bareAgentQvacResolveDeviceOpts, bareAgentQvacModelCardCtxSize, BARE_AGENT_QVAC_CTX_QWEN3, BARE_AGENT_QVAC_CTX_LLAMA32_1B }',
|
||||
sandbox
|
||||
)
|
||||
return sandbox.__exports
|
||||
@@ -40,18 +40,33 @@ test('qvac profiles include recommended + lite', async (t) => {
|
||||
const list = bareAgentQvacProfileList()
|
||||
t.ok(list.length >= 4)
|
||||
t.is(bareAgentQvacGetProfile('recommended').chatModel, 'QWEN3_1_7B_INST_Q4')
|
||||
t.is(bareAgentQvacGetProfile('recommended').ctxSize, 8192)
|
||||
t.is(bareAgentQvacGetProfile('recommended').ctxSize, 32768)
|
||||
t.is(bareAgentQvacGetProfile('lite').id, 'lite')
|
||||
t.is(bareAgentQvacGetProfile('lite').ctxSize, 4096)
|
||||
t.is(bareAgentQvacGetProfile('lite').ctxSize, 32768)
|
||||
t.is(bareAgentQvacGetProfile('tool-tiny').ctxSize, 131072)
|
||||
t.is(bareAgentQvacGetProfile('strong').ctxSize, 32768)
|
||||
t.is(bareAgentQvacGetProfile('nope').id, 'recommended')
|
||||
})
|
||||
|
||||
test('model-card ctx sizes match upstream cards', async (t) => {
|
||||
const { bareAgentQvacModelCardCtxSize } = loadAgentQvacHelpers()
|
||||
t.is(bareAgentQvacModelCardCtxSize('QWEN3_600M_INST_Q4'), 32768)
|
||||
t.is(bareAgentQvacModelCardCtxSize('QWEN3_1_7B_INST_Q4'), 32768)
|
||||
t.is(bareAgentQvacModelCardCtxSize('QWEN3_4B_INST_Q4_K_M'), 32768)
|
||||
t.is(bareAgentQvacModelCardCtxSize('LLAMA_TOOL_CALLING_1B_INST_Q4_K'), 131072)
|
||||
})
|
||||
|
||||
test('resolve qvac ctx size from profile or config override', async (t) => {
|
||||
const { bareAgentQvacGetProfile, bareAgentQvacResolveCtxSize } = loadAgentQvacHelpers()
|
||||
const rec = bareAgentQvacGetProfile('recommended')
|
||||
t.is(bareAgentQvacResolveCtxSize({}, rec), 8192)
|
||||
t.is(bareAgentQvacResolveCtxSize({ qvac_ctx_size: 4096 }, rec), 4096)
|
||||
t.is(bareAgentQvacResolveCtxSize({ qvac_ctx_size: 999999 }, rec), 32768)
|
||||
const lite = bareAgentQvacGetProfile('lite')
|
||||
const tiny = bareAgentQvacGetProfile('tool-tiny')
|
||||
t.is(bareAgentQvacResolveCtxSize({}, rec), 32768)
|
||||
t.is(bareAgentQvacResolveCtxSize({ qvac_ctx_size: 4096 }, rec), 8192) // tools need ≥8k
|
||||
t.is(bareAgentQvacResolveCtxSize({ qvac_ctx_size: 4096 }, lite), 4096) // lite tools=false
|
||||
t.is(bareAgentQvacResolveCtxSize({ qvac_ctx_size: 999999 }, rec), 131072)
|
||||
t.is(bareAgentQvacResolveCtxSize({}, lite), 32768)
|
||||
t.is(bareAgentQvacResolveCtxSize({}, tiny), 131072)
|
||||
})
|
||||
|
||||
test('resolve qvac device opts', async (t) => {
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import test from 'brittle'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import vm from 'node:vm'
|
||||
|
||||
const STATE_SRC = readFileSync(new URL('../lib/agent-state.js', import.meta.url), 'utf8')
|
||||
|
||||
function loadTrimHelpers() {
|
||||
const sandbox = { console, TextEncoder, TextDecoder }
|
||||
vm.createContext(sandbox)
|
||||
vm.runInContext(
|
||||
STATE_SRC +
|
||||
'\n;this.__exports = { bareAgentTrimMessages, bareAgentTrimMessagesForCtx, bareAgentEstimateTokens }',
|
||||
sandbox
|
||||
)
|
||||
return sandbox.__exports
|
||||
}
|
||||
|
||||
test('trim for ctx shrinks system when tools consume budget', async (t) => {
|
||||
const { bareAgentTrimMessagesForCtx, bareAgentEstimateTokens } = loadTrimHelpers()
|
||||
const tools = [{ name: 'x', description: 'y'.repeat(8000), parameters: {} }]
|
||||
const msgs = [
|
||||
{ role: 'system', content: 'S'.repeat(20_000) },
|
||||
{ role: 'user', content: 'hello' }
|
||||
]
|
||||
const out = bareAgentTrimMessagesForCtx(msgs, 4096, {
|
||||
tools,
|
||||
reserveCompletion: 512
|
||||
})
|
||||
t.is(out.length, 2)
|
||||
t.ok(String(/** @type {any} */ (out[0]).content).length < 20_000)
|
||||
t.ok(
|
||||
bareAgentEstimateTokens(out) + bareAgentEstimateTokens(tools) + 512 <=
|
||||
4096 + 200
|
||||
)
|
||||
})
|
||||
@@ -1404,6 +1404,64 @@ function bareAgentTrimMessages(msgs, maxBytes) {
|
||||
return out
|
||||
}
|
||||
|
||||
/**
|
||||
* Rough token estimate (chars/4). Good enough for local ctx budgeting.
|
||||
* @param {unknown} value
|
||||
*/
|
||||
function bareAgentEstimateTokens(value) {
|
||||
try {
|
||||
const n = JSON.stringify(value == null ? '' : value).length
|
||||
return Math.max(0, Math.ceil(n / 4))
|
||||
} catch {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim history + shrink system content so prompt fits a QVAC ctx window.
|
||||
* Reserves room for completion and optional tools JSON.
|
||||
* @param {unknown[]} msgs
|
||||
* @param {number} ctxSize
|
||||
* @param {{ tools?: unknown[], reserveCompletion?: number }} [opts]
|
||||
*/
|
||||
function bareAgentTrimMessagesForCtx(msgs, ctxSize, opts) {
|
||||
const ctx = Math.max(2048, Math.floor(Number(ctxSize) || 4096))
|
||||
const reserve =
|
||||
opts && Number.isFinite(Number(opts.reserveCompletion))
|
||||
? Math.max(256, Math.floor(Number(opts.reserveCompletion)))
|
||||
: Math.min(1024, Math.max(256, Math.floor(ctx * 0.15)))
|
||||
const toolsTok = bareAgentEstimateTokens(
|
||||
opts && Array.isArray(opts.tools) && opts.tools.length ? opts.tools : []
|
||||
)
|
||||
const budget = Math.max(512, ctx - reserve - toolsTok)
|
||||
|
||||
/** @type {unknown[]} */
|
||||
let out = Array.isArray(msgs) ? msgs.slice() : []
|
||||
// Drop middle turns first (keep system + recent).
|
||||
while (bareAgentEstimateTokens(out) > budget && out.length > 3) {
|
||||
out.splice(2, 1)
|
||||
}
|
||||
// Shrink system blob if still over (workspace/man/skills dominate).
|
||||
if (bareAgentEstimateTokens(out) > budget && out[0] && typeof out[0] === 'object') {
|
||||
const sys = /** @type {Record<string, unknown>} */ (out[0])
|
||||
if (sys.role === 'system' && typeof sys.content === 'string') {
|
||||
let content = sys.content
|
||||
let guard = 0
|
||||
while (
|
||||
bareAgentEstimateTokens(out) > budget &&
|
||||
content.length > 800 &&
|
||||
guard < 24
|
||||
) {
|
||||
content =
|
||||
content.slice(0, Math.floor(content.length * 0.82)) + '\n… truncated'
|
||||
out[0] = { ...sys, content }
|
||||
guard++
|
||||
}
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
/**
|
||||
* Best-effort load instruction files.
|
||||
* @param {Record<string, unknown>} ctx
|
||||
@@ -1597,6 +1655,16 @@ async function bareAgentResetChatSession(ctx, paths, argv0) {
|
||||
|
||||
/** @typedef {'lite'|'recommended'|'strong'|'tool-tiny'} BareAgentQvacProfileId */
|
||||
|
||||
/**
|
||||
* Native context windows from upstream model cards (not conservative laptop defaults).
|
||||
* Qwen3 dense (0.6B/1.7B/4B): https://huggingface.co/Qwen/Qwen3-0.6B — 32,768
|
||||
* Llama 3.2 1B (tool-calling finetune base): Meta Llama 3.2 — 128,000
|
||||
* Absolute ceiling for overrides / host clamp.
|
||||
*/
|
||||
const BARE_AGENT_QVAC_CTX_QWEN3 = 32768
|
||||
const BARE_AGENT_QVAC_CTX_LLAMA32_1B = 131072
|
||||
const BARE_AGENT_QVAC_CTX_ABSOLUTE_MAX = 131072
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* id: BareAgentQvacProfileId,
|
||||
@@ -1617,50 +1685,69 @@ const BARE_AGENT_QVAC_PROFILES = {
|
||||
id: 'lite',
|
||||
label: 'Lite',
|
||||
description:
|
||||
'Smallest download. Good for weak machines / ~4 GB VRAM; limited tool use.',
|
||||
'Smallest download (Qwen3-0.6B). Model-card context 32k; limited tool use.',
|
||||
chatModel: 'QWEN3_600M_INST_Q4',
|
||||
tools: false,
|
||||
minRamGb: 4,
|
||||
minDiskGb: 2,
|
||||
approxDownloadGb: 0.5,
|
||||
ctxSize: 4096
|
||||
ctxSize: BARE_AGENT_QVAC_CTX_QWEN3
|
||||
},
|
||||
recommended: {
|
||||
id: 'recommended',
|
||||
label: 'Recommended',
|
||||
description:
|
||||
'Best balance for Bare OS agent tool calling (fits ~4–8 GB VRAM at ctx 8k).',
|
||||
'Best balance for Bare OS agent tool calling (Qwen3-1.7B, model-card context 32k).',
|
||||
chatModel: 'QWEN3_1_7B_INST_Q4',
|
||||
tools: true,
|
||||
minRamGb: 8,
|
||||
minDiskGb: 5,
|
||||
approxDownloadGb: 2.5,
|
||||
ctxSize: 8192
|
||||
ctxSize: BARE_AGENT_QVAC_CTX_QWEN3
|
||||
},
|
||||
strong: {
|
||||
id: 'strong',
|
||||
label: 'Strong',
|
||||
description: 'Better reasoning. Needs more RAM/VRAM/disk.',
|
||||
description:
|
||||
'Better reasoning (Qwen3-4B). Model-card context 32k (131k with YaRN not enabled).',
|
||||
chatModel: 'QWEN3_4B_INST_Q4_K_M',
|
||||
tools: true,
|
||||
minRamGb: 16,
|
||||
minDiskGb: 8,
|
||||
approxDownloadGb: 3.5,
|
||||
ctxSize: 8192
|
||||
ctxSize: BARE_AGENT_QVAC_CTX_QWEN3
|
||||
},
|
||||
'tool-tiny': {
|
||||
id: 'tool-tiny',
|
||||
label: 'Tool-tiny',
|
||||
description: 'Llama tool-calling 1B fallback if Qwen tools misbehave.',
|
||||
description:
|
||||
'Llama 3.2 1B tool-calling fallback (model-card context 128k).',
|
||||
chatModel: 'LLAMA_TOOL_CALLING_1B_INST_Q4_K',
|
||||
tools: true,
|
||||
minRamGb: 6,
|
||||
minDiskGb: 3,
|
||||
approxDownloadGb: 1,
|
||||
ctxSize: 4096
|
||||
ctxSize: BARE_AGENT_QVAC_CTX_LLAMA32_1B
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Model-card / train context for a QVAC registry id (fallback 32k).
|
||||
* @param {string} [modelId]
|
||||
* @returns {number}
|
||||
*/
|
||||
function bareAgentQvacModelCardCtxSize(modelId) {
|
||||
const id = String(modelId || '')
|
||||
.trim()
|
||||
.toUpperCase()
|
||||
if (!id) return BARE_AGENT_QVAC_CTX_QWEN3
|
||||
if (id.includes('LLAMA') || id.includes('LLAMA_TOOL')) {
|
||||
return BARE_AGENT_QVAC_CTX_LLAMA32_1B
|
||||
}
|
||||
if (id.includes('QWEN3')) return BARE_AGENT_QVAC_CTX_QWEN3
|
||||
return BARE_AGENT_QVAC_CTX_QWEN3
|
||||
}
|
||||
|
||||
/** @returns {BareAgentQvacProfile[]} */
|
||||
function bareAgentQvacProfileList() {
|
||||
return Object.values(BARE_AGENT_QVAC_PROFILES)
|
||||
@@ -1749,17 +1836,33 @@ function bareAgentResolveBackend(config) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve context window for QVAC load (profile default or config override).
|
||||
* Resolve context window for QVAC load (profile/model-card default or config override).
|
||||
* Tool schemas alone are ~4.5k tokens, so tool-enabled profiles need ≥8192.
|
||||
* @param {Record<string, unknown>} config
|
||||
* @param {BareAgentQvacProfile} profile
|
||||
*/
|
||||
function bareAgentQvacResolveCtxSize(config, profile) {
|
||||
const modelId = String(
|
||||
(config && (config.qvac_model || config.model)) ||
|
||||
(profile && profile.chatModel) ||
|
||||
''
|
||||
)
|
||||
const cardCtx = bareAgentQvacModelCardCtxSize(modelId)
|
||||
const profileCtx = Math.max(
|
||||
2048,
|
||||
Number(profile && profile.ctxSize) || cardCtx
|
||||
)
|
||||
const raw = Number(config && config.qvac_ctx_size)
|
||||
let ctx
|
||||
if (Number.isFinite(raw) && raw >= 2048) {
|
||||
// Cap high overrides; 32k+ KV often OOMs laptop GPUs (~4 GB VRAM).
|
||||
return Math.min(32768, Math.floor(raw))
|
||||
ctx = Math.min(BARE_AGENT_QVAC_CTX_ABSOLUTE_MAX, Math.floor(raw))
|
||||
} else {
|
||||
// Prefer explicit profile ctx (already model-card sized); else card for model id.
|
||||
ctx = Math.min(BARE_AGENT_QVAC_CTX_ABSOLUTE_MAX, Math.max(profileCtx, cardCtx))
|
||||
}
|
||||
return Math.max(2048, Number(profile.ctxSize) || 8192)
|
||||
// Full Bare OS tool list ≈ 4.5k tokens; leave room for system + reply.
|
||||
if (profile && profile.tools !== false && ctx < 8192) ctx = 8192
|
||||
return ctx
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -6846,11 +6949,36 @@ async function bareOsRunAgentSession(ctx, argv0, task, runOpts) {
|
||||
if (needWizard) await bareAgentSyncWorkspaceFromConfig(ctx, paths, config)
|
||||
|
||||
const backendForPrompt = bareAgentResolveBackend(config)
|
||||
const promptProfile = bareAgentQvacGetProfile(
|
||||
String(config.qvac_profile || config.profile || '')
|
||||
)
|
||||
const promptCtxSize =
|
||||
backendForPrompt === 'qvac'
|
||||
? bareAgentQvacResolveCtxSize(config, promptProfile)
|
||||
: 32768
|
||||
// Local QVAC models have a hard ctx window; keep the system prompt lean.
|
||||
const workspaceBudget = backendForPrompt === 'qvac' ? 8000 : 24000
|
||||
const manBudget = backendForPrompt === 'qvac' ? 4000 : 12000
|
||||
const instructionsBudget = backendForPrompt === 'qvac' ? 3000 : 8000
|
||||
const skillsBudget = backendForPrompt === 'qvac' ? 2000 : 4000
|
||||
// Scale char budgets from ctx (chars ≈ tokens*4); leave room for tools/reply.
|
||||
const toolsOn = backendForPrompt === 'qvac' && promptProfile.tools !== false
|
||||
const promptCharBudget = Math.max(
|
||||
4000,
|
||||
Math.floor(promptCtxSize * 4 * (toolsOn ? 0.35 : 0.7))
|
||||
)
|
||||
const workspaceBudget =
|
||||
backendForPrompt === 'qvac'
|
||||
? Math.min(8000, Math.floor(promptCharBudget * 0.35))
|
||||
: 24000
|
||||
const manBudget =
|
||||
backendForPrompt === 'qvac'
|
||||
? Math.min(4000, Math.floor(promptCharBudget * 0.2))
|
||||
: 12000
|
||||
const instructionsBudget =
|
||||
backendForPrompt === 'qvac'
|
||||
? Math.min(3000, Math.floor(promptCharBudget * 0.2))
|
||||
: 8000
|
||||
const skillsBudget =
|
||||
backendForPrompt === 'qvac'
|
||||
? Math.min(2000, Math.floor(promptCharBudget * 0.15))
|
||||
: 4000
|
||||
|
||||
const workspacePromptBlock = await bareAgentLoadWorkspacePrompt(
|
||||
ctx,
|
||||
@@ -7005,6 +7133,27 @@ async function bareOsRunAgentSession(ctx, argv0, task, runOpts) {
|
||||
const backendIter = bareAgentResolveBackend(configRef.current)
|
||||
/** @type {Record<string, unknown>} */
|
||||
const providerNow = String(configRef.current.provider || '').trim().toLowerCase()
|
||||
let qvacToolsForTurn = /** @type {unknown[]} */ ([])
|
||||
if (backendIter === 'qvac') {
|
||||
const profileEarly = bareAgentQvacGetProfile(
|
||||
String(configRef.current.qvac_profile || 'recommended')
|
||||
)
|
||||
const ctxEarly = bareAgentQvacResolveCtxSize(
|
||||
configRef.current,
|
||||
profileEarly
|
||||
)
|
||||
qvacToolsForTurn =
|
||||
profileEarly.tools !== false
|
||||
? bareAgentFlattenToolsForQvac(tools)
|
||||
: []
|
||||
messages = bareAgentTrimMessagesForCtx(messages, ctxEarly, {
|
||||
tools: qvacToolsForTurn,
|
||||
reserveCompletion: Math.min(
|
||||
1024,
|
||||
Number(configRef.current.max_tokens) || 512
|
||||
)
|
||||
})
|
||||
}
|
||||
if (reasoningSettings.enabled && reasoningSettings.mode === 'trace') {
|
||||
bareAgentWriteOut(
|
||||
ctx,
|
||||
@@ -7095,6 +7244,29 @@ async function bareOsRunAgentSession(ctx, argv0, task, runOpts) {
|
||||
EDIT_ANSI_RESET +
|
||||
'\n'
|
||||
)
|
||||
try {
|
||||
const st =
|
||||
typeof ctx.bareOsQvacStatus === 'function'
|
||||
? ctx.bareOsQvacStatus()
|
||||
: null
|
||||
if (st && (st.cacheDir || st.hdmsPath || st.backendsDir)) {
|
||||
bareAgentWriteOut(
|
||||
ctx,
|
||||
stdout,
|
||||
bareEditSgr('dim', useColor) +
|
||||
'[qvac] cache=' +
|
||||
String(st.cacheDir || '') +
|
||||
' hdms=' +
|
||||
String(st.hdmsPath || '/mnt/models') +
|
||||
' backends=' +
|
||||
String(st.backendsDir || '(unresolved)') +
|
||||
EDIT_ANSI_RESET +
|
||||
'\n'
|
||||
)
|
||||
}
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
if (typeof ctx.bareOsQvacLoadModel === 'function') {
|
||||
const loaded = await ctx.bareOsQvacLoadModel({
|
||||
modelSrc,
|
||||
@@ -7145,7 +7317,7 @@ async function bareOsRunAgentSession(ctx, argv0, task, runOpts) {
|
||||
}
|
||||
await ctx.bareOsQvacComplete({
|
||||
history: messages,
|
||||
tools: bareAgentFlattenToolsForQvac(tools),
|
||||
tools: qvacToolsForTurn,
|
||||
stream: Boolean(configRef.current.stream !== false),
|
||||
captureThinking: reasoningSettings.enabled,
|
||||
modelSrc,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"schema": 2,
|
||||
"profileId": "bare-os-posix-like",
|
||||
"generatedAt": "2026-07-31T21:35:54.625Z",
|
||||
"generatedAt": "2026-07-31T23:16:21.588Z",
|
||||
"note": "Sparse POSIX Issue 7 coverage hints; commandIndex is generated each coreutils build.",
|
||||
"commandIndex": [
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema": 1,
|
||||
"atMs": 1785533754625,
|
||||
"atMs": 1785539781587,
|
||||
"commands": [
|
||||
"agent",
|
||||
"appctl",
|
||||
|
||||
@@ -30,10 +30,17 @@ After **`agent --config`** / **`--setup`** (or changing **`owner_name`** / **`ag
|
||||
|
||||
Default backend is **QVAC** (QuantumVerse Automatic Computer) — local in-process LLM via the booter **`ctx.bareOsQvac*`** bridge (`@qvac/sdk`). Weights download on first use after you pick a profile in **`agent --config`**.
|
||||
|
||||
Models are stored for durability on HDMS label **`models`** (guest path **`/mnt/models/`**) and materialize into a host cache for llama.cpp load:
|
||||
|
||||
- Host cache: **`$BARE_OS_HOST_DATA/qvac/models`** (default **`~/.bare-os/qvac/models`**)
|
||||
- Runtime config: **`$BARE_OS_HOST_DATA/qvac/qvac.config.json`** (`QVAC_CONFIG_PATH`, absolute `cacheDirectory`)
|
||||
|
||||
First load downloads via the QVAC registry into the **host cache**, then mirrors into HDMS. If HDMS already has the GGUF, Bare OS materializes it to the host cache before load. If auto-create fails, run **`hdms create models`** after unlock.
|
||||
|
||||
- `backend` — `qvac` (default) or `rest`
|
||||
- `qvac_profile` — `lite` / `recommended` / `strong` / `tool-tiny`
|
||||
- `qvac_model` — registry id (e.g. `QWEN3_1_7B_INST_Q4`)
|
||||
- `qvac_ctx_size` — optional context window override (profile defaults: lite/tool-tiny 4096, recommended/strong 8192; max 32768)
|
||||
- `qvac_ctx_size` — optional context window override. Profile defaults match model cards: Qwen3 profiles **32768**, tool-tiny (Llama 3.2 1B) **131072** (max override 131072). Tool-enabled profiles floor at 8192 (tool schemas alone are ~4.5k tokens). Cap further with host env `BARE_OS_QVAC_MAX_CTX` if VRAM is tight.
|
||||
- `qvac_device` — `gpu` (default) or `cpu` (bypass Vulkan; slower)
|
||||
- `qvac_main_gpu` — `auto` (default: pick highest-VRAM Vulkan GPU, else CPU), `dedicated`, `integrated`, or device index (`0`, `1`, …)
|
||||
- `qvac_gpu_layers` — optional layer offload count (`0` = CPU weights)
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user