forge

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jun 9, 2026 License: Apache-2.0 Imports: 17 Imported by: 0

Documentation

Overview

Package forge implements VORTEX Forge (build plan M13): the autonomous app builder. A user request ("build me an Android app for cricket scores") is parsed into a structured build intent, dependencies are installed, code is generated by the AI gateway, the app is built and QA-gated, and the artifact is delivered back to the requesting chat. All orchestration is stdlib-only; the AI provider is reached through the agents.AIGateway interface.

This file parses a free-form user message into a structured BuildIntent.

Index

Constants

This section is empty.

Variables

View Source
var ErrApprovalNeeded = errors.New("forge: dependency step requires approval (interpreter/package manager)")

ErrApprovalNeeded indicates a dependency step requires an interpreter/package manager (python3/npm/pip3) that the agent cannot run unattended; the caller must obtain human approval (the coordinator's ApprovalFunc) before proceeding.

Functions

func CheckCompiler

func CheckCompiler(language string) (found bool, binary, hint string)

CheckCompiler reports whether a usable toolchain exists for language. found is true when one candidate binary is on PATH; binary is that binary; hint is the install hint (set when not found). Unknown languages return found=true (no known toolchain requirement to enforce).

func CompilerGate

func CompilerGate(userMsg string) (msg string, ok bool)

CompilerGate checks whether the language explicitly requested in userMsg has an available toolchain. When a compiled language is requested but its compiler is missing, it returns a user-facing message suggesting installed alternatives and ok=false (the orchestrator should NOT start a build). When no specific language is requested, or its compiler is present, ok=true.

func RequestedLanguage

func RequestedLanguage(userMsg string) string

RequestedLanguage returns the explicit compiled language the user asked for (c, c++, rust, java), or "" when none is detected. It only matches languages that need a toolchain check; interpreted languages are not returned. Order matters: c++ is matched before c.

Types

type AIIntentParser

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

AIIntentParser parses intent using the AI gateway.

func NewAIIntentParser

func NewAIIntentParser(gateway agents.AIGateway) *AIIntentParser

NewAIIntentParser builds an AI-backed parser.

func (*AIIntentParser) Parse

func (p *AIIntentParser) Parse(_ context.Context, userMsg string) (BuildIntent, error)

Parse asks the AI gateway to classify the request into a BuildIntent. The caller's context is intentionally not used for the provider call (see below).

type AppType

type AppType string

AppType classifies what kind of artifact a build produces.

const (
	AppTypeWeb          AppType = "web"
	AppTypeMobile       AppType = "mobile"
	AppTypeAPI          AppType = "api"
	AppTypeScript       AppType = "script"
	AppTypeDataPipeline AppType = "data_pipeline"
	AppTypeBot          AppType = "bot"
)

App types.

type BuildAgent

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

BuildAgent runs headless builds for a generated project.

func NewBuildAgent

func NewBuildAgent(cfg BuildConfig) *BuildAgent

NewBuildAgent constructs the agent.

func (*BuildAgent) ArtifactPath

func (b *BuildAgent) ArtifactPath() string

ArtifactPath returns the expected path of the build output for the stack.

func (*BuildAgent) Build

func (b *BuildAgent) Build(ctx context.Context) (BuildOutput, error)

Build selects and runs the build command for the configured stack, capturing output. It returns an error when the sandbox is empty or the build fails.

type BuildConfig

type BuildConfig struct {
	SandboxDir string
	Stack      StackChoice
	Timeout    time.Duration // default 15m
	CacheDir   string        // reserved for build caches
}

BuildConfig configures the build agent.

type BuildIntent

type BuildIntent struct {
	AppType         AppType              `json:"app_type"`
	Description     string               `json:"description"`
	Requirements    []string             `json:"requirements"`
	DeliveryTargets []string             `json:"delivery_targets"` // "apk"|"web"|"api"|"script"
	Stack           StackChoice          `json:"stack"`
	NeedsLiveData   bool                 `json:"needs_live_data"`
	ClarifyingQs    []ClarifyingQuestion `json:"clarifying_questions"`
}

BuildIntent is the structured interpretation of a user request.

func (BuildIntent) ClarifyingTexts

func (b BuildIntent) ClarifyingTexts() []string

ClarifyingTexts returns the question texts (legacy string view) — used by the progress stream which carries questions as "❓ <text>" lines.

type BuildOutput

type BuildOutput struct {
	Success      bool   `json:"success"`
	ArtifactPath string `json:"artifact_path"`
	ArtifactType string `json:"artifact_type"` // "apk"|"web-dist"|"binary"|"script"
	Stdout       string `json:"stdout"`
	Stderr       string `json:"stderr"`
	DurationMs   int64  `json:"duration_ms"`
}

BuildOutput is the result of a build.

type ClarifyingQuestion

type ClarifyingQuestion struct {
	Question string   `json:"question"`
	Options  []string `json:"options,omitempty"` // empty → free text
	Key      string   `json:"key"`               // what this answer maps to
}

ClarifyingQuestion is a structured question the agent asks before building. When Options is non-empty it is rendered as a numbered selection (TUI) or inline buttons (Telegram); when empty it is a free-text question.

type CodegenAgent

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

CodegenAgent generates application code via the AI gateway and writes it into the sandbox.

func NewCodegenAgent

func NewCodegenAgent(cfg CodegenConfig) *CodegenAgent

NewCodegenAgent constructs the agent.

func (*CodegenAgent) Fix

func (c *CodegenAgent) Fix(ctx context.Context, files []GeneratedFile, errorOutput string) ([]GeneratedFile, error)

Fix asks the AI to repair the given files to resolve a build error, then overwrites them in the sandbox.

func (*CodegenAgent) Generate

func (c *CodegenAgent) Generate(ctx context.Context, intent BuildIntent, spec string) ([]GeneratedFile, error)

Generate produces application code for the given intent and writes each file into the sandbox. Malformed JSON is retried up to MaxRetries.

type CodegenConfig

type CodegenConfig struct {
	SandboxDir string
	AIGateway  agents.AIGateway
	MaxRetries int // default 3
}

CodegenConfig configures the code-generation agent.

type CompilerSpec

type CompilerSpec struct {
	Language    string
	Candidates  []string // first found on PATH wins
	InstallHint string
}

CompilerSpec describes the toolchain needed for a language: the candidate binaries (any one suffices) and an install hint shown when none is found.

type DeliveryAgent

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

DeliveryAgent delivers build output to the requester's channels.

func NewDeliveryAgent

func NewDeliveryAgent(cfg DeliveryConfig) *DeliveryAgent

NewDeliveryAgent constructs the agent.

func (*DeliveryAgent) Deliver

func (d *DeliveryAgent) Deliver(ctx context.Context, result BuildOutput, intent BuildIntent, chatID int64, cost float64) error

Deliver routes the build output to each delivery target in the intent, then sends a summary message. Cost is the AI spend for the build (USD).

func (*DeliveryAgent) DeployWebApp

func (d *DeliveryAgent) DeployWebApp(ctx context.Context, distDir, name string) (string, error)

DeployWebApp deploys a built web dist via the configured deployer, returning the public URL.

type DeliveryConfig

type DeliveryConfig struct {
	Sender    NotificationSender
	Deployer  WebDeployer
	ServeBase string // base directory web apps are copied into
}

DeliveryConfig configures the delivery agent.

type DepConfig

type DepConfig struct {
	SandboxDir string
	Timeout    time.Duration // per command; default 5m
	CacheDir   string        // for caching downloads (reserved)
}

DepConfig configures the dependency agent.

type DependencyAgent

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

DependencyAgent installs the packages a build needs.

func NewDependencyAgent

func NewDependencyAgent(cfg DepConfig) *DependencyAgent

NewDependencyAgent constructs the agent.

func (*DependencyAgent) CheckInstalled

func (d *DependencyAgent) CheckInstalled(name string) (bool, string, error)

CheckInstalled reports whether a tool is installed and its version. It never returns an error for a simply-missing tool (installed=false, err=nil); an error is returned only for unexpected failures.

func (*DependencyAgent) Install

func (d *DependencyAgent) Install(ctx context.Context, stack StackChoice) error

Install installs the packages implied by stack. Safe toolchains (Go modules, Flutter) are set up directly; stacks that require pip/npm return ErrApprovalNeeded so the orchestrator can gate them behind human approval. An empty stack is a no-op.

type Forge

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

Forge orchestrates the full autonomous build pipeline.

func NewForge

func NewForge(cfg ForgeConfig) (*Forge, error)

NewForge constructs the orchestrator.

func (*Forge) Build

func (f *Forge) Build(ctx context.Context, userMsg string, chatID int64, progressFn func(string)) error

Build runs the full pipeline for a user request. progressFn (optional) receives a message at each stage. It returns nil on a delivered build, or an error (the QA gate is never skipped — a failing QA after the fix cycles blocks delivery).

func (*Forge) Status

func (f *Forge) Status() ForgeStatus

Status returns a snapshot of the current build state.

type ForgeConfig

type ForgeConfig struct {
	AIGateway   agents.AIGateway
	Bus         *agents.Bus
	SandboxBase string
	CacheDir    string
	Delivery    DeliveryConfig

	// Optional injected steps (tests provide stubs; production leaves nil).
	Intent    intentStep
	Deps      depStep
	Codegen   func(sandbox string) codegenStep
	Builder   func(sandbox string, stack StackChoice) buildStep
	QA        func(sandbox string) qaStep
	Delivery2 deliverStep
}

ForgeConfig configures the orchestrator. The step fields are optional; when nil, Forge builds the concrete agents from the AI gateway and sandbox.

type ForgeStatus

type ForgeStatus struct {
	Active          bool                 `json:"active"`
	CurrentBuild    string               `json:"current_build"`
	Progress        string               `json:"progress"`
	ProgressHistory []string             `json:"progress_history"`
	Result          string               `json:"result"`
	DurationMs      int64                `json:"duration_ms"`
	Questions       []ClarifyingQuestion `json:"questions,omitempty"`
}

ForgeStatus is a snapshot of the orchestrator's current activity.

type GeneratedFile

type GeneratedFile struct {
	Path    string `json:"path"`
	Content string `json:"content"`
	Size    int    `json:"size"`
}

GeneratedFile is one file produced by the codegen agent.

type IntentParser

type IntentParser interface {
	Parse(ctx context.Context, userMsg string) (BuildIntent, error)
}

IntentParser turns a user message into a BuildIntent.

type Job

type Job struct {
	ID              string               `json:"id"`
	Message         string               `json:"message"`
	SessionID       string               `json:"session_id"`
	ChatID          int64                `json:"chat_id"`
	State           JobState             `json:"state"`
	Progress        string               `json:"progress"`
	ProgressHistory []string             `json:"progress_history,omitempty"`
	Questions       []ClarifyingQuestion `json:"questions,omitempty"`
	Result          string               `json:"result,omitempty"`
	DurationMs      int64                `json:"duration_ms,omitempty"`
	Error           string               `json:"error,omitempty"`
	CreatedAt       time.Time            `json:"created_at"`
	UpdatedAt       time.Time            `json:"updated_at"`
}

Job is one asynchronous build request.

type JobManager

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

JobManager runs forge builds asynchronously and tracks their status. Builds are serialized (the Forge runs one build at a time) via runMu, so submitted jobs queue rather than colliding.

func NewJobManager

func NewJobManager(f *Forge) *JobManager

NewJobManager constructs a manager over a Forge.

func (*JobManager) Get

func (m *JobManager) Get(id string) (Job, bool)

Get returns a copy of the job by ID.

func (*JobManager) List

func (m *JobManager) List() []Job

List returns all jobs, newest first.

func (*JobManager) SessionClarifying

func (m *JobManager) SessionClarifying(sessionID string) bool

SessionClarifying reports whether the most recent job for sessionID is in the needs-clarification state (so the coordinator treats the next message as an answer, not a new build request).

func (*JobManager) SessionPending

func (m *JobManager) SessionPending(sessionID string) bool

SessionPending reports whether the latest job for a session is non-terminal (queued, running, or awaiting clarification). The coordinator uses this so a follow-up message is treated as an ANSWER while a build is still in flight — the build is async, so the job may not have reached needs_clarification yet when the user replies. Without this, the reply starts a new job (the loop).

func (*JobManager) Submit

func (m *JobManager) Submit(ctx context.Context, message, sessionID string, chatID int64) string

Submit enqueues a build and starts it asynchronously, returning the job ID.

type JobState

type JobState string

JobState is the lifecycle state of a forge build job.

const (
	JobQueued   JobState = "queued"
	JobRunning  JobState = "running"
	JobComplete JobState = "complete"
	JobFailed   JobState = "failed"
	JobClarify  JobState = "needs_clarification"
)

Job states.

type NotificationSender

type NotificationSender interface {
	// SendMessage sends a text summary to the requester.
	SendMessage(ctx context.Context, chatID int64, text string) error
	// SendFile delivers a file (e.g. an APK) to the requester.
	SendFile(ctx context.Context, chatID int64, filename string, data []byte, caption string) error
}

NotificationSender delivers messages and files to the requesting chat. It is satisfied by an adapter over messaging.Router so forge stays decoupled from the messaging package.

type QAAgent

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

QAAgent runs the quality-assurance gate before delivery. The gate is never skipped: a failed QAResult must block delivery.

func NewQAAgent

func NewQAAgent(cfg QAConfig) *QAAgent

NewQAAgent constructs the agent.

func (*QAAgent) Run

func (q *QAAgent) Run(_ context.Context, output BuildOutput) (QAResult, error)

Run executes all applicable checks for the build output. All checks run even if one fails (a full report). The overall result Passed is the AND of every check; warnings (e.g. a hardcoded secret) do not fail the gate but are surfaced.

type QACheck

type QACheck struct {
	Name    string `json:"name"`
	Passed  bool   `json:"passed"`
	Message string `json:"message"`
}

QACheck is the outcome of one check.

type QAConfig

type QAConfig struct {
	SandboxDir      string
	ResponseTimeout time.Duration // per check; default 5s
}

QAConfig configures the QA gate.

type QAResult

type QAResult struct {
	Passed   bool      `json:"passed"`
	Checks   []QACheck `json:"checks"`
	Warnings []string  `json:"warnings"`
}

QAResult aggregates all checks. Passed is true only if every check passed.

type RuleIntentParser

type RuleIntentParser struct{}

RuleIntentParser is a keyword-based fallback used when no AI gateway is available. It is deterministic and needs no network.

func NewRuleIntentParser

func NewRuleIntentParser() *RuleIntentParser

NewRuleIntentParser builds the rule-based parser.

func (RuleIntentParser) Parse

func (RuleIntentParser) Parse(_ context.Context, userMsg string) (BuildIntent, error)

Parse classifies the message by keyword heuristics.

type StackChoice

type StackChoice struct {
	Backend  string `json:"backend"`  // "fastapi"|"express"|"go"|"none"
	Frontend string `json:"frontend"` // "flutter"|"react"|"none"
	ML       string `json:"ml"`       // "sklearn"|"pytorch"|"none"
	Database string `json:"database"` // "sqlite"|"postgres"|"none"
}

StackChoice records the chosen technology stack for a build.

type WebDeployer

type WebDeployer interface {
	DeployWebApp(ctx context.Context, distDir, name string) (string, error)
}

WebDeployer deploys a built web app and returns its public URL. It is satisfied by an adapter over the proxy manager.

Jump to

Keyboard shortcuts

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