Files
zero/internal/tools/task_test.go
KRATOSandClaude Opus 4.8 956f71ddf9 Batch 3: subagents — task tool spawns isolated sub-agent runs (PRD F11)
agent.Options gains Provider (auto-injected in Run) + Depth. A 'task' tool is intercepted in executeToolCall (like ask_user): it spawns agent.Run as a child with Depth+1, a registry filtered via new Registry.Without("task","ask_user") (no infinite nesting, no interactive prompts), inherited Sandbox/PermissionMode/Autonomy but all interactive callbacks nil, sharing ctx for cancellation; the child's final answer becomes the tool result. Depth guard (maxTaskDepth=2) refuses deeper nesting with a clear message. Synchronous; async task output/stop deferred. Build/vet/-race/full-suite green.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-07 00:51:06 +05:30

78 lines
2.4 KiB
Go

package tools
import (
"context"
"strings"
"testing"
)
func TestParseTaskRequestReadsPromptAndDescription(t *testing.T) {
request, err := ParseTaskRequest(map[string]any{
"description": "find bug",
"prompt": "locate the panic in the parser",
"subagent_type": "explorer",
})
if err != nil {
t.Fatal(err)
}
if request.Prompt != "locate the panic in the parser" {
t.Fatalf("unexpected prompt: %q", request.Prompt)
}
if request.Description != "find bug" {
t.Fatalf("unexpected description: %q", request.Description)
}
if request.SubagentType != "explorer" {
t.Fatalf("unexpected subagent_type: %q", request.SubagentType)
}
}
func TestParseTaskRequestAcceptsAliases(t *testing.T) {
// instructions/title are the aliased spellings weaker models emit.
request, err := ParseTaskRequest(map[string]any{
"instructions": "do the thing",
"title": "the thing",
})
if err != nil {
t.Fatal(err)
}
if request.Prompt != "do the thing" {
t.Fatalf("expected instructions to map to prompt, got %q", request.Prompt)
}
if request.Description != "the thing" {
t.Fatalf("expected title to map to description, got %q", request.Description)
}
}
func TestParseTaskRequestRequiresPrompt(t *testing.T) {
if _, err := ParseTaskRequest(map[string]any{"description": "no prompt here"}); err == nil {
t.Fatalf("expected error when prompt is missing")
}
if _, err := ParseTaskRequest(map[string]any{"prompt": " "}); err == nil {
t.Fatalf("expected error when prompt is blank")
}
}
func TestTaskToolRunIsGracefulFallback(t *testing.T) {
result := NewTaskTool().Run(context.Background(), map[string]any{"prompt": "do work"})
if result.Status != StatusOK {
t.Fatalf("expected ok fallback status, got %s", result.Status)
}
if !strings.Contains(strings.ToLower(result.Output), "unavailable") {
t.Fatalf("expected unavailable guidance, got %q", result.Output)
}
}
func TestTaskToolRunRejectsMissingPrompt(t *testing.T) {
result := NewTaskTool().Run(context.Background(), map[string]any{"description": "x"})
if result.Status != StatusError {
t.Fatalf("expected error status for missing prompt, got %s", result.Status)
}
}
func TestTaskToolIsReadOnlySafety(t *testing.T) {
safety := NewTaskTool().Safety()
if safety.SideEffect != SideEffectRead || safety.Permission != PermissionAllow {
t.Fatalf("expected read-only/allow safety, got %#v", safety)
}
}