feat(piagent): batch-generate images in one call when generators share a prompt

When multiple image-generator tasks carry the same brief, request all
images from a single GPT Image call with Count=N instead of firing one
call per image. Adds directImageBatchCount/Prompt detection, batch
(incremental) generation paths, and folds the planned count into the
idempotency key. Disables the streaming plan probe for multi-image
requests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-09 09:05:18 +08:00
parent 8a28a0bcea
commit cc30ae4284
4 changed files with 223 additions and 5 deletions
@@ -143,6 +143,33 @@ func TestImageClientSendsExplicitSize(t *testing.T) {
}
}
func TestImageClientSendsImageCount(t *testing.T) {
var requestBody map[string]any
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if err := json.NewDecoder(r.Body).Decode(&requestBody); err != nil {
t.Fatal(err)
}
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{"data":[{"url":"https://example.com/image-1.png"},{"url":"https://example.com/image-2.png"}]}`))
}))
defer server.Close()
client := NewImageClient(ImageClientOptions{BaseURL: server.URL, APIKey: "test-key"})
image, err := client.Generate(context.Background(), "create two images", ImageRequestOptions{Model: "gpt-image-2", Count: 2})
if err != nil {
t.Fatal(err)
}
if requestBody["n"] != float64(2) {
t.Fatalf("expected image request n=2, got %#v", requestBody["n"])
}
if requestBody["stream"] != nil {
t.Fatalf("expected multi-image request to avoid stream, got %#v", requestBody["stream"])
}
if len(image.URLs) != 2 {
t.Fatalf("expected two generated images, got %#v", image.URLs)
}
}
func TestImageClientUploadsDataReferenceImagesAsMultipart(t *testing.T) {
var requestPath string
var requestContentType string