Code Generation from Documentation¶
This example learns a library's API from documentation text and generates worked code examples for a set of use cases. It demonstrates list-valued output fields, composing several ChainOfThought predictors, and threading their outputs through a plain Scala class.
Signatures with list-valued fields¶
trait LibraryAnalyzer extends Spec:
def library_name: InputField[String]
def documentation_content: InputField[String]
def core_concepts: OutputField[List[String]]
def common_patterns: OutputField[List[String]]
def key_methods: OutputField[List[String]]
def installation_info: OutputField[String]
def code_examples: OutputField[List[String]]
A Spec trait declares the input and output fields. An OutputField[List[String]] decodes to List[String], so a single predictor call returns several structured lists at once. The example defines three such specs: one to analyze documentation, one to generate code for a use case, and one to refine code given feedback.
Composing ChainOfThought predictors¶
final class DocumentationLearningAgent:
private val analyzeDocs = ChainOfThought(Signature.of[LibraryAnalyzer])
private val generateCode = ChainOfThought(Signature.of[CodeGenerator])
private val refineCode = ChainOfThought(Signature.of[RefineCode])
DocumentationLearningAgent holds one ChainOfThought predictor per signature, built from Signature.of[T]. Each predictor is a field on the class; the agent's methods call them and map their outputs into the LibraryInfo and GeneratedExample case classes.
Threading outputs¶
def learnAndGenerate(
libraryName : String,
combinedContent: String,
useCases : Vector[String] = defaultUseCases
)(using RuntimeContext): Either[DspyError, (LibraryInfo, Vector[GeneratedExample])] =
val agent = new DocumentationLearningAgent
for
info <- agent.learnFromDocs(libraryName, combinedContent)
examples <- useCases.foldLeft[Either[DspyError, Vector[GeneratedExample]]](Right(Vector.empty)) {
(acc, useCase) =>
for
sofar <- acc
ex <- agent.generateExample(
info,
useCase,
requirements = "Include error handling, comments, and best practices"
)
yield sofar :+ ex
}
yield (info, examples)
learnAndGenerate runs the full flow inside an Either for comprehension. It first analyzes the combined documentation into a LibraryInfo, then folds over the use cases, generating one GeneratedExample per case and accumulating them in a Vector. Any DspyError short-circuits the comprehension.
Running it¶
OPENAI_API_KEY=sk-... sbt "examples/runMain dspy4s.examples.tutorials.sample_code_generation.sampleCodeGenerationMain"
Notes¶
Out of scope: fetching documentation over HTTP, the interactive console session,
and saving results to JSON. learnFromDocs takes already-combined documentation
text as input instead of fetching it.
Full source: SampleCodeGeneration.scala