VOOZH about

URL: https://deepwiki.com/guanguans/ai-commit/5.1-generator-architecture

⇱ Generator Architecture | guanguans/ai-commit | DeepWiki


Loading...
Menu

Generator Architecture

This page explains the internal structure shared by all AI generators: the GeneratorContract interface, the AbstractGenerator base class, and the GeneratorManager driver-resolution system. It covers the lifecycle of a generate() call from driver selection through process execution or HTTP dispatch.

For details on specific generator implementations, see API-Based Generators and CLI-Based Generators. For instructions on adding a new generator, see Adding New Generators.


Overview

The generator subsystem has three layers:

LayerFileRole
GeneratorContractapp/Contracts/GeneratorContract.phpSingle-method interface all generators implement
AbstractGeneratorapp/Generators/AbstractGenerator.phpShared state, process helpers, option hydration
GeneratorManagerapp/GeneratorManager.phpSelects and instantiates the correct driver from config

Class hierarchy diagram


Sources: app/Contracts/GeneratorContract.php1-19 app/Generators/AbstractGenerator.php1-106 app/GeneratorManager.php1-78


GeneratorContract

App\Contracts\GeneratorContract defines the single method every generator must implement:

generate(string $prompt): string

The $prompt is the fully-rendered diff+instructions string built by CommitCommand. The return value is the raw string produced by the AI backend.

GeneratorManager itself also implements GeneratorContract, forwarding calls to the currently active driver. This means callers can treat the manager as a generator without knowing which concrete driver is active.

Sources: app/Contracts/GeneratorContract.php1-19 app/GeneratorManager.php51-54


AbstractGenerator

App\Generators\AbstractGenerator is the shared base for all concrete generators. It is constructed with a single Illuminate\Config\Repository instance that carries the driver-specific configuration block from config/ai-commit.php.

Constructor

app/Generators/AbstractGenerator.php36-40

On construction:

  • $this->output is a cloned OutputStyle (Laravel Zero's Symfony-based output) with verbosity set to VERBOSITY_DEBUG.
  • $this->helperSet is extracted from the running Artisan application so that the Symfony ProcessHelper is available.

Process Execution Helpers

Both CLI-based and API-based generators may need to run subprocesses. AbstractGenerator provides two methods:

MethodThrows on failure?Description
mustRunProcess()Yes — ProcessFailedExceptionCalls runProcess() and throws if exit code is non-zero
runProcess()NoDelegates to ProcessHelper::run() with optional custom output and verbosity

app/Generators/AbstractGenerator.php42-70

runProcess() also accepts a plain string, converting it via Process::fromShellCommandline() before running.

runningCallback() returns a closure suitable as the $callback argument to Process::mustRun(). It writes stdout to the output stream and stderr wrapped in <fg=red>.

app/Generators/AbstractGenerator.php82-87

Option Hydration

hydratedOptions() converts the options key from a generator's config block into a flat array of CLI flag strings:

app/Generators/AbstractGenerator.php97-105

It uses http_build_query + urldecode to serialize each option value, then filters out blanks. The result is a list like ['--model', 'gpt-4', '--temperature', '0.7'].

ensureWithOptions(array $command) appends the hydrated options to a command array:

app/Generators/AbstractGenerator.php89-92

This is used by CLI generators to construct the final Process command.

Process execution flow


Sources: app/Generators/AbstractGenerator.php42-105


GeneratorManager

App\GeneratorManager extends Illuminate\Support\Manager, which provides the driver-caching and extend() (custom creator) pattern used by Laravel.

Default Driver

app/GeneratorManager.php41-44

getDefaultDriver() reads ai-commit.generator from the application config. This is the string name set by --generator on the command line or via the config file (e.g. "openai_chat").

Driver Resolution — createDriver()

app/GeneratorManager.php63-77

When a driver name is requested, createDriver() follows this sequence:

  1. Custom creators — if extend() was called for this driver name, the registered closure is called.

  2. Config lookup — reads ai-commit.generators.<driver> and wraps it in a Repository.

  3. Class name derivation — takes the driver key from the config block (falls back to the driver name itself), applies the substitution openaiOpenAI, then converts the result to StudlyCase and appends Generator:

    Driver keyStudly resultClass resolved
    openaiOpenAIApp\Generators\OpenAIGenerator
    openai_chatOpenAIChatApp\Generators\OpenAIChatGenerator
    bito_cliBitoCliApp\Generators\BitoCliGenerator
    github_copilot_cliGithubCopilotCliApp\Generators\GithubCopilotCliGenerator
    github_models_cliGithubModelsCliApp\Generators\GithubModelsCliGenerator
  4. Instantiationnew $class($config) where $config is the driver-specific Repository.

  5. Fallback — throws App\Exceptions\InvalidArgumentException if the class does not exist.

Driver resolution flow


Sources: app/GeneratorManager.php41-77

generate() Delegation

app/GeneratorManager.php51-54

Calling generate() on the manager resolves the default driver and delegates immediately. The manager also exposes generator(?string $generator) to retrieve a specific driver instance by name.


Dependency Injection and Binding

GeneratorManager is registered as a singleton in App\Providers\AppServiceProvider (see Application Foundation). Calling app(GeneratorManager::class) or resolve(GeneratorManager::class) always returns the same instance, which means the driver cache ($this->drivers from Illuminate Manager) persists for the lifetime of the command.

The Repository injected into each concrete generator carries only the settings for that one driver, isolating generator configuration from the global config.


Summary of Key Symbols

SymbolTypeFilePurpose
GeneratorContractInterfaceapp/Contracts/GeneratorContract.phpMandates generate(string): string
AbstractGeneratorAbstract classapp/Generators/AbstractGenerator.phpShared config, output, process execution
GeneratorManagerFinal classapp/GeneratorManager.phpDriver resolution via Manager pattern
mustRunProcess()MethodAbstractGeneratorRun a process, throw on failure
runProcess()MethodAbstractGeneratorRun a process, return it regardless
hydratedOptions()MethodAbstractGeneratorSerialize config options map to CLI flags
ensureWithOptions()MethodAbstractGeneratorAppend hydrated options to a command array
runningCallback()MethodAbstractGeneratorStdout/stderr output callback for Process
getDefaultDriver()MethodGeneratorManagerReads ai-commit.generator from config
createDriver()MethodGeneratorManagerResolves class name, instantiates generator

Sources: app/Contracts/GeneratorContract.php1-19 app/Generators/AbstractGenerator.php1-106 app/GeneratorManager.php1-78