Add large output handling and iteration budget to agent
- Tool outputs >2K chars saved to workspace/tool_outputs/ with preview - Agent gets first 1500 chars + file path to read the rest - Iteration budget bumped to 10 rounds (configurable per template) - Warning injected when 2 rounds remaining to help model wrap up
This commit is contained in:
@@ -32,7 +32,7 @@ OLLAMA_URL = CONFIG.get("ollama_url", "http://172.16.0.1:11434")
|
||||
CONTEXT_SIZE = CONFIG.get("context_size", 20)
|
||||
MAX_RESPONSE_LINES = CONFIG.get("max_response_lines", 50)
|
||||
TOOLS_ENABLED = CONFIG.get("tools", True)
|
||||
MAX_TOOL_ROUNDS = CONFIG.get("max_tool_rounds", 5)
|
||||
MAX_TOOL_ROUNDS = CONFIG.get("max_tool_rounds", 10)
|
||||
WORKSPACE = "/workspace"
|
||||
SKILL_DIRS = ["/opt/skills", f"{WORKSPACE}/skills"]
|
||||
|
||||
@@ -169,9 +169,15 @@ def discover_skills():
|
||||
return tools, scripts
|
||||
|
||||
|
||||
LARGE_OUTPUT_THRESHOLD = 2000
|
||||
LARGE_OUTPUT_DIR = f"{WORKSPACE}/tool_outputs"
|
||||
_output_counter = 0
|
||||
|
||||
|
||||
def execute_skill(script_path, args):
|
||||
"""Execute a skill script with args as JSON on stdin."""
|
||||
# Pass config extras via env
|
||||
"""Execute a skill script with args as JSON on stdin.
|
||||
Large outputs are saved to a file with a preview returned."""
|
||||
global _output_counter
|
||||
env = os.environ.copy()
|
||||
env["WORKSPACE"] = WORKSPACE
|
||||
env["SEARX_URL"] = CONFIG.get("searx_url", "https://searx.mymx.me")
|
||||
@@ -188,7 +194,19 @@ def execute_skill(script_path, args):
|
||||
output = result.stdout
|
||||
if result.stderr:
|
||||
output += f"\n[stderr] {result.stderr}"
|
||||
return output.strip() or "[no output]"
|
||||
output = output.strip() or "[no output]"
|
||||
|
||||
# Large output handling — save to file, return preview
|
||||
if len(output) > LARGE_OUTPUT_THRESHOLD:
|
||||
os.makedirs(LARGE_OUTPUT_DIR, exist_ok=True)
|
||||
_output_counter += 1
|
||||
filepath = f"{LARGE_OUTPUT_DIR}/output_{_output_counter}.txt"
|
||||
with open(filepath, "w") as f:
|
||||
f.write(output)
|
||||
preview = output[:1500]
|
||||
return f"{preview}\n\n[output truncated — full result ({len(output)} chars) saved to {filepath}. Use run_command to read it: cat {filepath}]"
|
||||
|
||||
return output
|
||||
except subprocess.TimeoutExpired:
|
||||
return "[skill timed out after 120s]"
|
||||
except Exception as e:
|
||||
@@ -323,6 +341,7 @@ def query_ollama(messages):
|
||||
payload["tools"] = TOOLS
|
||||
|
||||
for round_num in range(MAX_TOOL_ROUNDS):
|
||||
remaining = MAX_TOOL_ROUNDS - round_num
|
||||
try:
|
||||
data = ollama_request(payload)
|
||||
except (urllib.error.URLError, TimeoutError) as e:
|
||||
@@ -341,6 +360,9 @@ def query_ollama(messages):
|
||||
fn.get("arguments", {}),
|
||||
round_num + 1,
|
||||
)
|
||||
# Warn when budget is running low
|
||||
if remaining <= 2:
|
||||
result += f"\n[warning: {remaining - 1} tool rounds remaining — wrap up]"
|
||||
messages.append({"role": "tool", "content": result})
|
||||
payload["messages"] = messages
|
||||
continue
|
||||
@@ -353,6 +375,8 @@ def query_ollama(messages):
|
||||
if fn_name in SKILL_SCRIPTS:
|
||||
messages.append({"role": "assistant", "content": content})
|
||||
result = dispatch_tool(fn_name, fn_args, round_num + 1)
|
||||
if remaining <= 2:
|
||||
result += f"\n[warning: {remaining - 1} tool rounds remaining — wrap up]"
|
||||
messages.append({
|
||||
"role": "user",
|
||||
"content": f"Tool result:\n{result}\n\nNow respond to the user based on this result.",
|
||||
|
||||
Reference in New Issue
Block a user