Expose explicit execution group summaries

This commit is contained in:
2026-11-14 01:29:42 +00:00
parent 159d369b9b
commit 68daa61867
3 changed files with 203 additions and 0 deletions

View File

@@ -0,0 +1,151 @@
package promptkit_test
import (
"context"
"net/http"
"testing"
"go.maximumdirect.net/promptkit"
)
func TestExecutionGroupExplicitMembershipAndTerminalTotals(t *testing.T) {
responses := []*http.Response{
observedHTTPResponse(200, `{"choices":[{"message":{"content":"initial"}}],"usage":{"prompt_tokens":2}}`),
observedHTTPResponse(503, `{}`),
observedHTTPResponse(200, `{"choices":[{"message":{"content":"invalid"}}],"usage":{"prompt_tokens":3}}`),
observedHTTPResponse(200, `{"choices":[{"message":{"content":"{\"ok\":true}"}}],"usage":{"prompt_tokens":4}}`),
observedHTTPResponse(200, `{"choices":[{"message":{"content":"invalid"}}],"usage":{"prompt_tokens":5}}`),
observedHTTPResponse(422, `{"error":{}}`),
observedHTTPResponse(200, `{"choices":[{"message":{"content":"validator"}}],"usage":{"prompt_tokens":6}}`),
}
calls := 0
one := 1
config := simpleConfig("message")
config.TransientRetries = &one
config.HTTPClient = &http.Client{Transport: roundTripFunc(func(*http.Request) (*http.Response, error) {
response := responses[calls]
calls++
return response, nil
})}
engine, err := promptkit.NewEngine(config)
if err != nil {
t.Fatal(err)
}
ctx := context.Background()
var all, selected promptkit.ExecutionGroup
initial, err := engine.Run(ctx, promptkit.RunRequest{PromptID: "prompt", CaptureExchange: true, Observer: all.Observe})
if err != nil {
t.Fatal(err)
}
validation := &promptkit.OutputContract{Format: promptkit.FormatJSON, ValidationMode: promptkit.ValidationJSON, RepairAttempts: 1}
callbackCount := 0
var branchID, validatorID string
result, err := engine.Coordinate(ctx, promptkit.CoordinateRequest{Start: initial.Exchange, AdditionalTurns: 1, Observer: promptkit.ComposeObservers(all.Observe, selected.Observe), Next: func(ctx context.Context, turn promptkit.ConversationTurn) (*promptkit.RunRequest, error) {
callbackCount++
if turn.Result == nil {
return &promptkit.RunRequest{PromptID: "prompt", Validation: validation}, nil
}
branchID = turn.Result.RunID
return nil, nil
}})
if err != nil || result.Outcome != promptkit.CoordinationStopped || callbackCount != 2 {
t.Fatalf("coordinate=%#v, %v", result, err)
}
if failed, err := engine.Run(ctx, promptkit.RunRequest{PromptID: "prompt", ContinueFrom: initial.Exchange, Validation: validation, Observer: all.Observe}); err == nil || failed != nil {
t.Fatalf("failed branch=%#v, %v", failed, err)
}
validator, err := engine.Run(ctx, promptkit.RunRequest{PromptID: "prompt", Observer: selected.Observe})
if err != nil {
t.Fatal(err)
}
validatorID = validator.RunID
a, b := all.Snapshot(), selected.Snapshot()
if calls != 7 || len(a.Members) != 3 || a.Attempts != 6 || a.TransientRetries != 1 || a.RepairCalls != 2 || a.Usage.PromptTokens.Value != 14 || !a.Usage.PromptTokens.Known || !a.TerminalCoverageComplete {
t.Fatalf("all summary=%#v calls=%d", a, calls)
}
if len(b.Members) != 2 || b.Attempts != 4 || b.Usage.PromptTokens.Value != 13 || !b.TerminalCoverageComplete {
t.Fatalf("selected summary=%#v", b)
}
ids := map[string]bool{}
for _, member := range b.Members {
ids[member.RunID] = true
}
if !ids[branchID] || !ids[validatorID] || ids[initial.RunID] {
t.Fatalf("selected members=%#v", b.Members)
}
}
func TestExecutionGroupPreparedSilenceAndPanicCoverage(t *testing.T) {
engine := newSimpleEngine(t, "message", promptkit.WithLLMClient(&fakeLLMClient{response: &promptkit.GenerateResponse{Content: "ok"}}))
ctx := context.Background()
var group promptkit.ExecutionGroup
prepared, err := engine.PrepareExecution(ctx, promptkit.RunRequest{PromptID: "prompt", Observer: group.Observe})
if err != nil {
t.Fatal(err)
}
prepared.Discard()
_, _ = engine.RunPrepared(ctx, prepared)
if len(group.Snapshot().Members) != 0 {
t.Fatal("preparation or failed claim enrolled a run")
}
func() {
defer func() {
if recover() == nil {
t.Error("expected panic")
}
}()
_, _ = engine.Run(ctx, promptkit.RunRequest{PromptID: "prompt", Observer: promptkit.ComposeObservers(group.Observe, func(event promptkit.ExecutionEvent) {
_ = group.Snapshot()
if event.Kind == promptkit.ExecutionStarted {
panic("stop")
}
})})
}()
result := group.Snapshot()
if len(result.Members) != 1 || result.TerminalCoverageComplete || result.Members[0].TerminalObserved || result.Attempts != 0 {
t.Fatalf("panic summary=%#v", result)
}
}
func TestExecutionGroupPreparedAndCallbackMembership(t *testing.T) {
engine := newSimpleEngine(t, "message", promptkit.WithLLMClient(&fakeLLMClient{response: &promptkit.GenerateResponse{Content: "ok"}}))
ctx := context.Background()
var continuations, nested promptkit.ExecutionGroup
initial, err := engine.Run(ctx, promptkit.RunRequest{PromptID: "prompt", CaptureExchange: true})
if err != nil {
t.Fatal(err)
}
prepared, err := engine.PrepareExecution(ctx, promptkit.RunRequest{PromptID: "prompt", Observer: nested.Observe})
if err != nil {
t.Fatal(err)
}
preparedResult, err := engine.RunPrepared(ctx, prepared)
if err != nil {
t.Fatal(err)
}
var callbackID string
_, err = engine.Coordinate(ctx, promptkit.CoordinateRequest{Start: initial.Exchange, AdditionalTurns: 1, Observer: continuations.Observe, Next: func(ctx context.Context, turn promptkit.ConversationTurn) (*promptkit.RunRequest, error) {
if turn.Result == nil {
return &promptkit.RunRequest{PromptID: "prompt"}, nil
}
callbackResult, err := engine.Run(ctx, promptkit.RunRequest{PromptID: "prompt", Observer: nested.Observe})
if err == nil {
callbackID = callbackResult.RunID
}
return nil, err
}})
if err != nil {
t.Fatal(err)
}
a, b := continuations.Snapshot(), nested.Snapshot()
if len(a.Members) != 1 || len(b.Members) != 2 || !a.TerminalCoverageComplete || !b.TerminalCoverageComplete {
t.Fatalf("summaries = %#v %#v", a, b)
}
ids := map[string]bool{}
for _, member := range b.Members {
ids[member.RunID] = true
}
if !ids[preparedResult.RunID] || !ids[callbackID] || ids[initial.RunID] {
t.Fatalf("members=%#v", b.Members)
}
}