core

package
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 21, 2026 License: MIT Imports: 17 Imported by: 0

README

pkg/core

The core package contains Falcon's agent logic, the ReAct loop, and the tool management system. This is the brain of Falcon.

Package Overview

pkg/core/
├── types.go               # Core interfaces (Tool, AgentEvent, ConfirmableTool)
├── agent.go               # Agent struct, tool registration, call limit enforcement
├── react.go               # ReAct loop: ProcessMessage, ProcessMessageWithEvents
├── init.go                # .falcon folder setup, setup wizard, project config
├── globalconfig.go        # ~/.falcon global config management (providers, credentials)
├── memory.go              # Persistent MemoryStore across sessions
├── analysis.go            # Stack trace parsing, error context extraction
├── prompt_integration.go  # Helpers for injecting tool descriptions into system prompt
├── react_test.go          # Unit tests for the ReAct loop
├── prompt/                # Modular system prompt builder (workflow + tools sections)
└── tools/                 # 28+ tool implementations organized by testing type

Core Interfaces

Tool

Every Falcon tool must implement this interface:

type Tool interface {
    Name() string                        // Unique identifier, e.g. "http"
    Description() string                 // Human-readable description for the LLM
    Parameters() string                  // JSON Schema of accepted parameters
    Execute(args string) (string, error) // Main execution; args is a JSON string
}
ConfirmableTool

Tools that write files must also implement this:

type ConfirmableTool interface {
    Tool
    SetEventCallback(callback EventCallback)
}

When the agent calls a ConfirmableTool, it emits a confirmation_required event to the TUI before writing anything. The user must approve (Y) or reject (N) the change.

AgentEvent

Events emitted by the ReAct loop to drive the TUI in real time:

type AgentEvent struct {
    Type             string            // Event type (see below)
    Content          string            // Main payload
    ToolArgs         string            // Tool arguments (tool_call events)
    ToolUsage        *ToolUsageEvent   // Stats (tool_usage events)
    FileConfirmation *FileConfirmation // File write details (confirmation_required events)
}

Event Types:

Type Description
thinking Agent is reasoning (not displayed directly)
tool_call Agent is invoking a tool
observation Tool returned a result
answer Final answer from the agent
error An error occurred
streaming Partial LLM response chunk (real-time display)
confirmation_required File write awaiting user approval

Creating an Agent
agent := core.NewAgent(llmClient)
agent.SetFramework("gin")
agent.SetToolLimit("http", 25)
agent.RegisterTool(tools.NewHTTPTool())
Processing Messages

Blocking (simple use):

response, err := agent.ProcessMessage("GET http://localhost:8000/users")

With Events (for TUI):

err := agent.ProcessMessageWithEvents(ctx, input, func(event core.AgentEvent) {
    switch event.Type {
    case "streaming":
        // Update UI with partial response
    case "tool_call":
        // Show which tool is being executed
    case "answer":
        // Display final answer
    }
})

ReAct Loop

The ReAct (Reason + Act) loop in react.go:

1. Add user message to history, reset tool counters
2. Build system prompt with tool descriptions
3. Call LLM via Chat/ChatStream (retry up to 3× with exponential backoff: 2s, 4s, 8s)
4. Parse response for tool call or Final Answer
5. If Final Answer → emit "answer" event and return
6. Check per-tool and total call limits
7. Execute tool → emit "tool_call" + "observation" events
8. Append observation to conversation history
9. GOTO 2
LLM Response Format
Thought: <reasoning>
ACTION: tool_name({"arg": "value"})

or for a final response:

Final Answer: <response>

The parser (parseResponse) handles common LLM formatting variations — missing ACTION: prefix, raw tool_name(...) calls, and case differences.


System Prompt

The prompt in pkg/core/prompt/ is built from modular sections in workflow.go and tools.go:

