feat: configurable max_turns for elfs — LLM sets via agent tool param
This commit is contained in:
@@ -146,12 +146,12 @@ func TestManager_SpawnAndList(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Spawn two elfs
|
// Spawn two elfs
|
||||||
e1, err := mgr.Spawn(context.Background(), router.TaskGeneration, "task 1", "you are elf 1")
|
e1, err := mgr.Spawn(context.Background(), router.TaskGeneration, "task 1", "you are elf 1", 30)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Spawn 1: %v", err)
|
t.Fatalf("Spawn 1: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
e2, err := mgr.Spawn(context.Background(), router.TaskReview, "task 2", "you are elf 2")
|
e2, err := mgr.Spawn(context.Background(), router.TaskReview, "task 2", "you are elf 2", 30)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Spawn 2: %v", err)
|
t.Fatalf("Spawn 2: %v", err)
|
||||||
}
|
}
|
||||||
@@ -202,9 +202,9 @@ func TestManager_WaitAll(t *testing.T) {
|
|||||||
|
|
||||||
mgr := NewManager(ManagerConfig{Router: rtr, Tools: tool.NewRegistry()})
|
mgr := NewManager(ManagerConfig{Router: rtr, Tools: tool.NewRegistry()})
|
||||||
|
|
||||||
mgr.Spawn(context.Background(), router.TaskGeneration, "a", "")
|
mgr.Spawn(context.Background(), router.TaskGeneration, "a", "", 30)
|
||||||
mgr.Spawn(context.Background(), router.TaskGeneration, "b", "")
|
mgr.Spawn(context.Background(), router.TaskGeneration, "b", "", 30)
|
||||||
mgr.Spawn(context.Background(), router.TaskGeneration, "c", "")
|
mgr.Spawn(context.Background(), router.TaskGeneration, "c", "", 30)
|
||||||
|
|
||||||
results := mgr.WaitAll()
|
results := mgr.WaitAll()
|
||||||
if len(results) != 3 {
|
if len(results) != 3 {
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ func NewManager(cfg ManagerConfig) *Manager {
|
|||||||
|
|
||||||
// Spawn creates a new background elf with a router-selected provider.
|
// Spawn creates a new background elf with a router-selected provider.
|
||||||
// The elf gets its own engine, history, and tools — no shared state.
|
// The elf gets its own engine, history, and tools — no shared state.
|
||||||
func (m *Manager) Spawn(ctx context.Context, taskType router.TaskType, prompt, systemPrompt string) (Elf, error) {
|
func (m *Manager) Spawn(ctx context.Context, taskType router.TaskType, prompt, systemPrompt string, maxTurns int) (Elf, error) {
|
||||||
// Ask router for the best arm for this task type
|
// Ask router for the best arm for this task type
|
||||||
task := router.Task{
|
task := router.Task{
|
||||||
Type: taskType,
|
Type: taskType,
|
||||||
@@ -69,7 +69,7 @@ func (m *Manager) Spawn(ctx context.Context, taskType router.TaskType, prompt, s
|
|||||||
Tools: m.tools,
|
Tools: m.tools,
|
||||||
System: systemPrompt,
|
System: systemPrompt,
|
||||||
Model: arm.ModelName,
|
Model: arm.ModelName,
|
||||||
MaxTurns: 20,
|
MaxTurns: maxTurns,
|
||||||
Logger: m.logger,
|
Logger: m.logger,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -87,13 +87,13 @@ func (m *Manager) Spawn(ctx context.Context, taskType router.TaskType, prompt, s
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SpawnWithProvider creates an elf using a specific provider (bypasses router).
|
// SpawnWithProvider creates an elf using a specific provider (bypasses router).
|
||||||
func (m *Manager) SpawnWithProvider(prov provider.Provider, model, prompt, systemPrompt string) (Elf, error) {
|
func (m *Manager) SpawnWithProvider(prov provider.Provider, model, prompt, systemPrompt string, maxTurns int) (Elf, error) {
|
||||||
eng, err := engine.New(engine.Config{
|
eng, err := engine.New(engine.Config{
|
||||||
Provider: prov,
|
Provider: prov,
|
||||||
Tools: m.tools,
|
Tools: m.tools,
|
||||||
System: systemPrompt,
|
System: systemPrompt,
|
||||||
Model: model,
|
Model: model,
|
||||||
MaxTurns: 20,
|
MaxTurns: maxTurns,
|
||||||
Logger: m.logger,
|
Logger: m.logger,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -28,6 +28,10 @@ var paramSchema = json.RawMessage(`{
|
|||||||
"wait": {
|
"wait": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Wait for the elf to complete (default true)"
|
"description": "Wait for the elf to complete (default true)"
|
||||||
|
},
|
||||||
|
"max_turns": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Maximum tool-calling rounds for the elf (default 30)"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["prompt"]
|
"required": ["prompt"]
|
||||||
@@ -58,6 +62,7 @@ type agentArgs struct {
|
|||||||
Prompt string `json:"prompt"`
|
Prompt string `json:"prompt"`
|
||||||
TaskType string `json:"task_type,omitempty"`
|
TaskType string `json:"task_type,omitempty"`
|
||||||
Wait *bool `json:"wait,omitempty"`
|
Wait *bool `json:"wait,omitempty"`
|
||||||
|
MaxTurns int `json:"max_turns,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tool) Execute(ctx context.Context, args json.RawMessage) (tool.Result, error) {
|
func (t *Tool) Execute(ctx context.Context, args json.RawMessage) (tool.Result, error) {
|
||||||
@@ -74,10 +79,14 @@ func (t *Tool) Execute(ctx context.Context, args json.RawMessage) (tool.Result,
|
|||||||
if a.Wait != nil {
|
if a.Wait != nil {
|
||||||
wait = *a.Wait
|
wait = *a.Wait
|
||||||
}
|
}
|
||||||
|
maxTurns := a.MaxTurns
|
||||||
|
if maxTurns <= 0 {
|
||||||
|
maxTurns = 30 // default
|
||||||
|
}
|
||||||
|
|
||||||
systemPrompt := "You are an elf — a focused sub-agent of gnoma. Complete the given task thoroughly and concisely. Use tools as needed."
|
systemPrompt := "You are an elf — a focused sub-agent of gnoma. Complete the given task thoroughly and concisely. Use tools as needed."
|
||||||
|
|
||||||
e, err := t.manager.Spawn(ctx, taskType, a.Prompt, systemPrompt)
|
e, err := t.manager.Spawn(ctx, taskType, a.Prompt, systemPrompt, maxTurns)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return tool.Result{Output: fmt.Sprintf("Failed to spawn elf: %v", err)}, nil
|
return tool.Result{Output: fmt.Sprintf("Failed to spawn elf: %v", err)}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user