Add Scriptorium render diagnostics
This commit is contained in:
@@ -2,6 +2,7 @@ package stage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -130,6 +131,79 @@ func (analyzeStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*S
|
||||
return nil, fmt.Errorf("analyze: resolve timeout: %w", err)
|
||||
}
|
||||
|
||||
logPaths := []string{}
|
||||
generatedConfigs := []string{}
|
||||
meta := map[string]any{
|
||||
"stage": "analyze",
|
||||
"artifact_name": artifactName,
|
||||
"prompt_id": artifactCfg.PromptID,
|
||||
"profile_id": artifactCfg.ProfileID,
|
||||
"binary": env.Config.Pipeline.Scriptorium.Binary,
|
||||
"config_path": env.Config.Pipeline.Scriptorium.ConfigPath,
|
||||
"input_paths": inputPaths,
|
||||
"input_names": sortedMapKeys(inputPaths),
|
||||
"omitted_optional_inputs": omittedOptionalInputs,
|
||||
"vars": vars,
|
||||
"timeout": timeout.String(),
|
||||
"processed_transcript_path": processedTranscriptPath,
|
||||
"processed_transcript_source": processedSource,
|
||||
"render_debug_enabled": resolveRenderDebugEnabled(env.Config.Pipeline.Scriptorium.RenderDebug, artifactCfg.RenderDebug),
|
||||
}
|
||||
|
||||
if meta["render_debug_enabled"] == true {
|
||||
renderOutputPath := filepath.Join(paths.ArtifactsDir, artifactName+".render.json")
|
||||
renderStdoutPath := filepath.Join(paths.LogsDir, "scriptorium."+artifactName+".render.stdout.log")
|
||||
renderStderrPath := filepath.Join(paths.LogsDir, "scriptorium."+artifactName+".render.stderr.log")
|
||||
renderGeneratedConfigPath := filepath.Join(paths.ConfigDir, "scriptorium."+artifactName+".render.generated.yml")
|
||||
|
||||
renderReq := scriptorium.RenderArtifactRequest{
|
||||
Binary: env.Config.Pipeline.Scriptorium.Binary,
|
||||
ConfigPath: env.Config.Pipeline.Scriptorium.ConfigPath,
|
||||
PromptID: artifactCfg.PromptID,
|
||||
ProfileID: artifactCfg.ProfileID,
|
||||
InputPaths: inputPaths,
|
||||
Vars: vars,
|
||||
OutputPath: renderOutputPath,
|
||||
StdoutLogPath: renderStdoutPath,
|
||||
StderrLogPath: renderStderrPath,
|
||||
GeneratedConfigPath: renderGeneratedConfigPath,
|
||||
Timeout: timeout,
|
||||
}
|
||||
renderRes, renderErr := env.Scriptorium.RenderArtifact(ctx, renderReq)
|
||||
if renderErr != nil {
|
||||
return nil, fmt.Errorf("analyze: scriptorium render failed: %w", renderErr)
|
||||
}
|
||||
if renderRes.ValidationFailed {
|
||||
return nil, fmt.Errorf("analyze: scriptorium render returned validation_failed=true")
|
||||
}
|
||||
finalRenderOutputPath := coalesceString(renderRes.OutputPath, renderReq.OutputPath)
|
||||
if err := requireNonEmptyFile(finalRenderOutputPath, "session recap render output"); err != nil {
|
||||
return nil, fmt.Errorf("analyze: %w", err)
|
||||
}
|
||||
if err := validateJSONFile(finalRenderOutputPath); err != nil {
|
||||
return nil, fmt.Errorf("analyze: render diagnostics %q invalid json: %w", finalRenderOutputPath, err)
|
||||
}
|
||||
|
||||
logPaths = append(logPaths, renderStdoutPath, renderStderrPath)
|
||||
generatedConfigs = append(generatedConfigs, renderGeneratedConfigPath)
|
||||
meta["render_output_path"] = finalRenderOutputPath
|
||||
meta["render_stdout_log_path"] = renderStdoutPath
|
||||
meta["render_stderr_log_path"] = renderStderrPath
|
||||
meta["render_generated_config_path"] = renderGeneratedConfigPath
|
||||
meta["render_adapter_exit_code"] = renderRes.ExitCode
|
||||
meta["render_adapter_duration_ms"] = renderRes.Duration.Milliseconds()
|
||||
meta["render_adapter_command_mode"] = renderRes.CommandMode
|
||||
meta["render_adapter_prompt_id"] = renderRes.PromptID
|
||||
meta["render_adapter_profile_id"] = renderRes.ProfileID
|
||||
meta["render_adapter_output_path"] = renderRes.OutputPath
|
||||
meta["render_adapter_generated_config"] = renderRes.GeneratedConfigPath
|
||||
meta["render_adapter_stdout_log_path"] = renderRes.StdoutLogPath
|
||||
meta["render_adapter_stderr_log_path"] = renderRes.StderrLogPath
|
||||
if renderRes.Metadata != nil {
|
||||
meta["render_adapter_metadata"] = renderRes.Metadata
|
||||
}
|
||||
}
|
||||
|
||||
req := scriptorium.RunArtifactRequest{
|
||||
Binary: env.Config.Pipeline.Scriptorium.Binary,
|
||||
ConfigPath: env.Config.Pipeline.Scriptorium.ConfigPath,
|
||||
@@ -175,43 +249,30 @@ func (analyzeStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*S
|
||||
AbsolutePath: finalOutputPath,
|
||||
}
|
||||
|
||||
meta := map[string]any{
|
||||
"stage": "analyze",
|
||||
"artifact_name": artifactName,
|
||||
"prompt_id": artifactCfg.PromptID,
|
||||
"profile_id": artifactCfg.ProfileID,
|
||||
"output_path": finalOutputPath,
|
||||
"generated_config_path": generatedConfigPath,
|
||||
"stdout_log_path": stdoutLogPath,
|
||||
"stderr_log_path": stderrLogPath,
|
||||
"input_paths": inputPaths,
|
||||
"input_names": sortedMapKeys(inputPaths),
|
||||
"omitted_optional_inputs": omittedOptionalInputs,
|
||||
"vars": vars,
|
||||
"timeout": timeout.String(),
|
||||
"binary": env.Config.Pipeline.Scriptorium.Binary,
|
||||
"config_path": env.Config.Pipeline.Scriptorium.ConfigPath,
|
||||
"processed_transcript_path": processedTranscriptPath,
|
||||
"processed_transcript_source": processedSource,
|
||||
"adapter_exit_code": res.ExitCode,
|
||||
"adapter_duration_ms": res.Duration.Milliseconds(),
|
||||
"adapter_command_mode": res.CommandMode,
|
||||
"adapter_prompt_id": res.PromptID,
|
||||
"adapter_profile_id": res.ProfileID,
|
||||
"adapter_validation_failed": res.ValidationFailed,
|
||||
"adapter_output_path": res.OutputPath,
|
||||
"adapter_generated_config": res.GeneratedConfigPath,
|
||||
"adapter_stdout_log_path": res.StdoutLogPath,
|
||||
"adapter_stderr_log_path": res.StderrLogPath,
|
||||
}
|
||||
logPaths = append(logPaths, stdoutLogPath, stderrLogPath)
|
||||
generatedConfigs = append(generatedConfigs, generatedConfigPath)
|
||||
meta["output_path"] = finalOutputPath
|
||||
meta["generated_config_path"] = generatedConfigPath
|
||||
meta["stdout_log_path"] = stdoutLogPath
|
||||
meta["stderr_log_path"] = stderrLogPath
|
||||
meta["adapter_exit_code"] = res.ExitCode
|
||||
meta["adapter_duration_ms"] = res.Duration.Milliseconds()
|
||||
meta["adapter_command_mode"] = res.CommandMode
|
||||
meta["adapter_prompt_id"] = res.PromptID
|
||||
meta["adapter_profile_id"] = res.ProfileID
|
||||
meta["adapter_validation_failed"] = res.ValidationFailed
|
||||
meta["adapter_output_path"] = res.OutputPath
|
||||
meta["adapter_generated_config"] = res.GeneratedConfigPath
|
||||
meta["adapter_stdout_log_path"] = res.StdoutLogPath
|
||||
meta["adapter_stderr_log_path"] = res.StderrLogPath
|
||||
if res.Metadata != nil {
|
||||
meta["adapter_metadata"] = res.Metadata
|
||||
}
|
||||
|
||||
return &StageResult{
|
||||
Outputs: []artifacts.Ref{artifactRef},
|
||||
Logs: []string{stdoutLogPath, stderrLogPath},
|
||||
GeneratedConfigs: []string{generatedConfigPath},
|
||||
Logs: logPaths,
|
||||
GeneratedConfigs: generatedConfigs,
|
||||
Metadata: meta,
|
||||
}, nil
|
||||
}
|
||||
@@ -460,3 +521,22 @@ func coalesceString(primary, fallback string) string {
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
|
||||
func resolveRenderDebugEnabled(global bool, perArtifact *bool) bool {
|
||||
if perArtifact == nil {
|
||||
return global
|
||||
}
|
||||
return *perArtifact
|
||||
}
|
||||
|
||||
func validateJSONFile(path string) error {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("read file: %w", err)
|
||||
}
|
||||
var payload any
|
||||
if err := json.Unmarshal(data, &payload); err != nil {
|
||||
return fmt.Errorf("decode json: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user