X-Git-Url: https://git.giacomolli.uk/onechat/blobdiff_plain/59948b44c0fe2165b90e3aa0d18646f6c3d74af3..2a528fe2981639cf099c713a6be16b8ea0e2cc67:/subagent_run_test.go?ds=sidebyside diff --git a/subagent_run_test.go b/subagent_run_test.go index 71c96ea..047e6a8 100644 --- a/subagent_run_test.go +++ b/subagent_run_test.go @@ -64,6 +64,7 @@ func TestSpawnRunsASubagentInTheBackground(t *testing.T) { "work: " + report, "reply: Noted.", }, test.Log(t)) + require.Equal(t, Event{ Kind: "work", ID: 4, @@ -71,6 +72,7 @@ func TestSpawnRunsASubagentInTheBackground(t *testing.T) { Source: name, Status: subagentFinished, }, test.events.LastEvent("work")) + require.Equal(t, "<6>subagent started name="+name+"\n<6>subagent done name="+name+" after=0s\n", test.logs.String()) var first, second *ModelFakeCall @@ -180,7 +182,10 @@ func TestFullContextGivesAFailedReport(t *testing.T) { if subagentTestCall(call) { w.WriteHeader(http.StatusBadRequest) - _, _ = io.WriteString(w, subagentTestFullContext) + _, err := io.WriteString(w, subagentTestFullContext) + if err != nil { + panic(err) + } return } @@ -195,11 +200,12 @@ func TestFullContextGivesAFailedReport(t *testing.T) { name := test.events.Last("subagent") require.Equal(t, []string{ - "work: [" + name + "]\nfailed: create model response: model call: HTTP 400: " + subagentTestFullContext + "\n\nFull chat: zoom(\"" + name + "\")", + "work: [" + name + "]\nfailed: run worker chain: create model response: model call: HTTP 400: " + subagentTestFullContext + "\n\nFull chat: zoom(\"" + name + "\")", "reply: It failed.", }, test.Log(t)) + require.Equal(t, subagentFailed, test.events.LastEvent("work").Status) - require.Equal(t, "<6>subagent started name="+name+"\n<3>subagent failed name="+name+" after=0s: create model response: model call: HTTP 400: "+subagentTestFullContext+"\n", test.logs.String()) + require.Equal(t, "<6>subagent started name="+name+"\n<3>subagent failed name="+name+" after=0s: run worker chain: create model response: model call: HTTP 400: "+subagentTestFullContext+"\n", test.logs.String()) } func TestSubagentHasItsOwnEffortAndNoSpawn(t *testing.T) { @@ -351,7 +357,7 @@ func TestTellToAFinishedSubagentGoesOnFromItsLog(t *testing.T) { require.Equal(t, "work: "+subagentReport(name, []string{"Reply 2."}), test.Log(t)[2]) _, err = runs.Tell(t.Context(), "BlueFox", "Hello.") - require.EqualError(t, err, "no agent BlueFox") + require.EqualError(t, err, "open worker log: no agent BlueFox") } func TestStopEndsASubagentAndItsCommand(t *testing.T) { @@ -385,6 +391,7 @@ func TestStopEndsASubagentAndItsCommand(t *testing.T) { "note: Stopped by the user: " + name + ".", "work: " + subagentReport(name, []string{"stopped"}), }, test.Log(t)) + require.Equal(t, subagentStopped, test.events.LastEvent("work").Status) require.Equal(t, "<6>subagent started name="+name+"\n<6>subagent stopped name="+name+" after=0s\n", test.logs.String()) @@ -515,20 +522,50 @@ func TestRestartReportsASubagentThatCannotGoOn(t *testing.T) { events.WaitFor(t, "idle", 1) require.Equal(t, []string{ "note: The daemon restarted, cutting BlueFox; nothing was lost: go on.", - "work: " + subagentReport("BlueFox", []string{"failed: no agent BlueFox"}), + "work: " + subagentReport("BlueFox", []string{"failed: open worker log: no agent BlueFox"}), "reply: a line", }, subagentTestChat(t, memory)) + require.Equal(t, subagentFailed, events.LastEvent("work").Status) - require.Equal(t, "<3>subagent lost at restart name=BlueFox: no agent BlueFox\n", logs.String()) + require.Equal(t, "<3>subagent lost at restart name=BlueFox: open worker log: no agent BlueFox\n", logs.String()) data, err := os.ReadFile(filepath.Join(agent.dir, subagentWorkFileName)) require.NoError(t, err) require.JSONEq(t, `{"running": []}`, string(data)) } +// subagentTestLastItem returns the last input item of call. +func subagentTestLastItem(call ModelFakeCall) map[string]any { + input := call.body["input"].([]any) + + return input[len(input)-1].(map[string]any) +} + +// subagentTestCall tells if call is a call of a subagent. +func subagentTestCall(call ModelFakeCall) bool { + instructions, _ := call.body["instructions"].(string) + + return strings.HasPrefix(instructions, "You are a subagent") +} + +// subagentTestText returns the text of the user message item, or "" for another +// item. +func subagentTestText(item map[string]any) string { + content, _ := item["content"].([]any) + + var text strings.Builder + + for _, part := range content { + value, _ := part.(map[string]any)["text"].(string) + text.WriteString(value) + } + + return text.String() +} + // subagentTestStart runs a loop of agent with its memory and subagents in the -// agent directory, as the daemon does. The returned function stops the loop -// and closes the files. +// agent directory, as the daemon does. The returned function stops the loop and +// closes the files. func subagentTestStart(t *testing.T, agent *Agent, server *ModelFake, events *TurnEventRecorder, logger *slog.Logger) (*TurnLoop, *Memory, func()) { t.Helper() @@ -557,8 +594,7 @@ func subagentTestStart(t *testing.T, agent *Agent, server *ModelFake, events *Tu } } -// subagentTestChat returns each message of the chat in memory as -// "kind: text". +// subagentTestChat returns each message of the chat in memory as "kind: text". func subagentTestChat(t *testing.T, memory *Memory) []string { t.Helper() @@ -573,32 +609,3 @@ func subagentTestChat(t *testing.T, memory *Memory) []string { return lines } - -// subagentTestCall tells if call is a call of a subagent. -func subagentTestCall(call ModelFakeCall) bool { - instructions, _ := call.body["instructions"].(string) - - return strings.HasPrefix(instructions, "You are a subagent") -} - -// subagentTestLastItem returns the last input item of call. -func subagentTestLastItem(call ModelFakeCall) map[string]any { - input := call.body["input"].([]any) - - return input[len(input)-1].(map[string]any) -} - -// subagentTestText returns the text of the user message item, or "" for -// another item. -func subagentTestText(item map[string]any) string { - content, _ := item["content"].([]any) - - var text strings.Builder - - for _, part := range content { - value, _ := part.(map[string]any)["text"].(string) - text.WriteString(value) - } - - return text.String() -}