workflow.go sections:

  • Mandatory Session Startmemory(recall) + session_log(start) at every conversation start
  • Mandatory Session Endsession_log(end, summary) before every final answer
  • Testing Type Decision — decision table for 8 API testing types (Unit, Integration, Smoke, Functional, Contract, Performance, Security, E2E)
  • The Five Phases — Orient, Hypothesize, Act, Interpret, Persist
  • Tool Disambiguation — clarifies merged tools (auth, request, environment) and write-only tools (falcon_write, session_log)
  • .falcon Naming Convention — flat structure with type-prefixed filenames
  • Persistence Rules — what to save and where

tools.go sections:

  • Available Tools — all 28+ tools organized by domain
  • Compact Tool Reference — quick lookup table with tool intent, params, and domains

Configuration

Falcon splits configuration across two files:

Global Config (~/.falcon/config.yaml)

Managed by globalconfig.go. Stores LLM provider credentials, shared across all projects.

type GlobalConfig struct {
    DefaultProvider string                  `yaml:"default_provider"`
    Theme           string                  `yaml:"theme"`
    WebUI           WebUIConfig             `yaml:"web_ui"`
    Providers       map[string]ProviderEntry `yaml:"providers"`
}

type ProviderEntry struct {
    Model  string            `yaml:"model"`
    Config map[string]string `yaml:"config"`
}

Example:

default_provider: gemini
theme: dark
web_ui:
  enabled: true
  port: 0
providers:
  ollama:
    model: llama3
    config:
      mode: local
      url: http://localhost:11434
  gemini:
    model: gemini-2.5-flash-lite
    config:
      api_key: your-key-here
  openrouter:
    model: google/gemini-2.5-flash-lite
    config:
      api_key: sk-or-...

Key functions:

  • LoadGlobalConfig() — reads ~/.falcon/config.yaml, auto-migrates legacy format
  • SaveGlobalConfig(cfg) — writes with 0600 permissions
  • GetActiveProviderEntry(cfg) — returns the active provider ID, model, and config values
  • SetProviderEntry(cfg, id, model, values) — upserts one provider without touching others
  • RunGlobalConfigWizard() — interactive Huh wizard for add/update/remove/set-default
Project Config (.falcon/config.yaml)

Managed by init.go. Per-project overrides.

type Config struct {
    Provider       string            `yaml:"provider"`
    ProviderConfig map[string]string `yaml:"provider_config,omitempty"`
    DefaultModel   string            `yaml:"default_model"`
    Theme          string            `yaml:"theme"`
    Framework      string            `yaml:"framework"`
}

---

## Adding New Functionality

### New Event Type
1. Add a constant in `types.go`
2. Emit from `react.go` at the appropriate point
3. Handle in `pkg/tui/update.go`

### New System Prompt Section
1. Add a new file in `pkg/core/prompt/`
2. Register it in `prompt/builder.go`
3. Test with different LLM providers

### New LLM Provider
See `pkg/llm/README.md` — self-contained in `pkg/llm/`, no changes needed here.

### New Config Option
1. Add the field to `Config` in `init.go` (project-level) or `GlobalConfig` in `globalconfig.go` (global)
2. If user-configurable at setup time, add it to the wizard

---

## Testing

