Skip to content

Commit 7b9b810

Browse files
authored
Merge pull request #225 from yinwm/feat/cron-exec-timeout-config
feat(cron): add configurable execution timeout for cron jobs
2 parents f929268 + 881999a commit 7b9b810

8 files changed

Lines changed: 44 additions & 7 deletions

File tree

README.ja.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,9 @@ picoclaw onboard
195195
"api_key": "YOUR_BRAVE_API_KEY",
196196
"max_results": 5
197197
}
198+
},
199+
"cron": {
200+
"exec_timeout_minutes": 5
198201
}
199202
},
200203
"heartbeat": {
@@ -697,6 +700,9 @@ HEARTBEAT_OK 応答 ユーザーが直接結果を受け取る
697700
"search": {
698701
"apiKey": "BSA..."
699702
}
703+
},
704+
"cron": {
705+
"exec_timeout_minutes": 5
700706
}
701707
},
702708
"heartbeat": {

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,9 @@ picoclaw agent -m "Hello"
774774
"enabled": true,
775775
"max_results": 5
776776
}
777+
},
778+
"cron": {
779+
"exec_timeout_minutes": 5
777780
}
778781
},
779782
"heartbeat": {

README.zh.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,9 @@ picoclaw onboard
236236
"api_key": "YOUR_BRAVE_API_KEY",
237237
"max_results": 5
238238
}
239+
},
240+
"cron": {
241+
"exec_timeout_minutes": 5
239242
}
240243
}
241244
}
@@ -644,6 +647,9 @@ picoclaw agent -m "你好"
644647
"search": {
645648
"api_key": "BSA..."
646649
}
650+
},
651+
"cron": {
652+
"exec_timeout_minutes": 5
647653
}
648654
},
649655
"heartbeat": {

cmd/picoclaw/main.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -562,7 +562,8 @@ func gatewayCmd() {
562562
})
563563

564564
// Setup cron tool and service
565-
cronService := setupCronTool(agentLoop, msgBus, cfg.WorkspacePath(), cfg.Agents.Defaults.RestrictToWorkspace)
565+
execTimeout := time.Duration(cfg.Tools.Cron.ExecTimeoutMinutes) * time.Minute
566+
cronService := setupCronTool(agentLoop, msgBus, cfg.WorkspacePath(), cfg.Agents.Defaults.RestrictToWorkspace, execTimeout)
566567

567568
heartbeatService := heartbeat.NewHeartbeatService(
568569
cfg.WorkspacePath(),
@@ -987,14 +988,14 @@ func getConfigPath() string {
987988
return filepath.Join(home, ".picoclaw", "config.json")
988989
}
989990

990-
func setupCronTool(agentLoop *agent.AgentLoop, msgBus *bus.MessageBus, workspace string, restrict bool) *cron.CronService {
991+
func setupCronTool(agentLoop *agent.AgentLoop, msgBus *bus.MessageBus, workspace string, restrict bool, execTimeout time.Duration) *cron.CronService {
991992
cronStorePath := filepath.Join(workspace, "cron", "jobs.json")
992993

993994
// Create cron service
994995
cronService := cron.NewCronService(cronStorePath, nil)
995996

996997
// Create and register CronTool
997-
cronTool := tools.NewCronTool(cronService, agentLoop, msgBus, workspace, restrict)
998+
cronTool := tools.NewCronTool(cronService, agentLoop, msgBus, workspace, restrict, execTimeout)
998999
agentLoop.RegisterTool(cronTool)
9991000

10001001
// Set the onJob handler

config/config.example.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,9 @@
127127
"api_key": "pplx-xxx",
128128
"max_results": 5
129129
}
130+
},
131+
"cron": {
132+
"exec_timeout_minutes": 5
130133
}
131134
},
132135
"heartbeat": {

pkg/config/config.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,13 @@ type WebToolsConfig struct {
218218
Perplexity PerplexityConfig `json:"perplexity"`
219219
}
220220

221+
type CronToolsConfig struct {
222+
ExecTimeoutMinutes int `json:"exec_timeout_minutes" env:"PICOCLAW_TOOLS_CRON_EXEC_TIMEOUT_MINUTES"` // 0 means no timeout
223+
}
224+
221225
type ToolsConfig struct {
222-
Web WebToolsConfig `json:"web"`
226+
Web WebToolsConfig `json:"web"`
227+
Cron CronToolsConfig `json:"cron"`
223228
}
224229

225230
func DefaultConfig() *Config {
@@ -334,6 +339,9 @@ func DefaultConfig() *Config {
334339
MaxResults: 5,
335340
},
336341
},
342+
Cron: CronToolsConfig{
343+
ExecTimeoutMinutes: 5, // default 5 minutes for LLM operations
344+
},
337345
},
338346
Heartbeat: HeartbeatConfig{
339347
Enabled: true,

pkg/tools/cron.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,15 @@ type CronTool struct {
2828
}
2929

3030
// NewCronTool creates a new CronTool
31-
func NewCronTool(cronService *cron.CronService, executor JobExecutor, msgBus *bus.MessageBus, workspace string, restrict bool) *CronTool {
31+
// execTimeout: 0 means no timeout, >0 sets the timeout duration
32+
func NewCronTool(cronService *cron.CronService, executor JobExecutor, msgBus *bus.MessageBus, workspace string, restrict bool, execTimeout time.Duration) *CronTool {
33+
execTool := NewExecTool(workspace, restrict)
34+
execTool.SetTimeout(execTimeout) // 0 means no timeout
3235
return &CronTool{
3336
cronService: cronService,
3437
executor: executor,
3538
msgBus: msgBus,
36-
execTool: NewExecTool(workspace, restrict),
39+
execTool: execTool,
3740
}
3841
}
3942

pkg/tools/shell.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,14 @@ func (t *ExecTool) Execute(ctx context.Context, args map[string]interface{}) *To
8989
return ErrorResult(guardError)
9090
}
9191

92-
cmdCtx, cancel := context.WithTimeout(ctx, t.timeout)
92+
// timeout == 0 means no timeout
93+
var cmdCtx context.Context
94+
var cancel context.CancelFunc
95+
if t.timeout > 0 {
96+
cmdCtx, cancel = context.WithTimeout(ctx, t.timeout)
97+
} else {
98+
cmdCtx, cancel = context.WithCancel(ctx)
99+
}
93100
defer cancel()
94101

95102
var cmd *exec.Cmd

0 commit comments

Comments
 (0)