Implement Scriptorium subprocess adapter
This commit is contained in:
203
internal/adapters/scriptorium/fake.go
Normal file
203
internal/adapters/scriptorium/fake.go
Normal file
@@ -0,0 +1,203 @@
|
||||
package scriptorium
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"gitea.maximumdirect.net/eric/narratio/internal/adapters/subprocess"
|
||||
)
|
||||
|
||||
// NoopRunner is a deterministic no-op scriptorium adapter.
|
||||
type NoopRunner struct{}
|
||||
|
||||
// RunArtifact returns requested output path with placeholder metadata.
|
||||
func (n *NoopRunner) RunArtifact(ctx context.Context, req RunArtifactRequest) (ArtifactResult, error) {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return ArtifactResult{}, err
|
||||
}
|
||||
if err := materializeRunPlaceholders(req); err != nil {
|
||||
return ArtifactResult{}, err
|
||||
}
|
||||
return ArtifactResult{
|
||||
OutputPath: req.OutputPath,
|
||||
StdoutLogPath: req.StdoutLogPath,
|
||||
StderrLogPath: req.StderrLogPath,
|
||||
GeneratedConfigPath: req.GeneratedConfigPath,
|
||||
CommandMode: CommandModeRun,
|
||||
PromptID: req.PromptID,
|
||||
ProfileID: req.ProfileID,
|
||||
Metadata: map[string]any{"placeholder": true},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// RenderArtifact returns requested output path with placeholder metadata.
|
||||
func (n *NoopRunner) RenderArtifact(ctx context.Context, req RenderArtifactRequest) (ArtifactResult, error) {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return ArtifactResult{}, err
|
||||
}
|
||||
if err := materializeRenderPlaceholders(req); err != nil {
|
||||
return ArtifactResult{}, err
|
||||
}
|
||||
return ArtifactResult{
|
||||
OutputPath: req.OutputPath,
|
||||
StdoutLogPath: req.StdoutLogPath,
|
||||
StderrLogPath: req.StderrLogPath,
|
||||
GeneratedConfigPath: req.GeneratedConfigPath,
|
||||
CommandMode: CommandModeRender,
|
||||
PromptID: req.PromptID,
|
||||
ProfileID: req.ProfileID,
|
||||
Metadata: map[string]any{"placeholder": true},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// FakeRunner captures requests and returns deterministic responses.
|
||||
type FakeRunner struct {
|
||||
RunRequests []RunArtifactRequest
|
||||
RenderRequests []RenderArtifactRequest
|
||||
RunErr error
|
||||
RenderErr error
|
||||
RunResult ArtifactResult
|
||||
RenderResult ArtifactResult
|
||||
}
|
||||
|
||||
// RunArtifact records request and returns configured response.
|
||||
func (f *FakeRunner) RunArtifact(ctx context.Context, req RunArtifactRequest) (ArtifactResult, error) {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return ArtifactResult{}, err
|
||||
}
|
||||
f.RunRequests = append(f.RunRequests, req)
|
||||
if f.RunErr != nil {
|
||||
return ArtifactResult{}, f.RunErr
|
||||
}
|
||||
if err := materializeRunPlaceholders(req); err != nil {
|
||||
return ArtifactResult{}, err
|
||||
}
|
||||
res := f.RunResult
|
||||
if res.OutputPath == "" {
|
||||
res.OutputPath = req.OutputPath
|
||||
}
|
||||
if res.StdoutLogPath == "" {
|
||||
res.StdoutLogPath = req.StdoutLogPath
|
||||
}
|
||||
if res.StderrLogPath == "" {
|
||||
res.StderrLogPath = req.StderrLogPath
|
||||
}
|
||||
if res.GeneratedConfigPath == "" {
|
||||
res.GeneratedConfigPath = req.GeneratedConfigPath
|
||||
}
|
||||
if res.CommandMode == "" {
|
||||
res.CommandMode = CommandModeRun
|
||||
}
|
||||
if res.PromptID == "" {
|
||||
res.PromptID = req.PromptID
|
||||
}
|
||||
if res.ProfileID == "" {
|
||||
res.ProfileID = req.ProfileID
|
||||
}
|
||||
if res.Metadata == nil {
|
||||
res.Metadata = map[string]any{"fake": true}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// RenderArtifact records request and returns configured response.
|
||||
func (f *FakeRunner) RenderArtifact(ctx context.Context, req RenderArtifactRequest) (ArtifactResult, error) {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return ArtifactResult{}, err
|
||||
}
|
||||
f.RenderRequests = append(f.RenderRequests, req)
|
||||
if f.RenderErr != nil {
|
||||
return ArtifactResult{}, f.RenderErr
|
||||
}
|
||||
if err := materializeRenderPlaceholders(req); err != nil {
|
||||
return ArtifactResult{}, err
|
||||
}
|
||||
res := f.RenderResult
|
||||
if res.OutputPath == "" {
|
||||
res.OutputPath = req.OutputPath
|
||||
}
|
||||
if res.StdoutLogPath == "" {
|
||||
res.StdoutLogPath = req.StdoutLogPath
|
||||
}
|
||||
if res.StderrLogPath == "" {
|
||||
res.StderrLogPath = req.StderrLogPath
|
||||
}
|
||||
if res.GeneratedConfigPath == "" {
|
||||
res.GeneratedConfigPath = req.GeneratedConfigPath
|
||||
}
|
||||
if res.CommandMode == "" {
|
||||
res.CommandMode = CommandModeRender
|
||||
}
|
||||
if res.PromptID == "" {
|
||||
res.PromptID = req.PromptID
|
||||
}
|
||||
if res.ProfileID == "" {
|
||||
res.ProfileID = req.ProfileID
|
||||
}
|
||||
if res.Metadata == nil {
|
||||
res.Metadata = map[string]any{"fake": true}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func materializeRunPlaceholders(req RunArtifactRequest) error {
|
||||
if req.OutputPath != "" {
|
||||
if err := subprocess.WriteFileAtomic(req.OutputPath, []byte("scriptorium noop/fake run artifact\n"), 0o644); err != nil {
|
||||
return fmt.Errorf("write run output %q: %w", req.OutputPath, err)
|
||||
}
|
||||
}
|
||||
if req.GeneratedConfigPath != "" {
|
||||
payload := map[string]any{
|
||||
"schema": "scriptorium.generated.v1",
|
||||
"placeholder": true,
|
||||
"mode": CommandModeRun,
|
||||
"prompt_id": req.PromptID,
|
||||
"output_path": req.OutputPath,
|
||||
}
|
||||
if err := subprocess.WriteYAMLAtomic(req.GeneratedConfigPath, payload, 0o644); err != nil {
|
||||
return fmt.Errorf("write generated config %q: %w", req.GeneratedConfigPath, err)
|
||||
}
|
||||
}
|
||||
if req.StdoutLogPath != "" {
|
||||
if err := subprocess.WriteFileAtomic(req.StdoutLogPath, []byte("scriptorium noop/fake run stdout placeholder\n"), 0o644); err != nil {
|
||||
return fmt.Errorf("write stdout log %q: %w", req.StdoutLogPath, err)
|
||||
}
|
||||
}
|
||||
if req.StderrLogPath != "" {
|
||||
if err := subprocess.WriteFileAtomic(req.StderrLogPath, []byte("scriptorium noop/fake run stderr placeholder\n"), 0o644); err != nil {
|
||||
return fmt.Errorf("write stderr log %q: %w", req.StderrLogPath, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func materializeRenderPlaceholders(req RenderArtifactRequest) error {
|
||||
if req.OutputPath != "" {
|
||||
if err := subprocess.WriteFileAtomic(req.OutputPath, []byte("{\"schema\":\"scriptorium.render.v1\",\"placeholder\":true}\n"), 0o644); err != nil {
|
||||
return fmt.Errorf("write render output %q: %w", req.OutputPath, err)
|
||||
}
|
||||
}
|
||||
if req.GeneratedConfigPath != "" {
|
||||
payload := map[string]any{
|
||||
"schema": "scriptorium.generated.v1",
|
||||
"placeholder": true,
|
||||
"mode": CommandModeRender,
|
||||
"prompt_id": req.PromptID,
|
||||
"output_path": req.OutputPath,
|
||||
}
|
||||
if err := subprocess.WriteYAMLAtomic(req.GeneratedConfigPath, payload, 0o644); err != nil {
|
||||
return fmt.Errorf("write generated config %q: %w", req.GeneratedConfigPath, err)
|
||||
}
|
||||
}
|
||||
if req.StdoutLogPath != "" {
|
||||
if err := subprocess.WriteFileAtomic(req.StdoutLogPath, []byte("scriptorium noop/fake render stdout placeholder\n"), 0o644); err != nil {
|
||||
return fmt.Errorf("write stdout log %q: %w", req.StdoutLogPath, err)
|
||||
}
|
||||
}
|
||||
if req.StderrLogPath != "" {
|
||||
if err := subprocess.WriteFileAtomic(req.StderrLogPath, []byte("scriptorium noop/fake render stderr placeholder\n"), 0o644); err != nil {
|
||||
return fmt.Errorf("write stderr log %q: %w", req.StderrLogPath, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user