Refine course progression and runtime safety

This commit is contained in:
Haoran
2026-08-11 15:13:13 +08:00
parent b36dbcd84f
commit ab35e59672
83 changed files with 5291 additions and 2267 deletions

View File

@@ -8,13 +8,17 @@ Three gates inserted before tool execution:
Gate 2: Rule matching (write outside workspace? destructive cmd?)
Gate 3: User approval (pause and wait for confirmation)
+-------+ +--------+ +--------+ +--------+ +------+
| Tool | -> | Gate 1 | -> | Gate 2 | -> | Gate 3 | -> | Exec |
| call | | deny? | | match? | | allow? | | |
+-------+ +--------+ +--------+ +--------+ +------+
| | | |
v v v v
(normal) (blocked) (ask user) (user says no?)
+----------+ +-------+ +--------------+ +---------------+
| User | ---> | LLM | ---> | Permission | ---> | Tool Dispatch |
| prompt | | | | 1. deny list | | execute |
+----------+ +---+---+ | 2. rules | +-------+-------+
^ | 3. approval | |
| +------+-------+ |
| | deny |
| v v
| +-------------------------------+
+----------+ tool_result: denied or output |
+-------------------------------+
Only one line added to the agent loop:
@@ -27,7 +31,8 @@ Builds on s02 (multi-tool). Usage:
Needs: pip install anthropic python-dotenv + ANTHROPIC_API_KEY in .env
"""
import os, subprocess
import os
import subprocess
from pathlib import Path
try:
@@ -53,9 +58,7 @@ MODEL = os.environ["MODEL_ID"]
SYSTEM = f"You are a coding agent at {WORKDIR}. All destructive operations require user approval."
# ═══════════════════════════════════════════════════════════
# FROM s02 : Tool Implementations
# ═══════════════════════════════════════════════════════════
# -- From s02: tool implementations --
def run_bash(command: str) -> str:
try:
@@ -111,9 +114,7 @@ def run_glob(pattern: str) -> str:
return f"Error: {e}"
# ═══════════════════════════════════════════════════════════
# FROM s02 (unchanged): Tool Definitions & Dispatch
# ═══════════════════════════════════════════════════════════
# -- From s02 (unchanged): tool definitions and dispatch --
TOOLS = [
{"name": "bash", "description": "Run a shell command.",
@@ -134,11 +135,9 @@ TOOL_HANDLERS = {
}
# ═══════════════════════════════════════════════════════════
# NEW in s03: Three-Gate Permission Pipeline
# ═══════════════════════════════════════════════════════════
# -- New in s03: three-gate permission pipeline --
# Gate 1: Hard deny list always forbidden
# Gate 1: Hard deny list - always forbidden
DENY_LIST = ["rm -rf /", "sudo", "shutdown", "reboot", "mkfs", "dd if=", "> /dev/sda"]
def check_deny_list(command: str) -> str | None:
@@ -148,7 +147,7 @@ def check_deny_list(command: str) -> str | None:
return None
# Gate 2: Rule matching context-dependent checks
# Gate 2: Rule matching - context-dependent checks
PERMISSION_RULES = [
{"tools": ["read_file", "write_file", "edit_file"],
"check": lambda args: not (WORKDIR / args.get("path", "")).resolve().is_relative_to(WORKDIR),
@@ -165,9 +164,9 @@ def check_rules(tool_name: str, args: dict) -> str | None:
return None
# Gate 3: User approval wait for confirmation after rule match
# Gate 3: User approval - wait for confirmation after rule match
def ask_user(tool_name: str, args: dict, reason: str) -> str:
print(f"\n\033[33m {reason}\033[0m")
print(f"\n\033[33m[permission] {reason}\033[0m")
print(f" Tool: {tool_name}({args})")
choice = input(" Allow? [y/N] ").strip().lower()
return "allow" if choice in ("y", "yes") else "deny"
@@ -178,7 +177,7 @@ def check_permission(block) -> bool:
if block.name == "bash":
reason = check_deny_list(block.input.get("command", ""))
if reason:
print(f"\n\033[31m {reason}\033[0m")
print(f"\n\033[31m[blocked] {reason}\033[0m")
return False
reason = check_rules(block.name, block.input)
if reason:
@@ -188,9 +187,7 @@ def check_permission(block) -> bool:
return True
# ═══════════════════════════════════════════════════════════
# agent_loop — same as s02, with check_permission() inserted
# ═══════════════════════════════════════════════════════════
# -- Agent loop: same as s02, with check_permission() inserted --
def agent_loop(messages: list):
while True:
@@ -226,7 +223,7 @@ def agent_loop(messages: list):
if __name__ == "__main__":
print("s03: Permission")
print("输入问题,回车发送。输入 q 退出。\n")
print("Enter a question, press Enter to send. Type q to quit.\n")
history = []
while True: