configure image generation under tool settings

This commit is contained in:
Anton Bogdanovich 2026-05-05 14:11:00 -07:00
parent cd0b4f025e
commit 135f721dfc
6 changed files with 117 additions and 31 deletions

View file

@ -427,6 +427,10 @@
"i2c": {
"enabled": false
},
"image_generate": {
"enabled": false,
"model": "openai-codex/gpt-image-2"
},
"install_skill": {
"enabled": true
},

View file

@ -156,6 +156,30 @@ If `range` is omitted, PicoClaw performs an unrestricted search.
}
```
## Image Generation Tool
The `image_generate` tool creates image files through a provider that supports
image generation.
| Config | Type | Default | Description |
|--------|------|---------|-------------|
| `enabled` | bool | false | Enable the image generation tool |
| `model` | string | `gpt-image-2` | Image generation model. Values may include a provider prefix, for example `openai-codex/gpt-image-2` |
If `tools.image_generate.model` is not set, PicoClaw falls back to the legacy
`agents.defaults.image_model` setting, then to `gpt-image-2`.
```json
{
"tools": {
"image_generate": {
"enabled": true,
"model": "openai-codex/gpt-image-2"
}
}
}
```
## Exec Tool
The exec tool is used to execute shell commands.

View file

@ -216,10 +216,7 @@ func registerSharedTools(
}
if cfg.Tools.IsToolEnabled("image_generate") {
imageModel := cfg.Agents.Defaults.ImageModel
if imageModel == "" {
imageModel = "gpt-image-2"
}
imageModel := cfg.Tools.ImageGenerate.EffectiveModel(cfg.Agents.Defaults)
agent.Tools.Register(tools.NewImageGenerateTool(agent.Workspace, imageModel, nil))
}

View file

@ -626,6 +626,21 @@ type ToolConfig struct {
Enabled bool `json:"enabled" yaml:"-" env:"ENABLED"`
}
type ImageGenerateToolsConfig struct {
ToolConfig `yaml:"-" envPrefix:"PICOCLAW_TOOLS_IMAGE_GENERATE_"`
Model string `json:"model,omitempty" yaml:"-" env:"PICOCLAW_TOOLS_IMAGE_GENERATE_MODEL"`
}
func (c ImageGenerateToolsConfig) EffectiveModel(defaults AgentDefaults) string {
if model := strings.TrimSpace(c.Model); model != "" {
return model
}
if model := strings.TrimSpace(defaults.ImageModel); model != "" {
return model
}
return "gpt-image-2"
}
type BraveConfig struct {
Enabled bool `json:"enabled" yaml:"-" env:"PICOCLAW_TOOLS_WEB_BRAVE_ENABLED"`
APIKeys SecureStrings `json:"api_keys,omitzero" yaml:"api_keys,omitempty" env:"PICOCLAW_TOOLS_WEB_BRAVE_API_KEYS"`
@ -816,31 +831,31 @@ type ToolsConfig struct {
// FilterMinLength is the minimum content length required for filtering.
// Content shorter than this will be returned unchanged for performance.
// Default: 8
FilterMinLength int `json:"filter_min_length" yaml:"-" env:"PICOCLAW_TOOLS_FILTER_MIN_LENGTH"`
Web WebToolsConfig `json:"web" yaml:"web,omitempty"`
Cron CronToolsConfig `json:"cron" yaml:"-"`
Exec ExecConfig `json:"exec" yaml:"-"`
Skills SkillsToolsConfig `json:"skills" yaml:"skills,omitempty"`
MediaCleanup MediaCleanupConfig `json:"media_cleanup" yaml:"-"`
MCP MCPConfig `json:"mcp" yaml:"-"`
AppendFile ToolConfig `json:"append_file" yaml:"-" envPrefix:"PICOCLAW_TOOLS_APPEND_FILE_"`
EditFile ToolConfig `json:"edit_file" yaml:"-" envPrefix:"PICOCLAW_TOOLS_EDIT_FILE_"`
FindSkills ToolConfig `json:"find_skills" yaml:"-" envPrefix:"PICOCLAW_TOOLS_FIND_SKILLS_"`
I2C ToolConfig `json:"i2c" yaml:"-" envPrefix:"PICOCLAW_TOOLS_I2C_"`
ImageGenerate ToolConfig `json:"image_generate" yaml:"-" envPrefix:"PICOCLAW_TOOLS_IMAGE_GENERATE_"`
InstallSkill ToolConfig `json:"install_skill" yaml:"-" envPrefix:"PICOCLAW_TOOLS_INSTALL_SKILL_"`
ListDir ToolConfig `json:"list_dir" yaml:"-" envPrefix:"PICOCLAW_TOOLS_LIST_DIR_"`
Message ToolConfig `json:"message" yaml:"-" envPrefix:"PICOCLAW_TOOLS_MESSAGE_"`
ReadFile ReadFileToolConfig `json:"read_file" yaml:"-" envPrefix:"PICOCLAW_TOOLS_READ_FILE_"`
Serial ToolConfig `json:"serial" yaml:"-" envPrefix:"PICOCLAW_TOOLS_SERIAL_"`
SendFile ToolConfig `json:"send_file" yaml:"-" envPrefix:"PICOCLAW_TOOLS_SEND_FILE_"`
SendTTS ToolConfig `json:"send_tts" yaml:"-" envPrefix:"PICOCLAW_TOOLS_SEND_TTS_"`
Spawn ToolConfig `json:"spawn" yaml:"-" envPrefix:"PICOCLAW_TOOLS_SPAWN_"`
SpawnStatus ToolConfig `json:"spawn_status" yaml:"-" envPrefix:"PICOCLAW_TOOLS_SPAWN_STATUS_"`
SPI ToolConfig `json:"spi" yaml:"-" envPrefix:"PICOCLAW_TOOLS_SPI_"`
Subagent ToolConfig `json:"subagent" yaml:"-" envPrefix:"PICOCLAW_TOOLS_SUBAGENT_"`
WebFetch ToolConfig `json:"web_fetch" yaml:"-" envPrefix:"PICOCLAW_TOOLS_WEB_FETCH_"`
WriteFile ToolConfig `json:"write_file" yaml:"-" envPrefix:"PICOCLAW_TOOLS_WRITE_FILE_"`
FilterMinLength int `json:"filter_min_length" yaml:"-" env:"PICOCLAW_TOOLS_FILTER_MIN_LENGTH"`
Web WebToolsConfig `json:"web" yaml:"web,omitempty"`
Cron CronToolsConfig `json:"cron" yaml:"-"`
Exec ExecConfig `json:"exec" yaml:"-"`
Skills SkillsToolsConfig `json:"skills" yaml:"skills,omitempty"`
MediaCleanup MediaCleanupConfig `json:"media_cleanup" yaml:"-"`
MCP MCPConfig `json:"mcp" yaml:"-"`
AppendFile ToolConfig `json:"append_file" yaml:"-" envPrefix:"PICOCLAW_TOOLS_APPEND_FILE_"`
EditFile ToolConfig `json:"edit_file" yaml:"-" envPrefix:"PICOCLAW_TOOLS_EDIT_FILE_"`
FindSkills ToolConfig `json:"find_skills" yaml:"-" envPrefix:"PICOCLAW_TOOLS_FIND_SKILLS_"`
I2C ToolConfig `json:"i2c" yaml:"-" envPrefix:"PICOCLAW_TOOLS_I2C_"`
ImageGenerate ImageGenerateToolsConfig `json:"image_generate" yaml:"-"`
InstallSkill ToolConfig `json:"install_skill" yaml:"-" envPrefix:"PICOCLAW_TOOLS_INSTALL_SKILL_"`
ListDir ToolConfig `json:"list_dir" yaml:"-" envPrefix:"PICOCLAW_TOOLS_LIST_DIR_"`
Message ToolConfig `json:"message" yaml:"-" envPrefix:"PICOCLAW_TOOLS_MESSAGE_"`
ReadFile ReadFileToolConfig `json:"read_file" yaml:"-" envPrefix:"PICOCLAW_TOOLS_READ_FILE_"`
Serial ToolConfig `json:"serial" yaml:"-" envPrefix:"PICOCLAW_TOOLS_SERIAL_"`
SendFile ToolConfig `json:"send_file" yaml:"-" envPrefix:"PICOCLAW_TOOLS_SEND_FILE_"`
SendTTS ToolConfig `json:"send_tts" yaml:"-" envPrefix:"PICOCLAW_TOOLS_SEND_TTS_"`
Spawn ToolConfig `json:"spawn" yaml:"-" envPrefix:"PICOCLAW_TOOLS_SPAWN_"`
SpawnStatus ToolConfig `json:"spawn_status" yaml:"-" envPrefix:"PICOCLAW_TOOLS_SPAWN_STATUS_"`
SPI ToolConfig `json:"spi" yaml:"-" envPrefix:"PICOCLAW_TOOLS_SPI_"`
Subagent ToolConfig `json:"subagent" yaml:"-" envPrefix:"PICOCLAW_TOOLS_SUBAGENT_"`
WebFetch ToolConfig `json:"web_fetch" yaml:"-" envPrefix:"PICOCLAW_TOOLS_WEB_FETCH_"`
WriteFile ToolConfig `json:"write_file" yaml:"-" envPrefix:"PICOCLAW_TOOLS_WRITE_FILE_"`
}
// IsFilterSensitiveDataEnabled returns true if sensitive data filtering is enabled

View file

@ -195,6 +195,50 @@ func TestLoadConfig_MCPMaxInlineTextChars(t *testing.T) {
}
}
func TestImageGenerateToolsConfig_EffectiveModel(t *testing.T) {
defaults := AgentDefaults{ImageModel: "legacy-image-model"}
if got := (ImageGenerateToolsConfig{}).EffectiveModel(defaults); got != "legacy-image-model" {
t.Fatalf("legacy fallback model = %q, want legacy-image-model", got)
}
cfg := ImageGenerateToolsConfig{Model: "openai-codex/gpt-image-2"}
if got := cfg.EffectiveModel(defaults); got != "openai-codex/gpt-image-2" {
t.Fatalf("tool model = %q, want openai-codex/gpt-image-2", got)
}
if got := (ImageGenerateToolsConfig{}).EffectiveModel(AgentDefaults{}); got != "gpt-image-2" {
t.Fatalf("default model = %q, want gpt-image-2", got)
}
}
func TestLoadConfig_ImageGenerateModel(t *testing.T) {
dir := t.TempDir()
configPath := filepath.Join(dir, "config.json")
raw := `{
"tools": {
"image_generate": {
"enabled": true,
"model": "openai-codex/gpt-image-2"
}
}
}`
if err := os.WriteFile(configPath, []byte(raw), 0o644); err != nil {
t.Fatalf("WriteFile(configPath): %v", err)
}
cfg, err := LoadConfig(configPath)
if err != nil {
t.Fatalf("LoadConfig() error: %v", err)
}
if !cfg.Tools.ImageGenerate.Enabled {
t.Fatal("cfg.Tools.ImageGenerate.Enabled should be true")
}
if got := cfg.Tools.ImageGenerate.Model; got != "openai-codex/gpt-image-2" {
t.Fatalf("cfg.Tools.ImageGenerate.Model = %q, want openai-codex/gpt-image-2", got)
}
}
func TestConfig_BackwardCompat_NoAgentsList(t *testing.T) {
jsonData := `{
"agents": {

View file

@ -397,8 +397,10 @@ func DefaultConfig() *Config {
SendFile: ToolConfig{
Enabled: true,
},
ImageGenerate: ToolConfig{
Enabled: false,
ImageGenerate: ImageGenerateToolsConfig{
ToolConfig: ToolConfig{
Enabled: false,
},
},
SendTTS: ToolConfig{
Enabled: false,