feat(ssa): finalize strict stepwise agent execution flow

Align Agent mode to strict stepwise generation and execution, add deterministic and safety hardening, and sync deployment/module documentation for Phase 5A.5/5B/5C rollout.

- implement strict stepwise execution path and dependency short-circuiting
- persist step-level errors/results and stream step_* progress events
- add agent plan params patch route and schema/migration support
- improve R sanitizer/security checks and step result rendering in workspace
- update SSA module guide and deployment change checklist

Made-with: Cursor
This commit is contained in:
2026-03-11 22:49:05 +08:00
parent d3b24bd8c3
commit 6edfad032f
19 changed files with 2105 additions and 158 deletions

View File

@@ -221,9 +221,10 @@ function(req) {
message(glue::glue("[ExecuteCode] session={session_id}, code_length={nchar(code)}, timeout={timeout_sec}s"))
# ── AST 语法预检parse() 先于 eval(),快速捕获语法错误 ──
# ── AST + 安全双层预检:语法检查 + 危险调用拦截 ──
parsed_code <- NULL
ast_check <- tryCatch({
parse(text = code)
parsed_code <<- parse(text = code)
NULL
}, error = function(e) {
e$message
@@ -252,8 +253,32 @@ function(req) {
duration_ms = 0
))
}
# 安全预检静态扫描MVP
# 注:为减少误报,先粗略移除注释行再扫描
code_for_scan <- gsub("(?m)^\\s*#.*$", "", code, perl = TRUE)
forbidden_pattern <- "(^|[^[:alnum:]_\\.])((base::)?system|(base::)?eval|(base::)?parse|(base::)?source|file\\.remove|setwd|download\\.file|readLines|writeLines)\\s*\\("
security_hit <- regexpr(forbidden_pattern, code_for_scan, perl = TRUE, ignore.case = TRUE)
if (security_hit[1] != -1) {
hit_text <- regmatches(code_for_scan, security_hit)[1]
return(list(
status = "error",
error_code = "E_SECURITY",
error_type = "security",
message = paste0("Security Violation: Detected forbidden function call: ", hit_text),
user_hint = "代码包含高风险函数调用(如 system/eval/source/file.remove/setwd已被系统拦截",
console_output = list(),
duration_ms = 0
))
}
sandbox_env <- new.env(parent = globalenv())
# 运行时保护:即使静态扫描漏检,也在沙箱层阻断关键高风险调用
sandbox_env$system <- function(...) stop("Security Violation: function 'system' is forbidden.")
sandbox_env$eval <- function(...) stop("Security Violation: function 'eval' is forbidden.")
sandbox_env$source <- function(...) stop("Security Violation: function 'source' is forbidden.")
sandbox_env$setwd <- function(...) stop("Security Violation: function 'setwd' is forbidden.")
sandbox_env$file.remove <- function(...) stop("Security Violation: function 'file.remove' is forbidden.")
if (!is.null(session_id) && nchar(session_id) > 0) {
sandbox_env$SESSION_ID <- session_id
@@ -269,7 +294,7 @@ function(req) {
{
captured_output <- utils::capture.output({
result <- withCallingHandlers(
eval(parse(text = code), envir = sandbox_env),
eval(parsed_code, envir = sandbox_env),
warning = function(w) {
collected_warnings[[length(collected_warnings) + 1]] <<- w$message
invokeRestart("muffleWarning")