Skip to content

Feat/stateless backend creation tool - #242

Open
StpMax wants to merge 14 commits into
stagingfrom
feat/stateless_backend_creation_tool
Open

Feat/stateless backend creation tool#242
StpMax wants to merge 14 commits into
stagingfrom
feat/stateless_backend_creation_tool

Conversation

@StpMax

@StpMax StpMax commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Feat: generate_artifact — FSM orchestrator for LLM-driven artifact generation

FQE-2213

Description

Adds a new generate_artifact tool — an orchestrator built around a deterministic finite-state machine (FSM) that drives LLM generation of finished artifacts (HTML apps and fullstack apps), including data-sufficiency checks, spec generation, code generation, and verification steps.

Unlike the previous description, this is not a simple async tool-use/tool-result loop wrapped around a single call — it's a graph of steps (orchestrator.py) where decision nodes ("is there enough data?", "can the data be fetched?", "is this a fullstack stack or not?") produce Pydantic verdicts, and generation nodes are bounded tool-use loops (engine.py).

Architecture

  • state.pyGenState: session, artifact type, path, brief, fullstack flag, data notes, API spec, list of written files, step trace. Also the verdict models: DataVerdict, RequiredData, FetchVerdict, VerifyResult.
  • orchestrator.py — the FSM graph itself (described as a Graphviz digraph and embedded into the prompts so the LLM understands its place in the pipeline):
    1. Data-sufficiency loop: is_data_enoughdefine_required_datais_possible_to_fetchfetch_data_sample → back to is_data_enough (capped at DATA_LOOP_MAX = 3 iterations).
    2. make_tech_spec → deterministic branch on is_fullstack.
    3. For html-app: generate_frontendverify_frontend.
    4. For fullstack types: make_api_spec (single call producing an OpenAPI 3.1 JSON spec) → in parallel (asyncio.gather) generate_backendverify_backend and generate_frontendverify_frontend → then run_appverify_fullstack (actually launches the backend and health-checks it).
  • engine.py — the reusable primitives: one-shot API spec generation, and _run_loop — the shared bounded tool-use/tool-result loop (MAX_ROUNDS = 16, raised from 12 because sub-generators now also spend rounds on scratchpad calls). Once backend.py is written, the backend step auto-injects an instruction to also write requirements.txt. Each side (backend/frontend) may retry generation once (GEN_VERIFY_MAX_RETRIES = 1) with verifier errors fed back in; app launch also allows one retry (RUNAPP_MAX_RETRIES = 1) with the backend.log tail included.

Artifact types

  • html-app — a single self-contained HTML file with data embedded inline; no API spec, no backend.
  • fullstack-stateless-app — backend + frontend, with an explicit "STATELESS" constraint injected into the prompts: no sqlite/local files/in-process mutable stores; external DB/API access is fine.
  • fullstack-stateful-app — same flow, but local persistence (e.g. sqlite) is allowed.

Verification (verifiers.py)

  • verify_frontend — static HTML checks: valid <body>, viewport meta, api-base meta (fullstack only), no absolute URLs in fetch() (CDN exempted), mandatory /api/* prefix, forbidden globals, no !important on * and no z-index > 1000; warnings for missing stable ids and non-ECharts chart CDNs.
  • evaluate_backend/verify_backend — checks for the presence of app/handler/SECRETS, that all routes live under /api/* (root routes are an error), presence of /api/health, an AST-based check that SECRETS[...] isn't copied at module level, presence of core dependencies (fastapi, mangum, uvicorn) in requirements.txt (PEP 508-aware parsing with extras/specifiers), and extraction of DS_* env vars. The real verification installs dependencies into the scratchpad's venv, runs py_compile, and imports/introspects backend.py in a subprocess with a 15s timeout.

Data access (sub_tools.py)

The previous data_refs/test-data-pickling mechanism is gone — the engine explicitly no longer fabricates test data or pre-pickles variables. Instead, the sub-generator only has access to write_file/read_file/finish (all sandboxed under the artifact root, rejecting ../absolute-path escapes) plus the same scratchpad tool the main agent uses. The brief's free-form ## Data section is still central, but data is now obtained through the fetch_data_sample loop, and every scratchpad exec call is recorded and deterministically rendered into data_notes (_render_exec_notes, capped by EXEC_CODE_MAX=2000, EXEC_OUTPUT_MAX=300, EXEC_NOTES_MAX=8000, oldest entries dropped first) — so backend/frontend generation sees the actual working data-access code rather than a free-text summary.

Other new modules

  • anton/core/llm/serialize.py — provider-agnostic serialization of LLM messages/responses into JSON-compatible dicts (serialize_content, serialize_messages, serialize_response), used by both the existing history hook and the new debug_trace.py.
  • debug_trace.py — JSONL step tracing for the FSM, enabled via the ANTON_DEBUG_ARTIFACT_GENERATE_TOOL env var; a no-op (NullTrace) otherwise. Writes are best-effort and never raise.

Integration

  • session.py — registers GENERATE_ARTIFACT_TOOL in the core tool set.
  • tool_defs.py — defines the tool (slug + context); its description requires a 4-section markdown brief (## User request, ## Conversation context, ## Functional Requirements Specification, ## Data); also updates create_artifact's description to recommend fullstack-stateless-app whenever external DB access can be done statelessly.
  • tool_handlers.pyhandle_generate_artifact: validates input, calls generate_artifact.generate(...), and wraps errors/exceptions via _generation_failed(), which explicitly instructs the outer agent not to try to fix the artifact itself but to report the failure to the user instead.

Tests

Adds 7 test files (tests/test_artifact_*.py) covering: FSM graph/prompt completeness, _run_loop behavior, state constants and models, the full orchestrator (data loop, backend/frontend retries, happy paths for html-app and fullstack), backend verification (import/health/routes/secrets/requirements), frontend verification (viewport/api-base/URL policies), and error wrapping in tool_handlers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant