package promptkit_test import ( "context" "errors" "strings" "testing" "go.maximumdirect.net/promptkit" ) func TestNestedErrorsRetainEachCauseWithoutDuplicatingDiagnostics(t *testing.T) { cause := errors.New("independent-leaf-diagnostic") for range 10 { parent := newSimpleEngine(t, "parent", promptkit.WithLLMClient(&fakeLLMClient{err: cause})) _, err := parent.Run(context.Background(), promptkit.RunRequest{PromptID: "prompt"}) if !errors.Is(err, cause) || !errors.Is(err, promptkit.ErrLLMGenerate) { t.Fatalf("lost owner or cause: %v", err) } if strings.Count(err.Error(), "independent-leaf-diagnostic") != 1 { t.Fatalf("duplicated leaf: %v", err) } cause = err } } type nestedErrorReader struct{ cause error } func (r nestedErrorReader) Read(context.Context, promptkit.ArtifactRef) (*promptkit.Artifact, error) { return nil, r.cause } func TestNestedEngineErrorKeepsOwningOperation(t *testing.T) { child := newSimpleEngine(t, "child") _, childErr := child.Run(context.Background(), promptkit.RunRequest{PromptID: "missing"}) if !errors.Is(childErr, promptkit.ErrPromptNotFound) { t.Fatalf("child error = %v", childErr) } client := &fakeLLMClient{err: childErr} parent := newSimpleEngine(t, "hello", promptkit.WithLLMClient(client)) _, err := parent.Run(context.Background(), promptkit.RunRequest{PromptID: "prompt"}) if !errors.Is(err, promptkit.ErrLLMGenerate) || !errors.Is(err, childErr) || !errors.Is(err, promptkit.ErrPromptNotFound) { t.Fatalf("generation error = %v", err) } readerParent := newSimpleEngine(t, "hello", promptkit.WithArtifactReader(nestedErrorReader{cause: childErr})) _, err = readerParent.Prepare(context.Background(), promptkit.RunRequest{PromptID: "prompt", Inputs: map[string]promptkit.ArtifactRef{"extra": promptkit.Inline("data")}}) if !errors.Is(err, promptkit.ErrArtifactLoad) || !errors.Is(err, childErr) || !errors.Is(err, promptkit.ErrPromptNotFound) { t.Fatalf("artifact error = %v", err) } }