Files
narratio/internal/stage/placeholders.go

167 lines
6.1 KiB
Go

package stage
import (
"context"
"fmt"
"path/filepath"
"gitea.maximumdirect.net/eric/narratio/internal/adapters/analyzer"
"gitea.maximumdirect.net/eric/narratio/internal/adapters/audita"
"gitea.maximumdirect.net/eric/narratio/internal/adapters/notify"
"gitea.maximumdirect.net/eric/narratio/internal/adapters/seriatim"
"gitea.maximumdirect.net/eric/narratio/internal/adapters/storage"
"gitea.maximumdirect.net/eric/narratio/internal/artifacts"
"gitea.maximumdirect.net/eric/narratio/internal/manifest"
)
const placeholderMessage = "placeholder stage: no real work executed"
type placeholderStage struct {
name string
}
func (s placeholderStage) Name() string { return s.name }
func (s placeholderStage) Declares() IODecl {
return IODecl{
Inputs: []artifacts.Ref{{Kind: "artifact", Category: "input", RelativePath: s.name + ".input.placeholder"}},
Outputs: []artifacts.Ref{{Kind: "artifact", Category: "output", RelativePath: s.name + ".output.placeholder"}},
}
}
func (s placeholderStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*StageResult, error) {
result := &StageResult{
Metadata: map[string]any{
"placeholder": true,
"stage": s.name,
"message": placeholderMessage,
},
}
if env == nil || env.Config == nil || env.ArtifactStore == nil {
return result, nil
}
sessionID := m.SessionID
if sessionID == "" && env.Config.Session != nil {
sessionID = env.Config.Session.SessionID
}
if sessionID == "" {
return result, nil
}
paths := env.ArtifactStore.SessionPaths(sessionID)
switch s.name {
case "merge":
if env.Seriatim != nil {
req := seriatim.MergeRequest{
GeneratedConfigPath: filepath.Join(paths.ConfigDir, "seriatim.generated.yml"),
InputTranscriptPaths: []string{filepath.Join(paths.TranscriptsNormalizedDir, "placeholder-speaker.json")},
OutputMergedTranscriptPath: filepath.Join(paths.TranscriptsDir, "merged.json"),
StdoutLogPath: filepath.Join(paths.LogsDir, "seriatim.stdout.log"),
StderrLogPath: filepath.Join(paths.LogsDir, "seriatim.stderr.log"),
}
resp, err := env.Seriatim.Run(ctx, req)
if err != nil {
return nil, fmt.Errorf("placeholder merge adapter call failed: %w", err)
}
result.Outputs = append(result.Outputs, artifacts.Ref{Kind: "transcript_merged", Category: "transcripts", SessionID: sessionID, AbsolutePath: resp.MergedTranscriptPath})
result.Logs = append(result.Logs, req.StdoutLogPath, req.StderrLogPath)
result.GeneratedConfigs = append(result.GeneratedConfigs, req.GeneratedConfigPath)
}
case "polish":
if env.Audita != nil {
req := audita.PolishRequest{
GeneratedConfigPath: filepath.Join(paths.ConfigDir, "audita.generated.yml"),
MergedTranscriptPath: filepath.Join(paths.TranscriptsDir, "merged.json"),
OutputProcessedPath: filepath.Join(paths.TranscriptsDir, "processed.json"),
StdoutLogPath: filepath.Join(paths.LogsDir, "audita.stdout.log"),
StderrLogPath: filepath.Join(paths.LogsDir, "audita.stderr.log"),
}
resp, err := env.Audita.Run(ctx, req)
if err != nil {
return nil, fmt.Errorf("placeholder polish adapter call failed: %w", err)
}
result.Outputs = append(result.Outputs, artifacts.Ref{Kind: "transcript_processed", Category: "transcripts", SessionID: sessionID, AbsolutePath: resp.ProcessedTranscriptPath})
result.Logs = append(result.Logs, req.StdoutLogPath, req.StderrLogPath)
result.GeneratedConfigs = append(result.GeneratedConfigs, req.GeneratedConfigPath)
}
case "analyze":
if env.Analyzer != nil {
req := analyzer.AnalyzeRequest{
ArtifactType: "session-log",
ProcessedTranscriptPath: filepath.Join(paths.TranscriptsDir, "processed.json"),
ContextReferences: []string{"previous-session"},
OutputPath: filepath.Join(paths.ArtifactsDir, "session-log.md"),
GeneratedConfigPath: filepath.Join(paths.ConfigDir, "analyzer.session-log.generated.yml"),
StdoutLogPath: filepath.Join(paths.LogsDir, "analyzer.session-log.stdout.log"),
StderrLogPath: filepath.Join(paths.LogsDir, "analyzer.session-log.stderr.log"),
}
resp, err := env.Analyzer.Run(ctx, req)
if err != nil {
return nil, fmt.Errorf("placeholder analyze adapter call failed: %w", err)
}
result.Outputs = append(result.Outputs, artifacts.Ref{Kind: "artifact", Category: "artifacts", SessionID: sessionID, AbsolutePath: resp.ArtifactPath})
result.Logs = append(result.Logs, req.StdoutLogPath, req.StderrLogPath)
result.GeneratedConfigs = append(result.GeneratedConfigs, req.GeneratedConfigPath)
}
case "archive":
if env.Storage != nil {
req := storage.ArchiveRequest{
SessionID: sessionID,
ManifestPath: paths.ManifestPath,
Items: []storage.ArchiveItem{{
Kind: "artifact",
LocalPath: filepath.Join(paths.ArtifactsDir, "session-log.md"),
RemoteKey: "sessions/" + sessionID + "/artifacts/session-log.md",
}},
}
_, err := env.Storage.Archive(ctx, req)
if err != nil {
return nil, fmt.Errorf("placeholder archive adapter call failed: %w", err)
}
}
case "notify":
if env.Notifier != nil {
req := notify.SendRequest{
Subject: "narratio placeholder run complete",
Body: "placeholder stage execution finished",
Metadata: map[string]string{
"session_id": sessionID,
},
}
_, err := env.Notifier.Send(ctx, req)
if err != nil {
return nil, fmt.Errorf("placeholder notify adapter call failed: %w", err)
}
}
}
return result, nil
}
// All returns the canonical ordered stage list for full pipeline execution.
func All() []Stage {
return []Stage{
prepareStage{},
transcribeStage{},
placeholderStage{name: "normalize"},
placeholderStage{name: "merge"},
placeholderStage{name: "polish"},
placeholderStage{name: "analyze"},
placeholderStage{name: "archive"},
placeholderStage{name: "notify"},
}
}
// Select returns one stage by exact name from the canonical stage set.
func Select(name string) (Stage, error) {
for _, s := range All() {
if s.Name() == name {
return s, nil
}
}
return nil, fmt.Errorf("unknown stage %q", name)
}