···11+package agent
22+33+const (
44+ DefaultMaxSteps = 15
55+ DefaultParseRetries = 2
66+ DefaultToolRepeatLimit = 3
77+)
88+99+// Limits groups loop-control knobs so upper layers can pass agent limits
1010+// as a single value instead of repeating individual fields.
1111+type Limits struct {
1212+ MaxSteps int
1313+ ParseRetries int
1414+ MaxTokenBudget int
1515+ ToolRepeatLimit int
1616+}
1717+1818+func (l Limits) ToConfig() Config {
1919+ return Config{
2020+ MaxSteps: l.MaxSteps,
2121+ ParseRetries: l.ParseRetries,
2222+ MaxTokenBudget: l.MaxTokenBudget,
2323+ ToolRepeatLimit: l.ToolRepeatLimit,
2424+ }
2525+}
2626+2727+// NormalizeForRuntime applies channel/runtime defaults that historically
2828+// treated <=0 values as unset for retries/repeat limits.
2929+func (l Limits) NormalizeForRuntime() Limits {
3030+ if l.MaxSteps <= 0 {
3131+ l.MaxSteps = DefaultMaxSteps
3232+ }
3333+ if l.ParseRetries <= 0 {
3434+ l.ParseRetries = DefaultParseRetries
3535+ }
3636+ if l.ToolRepeatLimit <= 0 {
3737+ l.ToolRepeatLimit = DefaultToolRepeatLimit
3838+ }
3939+ if l.MaxTokenBudget < 0 {
4040+ l.MaxTokenBudget = 0
4141+ }
4242+ return l
4343+}
+2
assets/config/config.example.yaml
···333333parse_retries: 2
334334# - max_token_budget: stop the loop once cumulative tokens exceed this (0 disables).
335335max_token_budget: 0
336336+# - tool_repeat_limit: force final when the same successful tool call repeats this many times.
337337+tool_repeat_limit: 3
336338# Overall run timeout.
337339timeout: "10m"
338340# If true, prints extra debug info to stderr (tool steps, selected skills, etc).
···1717GOCACHE=/tmp/gocache GOPATH=/tmp/gopath GOMODCACHE=/tmp/gomodcache \
1818 go run . \
1919 --mode task \
2020+ --max-steps 20 \
2121+ --tool-repeat-limit 5 \
2022 --task "List files in the current directory and summarize what this project is."
2123```
2224···48504951- This demo uses OpenAI-compatible provider, so network access is required to actually run.
5052- `--inspect-prompt` and `--inspect-request` are supported in all modes.
5353+- `--max-steps` and `--tool-repeat-limit` are supported in all modes.
5154- In `task` mode, the demo also registers example project tools (`list_dir`, `get_weather`) on top of selected built-ins.
5255- `telegram` and `slack` modes run until interrupted (`Ctrl+C`).
+10-6
demo/embed-go/main.go
···116116117117func main() {
118118 var (
119119- mode = flag.String("mode", "task", "Run mode: task|telegram|slack.")
120120- task = flag.String("task", "List files and summarize the project.", "Task to run in --mode task.")
121121- model = flag.String("model", "gpt-5.2", "Model name.")
122122- apiKey = flag.String("api-key", os.Getenv("OPENAI_API_KEY"), "API key (defaults to OPENAI_API_KEY).")
123123- inspectPrompt = flag.Bool("inspect-prompt", false, "Dump prompts to ./dump.")
124124- inspectRequest = flag.Bool("inspect-request", false, "Dump request/response payloads to ./dump.")
119119+ mode = flag.String("mode", "task", "Run mode: task|telegram|slack.")
120120+ task = flag.String("task", "List files and summarize the project.", "Task to run in --mode task.")
121121+ model = flag.String("model", "gpt-5.2", "Model name.")
122122+ apiKey = flag.String("api-key", os.Getenv("OPENAI_API_KEY"), "API key (defaults to OPENAI_API_KEY).")
123123+ maxSteps = flag.Int("max-steps", 15, "Agent max tool-call steps.")
124124+ toolRepeatLimit = flag.Int("tool-repeat-limit", 3, "Force final when the same successful tool call repeats this many times.")
125125+ inspectPrompt = flag.Bool("inspect-prompt", false, "Dump prompts to ./dump.")
126126+ inspectRequest = flag.Bool("inspect-request", false, "Dump request/response payloads to ./dump.")
125127126128 telegramBotToken = flag.String("telegram-bot-token", os.Getenv("TG_BOT_TOKEN"), "Telegram bot token (or TG_BOT_TOKEN).")
127129···138140 cfg.Set("llm.api_key", strings.TrimSpace(*apiKey))
139141 cfg.Set("llm.model", strings.TrimSpace(*model))
140142 cfg.Set("tools.todo_update.enabled", true)
143143+ cfg.Set("max_steps", *maxSteps)
144144+ cfg.Set("tool_repeat_limit", *toolRepeatLimit)
141145142146 rt := integration.New(cfg)
143147