ExecuteWithStream runs the generation. Progress feedback is the agent loop's animated spinner (this tool is blocking, not streaming).
(ctx context.Context, args []string, _ func(string))
| 149 | // ExecuteWithStream runs the generation. Progress feedback is the agent loop's |
| 150 | // animated spinner (this tool is blocking, not streaming). |
| 151 | func (p *BuiltinImagePlugin) ExecuteWithStream(ctx context.Context, args []string, _ func(string)) (string, error) { |
| 152 | if len(args) == 0 { |
| 153 | return "", errors.New(`@image: empty args. Example: <tool_call name="@image" args='{"cmd":"gen","args":{"prompt":"..."}}' />`) |
| 154 | } |
| 155 | cmd, inner, err := parseImageInvocation(args) |
| 156 | if err != nil { |
| 157 | return "", fmt.Errorf("@image: %w", err) |
| 158 | } |
| 159 | |
| 160 | provider := imagegen.NewFromEnvContext(ctx, nil) |
| 161 | |
| 162 | switch cmd { |
| 163 | case "status": |
| 164 | if imagegen.IsNull(provider) { |
| 165 | return "@image: no image backend configured. Set CHATCLI_IMAGE_PROVIDER=sdwebui (self-hosted Stable Diffusion), CHATCLI_IMAGE_URL, or OPENAI_API_KEY.", nil |
| 166 | } |
| 167 | return "@image backend: " + provider.Name(), nil |
| 168 | case "models": |
| 169 | return imageModelsList(ctx), nil |
| 170 | case "gen": |
| 171 | var in struct { |
| 172 | Prompt string `json:"prompt"` |
| 173 | Size string `json:"size"` |
| 174 | N int `json:"n"` |
| 175 | Out string `json:"out"` |
| 176 | } |
| 177 | _ = json.Unmarshal([]byte(inner), &in) |
| 178 | if strings.TrimSpace(in.Prompt) == "" { |
| 179 | return "", errors.New(`@image gen: "prompt" is required`) |
| 180 | } |
| 181 | if imagegen.IsNull(provider) { |
| 182 | return "", imagegen.ErrDisabled |
| 183 | } |
| 184 | // No progress line here: the agent loop runs an animated spinner during |
| 185 | // execution (a streamed line would stop it, then the blocking call would |
| 186 | // look frozen). The spinner's label already names the operation. |
| 187 | images, err := provider.Generate(ctx, in.Prompt, imagegen.Options{Size: in.Size, N: in.N}) |
| 188 | if err != nil { |
| 189 | return "", fmt.Errorf("@image: %w", err) |
| 190 | } |
| 191 | paths, err := writeImages(in.Out, images) |
| 192 | if err != nil { |
| 193 | return "", fmt.Errorf("@image: %w", err) |
| 194 | } |
| 195 | RecordGeneratedImages(paths...) |
| 196 | return i18n.T("image.tool.generated", len(paths), provider.Name(), strings.Join(paths, "\n ")), nil |
| 197 | case "edit": |
| 198 | var in struct { |
| 199 | Prompt string `json:"prompt"` |
| 200 | Image string `json:"image"` |
| 201 | Images []string `json:"images"` |
| 202 | Mask string `json:"mask"` |
| 203 | Size string `json:"size"` |
| 204 | N int `json:"n"` |
| 205 | Strength float64 `json:"strength"` |
| 206 | Out string `json:"out"` |
| 207 | } |
| 208 | _ = json.Unmarshal([]byte(inner), &in) |
no test coverage detected