Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,16 @@ MAX_LIMITED_AGENT_TOOL_CALLS=
## Agent planning step for pentester, coder, installer
AGENT_PLANNING_STEP_ENABLED=

## Deaf Guard — pre-execution command classification engine
## See backend/docs/deaf-guard.md for management, tier taxonomy, and debug guidance.
## DEAF_GUARD_ENABLED : master switch (true/false). When false, no classification happens.
## DEAF_GUARD_MODE : enforcement posture.
## log = classify and record only, never block (default baseline)
## warn = BLOCK-tier commands are blocked; WARN-tier is allowed
## enforce = BLOCK-tier and WARN-tier commands are both hard-blocked
DEAF_GUARD_ENABLED=true
DEAF_GUARD_MODE=log

## HTTP proxy to use it in isolation environment
PROXY_URL=

Expand Down
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,15 @@ PentAGI includes sophisticated multi-layered agent supervision mechanisms to ens

**Enhanced Adviser Configuration**: Works exceptionally well when adviser agent uses stronger model or enhanced settings. Example: using same base model with maximum reasoning mode for adviser (see [`vllm-qwen3.5-27b-fp8.provider.yml`](examples/configs/vllm-qwen3.5-27b-fp8.provider.yml)) enables comprehensive task analysis and strategic planning from identical model architecture.

### Deaf Guard
- **Pre-execution classification**: Every `terminal` tool call is matched against a 9-tier regex rule table before it runs in the sandbox
- **Modes**: `log` (record only), `warn` (block BLOCK-tier), `enforce` (block BLOCK and WARN)
- **Settings UI**: Settings → Security toggles enabled/mode at runtime (applies to the next flow)
- **Flow UI**: Deaf Guard tab on a flow (between Agents and Searches) streams live classifications
- **Configurable**: `DEAF_GUARD_ENABLED` (default: true) and `DEAF_GUARD_MODE` (default: log)

Full management reference: [`backend/docs/deaf-guard.md`](backend/docs/deaf-guard.md).

**Performance Impact**: Adds planning overhead but significantly improves completion rates and reduces redundant work

### Tool Call Limits (Always Active)
Expand Down
14 changes: 14 additions & 0 deletions backend/cmd/installer/wizard/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -1389,6 +1389,8 @@ type AIAgentsConfig struct {
MaxGeneralAgentToolCalls loader.EnvVar // MAX_GENERAL_AGENT_TOOL_CALLS
MaxLimitedAgentToolCalls loader.EnvVar // MAX_LIMITED_AGENT_TOOL_CALLS
AgentPlanningStepEnabled loader.EnvVar // AGENT_PLANNING_STEP_ENABLED
DeafGuardEnabled loader.EnvVar // DEAF_GUARD_ENABLED
DeafGuardMode loader.EnvVar // DEAF_GUARD_MODE
}

