Write prompt data packages as YAML

This commit is contained in:
2026-06-09 21:08:17 +00:00
parent 2483c2362d
commit 0b516d9762
11 changed files with 394 additions and 255 deletions

View File

@@ -522,7 +522,19 @@ func GenerateReport(ctx context.Context, req ReportRequest) (*ReportResult, erro
if err != nil {
return nil, err
}
dataPackage, err := promptinput.BuildWithRecentChanges(briefingPackage, recentChanges)
metadata := state.BuildMetadata(req.Resolved, briefingPackage, state.ArtifactPaths{
Briefing: briefingPath,
ModuleSnapshot: moduleSnapshotPath,
Metadata: paths.Metadata,
DataPackage: paths.DataPackage,
Preflight: paths.Preflight,
RenderedReport: paths.RenderedReport,
})
dataPackage, err := promptinput.Build(promptinput.BuildRequest{
Metadata: promptMetadata(metadata),
Modules: moduleSnapshot,
RecentChanges: recentChanges,
})
if err != nil {
return nil, err
}
@@ -530,6 +542,7 @@ func GenerateReport(ctx context.Context, req ReportRequest) (*ReportResult, erro
if err != nil {
return nil, err
}
metadata.DataPackagePath = dataPackagePath
renderer := req.Renderer
if renderer == nil {
@@ -554,14 +567,7 @@ func GenerateReport(ctx context.Context, req ReportRequest) (*ReportResult, erro
return nil, err
}
}
metadata := state.BuildMetadata(req.Resolved, briefingPackage, state.ArtifactPaths{
Briefing: briefingPath,
ModuleSnapshot: moduleSnapshotPath,
Metadata: paths.Metadata,
DataPackage: dataPackagePath,
Preflight: preflightPath,
RenderedReport: paths.RenderedReport,
})
metadata.PreflightPath = preflightPath
metadataPath, metadataErr := store.SaveMetadata(ctx, metadata)
if metadataErr != nil {
return nil, metadataErr
@@ -894,6 +900,19 @@ func BuildModuleSnapshot(req ModuleSnapshotRequest, bundle *weatherdata.Bundle)
return module.NewSnapshot(outputs)
}
func promptMetadata(metadata state.Metadata) promptinput.Metadata {
return promptinput.Metadata{
RunID: metadata.RunID,
ReportID: metadata.ReportID,
Variant: metadata.Variant,
PromptID: metadata.PromptID,
GeneratedAt: metadata.GeneratedAt,
Timezone: metadata.Timezone,
ValidPeriod: metadata.ValidPeriod,
SourceWarnings: metadata.SourceWarnings,
}
}
func buildDerivedFacts(cfg config.Config, resolved report.Resolved, collected facts.CollectedFacts) (facts.DerivedFacts, error) {
dayparts := make([]forecast.DaypartDefinition, 0, len(cfg.Dayparts))
for _, daypart := range cfg.Dayparts {

View File

@@ -17,6 +17,7 @@ import (
"gitea.maximumdirect.net/eric/weatherreporter/internal/config"
"gitea.maximumdirect.net/eric/weatherreporter/internal/forecast"
"gitea.maximumdirect.net/eric/weatherreporter/internal/module"
"gitea.maximumdirect.net/eric/weatherreporter/internal/promptinput"
"gitea.maximumdirect.net/eric/weatherreporter/internal/report"
"gitea.maximumdirect.net/eric/weatherreporter/internal/state"
)
@@ -206,31 +207,32 @@ func TestGenerateReportWritesReportAndPreflight(t *testing.T) {
if err != nil {
t.Fatalf("read data package: %v", err)
}
if !strings.Contains(string(data), `"recentChanges"`) || !strings.Contains(string(data), `data_package.v1`) {
if !strings.HasSuffix(result.DataPackagePath, ".data_package.yaml") {
t.Fatalf("DataPackagePath = %q, want YAML data package path", result.DataPackagePath)
}
if !strings.Contains(string(data), "schema_version: weatherreporter.data_package.v2") ||
!strings.Contains(string(data), "recent_changes:") ||
!strings.Contains(string(data), "current_conditions:") ||
!strings.Contains(string(data), "area_forecast_discussion:") {
t.Fatalf("data package missing expected content:\n%s", string(data))
}
var savedDataPackage struct {
Report struct {
CurrentLocalDate string `json:"currentLocalDate"`
} `json:"report"`
Briefing briefing.Package `json:"briefing"`
}
if err := json.Unmarshal(data, &savedDataPackage); err != nil {
savedDataPackage, err := promptinput.LoadYAML(data)
if err != nil {
t.Fatalf("decode data package: %v", err)
}
if savedDataPackage.Report.CurrentLocalDate != "2026-05-29" {
t.Fatalf("data package currentLocalDate = %q, want 2026-05-29", savedDataPackage.Report.CurrentLocalDate)
}
location := savedDataPackage.Briefing.Metadata.Location
if location == nil || location.ID != "home" || location.Name != "Brentwood" || location.Region != "St. Louis Metro" || location.Timezone != "America/Chicago" {
t.Fatalf("data package location = %#v, want configured prompt location", location)
if _, ok := savedDataPackage.Briefing.Values["metadata"]; !ok {
t.Fatal("data package metadata stanza missing")
}
current := savedDataPackage.Briefing.CurrentConditions
if current == nil || current.ConditionText != "Clear" || current.TemperatureF == nil || *current.TemperatureF != 75 {
t.Fatalf("data package current conditions = %#v, want current conditions", current)
current, ok := savedDataPackage.Briefing.Values["current_conditions"].(map[string]any)
if !ok || current["condition_text"] != "Clear" {
t.Fatalf("data package current conditions = %#v, want current conditions", savedDataPackage.Briefing.Values["current_conditions"])
}
if savedDataPackage.Briefing.Daily == nil || savedDataPackage.Briefing.Daily.WeatherStory == nil || savedDataPackage.Briefing.Daily.WeatherStory.Title != "Several Chances for Rain Through Monday" {
t.Fatalf("data package weather story = %#v, want weather story title", savedDataPackage.Briefing.Daily)
story, ok := savedDataPackage.Briefing.Values["weather_story"].(map[string]any)
if !ok || story["title"] != "Several Chances for Rain Through Monday" {
t.Fatalf("data package weather story = %#v, want weather story title", savedDataPackage.Briefing.Values["weather_story"])
}
if !strings.Contains(string(data), "Short-term AFD narrative for generated report.") || !strings.Contains(string(data), "Long-term AFD narrative for generated report.") {
t.Fatalf("data package missing AFD short/long-term discussion:\n%s", string(data))
@@ -1012,7 +1014,7 @@ func TestGenerateStormReportWritesReport(t *testing.T) {
if err != nil {
t.Fatalf("read data package: %v", err)
}
if !strings.Contains(string(data), `"storm"`) || !strings.Contains(string(data), `"weather.storm_report"`) {
if !strings.Contains(string(data), "id: storm") || !strings.Contains(string(data), "prompt_id: weather.storm_report") || !strings.Contains(string(data), "precip_timing:") {
t.Fatalf("data package missing storm content:\n%s", string(data))
}
}