feat: updade workspace
This commit is contained in:
@@ -29,22 +29,22 @@ except ImportError: # non-POSIX (e.g. Windows): best-effort, no OS lock
|
||||
|
||||
|
||||
SETTINGS_POLICY = {
|
||||
"compression.enabled": {"securitySensitive": False, "description": "Toggle context/token compression"},
|
||||
"compression.mode": {"securitySensitive": False, "description": "extractive | structural | semantic-dedup | abstractive"},
|
||||
"cost.absolute_cap_usd": {"securitySensitive": False, "description": "Absolute per-call cost cap"},
|
||||
"model.primary": {"securitySensitive": False, "description": "Primary model spec (e.g. ollama:ornith:9b)"},
|
||||
"security.strict": {"securitySensitive": True, "description": "H4 fail-closed strict mode"},
|
||||
"kill_switch.global": {"securitySensitive": True, "description": "Global kill-switch engage/disengage"},
|
||||
"compression.enabled": {"securitySensitive": False, "description": "Toggle context/token compression", "type": "boolean"},
|
||||
"compression.mode": {"securitySensitive": False, "description": "extractive | structural | semantic-dedup | abstractive", "type": "enum", "options": ["extractive", "structural", "semantic-dedup", "abstractive"]},
|
||||
"cost.absolute_cap_usd": {"securitySensitive": False, "description": "Absolute per-call cost cap", "type": "number", "min": 0, "max": 1000},
|
||||
"model.primary": {"securitySensitive": False, "description": "Primary model spec (e.g. ollama:ornith:9b)", "type": "string", "minLength": 3, "maxLength": 200},
|
||||
"security.strict": {"securitySensitive": True, "description": "H4 fail-closed strict mode", "type": "boolean"},
|
||||
"kill_switch.global": {"securitySensitive": True, "description": "Global kill-switch engage/disengage", "type": "boolean"},
|
||||
# Plan-17 loop governance overrides (meta-loop, T5). Loosening a loop budget /
|
||||
# widening a convergence window is security-sensitive: it grants the agent more
|
||||
# autonomy, so it needs a real approval + SoD and is clamped to org_ceiling.
|
||||
"loop.max_steps": {"securitySensitive": True, "description": "Loop Governor: max steps per run"},
|
||||
"loop.max_tokens": {"securitySensitive": True, "description": "Loop Governor: max tokens per run"},
|
||||
"loop.max_wall_clock_sec": {"securitySensitive": True, "description": "Loop Governor: max wall-clock seconds per run"},
|
||||
"loop.max_cost_usd": {"securitySensitive": True, "description": "Loop Governor: max cost USD per run"},
|
||||
"loop.max_corrections_per_step": {"securitySensitive": True, "description": "Loop Governor: max corrections per step"},
|
||||
"loop.oscillation_repeat": {"securitySensitive": True, "description": "Convergence: identical-action repeats before OSCILLATING"},
|
||||
"loop.no_progress_window": {"securitySensitive": True, "description": "Convergence: no-progress window before STALLED"},
|
||||
"loop.max_steps": {"securitySensitive": True, "description": "Loop Governor: max steps per run", "type": "integer", "min": 1, "max": 100},
|
||||
"loop.max_tokens": {"securitySensitive": True, "description": "Loop Governor: max tokens per run", "type": "integer", "min": 128, "max": 1000000},
|
||||
"loop.max_wall_clock_sec": {"securitySensitive": True, "description": "Loop Governor: max wall-clock seconds per run", "type": "integer", "min": 1, "max": 86400},
|
||||
"loop.max_cost_usd": {"securitySensitive": True, "description": "Loop Governor: max cost USD per run", "type": "number", "min": 0, "max": 1000},
|
||||
"loop.max_corrections_per_step": {"securitySensitive": True, "description": "Loop Governor: max corrections per step", "type": "integer", "min": 0, "max": 20},
|
||||
"loop.oscillation_repeat": {"securitySensitive": True, "description": "Convergence: identical-action repeats before OSCILLATING", "type": "integer", "min": 2, "max": 20},
|
||||
"loop.no_progress_window": {"securitySensitive": True, "description": "Convergence: no-progress window before STALLED", "type": "integer", "min": 1, "max": 50},
|
||||
}
|
||||
|
||||
GENESIS_HASH = "0" * 64
|
||||
@@ -263,6 +263,10 @@ def do_set(key, value, actor, reason, approval):
|
||||
if policy is None:
|
||||
print(f"SETTING_NOT_ALLOWED {key}", file=sys.stderr)
|
||||
return 2
|
||||
validation_error = validate_value(policy, value)
|
||||
if validation_error:
|
||||
print(f"SETTING_VALIDATION_ERROR {key}: {validation_error}", file=sys.stderr)
|
||||
return 5
|
||||
if policy["securitySensitive"]:
|
||||
ok, reason_ = check_approval(key, actor, approval)
|
||||
if not ok:
|
||||
@@ -292,6 +296,31 @@ def do_set(key, value, actor, reason, approval):
|
||||
return 0
|
||||
|
||||
|
||||
def validate_value(policy, value):
|
||||
expected = policy.get("type")
|
||||
if expected == "boolean" and not isinstance(value, bool):
|
||||
return "must be true or false"
|
||||
if expected == "string":
|
||||
if not isinstance(value, str):
|
||||
return "must be a string"
|
||||
if len(value) < policy.get("minLength", 0):
|
||||
return f"must contain at least {policy['minLength']} characters"
|
||||
if len(value) > policy.get("maxLength", sys.maxsize):
|
||||
return f"must contain at most {policy['maxLength']} characters"
|
||||
if expected == "enum" and value not in policy.get("options", []):
|
||||
return "must be one of: " + ", ".join(policy.get("options", []))
|
||||
if expected in ("number", "integer"):
|
||||
if isinstance(value, bool) or not isinstance(value, (int, float)):
|
||||
return "must be a number"
|
||||
if expected == "integer" and not isinstance(value, int):
|
||||
return "must be an integer"
|
||||
if value < policy.get("min", value):
|
||||
return f"must be at least {policy['min']}"
|
||||
if value > policy.get("max", value):
|
||||
return f"must be at most {policy['max']}"
|
||||
return None
|
||||
|
||||
|
||||
def do_rollback(key, actor, reason):
|
||||
with store_lock(): # SEC-19: atomic read-modify-write
|
||||
store = load_store()
|
||||
|
||||
Reference in New Issue
Block a user