mirror of
https://github.com/shareAI-lab/analysis_claude_code.git
synced 2026-03-22 02:15:42 +08:00
Comprehensive rewrite establishing the harness engineering narrative across the entire repository. README (EN/ZH/JA): added "The Model IS the Agent" manifesto with historical proof (DQN, OpenAI Five, AlphaStar, Tencent Jueyu), "What an Agent Is NOT" critique, harness engineer role definition, "Why Claude Code" as masterclass in harness design, and universe vision. Consistent framing: model = driver, harness = vehicle. docs (36 files, 3 languages): injected one-line "Harness layer" callout after the motto in every session document (s01-s12). agents (13 Python files): added harness framing comment before each module docstring. skills/agent-philosophy.md: full rewrite aligned with harness narrative.
108 lines
3.5 KiB
Python
108 lines
3.5 KiB
Python
#!/usr/bin/env python3
|
|
# Harness: the loop -- the model's first connection to the real world.
|
|
"""
|
|
s01_agent_loop.py - The Agent Loop
|
|
|
|
The entire secret of an AI coding agent in one pattern:
|
|
|
|
while stop_reason == "tool_use":
|
|
response = LLM(messages, tools)
|
|
execute tools
|
|
append results
|
|
|
|
+----------+ +-------+ +---------+
|
|
| User | ---> | LLM | ---> | Tool |
|
|
| prompt | | | | execute |
|
|
+----------+ +---+---+ +----+----+
|
|
^ |
|
|
| tool_result |
|
|
+---------------+
|
|
(loop continues)
|
|
|
|
This is the core loop: feed tool results back to the model
|
|
until the model decides to stop. Production agents layer
|
|
policy, hooks, and lifecycle controls on top.
|
|
"""
|
|
|
|
import os
|
|
import subprocess
|
|
|
|
from anthropic import Anthropic
|
|
from dotenv import load_dotenv
|
|
|
|
load_dotenv(override=True)
|
|
|
|
if os.getenv("ANTHROPIC_BASE_URL"):
|
|
os.environ.pop("ANTHROPIC_AUTH_TOKEN", None)
|
|
|
|
client = Anthropic(base_url=os.getenv("ANTHROPIC_BASE_URL"))
|
|
MODEL = os.environ["MODEL_ID"]
|
|
|
|
SYSTEM = f"You are a coding agent at {os.getcwd()}. Use bash to solve tasks. Act, don't explain."
|
|
|
|
TOOLS = [{
|
|
"name": "bash",
|
|
"description": "Run a shell command.",
|
|
"input_schema": {
|
|
"type": "object",
|
|
"properties": {"command": {"type": "string"}},
|
|
"required": ["command"],
|
|
},
|
|
}]
|
|
|
|
|
|
def run_bash(command: str) -> str:
|
|
dangerous = ["rm -rf /", "sudo", "shutdown", "reboot", "> /dev/"]
|
|
if any(d in command for d in dangerous):
|
|
return "Error: Dangerous command blocked"
|
|
try:
|
|
r = subprocess.run(command, shell=True, cwd=os.getcwd(),
|
|
capture_output=True, text=True, timeout=120)
|
|
out = (r.stdout + r.stderr).strip()
|
|
return out[:50000] if out else "(no output)"
|
|
except subprocess.TimeoutExpired:
|
|
return "Error: Timeout (120s)"
|
|
|
|
|
|
# -- The core pattern: a while loop that calls tools until the model stops --
|
|
def agent_loop(messages: list):
|
|
while True:
|
|
response = client.messages.create(
|
|
model=MODEL, system=SYSTEM, messages=messages,
|
|
tools=TOOLS, max_tokens=8000,
|
|
)
|
|
# Append assistant turn
|
|
messages.append({"role": "assistant", "content": response.content})
|
|
# If the model didn't call a tool, we're done
|
|
if response.stop_reason != "tool_use":
|
|
return
|
|
# Execute each tool call, collect results
|
|
results = []
|
|
for block in response.content:
|
|
if block.type == "tool_use":
|
|
print(f"\033[33m$ {block.input['command']}\033[0m")
|
|
output = run_bash(block.input["command"])
|
|
print(output[:200])
|
|
results.append({"type": "tool_result", "tool_use_id": block.id,
|
|
"content": output})
|
|
messages.append({"role": "user", "content": results})
|
|
|
|
|
|
if __name__ == "__main__":
|
|
history = []
|
|
while True:
|
|
try:
|
|
query = input("\033[36ms01 >> \033[0m")
|
|
except (EOFError, KeyboardInterrupt):
|
|
break
|
|
if query.strip().lower() in ("q", "exit", ""):
|
|
break
|
|
history.append({"role": "user", "content": query})
|
|
agent_loop(history)
|
|
response_content = history[-1]["content"]
|
|
if isinstance(response_content, list):
|
|
for block in response_content:
|
|
if hasattr(block, "text"):
|
|
print(block.text)
|
|
print()
|