```bash
go test ./pkg/core/...

react_test.go covers:

  • Tool call parsing from LLM output
  • Event emission order
  • History management

Documentation

Overview

Package core provides the central agent logic, tool management, and ReAct loop implementation for the Falcon API debugging assistant.

Package core provides the central agent logic, tool management, and ReAct loop implementation for the Falcon API debugging assistant.

Index

Constants

View Source
const (
	DefaultMaxHistory = 100 // Default max messages to keep in history
)

Default limits for history management.

View Source
const FalconFolderName = ".falcon"

Variables

View Source
var ErrSetupCancelled = errors.New("setup cancelled by user")

ErrSetupCancelled is returned when the user cancels the setup wizard.

View Source
var SupportedFrameworks = []string{
	"gin",
	"echo",
	"chi",
	"fiber",
	"fastapi",
	"flask",
	"django",
	"express",
	"nestjs",
	"hono",
	"spring",
	"laravel",
	"rails",
	"actix",
	"axum",
	"other",
}

SupportedFrameworks lists frameworks that Falcon recognizes

Functions

func EnsureGlobalFalconDir

func EnsureGlobalFalconDir() error

EnsureGlobalFalconDir creates ~/.falcon if it doesn't exist (with 0700 permissions) and ensures memory.json exists with an empty valid structure.

func GetActiveProviderEntry

func GetActiveProviderEntry(cfg *GlobalConfig) (providerID, model string, values map[string]string)

GetActiveProviderEntry returns the ID, model, and config values for the currently active (default) provider. Returns empty strings/nil if nothing configured.

func GetConfigFramework

func GetConfigFramework() string

GetConfigFramework reads the framework from the config file

func GlobalConfigPath

func GlobalConfigPath() string

GlobalConfigPath returns the path to the global config file.

func GlobalFalconDir

func GlobalFalconDir() string

GlobalFalconDir returns the path to the global ~/.falcon directory.

func InitializeFalconFolder

func InitializeFalconFolder(framework string, skipIndex bool) error

InitializeFalconFolder creates the .falcon directory and initializes default files if they don't exist. If framework is empty and this is a first-time setup, prompts the user to select one. skipIndex determines if we should auto-run the spec ingester.

func RunGlobalConfigWizard

func RunGlobalConfigWizard() error

RunGlobalConfigWizard runs the interactive provider/model setup wizard and saves to global config. Presents a sub-action menu: add/update a provider, set default provider, or remove a provider.

func SaveGlobalConfig

func SaveGlobalConfig(cfg *GlobalConfig) error

SaveGlobalConfig writes the GlobalConfig to ~/.falcon/config.yaml (0600 perms).

func SetProviderEntry

func SetProviderEntry(cfg *GlobalConfig, providerID, model string, values map[string]string)

SetProviderEntry upserts a provider entry into the config without touching any other provider entries.

Types

type Agent

type Agent struct {
	// contains filtered or unexported fields
}

Agent represents the Falcon AI agent that processes user messages, executes tools, and provides API debugging assistance.

func NewAgent

func NewAgent(llmClient llm.LLMClient) *Agent

NewAgent creates a new Falcon agent with the given LLM client.

func (*Agent) AppendHistory

func (a *Agent) AppendHistory(msg llm.Message)

AppendHistory adds a message to the history and truncates if necessary. When maxHistory is reached, older messages are removed to make room. The truncation keeps the most recent messages while preserving context. This method is thread-safe.

func (*Agent) AppendHistoryPair

func (a *Agent) AppendHistoryPair(assistantMsg, observationMsg llm.Message)

AppendHistoryPair adds an assistant message and observation to history atomically. This ensures tool call and observation stay together during truncation. This method is thread-safe.

func (*Agent) ExecuteTool

func (a *Agent) ExecuteTool(toolName string, args string) (string, error)

ExecuteTool executes a tool by name (used by retry tool). This method is thread-safe for looking up the tool.

func (*Agent) GetFramework

func (a *Agent) GetFramework() string

GetFramework returns the configured API framework.

func (*Agent) GetHistory

func (a *Agent) GetHistory() []llm.Message

GetHistory returns a copy of the agent's conversation history. This method is thread-safe.

func (*Agent) GetPromptTokenEstimate

func (a *Agent) GetPromptTokenEstimate() int

GetPromptTokenEstimate returns an estimate of how many tokens the system prompt uses.

func (*Agent) LLMClient

func (a *Agent) LLMClient() llm.LLMClient

LLMClient returns the agent's LLM client.

func (*Agent) ProcessMessage

func (a *Agent) ProcessMessage(input string) (string, error)

ProcessMessage handles a user message using ReAct logic. It runs the think-act-observe cycle until a final answer is reached. This is the blocking version without events.

func (*Agent) ProcessMessageWithEvents

func (a *Agent) ProcessMessageWithEvents(ctx context.Context, input string, callback EventCallback) (string, error)

ProcessMessageWithEvents handles a user message and emits events for each stage. This enables real-time UI updates as the agent thinks, uses tools, and responds. Events emitted: thinking, tool_call, observation, answer, error, streaming, confirmation_required The context can be used to cancel the agent mid-processing.

func (*Agent) RegisterTool

func (a *Agent) RegisterTool(tool Tool)

RegisterTool adds a tool to the agent's arsenal. This method is thread-safe.

func (*Agent) SetFramework

func (a *Agent) SetFramework(framework string)

SetFramework sets the user's API framework for context-aware assistance. Supported frameworks include: gin, echo, chi, fiber, fastapi, flask, django, express, nestjs, hono, spring, laravel, rails, actix, axum, other.

func (*Agent) SetLastResponse

func (a *Agent) SetLastResponse(response interface{})

SetLastResponse stores the last response from a tool for chaining.

func (*Agent) SetMaxHistory

func (a *Agent) SetMaxHistory(max int)

SetMaxHistory sets the maximum number of messages to keep in history. Set to 0 for unlimited history (not recommended for long sessions).

func (*Agent) SetMemoryStore

func (a *Agent) SetMemoryStore(store *MemoryStore)

SetMemoryStore sets the persistent memory store for the agent.

func (*Agent) SwapLLMClient

func (a *Agent) SwapLLMClient(client llm.LLMClient)

SwapLLMClient replaces the agent's LLM client at runtime.

type AgentEvent

type AgentEvent struct {
	// Type indicates the event type: "thinking", "tool_call", "observation",
	// "answer", "error", "streaming", "confirmation_required"
	Type string
	// Content holds the main event payload (varies by type)
	Content string
	// ToolArgs contains tool arguments (present only for "tool_call" events)
	ToolArgs string
	// FileConfirmation contains file write info (present only for "confirmation_required" events)
	FileConfirmation *FileConfirmation
}

AgentEvent represents a state change during agent processing. Events are emitted via callbacks to enable real-time UI updates.

type Config

type Config struct {
	Provider       string            `yaml:"provider"`                  // "ollama", "gemini", "openrouter", …
	ProviderConfig map[string]string `yaml:"provider_config,omitempty"` // provider-specific key/value pairs
	DefaultModel   string            `yaml:"default_model"`
	Theme          string            `yaml:"theme"`
	Framework      string            `yaml:"framework"` // API framework (e.g., gin, fastapi, express)

	// Legacy fields — migrated automatically on first load; do not use in new code.
	OllamaConfig     *OllamaConfig     `yaml:"ollama,omitempty"`
	GeminiConfig     *GeminiConfig     `yaml:"gemini,omitempty"`
	OpenRouterConfig *OpenRouterConfig `yaml:"openrouter,omitempty"`
	OllamaURL        string            `yaml:"ollama_url,omitempty"`
	OllamaAPIKey     string            `yaml:"ollama_api_key,omitempty"`
}

Config represents the user's Falcon configuration. Provider-specific settings are stored generically in ProviderConfig so that new providers can be added without changing this struct.

type ConfirmableTool

type ConfirmableTool interface {
	Tool
	// SetEventCallback sets the callback function for emitting events
	SetEventCallback(callback EventCallback)
}

ConfirmableTool is a tool that requires user confirmation before executing. Tools implementing this interface can emit confirmation requests back to the TUI, enabling human-in-the-loop approval for potentially destructive operations.

type ErrorContext

type ErrorContext struct {
	Message     string       `json:"message"`      // Main error message
	ErrorType   string       `json:"error_type"`   // Type of error (e.g., "ValueError")
	StackFrames []StackFrame `json:"stack_frames"` // Parsed stack trace
	Details     []string     `json:"details"`      // Additional error details
	Fields      []string     `json:"fields"`       // Validation error fields
}

ErrorContext contains extracted error information from a response.

func ExtractErrorContext

func ExtractErrorContext(body string, statusCode int) *ErrorContext

ExtractErrorContext extracts error information from an HTTP response body

func (*ErrorContext) FormatErrorContext

func (ctx *ErrorContext) FormatErrorContext() string

FormatErrorContext returns a human-readable summary of the error context

type EventCallback

type EventCallback func(AgentEvent)

EventCallback is the function signature for agent event handlers. Callbacks receive events as the agent progresses through the ReAct loop.

type FileConfirmation

type FileConfirmation struct {
	// FilePath is the path to the file being modified
	FilePath string
	// IsNewFile is true if creating a new file, false if modifying existing
	IsNewFile bool
	// Diff is the unified diff showing the proposed changes
	Diff string
}

FileConfirmation contains information for file write confirmation prompts. This enables human-in-the-loop approval before any file modifications.

type GeminiConfig

type GeminiConfig struct {
	APIKey string `yaml:"api_key"`
}

GeminiConfig holds Gemini-specific configuration (legacy).

type GlobalConfig

type GlobalConfig struct {
	DefaultProvider string                   `yaml:"default_provider"`
	Theme           string                   `yaml:"theme"`
	Providers       map[string]ProviderEntry `yaml:"providers,omitempty"`

	// Legacy migration fields — present only in old single-provider configs.
	// LoadGlobalConfig migrates them into Providers on first read.
	LegacyProvider       string            `yaml:"provider,omitempty"`
	LegacyProviderConfig map[string]string `yaml:"provider_config,omitempty"`
	LegacyDefaultModel   string            `yaml:"default_model,omitempty"`
}

GlobalConfig is the multi-provider global config written to ~/.falcon/config.yaml.

func LoadGlobalConfig

func LoadGlobalConfig() (*GlobalConfig, error)

LoadGlobalConfig reads the global config. If the file doesn't exist, returns a zero-value GlobalConfig with no error. Automatically migrates old single-provider format (top-level provider/provider_config/default_model keys) into the new Providers map on first read.

type MemoryEntry

type MemoryEntry struct {
	Key       string `json:"key"`
	Value     string `json:"value"`
	Category  string `json:"category"`  // "preference", "endpoint", "error", "project", "general"
	Timestamp string `json:"timestamp"` // RFC3339
	Source    string `json:"source"`    // Session ID that created this
}

MemoryEntry represents a single fact saved by the agent.

type MemoryStore

type MemoryStore struct {
	// contains filtered or unexported fields
}

MemoryStore manages persistent agent memory.

func NewMemoryStore

func NewMemoryStore(falconDir string) *MemoryStore

NewMemoryStore creates a MemoryStore and loads existing memory.

func (*MemoryStore) FalconDir

func (ms *MemoryStore) FalconDir() string

FalconDir returns the base .falcon directory path.

func (*MemoryStore) Forget

func (ms *MemoryStore) Forget(key string) error

Forget removes a memory entry by key and persists the change.

func (*MemoryStore) GetCompactSummary

func (ms *MemoryStore) GetCompactSummary() string

GetCompactSummary generates a compact string for injection into the system prompt. Returns empty string if no knowledge base content or memories exist.

func (*MemoryStore) List

func (ms *MemoryStore) List() []MemoryEntry

List returns all memory entries.

func (*MemoryStore) ListByCategory

func (ms *MemoryStore) ListByCategory(category string) []MemoryEntry

ListByCategory returns entries matching the given category.

func (*MemoryStore) Recall

func (ms *MemoryStore) Recall(query string) []MemoryEntry

Recall searches memory entries by substring match across key, value, and category.

func (*MemoryStore) Save

func (ms *MemoryStore) Save(key, value, category string) error

Save upserts a memory entry (updates if key exists, inserts otherwise) and persists to disk. Returns an error if attempting to save secrets to memory.

func (*MemoryStore) UpdateKnowledge

func (ms *MemoryStore) UpdateKnowledge(section, newContent string) error

UpdateKnowledge rewrites a named section in falcon.md with new content. If the section heading does not exist, it is appended. If it exists, the content between that heading and the next H2 heading is replaced.

type OllamaConfig

type OllamaConfig struct {
	Mode   string `yaml:"mode"`    // "local" or "cloud"
	URL    string `yaml:"url"`     // API URL
	APIKey string `yaml:"api_key"` // API key (for cloud mode)
}

OllamaConfig holds Ollama-specific configuration (legacy).

type OpenRouterConfig

type OpenRouterConfig struct {
	APIKey string `yaml:"api_key"`
}

OpenRouterConfig holds OpenRouter-specific configuration (legacy).

type ProviderEntry

type ProviderEntry struct {
	Model  string            `yaml:"model"`
	Config map[string]string `yaml:"config"`
}

ProviderEntry holds the model and credentials for a single configured provider.

type SetupResult

type SetupResult struct {
	Framework      string
	Provider       string
	ProviderValues map[string]string // keyed by SetupField.Key
	Model          string
}

SetupResult holds the values collected by the first-run setup wizard.

type StackFrame

type StackFrame struct {
	File     string `json:"file"`     // File path where error occurred
	Line     int    `json:"line"`     // Line number
	Function string `json:"function"` // Function name (if available)
	Code     string `json:"code"`     // Source code snippet (optional)
}

StackFrame represents a single frame in a stack trace.

func ParseStackTrace

func ParseStackTrace(text string) []StackFrame

ParseStackTrace extracts stack frames from various stack trace formats

type Tool

type Tool interface {
	// Name returns the unique identifier for this tool.
	Name() string
	// Description returns a human-readable description of what this tool does.
	Description() string
	// Parameters returns a description of the JSON parameters this tool accepts.
	Parameters() string
	// Execute runs the tool with the given JSON arguments and returns the result.
	Execute(args string) (string, error)
}

Tool represents an agent capability that can be executed. Each tool has a name, description, parameters schema, and execution logic. Tools are registered with the Agent and can be invoked during the ReAct loop.

Directories

Path Synopsis
agent
Package agent provides agent memory and reporting tools for ZAP.
Package agent provides agent memory and reporting tools for ZAP.
data_driven_engine
Package data_driven_engine provides template-based parameterized test execution for ZAP.
Package data_driven_engine provides template-based parameterized test execution for ZAP.
debugging
Package debugging provides debugging and codebase analysis tools for ZAP.
Package debugging provides debugging and codebase analysis tools for ZAP.
functional_test_generator
Package functional_test_generator provides spec-driven functional test generation for ZAP.
Package functional_test_generator provides spec-driven functional test generation for ZAP.
idempotency_verifier
Package idempotency_verifier provides idempotency validation for API endpoints for ZAP.
Package idempotency_verifier provides idempotency validation for API endpoints for ZAP.
integration_orchestrator
Package integration_orchestrator provides multi-step integration test workflows for ZAP.
Package integration_orchestrator provides multi-step integration test workflows for ZAP.
performance_engine
Package performance_engine provides multi-mode performance and load testing for ZAP.
Package performance_engine provides multi-mode performance and load testing for ZAP.
persistence
Package persistence provides request persistence and environment management tools for ZAP.
Package persistence provides request persistence and environment management tools for ZAP.
regression_watchdog
Package regression_watchdog provides baseline comparison and regression detection for ZAP.
Package regression_watchdog provides baseline comparison and regression detection for ZAP.
security_scanner
Package security_scanner provides OWASP security scanning and vulnerability detection for ZAP.
Package security_scanner provides OWASP security scanning and vulnerability detection for ZAP.
shared
Package shared provides merged authentication tools for the Falcon agent.
Package shared provides merged authentication tools for the Falcon agent.
smoke_runner
Package smoke_runner provides lightweight deployment health checks for ZAP.
Package smoke_runner provides lightweight deployment health checks for ZAP.
spec_ingester
Package spec_ingester provides API specification parsing and knowledge graph building for ZAP.
Package spec_ingester provides API specification parsing and knowledge graph building for ZAP.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL