Added a configurable timeout knob
This commit is contained in:
@@ -40,6 +40,7 @@ type runConfig struct {
|
||||
temperature float64
|
||||
maxTokens int
|
||||
schemaDir string
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
type serveConfig struct {
|
||||
@@ -93,10 +94,13 @@ func runCommand(args []string, stdout, stderr io.Writer) int {
|
||||
fmt.Fprintf(stderr, "input parse error: %v\n", err)
|
||||
return ExitRuntimeError
|
||||
}
|
||||
varMappings, err := parseMappings(cfg.varRaw, false)
|
||||
if err != nil {
|
||||
fmt.Fprintf(stderr, "var parse error: %v\n", err)
|
||||
return ExitRuntimeError
|
||||
varMappings := map[string]string{}
|
||||
if len(cfg.varRaw) > 0 {
|
||||
varMappings, err = parseMappings(cfg.varRaw, false)
|
||||
if err != nil {
|
||||
fmt.Fprintf(stderr, "var parse error: %v\n", err)
|
||||
return ExitRuntimeError
|
||||
}
|
||||
}
|
||||
|
||||
inputs := make(map[string]domain.ArtifactRef, len(inputMappings))
|
||||
@@ -108,7 +112,7 @@ func runCommand(args []string, stdout, stderr io.Writer) int {
|
||||
BaseURL: cfg.llmBaseURL,
|
||||
APIKey: cfg.llmAPIKey,
|
||||
Model: cfg.model,
|
||||
Timeout: 60 * time.Second,
|
||||
Timeout: cfg.timeout,
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Fprintf(stderr, "llm client error: %v\n", err)
|
||||
@@ -205,6 +209,7 @@ func parseRunArgs(args []string) (*runConfig, error) {
|
||||
fs.Float64Var(&cfg.temperature, "temperature", 0, "optional temperature override")
|
||||
fs.IntVar(&cfg.maxTokens, "max-tokens", 0, "optional max tokens override")
|
||||
fs.StringVar(&cfg.schemaDir, "schema-dir", ".", "base directory for validation schemas")
|
||||
fs.DurationVar(&cfg.timeout, "timeout", 10*time.Minute, "LLM request timeout")
|
||||
|
||||
if err := fs.Parse(args); err != nil {
|
||||
return nil, err
|
||||
@@ -249,7 +254,7 @@ func parseServeArgs(args []string) (*serveConfig, error) {
|
||||
fs.StringVar(&cfg.llmBaseURL, "llm-base-url", "", "OpenAI-compatible base URL including /v1")
|
||||
fs.StringVar(&cfg.llmAPIKey, "llm-api-key", "", "optional API key")
|
||||
fs.StringVar(&cfg.model, "model", "", "optional default model")
|
||||
fs.DurationVar(&cfg.timeout, "timeout", 60*time.Second, "LLM request timeout")
|
||||
fs.DurationVar(&cfg.timeout, "timeout", 10*time.Minute, "LLM request timeout")
|
||||
|
||||
if err := fs.Parse(args); err != nil {
|
||||
return nil, err
|
||||
@@ -346,6 +351,6 @@ func printSummary(stderr io.Writer, res *domain.RunResult) {
|
||||
|
||||
func printUsage(w io.Writer) {
|
||||
fmt.Fprintln(w, "usage: scriptorium <run|serve> ...")
|
||||
fmt.Fprintln(w, " run: scriptorium run --profile-dir DIR --profile-id ID --input name=path [--input ...] --llm-base-url URL --model NAME [--var k=v] [--out path]")
|
||||
fmt.Fprintln(w, " serve: scriptorium serve --addr :8080 --profile-dir DIR --llm-base-url URL [--schema-dir DIR] [--llm-api-key KEY] [--model NAME]")
|
||||
fmt.Fprintln(w, " run: scriptorium run --profile-dir DIR --profile-id ID --input name=path [--input ...] --llm-base-url URL --model NAME [--var k=v] [--out path] [--timeout 10m]")
|
||||
fmt.Fprintln(w, " serve: scriptorium serve --addr :8080 --profile-dir DIR --llm-base-url URL [--schema-dir DIR] [--llm-api-key KEY] [--model NAME] [--timeout 10m]")
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gitea.maximumdirect.net/eric/scriptorium/internal/domain"
|
||||
)
|
||||
@@ -92,6 +95,40 @@ func TestParseServeArgsRequiredFlags(t *testing.T) {
|
||||
if cfg.addr != ":8080" {
|
||||
t.Fatalf("expected default addr :8080, got %q", cfg.addr)
|
||||
}
|
||||
if cfg.timeout != 10*time.Minute {
|
||||
t.Fatalf("expected default timeout 10m, got %s", cfg.timeout)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseRunArgsTimeout(t *testing.T) {
|
||||
cfg, err := parseRunArgs([]string{
|
||||
"--profile-dir", "./profiles",
|
||||
"--profile-id", "p",
|
||||
"--input", "a=b",
|
||||
"--llm-base-url", "http://x/v1",
|
||||
"--model", "m",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("expected valid run args, got %v", err)
|
||||
}
|
||||
if cfg.timeout != 10*time.Minute {
|
||||
t.Fatalf("expected default timeout 10m, got %s", cfg.timeout)
|
||||
}
|
||||
|
||||
cfg, err = parseRunArgs([]string{
|
||||
"--profile-dir", "./profiles",
|
||||
"--profile-id", "p",
|
||||
"--input", "a=b",
|
||||
"--llm-base-url", "http://x/v1",
|
||||
"--model", "m",
|
||||
"--timeout", "2m30s",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("expected valid run args with timeout override, got %v", err)
|
||||
}
|
||||
if cfg.timeout != 2*time.Minute+30*time.Second {
|
||||
t.Fatalf("expected timeout override 2m30s, got %s", cfg.timeout)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDetermineExitCode(t *testing.T) {
|
||||
@@ -108,3 +145,26 @@ func TestDetermineExitCode(t *testing.T) {
|
||||
t.Fatalf("expected success exit code for skipped validation, got %d", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCommandVarsOptional(t *testing.T) {
|
||||
var stdout bytes.Buffer
|
||||
var stderr bytes.Buffer
|
||||
|
||||
code := runCommand([]string{
|
||||
"--profile-dir", "./profiles",
|
||||
"--profile-id", "p",
|
||||
"--input", "transcript=./t.md",
|
||||
"--llm-base-url", "://bad-url",
|
||||
"--model", "m",
|
||||
}, &stdout, &stderr)
|
||||
|
||||
if code != ExitRuntimeError {
|
||||
t.Fatalf("expected runtime error exit code, got %d", code)
|
||||
}
|
||||
if strings.Contains(stderr.String(), "var parse error") {
|
||||
t.Fatalf("expected --var to be optional, got stderr=%q", stderr.String())
|
||||
}
|
||||
if !strings.Contains(stderr.String(), "llm client error") {
|
||||
t.Fatalf("expected llm client error after parsing succeeds, got stderr=%q", stderr.String())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user