Documentation
¶
Overview ¶
Package result extracts a JSON result from free-form model text.
It exports two functions:
- ExtractJSON pulls the JSON content out of a text response, stripping a surrounding markdown code fence when present and returning the trimmed input otherwise.
- Extract combines ExtractJSON with json.Unmarshal into a caller-supplied type.
The executors use it as a text fallback: when a model replies with plain text instead of calling the submit_result tool, the text is parsed as a submit-shaped result:
resp, err := result.Extract[Response](textContent)
if err != nil {
return response, true, fmt.Errorf("failed to parse response: %w", err)
}
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Extract ¶
Extract extracts JSON content from a text response and unmarshals it into the provided type. It combines ExtractJSON with json.Unmarshal for convenience.
Example ¶
ExampleExtract demonstrates type-safe extraction and unmarshaling.
package main
import (
"fmt"
"log"
"chainguard.dev/driftlessaf/agents/result"
)
func main() {
// AI response with structured data
response := `I've analyzed your request. Here are the results:
` + "```json" + `
{
"analysis": {
"sentiment": "positive",
"confidence": 0.95,
"keywords": ["golang", "example", "documentation"]
},
"metadata": {
"model": "gpt-4",
"timestamp": "2024-01-15T10:30:00Z"
}
}
` + "```" + `
This analysis is based on the provided context.`
// Define the expected structure
type Response struct {
Analysis struct {
Sentiment string `json:"sentiment"`
Confidence float64 `json:"confidence"`
Keywords []string `json:"keywords"`
} `json:"analysis"`
Metadata struct {
Model string `json:"model"`
Timestamp string `json:"timestamp"`
} `json:"metadata"`
}
// Extract and unmarshal
data, err := result.Extract[Response](response)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Sentiment: %s (%.0f%% confidence)\n",
data.Analysis.Sentiment,
data.Analysis.Confidence*100)
fmt.Printf("Keywords: %v\n", data.Analysis.Keywords)
}
Output: Sentiment: positive (95% confidence) Keywords: [golang example documentation]
Example (ArrayResponse) ¶
ExampleExtract_arrayResponse demonstrates extracting array responses.
package main
import (
"fmt"
"log"
"chainguard.dev/driftlessaf/agents/result"
)
func main() {
// AI response with array of items
response := `Here are the search results:
` + "```json" + `
[
{"id": 1, "title": "Introduction to Go", "score": 0.98},
{"id": 2, "title": "Advanced Go Patterns", "score": 0.85},
{"id": 3, "title": "Go Best Practices", "score": 0.79}
]
` + "```" + `
`
type SearchResult struct {
ID int `json:"id"`
Title string `json:"title"`
Score float64 `json:"score"`
}
results, err := result.Extract[[]SearchResult](response)
if err != nil {
log.Fatal(err)
}
for _, r := range results {
fmt.Printf("%d. %s (score: %.2f)\n", r.ID, r.Title, r.Score)
}
}
Output: 1. Introduction to Go (score: 0.98) 2. Advanced Go Patterns (score: 0.85) 3. Go Best Practices (score: 0.79)
Example (ComplexStructure) ¶
ExampleExtract_complexStructure demonstrates extracting deeply nested structures.
package main
import (
"fmt"
"log"
"chainguard.dev/driftlessaf/agents/result"
)
func main() {
// AI response with complex nested structure
response := `Analysis complete:
` + "```json" + `
{
"project": {
"name": "awesome-app",
"language": "go",
"dependencies": {
"direct": [
{"name": "github.com/gorilla/mux", "version": "v1.8.0"},
{"name": "github.com/stretchr/testify", "version": "v1.8.4"}
],
"indirect": 15
},
"metrics": {
"lines_of_code": 5420,
"test_coverage": 87.3,
"complexity": {
"average": 3.2,
"max": 12
}
}
}
}
` + "```" + `
`
type ProjectAnalysis struct {
Project struct {
Name string `json:"name"`
Language string `json:"language"`
Dependencies struct {
Direct []struct {
Name string `json:"name"`
Version string `json:"version"`
} `json:"direct"`
Indirect int `json:"indirect"`
} `json:"dependencies"`
Metrics struct {
LinesOfCode int `json:"lines_of_code"`
TestCoverage float64 `json:"test_coverage"`
Complexity struct {
Average float64 `json:"average"`
Max int `json:"max"`
} `json:"complexity"`
} `json:"metrics"`
} `json:"project"`
}
analysis, err := result.Extract[ProjectAnalysis](response)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Project: %s (%s)\n", analysis.Project.Name, analysis.Project.Language)
fmt.Printf("Test Coverage: %.1f%%\n", analysis.Project.Metrics.TestCoverage)
fmt.Printf("Direct Dependencies: %d\n", len(analysis.Project.Dependencies.Direct))
}
Output: Project: awesome-app (go) Test Coverage: 87.3% Direct Dependencies: 2
Example (ErrorHandling) ¶
ExampleExtract_errorHandling demonstrates error handling during extraction.
package main
import (
"fmt"
"chainguard.dev/driftlessaf/agents/result"
)
func main() {
// Response with invalid JSON
response := `Here's the data:
` + "```json" + `
{
"status": "error",
"message": "Missing closing brace"
` + "```" + `
`
type Status struct {
Status string `json:"status"`
Message string `json:"message"`
}
_, err := result.Extract[Status](response)
if err != nil {
fmt.Printf("Error: JSON parsing failed\n")
}
}
Output: Error: JSON parsing failed
Example (FileOperations) ¶
ExampleExtract_fileOperations demonstrates extracting file modification instructions.
package main
import (
"fmt"
"log"
"chainguard.dev/driftlessaf/agents/result"
)
func main() {
// AI response with file modifications
response := `I'll fix the issue in your code:
` + "```json" + `
{
"files": [
{
"filename": "main.go",
"action": "modify",
"content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println(\"Hello, World!\")\n}"
},
{
"filename": "go.mod",
"action": "create",
"content": "module example\n\ngo 1.21"
}
],
"summary": "Added missing import and created go.mod file"
}
` + "```" + `
These changes should resolve the compilation error.`
type FileOperation struct {
Files []struct {
Filename string `json:"filename"`
Action string `json:"action"`
Content string `json:"content"`
} `json:"files"`
Summary string `json:"summary"`
}
ops, err := result.Extract[FileOperation](response)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Summary: %s\n", ops.Summary)
for _, file := range ops.Files {
fmt.Printf("- %s file: %s\n", file.Action, file.Filename)
}
}
Output: Summary: Added missing import and created go.mod file - modify file: main.go - create file: go.mod
func ExtractJSON ¶
ExtractJSON extracts JSON content from a text response that may contain markdown code blocks. It looks for content between ```json and ``` markers, or returns the input trimmed if no markers are found.
Example ¶
ExampleExtractJSON demonstrates extracting JSON from various markdown formats.
package main
import (
"fmt"
"chainguard.dev/driftlessaf/agents/result"
)
func main() {
// Standard markdown code block
response := `Here is the requested data:
` + "```json" + `
{
"status": "success",
"count": 42
}
` + "```" + `
Additional information follows.`
json := result.ExtractJSON(response)
fmt.Println(json)
}
Output: { "status": "success", "count": 42 }
Example (EmptyBlock) ¶
ExampleExtractJSON_emptyBlock demonstrates handling of empty JSON blocks.
package main
import (
"fmt"
"chainguard.dev/driftlessaf/agents/result"
)
func main() {
// Empty JSON block
response := `The operation failed.
` + "```json" + `
` + "```" + `
No data available.`
json := result.ExtractJSON(response)
fmt.Printf("Result: %q\n", json)
}
Output: Result: ""
Example (MultipleBlocks) ¶
ExampleExtractJSON_multipleBlocks demonstrates behavior with multiple JSON blocks.
package main
import (
"fmt"
"chainguard.dev/driftlessaf/agents/result"
)
func main() {
// Response with multiple JSON blocks (only first is extracted)
response := `First dataset:
` + "```json" + `
{"dataset": 1, "value": "first"}
` + "```" + `
Second dataset:
` + "```json" + `
{"dataset": 2, "value": "second"}
` + "```" + `
`
// ExtractJSON returns the first JSON block found
json := result.ExtractJSON(response)
fmt.Println(json)
}
Output: {"dataset": 1, "value": "first"}
Example (PlainJSON) ¶
ExampleExtractJSON_plainJSON demonstrates extraction when no markdown is present.
package main
import (
"fmt"
"chainguard.dev/driftlessaf/agents/result"
)
func main() {
// Plain JSON without markdown
response := `{"message": "Hello, World!", "timestamp": 1234567890}`
json := result.ExtractJSON(response)
fmt.Println(json)
}
Output: {"message": "Hello, World!", "timestamp": 1234567890}
Types ¶
This section is empty.