67 lines
1.8 KiB
Go
67 lines
1.8 KiB
Go
|
|
package usecase
|
||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
|
||
|
|
"go.maximumdirect.net/promptkit/internal/domain"
|
||
|
|
)
|
||
|
|
|
||
|
|
// ConversationTurn is one delivery to a coordinator callback.
|
||
|
|
type ConversationTurn[R any] struct {
|
||
|
|
Exchange *domain.Exchange
|
||
|
|
Result *R
|
||
|
|
RemainingTurns int
|
||
|
|
}
|
||
|
|
|
||
|
|
// CoordinationOutcome describes a normal coordinator termination.
|
||
|
|
type CoordinationOutcome string
|
||
|
|
|
||
|
|
const (
|
||
|
|
CoordinationStopped CoordinationOutcome = "stopped"
|
||
|
|
CoordinationExhausted CoordinationOutcome = "exhausted"
|
||
|
|
)
|
||
|
|
|
||
|
|
// CoordinationResult holds a normal outcome or a completed undelivered result.
|
||
|
|
type CoordinationResult[R any] struct {
|
||
|
|
Outcome CoordinationOutcome
|
||
|
|
Undelivered *R
|
||
|
|
}
|
||
|
|
|
||
|
|
// Coordinate advances one branch using the supplied callback and ordinary run.
|
||
|
|
func Coordinate[Q, R any](ctx context.Context, start *domain.Exchange, turns int,
|
||
|
|
next func(context.Context, ConversationTurn[R]) (*Q, error),
|
||
|
|
run func(context.Context, *domain.Exchange, *Q) (*R, *domain.Exchange, error),
|
||
|
|
) (CoordinationResult[R], error) {
|
||
|
|
current := start
|
||
|
|
var pending *R
|
||
|
|
for {
|
||
|
|
if err := ctx.Err(); err != nil {
|
||
|
|
return CoordinationResult[R]{Undelivered: pending}, err
|
||
|
|
}
|
||
|
|
request, err := next(ctx, ConversationTurn[R]{Exchange: current, Result: pending, RemainingTurns: turns})
|
||
|
|
pending = nil
|
||
|
|
if contextErr := ctx.Err(); contextErr != nil {
|
||
|
|
return CoordinationResult[R]{}, contextErr
|
||
|
|
}
|
||
|
|
if err != nil {
|
||
|
|
return CoordinationResult[R]{}, err
|
||
|
|
}
|
||
|
|
if request == nil {
|
||
|
|
return CoordinationResult[R]{Outcome: CoordinationStopped}, nil
|
||
|
|
}
|
||
|
|
if turns == 0 {
|
||
|
|
return CoordinationResult[R]{Outcome: CoordinationExhausted}, nil
|
||
|
|
}
|
||
|
|
if err := ctx.Err(); err != nil {
|
||
|
|
return CoordinationResult[R]{}, err
|
||
|
|
}
|
||
|
|
turns--
|
||
|
|
var nextExchange *domain.Exchange
|
||
|
|
pending, nextExchange, err = run(ctx, current, request)
|
||
|
|
if err != nil {
|
||
|
|
return CoordinationResult[R]{}, err
|
||
|
|
}
|
||
|
|
current = nextExchange
|
||
|
|
}
|
||
|
|
}
|