This commit is contained in:
@@ -247,6 +247,8 @@ const BARE_AGENT_STATIC_SYSTEM = `You are the Bare OS coding agent — a senior
|
||||
|
||||
YOU RUN THE TOOLS. The user never runs your tools, commands, patches, or scripts. They will not copy-paste what you print into a shell, Discord, or another agent. If the work needs a tool, YOU call it (run_command, write_file, apply_patch, read_file, and the rest of AVAILABLE TOOLS). Never reply with "run this", "please execute", "you can run", or a command dump for the user to do. The user is not your tool runner.
|
||||
|
||||
YOU CAN EXECUTE. Never say "I cannot execute commands", "I cannot run CLI", "I can help you use available tools", or "try:". That is a failure. Guest shell is run_command({command, cwd?}). There is no bash, shell, cli, or terminal tool — those names map to run_command. Emitting a ```bash fence instead of calling run_command is a failure. If the operator says "run it yourself", call the tool immediately and return the result.
|
||||
|
||||
Bare OS by Raven Scott (https://raven-scott.fyi). Repo: https://git.ssh.surf/snxraven/bare-operating-system. Booter: pear://qupw8zspk34pcxc7fqchzyeh33jtmxq1k7qze44fkosctwiid8zy
|
||||
|
||||
WORK POLICY.
|
||||
@@ -260,7 +262,7 @@ ACCESS (denylist, not allowlist). You already have full guest admin. You can cre
|
||||
- Create and edit with write_file, create_directory, search_replace, edit_file, and apply_patch. Never say you cannot write files. Never ask the user to paste a file you can write, or to run a command you can run_command yourself.
|
||||
- Writable paths: /home, /tmp, /mnt, /root, /var, /opt, extra drives, ~/.agent. Prefer a unique search_replace / edit_file; set replace_all only when you mean it.
|
||||
- Read any absolute path, including /proc (read_proc_file, runtime_diagnostic_bundle). Use read_file offset/limit for large files.
|
||||
- Run every guest command via run_command (command_deny is empty by default). Prefer list_directory, glob_files, and file_stat over ls/find when you only need names. list_bin lists guest /bin utilities (POSIX-in-JS, not GNU).
|
||||
- Run every guest command via run_command (command_deny is empty by default). Prefer list_directory, glob_files, and file_stat over ls/find when you only need names. list_bin lists guest /bin utilities (POSIX-in-JS, not GNU). Never dump curl/ip/ls for the user — call run_command and report stdout.
|
||||
- Delete and move are enabled. Do not mutate the read-only base system: /bin /etc /boot /lib /usr /share /proc /dev /sys /run.
|
||||
- Node is not installed in the guest. Never plan or run node, npm, or npx here. Do not use run_js_script to read files, write files, or run shell — call read_file, write_file, run_command instead. Only use run_js_script for custom guest JS. The kernel already injects ctx and argv: never write const/let/var ctx, never export. Body must be only async function run(ctx, argv) { const vfs = ctx.vfs; ... }. Do not import Node builtins. Never paste a "final correct script" into the user reply — call the tool.
|
||||
- Live kernel: read_proc_file on /proc/bare_os/features (or features.json) and /proc/bare_os/capabilities.json. Man pages and apropos_man are documentation only — never infer what is enabled from them.
|
||||
@@ -279,7 +281,8 @@ CODING LOOP. Multi-step work: todo_write (merge=true). Large unknown surface: en
|
||||
TOOL DISCIPLINE.
|
||||
- YOU call every tool. The user will never run them. Do not print commands, patches, or "run this" for the user.
|
||||
- The live registry is AVAILABLE TOOLS at the end of this prompt. Those names are the only callable functions. Skills and /bin utilities are not tools.
|
||||
- Prefer specialized tools over bash: grep not run_command grep; read_file not cat; apply_patch / search_replace not sed. Never use run_command to print thoughts.
|
||||
- There is no bash/shell/cli tool. Guest shell is run_command. Prefer specialized tools over shell: grep not run_command grep; read_file not cat; apply_patch / search_replace not sed. Never use run_command to print thoughts.
|
||||
- Forbidden replies: "I cannot execute", "run this yourself", "try:" plus a command fence. Call the tool instead.
|
||||
- Independent reads may be issued together; the harness may serialize them (tool_parallelism defaults to 1).
|
||||
- Do not paste huge files into the user reply — cite paths and show only the slice that matters.
|
||||
- Persist durable facts in MEMORY.md; older turns may be compacted.
|
||||
@@ -304,7 +307,8 @@ This turn is shown in Discord. This block overrides the TTY plain-text rule abov
|
||||
- Use [label](https://url) for links. Do not wrap the entire reply in one fence.
|
||||
- The Discord message is ONLY your final answer. Do not prefix status, model name, "Loading", or a restatement of the prompt.
|
||||
- Tool chatter and process steps belong in tools (progress.txt is automated), not the reply.
|
||||
- Do not tell the user to run a command. Call tools yourself.
|
||||
- Do not tell the user to run a command. Call tools yourself. If they say "run it yourself", that is an order to call run_command now — not to print curl/ip/bash for them.
|
||||
- Forbidden: "I cannot execute commands directly", "I can help you use available tools", dumping \`\`\`bash fences for the operator to copy. Execute, then answer with the result.
|
||||
- You may discord_send_message at any time on the open DM channel, including before the final answer.`
|
||||
|
||||
const BARE_AGENT_OPERATING_CONTRACT = `
|
||||
@@ -417,10 +421,18 @@ function bareAgentFinalizeToolCalls(acc) {
|
||||
for (const i of indices) {
|
||||
const c = acc.get(i)
|
||||
if (!c || !c.name) continue
|
||||
const args = c.args || '{}'
|
||||
const name =
|
||||
typeof bareAgentCanonicalToolName === 'function'
|
||||
? bareAgentCanonicalToolName(c.name)
|
||||
: c.name
|
||||
if (!name) continue
|
||||
const args =
|
||||
typeof bareAgentCoerceToolArgs === 'function'
|
||||
? bareAgentCoerceToolArgs(name, c.args || '{}')
|
||||
: c.args || '{}'
|
||||
// Drop stream+final duplicates (same id, or same name+args).
|
||||
const idKey = c.id ? 'id:' + c.id : ''
|
||||
const naKey = 'na:' + c.name + '\0' + args
|
||||
const naKey = 'na:' + name + '\0' + args
|
||||
if ((idKey && seen.has(idKey)) || seen.has(naKey)) continue
|
||||
if (idKey) seen.add(idKey)
|
||||
seen.add(naKey)
|
||||
@@ -428,7 +440,7 @@ function bareAgentFinalizeToolCalls(acc) {
|
||||
id: c.id || 'call_' + i + '_' + String(Math.random()).slice(2, 10),
|
||||
type: 'function',
|
||||
function: {
|
||||
name: c.name,
|
||||
name: name,
|
||||
arguments: args
|
||||
}
|
||||
})
|
||||
@@ -437,9 +449,184 @@ function bareAgentFinalizeToolCalls(acc) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Recover tool calls the provider streamed as plain text (Hermes / Qwen XML)
|
||||
* instead of `delta_tool_calls`. Today's models often do this when the SDK
|
||||
* drops tools or picks the wrong dialect.
|
||||
* Map common leaked tool names (Grok/Claude `bash`, `shell`, …) onto the
|
||||
* live registry. Used by text recovery and finalize.
|
||||
* @param {string} name
|
||||
*/
|
||||
function bareAgentCanonicalToolName(name) {
|
||||
const n = String(name || '').trim()
|
||||
if (!n) return ''
|
||||
const key = n.toLowerCase().replace(/[\s-]+/g, '_')
|
||||
const aliases = {
|
||||
bash: 'run_command',
|
||||
shell: 'run_command',
|
||||
sh: 'run_command',
|
||||
zsh: 'run_command',
|
||||
fish: 'run_command',
|
||||
cli: 'run_command',
|
||||
exec: 'run_command',
|
||||
execute: 'run_command',
|
||||
terminal: 'run_command',
|
||||
run: 'run_command',
|
||||
cmd: 'run_command',
|
||||
command: 'run_command',
|
||||
run_cmd: 'run_command',
|
||||
run_shell: 'run_command',
|
||||
execute_command: 'run_command',
|
||||
execute_bash: 'run_command',
|
||||
shell_command: 'run_command',
|
||||
list_dir: 'list_directory',
|
||||
glob: 'glob_files',
|
||||
ripgrep: 'grep',
|
||||
rg: 'grep'
|
||||
}
|
||||
return aliases[key] || n
|
||||
}
|
||||
|
||||
/**
|
||||
* Coerce leaked bash/run_command argument blobs into {command, cwd?}.
|
||||
* @param {string} name
|
||||
* @param {string} args
|
||||
*/
|
||||
function bareAgentCoerceToolArgs(name, args) {
|
||||
let a = String(args == null ? '' : args).trim()
|
||||
if (!a) a = '{}'
|
||||
const canon = bareAgentCanonicalToolName(name)
|
||||
if (canon !== 'run_command') {
|
||||
if (a[0] !== '{' && a[0] !== '[') {
|
||||
try {
|
||||
JSON.parse(a)
|
||||
} catch {
|
||||
a = JSON.stringify({ value: a })
|
||||
}
|
||||
}
|
||||
return a
|
||||
}
|
||||
/** @type {Record<string, unknown> | null} */
|
||||
let obj = null
|
||||
try {
|
||||
const p = JSON.parse(a[0] === '{' || a[0] === '[' ? a : JSON.stringify(a))
|
||||
if (p && typeof p === 'object' && !Array.isArray(p)) obj = p
|
||||
else if (typeof p === 'string') obj = { command: p }
|
||||
} catch {
|
||||
obj = { command: a }
|
||||
}
|
||||
if (!obj) return JSON.stringify({ command: a })
|
||||
const cmd =
|
||||
obj.command || obj.cmd || obj.code || obj.script || obj.input || obj.value || obj.query
|
||||
if (typeof cmd === 'string' && cmd.trim()) {
|
||||
const out = { command: cmd.trim() }
|
||||
if (typeof obj.cwd === 'string' && obj.cwd.trim()) out.cwd = obj.cwd.trim()
|
||||
return JSON.stringify(out)
|
||||
}
|
||||
if (a[0] !== '{' && a[0] !== '[') return JSON.stringify({ command: a })
|
||||
return a
|
||||
}
|
||||
|
||||
/**
|
||||
* True when a fenced block looks like a guest shell line, not prose or JSON.
|
||||
* @param {string} text
|
||||
*/
|
||||
function bareAgentLooksLikeShellCommand(text) {
|
||||
const s = String(text || '').trim()
|
||||
if (!s || s.length > 4000) return false
|
||||
if (/^[\s]*[{\[]/.test(s)) return false
|
||||
const lines = s.split(/\r?\n/).filter(function (l) {
|
||||
return l.trim() && !/^\s*#/.test(l)
|
||||
})
|
||||
if (!lines.length || lines.length > 16) return false
|
||||
const first = lines[0].trim()
|
||||
if (
|
||||
/^(curl|wget|ip|ping|uname|ifconfig|hostname|cat|ls|pwd|whoami|id|df|ps|env|printenv|date|echo|head|tail|grep|sed|awk|chmod|mkdir|rm|cp|mv|git|systemctl|journalctl|procstat|ss|netstat|traceroute|nslookup|dig|host|which|realpath|stat|find|xargs|tar|unzip|python|node|npm)\b/i.test(
|
||||
first
|
||||
)
|
||||
) {
|
||||
return true
|
||||
}
|
||||
if (/^(\.\/|\/(bin|usr\/bin|sbin|home|tmp|opt)\/)/.test(first)) return true
|
||||
if (lines.length === 1 && first.length < 240 && !/[.!?]$/.test(first)) {
|
||||
const tok = first.split(/\s+/)[0] || ''
|
||||
if (!/^[a-zA-Z0-9_./-]+$/.test(tok)) return false
|
||||
if (
|
||||
/^(the|this|that|for|and|or|if|when|please|you|i|we|it|to|a|an|try|here|command|example)$/i.test(
|
||||
tok
|
||||
)
|
||||
) {
|
||||
return false
|
||||
}
|
||||
return first.split(/\s+/).length <= 14
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Assistant dumped "run this yourself" instead of calling tools.
|
||||
* @param {string} text
|
||||
*/
|
||||
function bareAgentLooksLikeInstructionDump(text) {
|
||||
const s = String(text || '')
|
||||
if (!s.trim()) return false
|
||||
const low = s.toLowerCase()
|
||||
if (
|
||||
/i cannot execute/.test(low) ||
|
||||
/i can't execute/.test(low) ||
|
||||
/cannot execute commands/.test(low) ||
|
||||
/can't execute commands/.test(low) ||
|
||||
/i cannot run (commands|them|that|it|cli|the command)/.test(low) ||
|
||||
/i can't run (commands|them|that|it|cli|the command)/.test(low) ||
|
||||
/don't have (access|the ability) to (run|execute)/.test(low) ||
|
||||
/do not have (access|the ability) to (run|execute)/.test(low) ||
|
||||
/as an ai.{0,40}(cannot|can't)/.test(low) ||
|
||||
/i can help you use available tools/.test(low) ||
|
||||
/help you use available tools/.test(low) ||
|
||||
/run the command yourself/.test(low) ||
|
||||
/you (can|should|could) (run|execute|try)/.test(low) ||
|
||||
/please (run|execute|try) (this|the|it)/.test(low) ||
|
||||
/try this command/.test(low) ||
|
||||
/for .{0,60} try:/.test(low) ||
|
||||
/let me know if you need help with other commands/.test(low)
|
||||
) {
|
||||
return true
|
||||
}
|
||||
if (
|
||||
/```(?:bash|sh|shell|zsh|console|terminal)\b/i.test(s) &&
|
||||
/(try|run this|you can|example:|for .{0,20}, try)/i.test(low)
|
||||
) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Operator told the agent to stop instructing and execute.
|
||||
* @param {string} text
|
||||
*/
|
||||
function bareAgentLooksLikeDoItYourself(text) {
|
||||
const s = String(text || '').toLowerCase()
|
||||
if (!s.trim()) return false
|
||||
return (
|
||||
/run .{0,48}yourself/.test(s) ||
|
||||
/run (it|them|that|this) (yourself|for me)/.test(s) ||
|
||||
/do(n't| not) (tell|instruct|show) me (how|to)/.test(s) ||
|
||||
/just (do|run|execute) it/.test(s) ||
|
||||
/execute .{0,48}yourself/.test(s) ||
|
||||
/don'?t ask me to run/.test(s) ||
|
||||
/stop (telling|instructing) me/.test(s)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Bounce a refusal/instruction dump back into the ReAct loop.
|
||||
*/
|
||||
function bareAgentRefusalNudge() {
|
||||
return (
|
||||
'[harness] You CAN execute. Full guest admin is already on. The shell tool is run_command with {"command":"..."}. There is no bash/shell/cli tool. Never say you cannot execute. Never print a command for the user. Call run_command now and keep going until you have the result.'
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Recover tool calls the provider streamed as plain text (Hermes / Qwen XML,
|
||||
* ```bash fences, Grok/Claude `bash` dumps) instead of `delta_tool_calls`.
|
||||
* @param {string} text
|
||||
* @returns {{ index: number, id: string, function: { name: string, arguments: string } }[]}
|
||||
*/
|
||||
@@ -449,23 +636,20 @@ function bareAgentExtractToolCallsFromText(text) {
|
||||
/** @type {{ index: number, id: string, function: { name: string, arguments: string } }[]} */
|
||||
const out = []
|
||||
let idx = 0
|
||||
/** @type {Set<string>} */
|
||||
const seen = new Set()
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {string} args
|
||||
*/
|
||||
function push(name, args) {
|
||||
const n = String(name || '').trim()
|
||||
const n = bareAgentCanonicalToolName(name)
|
||||
if (!n) return
|
||||
let a = String(args == null ? '' : args).trim()
|
||||
if (!a) a = '{}'
|
||||
else if (a[0] !== '{' && a[0] !== '[') {
|
||||
try {
|
||||
JSON.parse(a)
|
||||
} catch {
|
||||
a = JSON.stringify({ value: a })
|
||||
}
|
||||
}
|
||||
const a = bareAgentCoerceToolArgs(n, args)
|
||||
const key = n + '\0' + a
|
||||
if (seen.has(key)) return
|
||||
seen.add(key)
|
||||
out.push({
|
||||
index: idx,
|
||||
id: 'text_call_' + idx,
|
||||
@@ -508,6 +692,81 @@ function bareAgentExtractToolCallsFromText(text) {
|
||||
}
|
||||
}
|
||||
|
||||
const invoke = /<invoke\s+name=["']([^"']+)["']>([\s\S]*?)<\/invoke>/gi
|
||||
while ((m = invoke.exec(src))) {
|
||||
/** @type {Record<string, string>} */
|
||||
const args = {}
|
||||
const paramRe = /<parameter\s+name=["']([^"']+)["']>([\s\S]*?)<\/parameter>/gi
|
||||
let pm
|
||||
while ((pm = paramRe.exec(m[2] || ''))) {
|
||||
args[String(pm[1] || '').trim()] = String(pm[2] || '').trim()
|
||||
}
|
||||
push(m[1], JSON.stringify(args))
|
||||
}
|
||||
|
||||
const bracket = /\[(?:tool_call\s+)?([a-zA-Z0-9_]+)\s*\(([^)]*)\)\]/g
|
||||
while ((m = bracket.exec(src))) {
|
||||
const name = m[1]
|
||||
const raw = String(m[2] || '').trim()
|
||||
if (!raw) {
|
||||
push(name, '{}')
|
||||
continue
|
||||
}
|
||||
if (/^[{\[]/.test(raw)) {
|
||||
push(name, raw)
|
||||
continue
|
||||
}
|
||||
const kv = /^([a-zA-Z0-9_]+)\s*=\s*(["']?)([\s\S]*)\2$/.exec(raw)
|
||||
if (kv) {
|
||||
const rec = {}
|
||||
rec[kv[1]] = kv[3]
|
||||
push(name, JSON.stringify(rec))
|
||||
continue
|
||||
}
|
||||
push(name, raw)
|
||||
}
|
||||
|
||||
const dump = bareAgentLooksLikeInstructionDump(src)
|
||||
const fence = /```([a-zA-Z0-9_-]*)[ \t]*\r?\n([\s\S]*?)```/g
|
||||
const shellLang = /^(bash|sh|shell|zsh|fish|console|terminal|posix|busybox)$/i
|
||||
while ((m = fence.exec(src))) {
|
||||
const lang = String(m[1] || '').trim()
|
||||
const body = String(m[2] || '').trim()
|
||||
if (!body) continue
|
||||
if (shellLang.test(lang) || ((dump || !lang) && bareAgentLooksLikeShellCommand(body))) {
|
||||
push('run_command', JSON.stringify({ command: body }))
|
||||
}
|
||||
}
|
||||
|
||||
if (dump) {
|
||||
const lines = src.split(/\r?\n/)
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
let t = String(lines[i] || '').trim()
|
||||
t = t.replace(/^[-*]\s+/, '').replace(/^`+|`+$/g, '')
|
||||
if (/^(bash|sh|shell|zsh|fish|console|terminal)$/i.test(t)) {
|
||||
const nxt = String(lines[i + 1] || '')
|
||||
.trim()
|
||||
.replace(/^`+|`+$/g, '')
|
||||
if (bareAgentLooksLikeShellCommand(nxt)) {
|
||||
push('run_command', JSON.stringify({ command: nxt }))
|
||||
i += 1
|
||||
}
|
||||
continue
|
||||
}
|
||||
if (bareAgentLooksLikeShellCommand(t)) {
|
||||
push('run_command', JSON.stringify({ command: t }))
|
||||
}
|
||||
}
|
||||
const inline = /`([^`\n]{1,240})`/g
|
||||
let im
|
||||
while ((im = inline.exec(src))) {
|
||||
const body = String(im[1] || '').trim()
|
||||
if (bareAgentLooksLikeShellCommand(body)) {
|
||||
push('run_command', JSON.stringify({ command: body }))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
@@ -517,6 +776,10 @@ function bareAgentExtractToolCallsFromText(text) {
|
||||
function bareAgentStripToolCallsFromText(text) {
|
||||
return String(text || '')
|
||||
.replace(/<tool_call>[\s\S]*?<\/tool_call>/gi, '')
|
||||
.replace(/<function_calls>[\s\S]*?<\/function_calls>/gi, '')
|
||||
.replace(/<invoke\s+name=["'][^"']+["']>[\s\S]*?<\/invoke>/gi, '')
|
||||
.replace(/```(?:bash|sh|shell|zsh|fish|console|terminal|posix|busybox)[ \t]*\r?\n[\s\S]*?```/gi, '')
|
||||
.replace(/\[(?:tool_call\s+)?(?:run_command|bash|shell|sh)\s*\([^)]*\)\]/gi, '')
|
||||
.replace(/\n{3,}/g, '\n\n')
|
||||
.trim()
|
||||
}
|
||||
@@ -1660,6 +1923,17 @@ async function bareOsRunAgentSession(ctx, argv0, task, runOpts) {
|
||||
userTask +=
|
||||
'\n\n[harness] Answer from AVAILABLE TOOLS / list_agent_tools. List every callable tool name. Do not list skills or /bin names as tools.'
|
||||
}
|
||||
if (
|
||||
typeof bareAgentLooksLikeDoItYourself === 'function' &&
|
||||
bareAgentLooksLikeDoItYourself(userTask)
|
||||
) {
|
||||
userTask +=
|
||||
'\n\n[harness] The operator told you to execute. Call run_command / write_file / the rest of AVAILABLE TOOLS yourself. Do not print commands for them. There is no bash tool — use run_command.'
|
||||
}
|
||||
if (discordReply) {
|
||||
userTask +=
|
||||
'\n\n[harness] This is Discord. Execute with tools. The operator will not run your commands. Call run_command yourself. Never dump curl/ip/bash for them to copy. Never say you cannot execute.'
|
||||
}
|
||||
if (config.autonomous_active) {
|
||||
userTask =
|
||||
'AUTONOMOUS RUN. Execute until the goal is done. Do not stop after a plan — use tools, then call task_complete.\n' +
|
||||
@@ -1815,6 +2089,7 @@ async function bareOsRunAgentSession(ctx, argv0, task, runOpts) {
|
||||
|
||||
const maxIterBase = Number(configRef.current.max_iterations) || 64
|
||||
let iter = 0
|
||||
let instructionDumpNudges = 0
|
||||
|
||||
for (;;) {
|
||||
if (masterAbort.signal.aborted) {
|
||||
@@ -2057,15 +2332,22 @@ async function bareOsRunAgentSession(ctx, argv0, task, runOpts) {
|
||||
recoveredFromText = true
|
||||
if (typeof bareAgentExtractToolCallsFromText !== 'function') return
|
||||
const extracted = bareAgentExtractToolCallsFromText(assistantContent)
|
||||
if (!toolAcc.size && extracted.length) {
|
||||
for (const tc of extracted) bareAgentMergeToolCallDelta(toolAcc, tc)
|
||||
appendProgress(
|
||||
'recovered_tool_calls_from_text n=' + String(extracted.length)
|
||||
)
|
||||
}
|
||||
if (extracted.length) {
|
||||
if (!toolAcc.size) {
|
||||
for (const tc of extracted) bareAgentMergeToolCallDelta(toolAcc, tc)
|
||||
appendProgress(
|
||||
'recovered_tool_calls_from_text n=' + String(extracted.length)
|
||||
)
|
||||
}
|
||||
assistantContent = bareAgentStripToolCallsFromText(assistantContent)
|
||||
}
|
||||
if (
|
||||
typeof bareAgentLooksLikeInstructionDump === 'function' &&
|
||||
bareAgentLooksLikeInstructionDump(assistantContent) &&
|
||||
(toolAcc.size || extracted.length)
|
||||
) {
|
||||
assistantContent = ''
|
||||
}
|
||||
}
|
||||
const hideThinkEnv = String(envBag.BARE_OS_AGENT_HIDE_THINK || '')
|
||||
.trim()
|
||||
@@ -2504,6 +2786,12 @@ async function bareOsRunAgentSession(ctx, argv0, task, runOpts) {
|
||||
for (const tc of extracted) bareAgentMergeToolCallDelta(toolAcc, tc)
|
||||
toolCallsArr = bareAgentFinalizeToolCalls(toolAcc)
|
||||
assistantContent = bareAgentStripToolCallsFromText(assistantContent)
|
||||
if (
|
||||
typeof bareAgentLooksLikeInstructionDump === 'function' &&
|
||||
bareAgentLooksLikeInstructionDump(assistantContent)
|
||||
) {
|
||||
assistantContent = ''
|
||||
}
|
||||
appendProgress(
|
||||
'recovered_tool_calls_from_text n=' + String(toolCallsArr.length)
|
||||
)
|
||||
@@ -2516,6 +2804,13 @@ async function bareOsRunAgentSession(ctx, argv0, task, runOpts) {
|
||||
providerNow
|
||||
)
|
||||
}
|
||||
if (
|
||||
hasTools &&
|
||||
typeof bareAgentLooksLikeInstructionDump === 'function' &&
|
||||
bareAgentLooksLikeInstructionDump(assistantContent)
|
||||
) {
|
||||
assistantContent = ''
|
||||
}
|
||||
|
||||
/** @type {Record<string, unknown>} */
|
||||
const assistantMsg = {
|
||||
@@ -2548,6 +2843,25 @@ async function bareOsRunAgentSession(ctx, argv0, task, runOpts) {
|
||||
}
|
||||
|
||||
if (!hasTools) {
|
||||
if (
|
||||
instructionDumpNudges < 2 &&
|
||||
typeof bareAgentLooksLikeInstructionDump === 'function' &&
|
||||
bareAgentLooksLikeInstructionDump(assistantContent)
|
||||
) {
|
||||
instructionDumpNudges += 1
|
||||
messages.push({
|
||||
role: 'user',
|
||||
content:
|
||||
typeof bareAgentRefusalNudge === 'function'
|
||||
? bareAgentRefusalNudge()
|
||||
: '[harness] Call run_command now. Do not tell the user to run it.'
|
||||
})
|
||||
appendProgress(
|
||||
'instruction_dump_nudge n=' + String(instructionDumpNudges)
|
||||
)
|
||||
await bareAgentSaveHistory(ctx, paths.history, messages)
|
||||
continue
|
||||
}
|
||||
if (
|
||||
bareAgentAutonomousShouldContinue(configRef.current, {
|
||||
completed: completed,
|
||||
|
||||
Reference in New Issue
Block a user