func (c *controller) GetAIAgentsConfig() *AIAgentsConfig {
Expand All @@ -1402,6 +1404,8 @@ func (c *controller) GetAIAgentsConfig() *AIAgentsConfig {
config.MaxGeneralAgentToolCalls, _ = c.GetVar("MAX_GENERAL_AGENT_TOOL_CALLS")
config.MaxLimitedAgentToolCalls, _ = c.GetVar("MAX_LIMITED_AGENT_TOOL_CALLS")
config.AgentPlanningStepEnabled, _ = c.GetVar("AGENT_PLANNING_STEP_ENABLED")
config.DeafGuardEnabled, _ = c.GetVar("DEAF_GUARD_ENABLED")
config.DeafGuardMode, _ = c.GetVar("DEAF_GUARD_MODE")

return config
}
Expand Down Expand Up @@ -1435,6 +1439,12 @@ func (c *controller) UpdateAIAgentsConfig(config *AIAgentsConfig) error {
if err := c.SetVar("AGENT_PLANNING_STEP_ENABLED", config.AgentPlanningStepEnabled.Value); err != nil {
return fmt.Errorf("failed to set AGENT_PLANNING_STEP_ENABLED: %w", err)
}
if err := c.SetVar("DEAF_GUARD_ENABLED", config.DeafGuardEnabled.Value); err != nil {
return fmt.Errorf("failed to set DEAF_GUARD_ENABLED: %w", err)
}
if err := c.SetVar("DEAF_GUARD_MODE", config.DeafGuardMode.Value); err != nil {
return fmt.Errorf("failed to set DEAF_GUARD_MODE: %w", err)
}

return nil
}
Expand Down Expand Up @@ -2414,6 +2424,8 @@ func (c *controller) getVariableDescription(varName string) string {
"MAX_GENERAL_AGENT_TOOL_CALLS": locale.EnvDesc_MAX_GENERAL_AGENT_TOOL_CALLS,
"MAX_LIMITED_AGENT_TOOL_CALLS": locale.EnvDesc_MAX_LIMITED_AGENT_TOOL_CALLS,
"AGENT_PLANNING_STEP_ENABLED": locale.EnvDesc_AGENT_PLANNING_STEP_ENABLED,
"DEAF_GUARD_ENABLED": locale.EnvDesc_DEAF_GUARD_ENABLED,
"DEAF_GUARD_MODE": locale.EnvDesc_DEAF_GUARD_MODE,

"SCRAPER_PUBLIC_URL": locale.EnvDesc_SCRAPER_PUBLIC_URL,
"SCRAPER_PRIVATE_URL": locale.EnvDesc_SCRAPER_PRIVATE_URL,
Expand Down Expand Up @@ -2728,6 +2740,8 @@ var criticalVariables = map[string]bool{
"MAX_GENERAL_AGENT_TOOL_CALLS": true,
"MAX_LIMITED_AGENT_TOOL_CALLS": true,
"AGENT_PLANNING_STEP_ENABLED": true,
"DEAF_GUARD_ENABLED": true,
"DEAF_GUARD_MODE": true,

"TENANT_ID": true,
"LICENSE_KEY": true,
Expand Down
13 changes: 13 additions & 0 deletions backend/cmd/installer/wizard/locale/locale.go
Original file line number Diff line number Diff line change
Expand Up @@ -1478,6 +1478,10 @@ Tool Call Limits:
Task Planning (⚠️ BETA):
• Enable Task Planning: generate structured execution plans for specialist agents

Deaf Guard:
• Enable Deaf Guard: classify terminal commands before execution
• Deaf Guard Mode: log (record only), warn (block BLOCK-tier), enforce (block BLOCK and WARN)

⚠️ BETA features are under active development. Enable for testing only.`

// field labels and descriptions
Expand All @@ -1497,6 +1501,10 @@ Task Planning (⚠️ BETA):
ToolsAIAgentsSettingMaxLimitedToolCallsDesc = "Maximum tool calls for Searcher, Enricher, Memorist, etc."
ToolsAIAgentsSettingTaskPlanning = "Enable Task Planning (beta)"
ToolsAIAgentsSettingTaskPlanningDesc = "Generate structured execution plans for specialist agents"
ToolsAIAgentsSettingDeafGuardEnabled = "Enable Deaf Guard"
ToolsAIAgentsSettingDeafGuardEnabledDesc = "Classify terminal commands before execution (Settings → Security)"
ToolsAIAgentsSettingDeafGuardMode = "Deaf Guard Mode"
ToolsAIAgentsSettingDeafGuardModeDesc = "log (record only), warn (block BLOCK-tier), enforce (block BLOCK and WARN)"

// help content
ToolsAIAgentsSettingsHelp = `AI Agents Settings define how agents collaborate, interact with users, and handle execution control.
Expand All @@ -1514,6 +1522,9 @@ Generates 3-7 step execution plans before specialist agents begin work. Prevents
Tool Call Limits (always active):
Hard limits prevent infinite loops: General agents default 100, Limited agents default 20. Works independently from beta features.

Deaf Guard:
Classifies every terminal command against a 9-tier rule table before execution. Modes: log (record only), warn (block BLOCK-tier), enforce (block BLOCK and WARN). Runtime toggles also live in Settings → Security.

OPEN SOURCE MODELS < 32B (Qwen3.5-27B, DeepSeek-V3, Llama-3.1-70B):
✓ ENABLE both beta features - ESSENTIAL for quality results
✓ Testing shows 2x improvement in result quality vs. baseline
Expand Down Expand Up @@ -2419,6 +2430,8 @@ const (
EnvDesc_MAX_GENERAL_AGENT_TOOL_CALLS = "Max Tool Calls for General Agents"
EnvDesc_MAX_LIMITED_AGENT_TOOL_CALLS = "Max Tool Calls for Limited Agents"
EnvDesc_AGENT_PLANNING_STEP_ENABLED = "Enable Task Planning (beta)"
EnvDesc_DEAF_GUARD_ENABLED = "Enable Deaf Guard command classification"
EnvDesc_DEAF_GUARD_MODE = "Deaf Guard mode (log, warn, enforce)"

EnvDesc_SCRAPER_PUBLIC_URL = "Scraper Public URL"
EnvDesc_SCRAPER_PRIVATE_URL = "Scraper Private URL"
Expand Down
71 changes: 69 additions & 2 deletions backend/cmd/installer/wizard/models/ai_agents_settings_form.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,18 @@ func (m *AIAgentsSettingsFormModel) BuildForm() tea.Cmd {
locale.ToolsAIAgentsSettingTaskPlanningDesc,
cfg.AgentPlanningStepEnabled,
),
m.createBooleanField(
"deaf_guard_enabled",
locale.ToolsAIAgentsSettingDeafGuardEnabled,
locale.ToolsAIAgentsSettingDeafGuardEnabledDesc,
cfg.DeafGuardEnabled,
),
m.createTextField(
"deaf_guard_mode",
locale.ToolsAIAgentsSettingDeafGuardMode,
locale.ToolsAIAgentsSettingDeafGuardModeDesc,
cfg.DeafGuardMode,
),
}

m.SetFormFields(fields)
Expand Down Expand Up @@ -134,6 +146,23 @@ func (m *AIAgentsSettingsFormModel) createIntegerField(key, title, description s
}
}

func (m *AIAgentsSettingsFormModel) createTextField(key, title, description string, envVar loader.EnvVar) FormField {
input := NewTextInput(m.GetStyles(), m.GetWindow(), envVar)
if envVar.Default != "" {
input.Placeholder = envVar.Default
}

return FormField{
Key: key,
Title: title,
Description: description,
Required: false,
Masked: false,
Input: input,
Value: input.Value(),
}
}

func (m *AIAgentsSettingsFormModel) validateBooleanField(value, fieldName string) error {
if value != "" && value != "true" && value != "false" {
return fmt.Errorf("invalid boolean value for %s: %s (must be 'true' or 'false')", fieldName, value)
Expand All @@ -158,6 +187,18 @@ func (m *AIAgentsSettingsFormModel) validateIntegerField(value, fieldName string
return intVal, nil
}

func (m *AIAgentsSettingsFormModel) validateDeafGuardMode(value string) error {
if value == "" {
return nil
}
switch strings.ToLower(value) {
case "log", "warn", "enforce":
return nil
default:
return fmt.Errorf("invalid Deaf Guard mode: %s (must be 'log', 'warn', or 'enforce')", value)
}
}

func (m *AIAgentsSettingsFormModel) formatNumber(n int) string {
if n >= 1000 {
return fmt.Sprintf("%d,%03d", n/1000, n%1000)
Expand Down Expand Up @@ -229,6 +270,8 @@ func (m *AIAgentsSettingsFormModel) GetCurrentConfiguration() string {

// task planning
displayBoolean(cfg.AgentPlanningStepEnabled, locale.ToolsAIAgentsSettingTaskPlanning)
displayBoolean(cfg.DeafGuardEnabled, locale.ToolsAIAgentsSettingDeafGuardEnabled)
displayInteger(cfg.DeafGuardMode, locale.ToolsAIAgentsSettingDeafGuardMode)

return strings.Join(sections, "\n")
}
Expand All @@ -242,7 +285,9 @@ func (m *AIAgentsSettingsFormModel) IsConfigured() bool {
cfg.ExecutionMonitorTotalToolLimit.IsPresent() || cfg.ExecutionMonitorTotalToolLimit.IsChanged ||
cfg.MaxGeneralAgentToolCalls.IsPresent() || cfg.MaxGeneralAgentToolCalls.IsChanged ||
cfg.MaxLimitedAgentToolCalls.IsPresent() || cfg.MaxLimitedAgentToolCalls.IsChanged ||
cfg.AgentPlanningStepEnabled.IsPresent() || cfg.AgentPlanningStepEnabled.IsChanged
cfg.AgentPlanningStepEnabled.IsPresent() || cfg.AgentPlanningStepEnabled.IsChanged ||
cfg.DeafGuardEnabled.IsPresent() || cfg.DeafGuardEnabled.IsChanged ||
cfg.DeafGuardMode.IsPresent() || cfg.DeafGuardMode.IsChanged
}

func (m *AIAgentsSettingsFormModel) GetHelpContent() string {
Expand All @@ -255,7 +300,7 @@ func (m *AIAgentsSettingsFormModel) GetHelpContent() string {

func (m *AIAgentsSettingsFormModel) HandleSave() error {
fields := m.GetFormFields()
if len(fields) != 8 {
if len(fields) != 10 {
return fmt.Errorf("unexpected number of fields: %d", len(fields))
}

Expand All @@ -269,6 +314,8 @@ func (m *AIAgentsSettingsFormModel) HandleSave() error {
MaxGeneralAgentToolCalls: cur.MaxGeneralAgentToolCalls,
MaxLimitedAgentToolCalls: cur.MaxLimitedAgentToolCalls,
AgentPlanningStepEnabled: cur.AgentPlanningStepEnabled,
DeafGuardEnabled: cur.DeafGuardEnabled,
DeafGuardMode: cur.DeafGuardMode,
}

// validate and set each field
Expand Down Expand Up @@ -328,6 +375,18 @@ func (m *AIAgentsSettingsFormModel) HandleSave() error {
}
newCfg.AgentPlanningStepEnabled.Value = value

case "deaf_guard_enabled":
if err := m.validateBooleanField(value, locale.ToolsAIAgentsSettingDeafGuardEnabled); err != nil {
return err
}
newCfg.DeafGuardEnabled.Value = value

case "deaf_guard_mode":
if err := m.validateDeafGuardMode(value); err != nil {
return err
}
newCfg.DeafGuardMode.Value = value

default:
return fmt.Errorf("unknown field key at index %d: %s", i, field.Key)
}
Expand Down Expand Up @@ -377,6 +436,14 @@ func (m *AIAgentsSettingsFormModel) HandleReset() {
fields[7].Input.SetValue(cfg.AgentPlanningStepEnabled.Value)
fields[7].Value = fields[7].Input.Value()
}
if len(fields) >= 9 {
fields[8].Input.SetValue(cfg.DeafGuardEnabled.Value)
fields[8].Value = fields[8].Input.Value()
}
if len(fields) >= 10 {
fields[9].Input.SetValue(cfg.DeafGuardMode.Value)
fields[9].Value = fields[9].Input.Value()
}

m.SetFormFields(fields)
}
Expand Down
3 changes: 3 additions & 0 deletions backend/docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ The running PentAGI instance already exposes several settings areas in the web U
- **Settings -> Providers**: Manage user-defined provider profiles, per-agent model and runtime options, and provider test actions for provider types supported by the running server.
- **Settings -> Prompts**: Manage system, human, and tool prompt templates.
- **Settings -> PentAGI API**: Create, revoke, and delete PentAGI API tokens.
- **Settings -> Security**: Enable Deaf Guard and set enforcement mode (`log` / `warn` / `enforce`). Runtime changes apply to new flows only; see [deaf-guard.md](./deaf-guard.md).
- **Other UI-managed preferences**: Favorite flows are stored as user preferences, and theme selection is handled client-side from the main sidebar/profile controls.

These web-console features do not replace the environment variables in this guide for provider credentials, endpoints, or external integrations.
Expand Down Expand Up @@ -1900,6 +1901,8 @@ These settings control the agent supervision system, including execution monitor
| MaxGeneralAgentToolCalls | `MAX_GENERAL_AGENT_TOOL_CALLS` | `100` | Maximum tool calls for general agents (Assistant, Primary, Pentester, Coder, Installer) |
| MaxLimitedAgentToolCalls | `MAX_LIMITED_AGENT_TOOL_CALLS` | `20` | Maximum tool calls for limited agents (Searcher, Enricher, etc.) |
| AgentPlanningStepEnabled | `AGENT_PLANNING_STEP_ENABLED` | `false` | Enable automatic task planning for specialist agents |
| DeafGuardEnabled | `DEAF_GUARD_ENABLED` | `true` | Master switch for pre-execution terminal command classification |
| DeafGuardMode | `DEAF_GUARD_MODE` | `log` | Enforcement posture: `log` (record only), `warn` (block BLOCK-tier), `enforce` (block BLOCK and WARN) |

### Usage Details

Expand Down
Loading