wip: P1 feature batch — retry, search, code symbols, diff/status/test commands, tool output head+tail

- retry logic for transient LLM errors (openai.go)
- file_search context_lines + max_results (file.go)
- FormatResult now preserves head+tail with omitted bytes (tools.go)
- /status /diff /test slash commands wired (workflow.go, app.go)
- CodeSymbolsTool for Go package/type/func listing (code.go)
- README updated with v0.0.4 features
This commit is contained in:
loveuer
2026-06-24 10:13:28 +08:00
parent e4c75c7c0e
commit 86f69f6dd3
11 changed files with 724 additions and 57 deletions
+31
View File
@@ -66,6 +66,37 @@ func TestOpenAICompatibleClientStreamsContentAndToolCalls(t *testing.T) {
}
}
func TestOpenAICompatibleClientRetriesTransientHTTPError(t *testing.T) {
attempts := 0
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
attempts++
if attempts == 1 {
http.Error(w, "temporary", http.StatusBadGateway)
return
}
w.Header().Set("Content-Type", "text/event-stream")
_, _ = w.Write([]byte(`data: {"choices":[{"delta":{"content":"ok"},"finish_reason":""}]}` + "\n\n"))
_, _ = w.Write([]byte("data: [DONE]\n\n"))
}))
defer server.Close()
client := NewOpenAICompatibleClient(server.URL, "sk-test", server.Client())
var content strings.Builder
err := client.ChatStream(context.Background(), ChatRequest{Model: "test"}, func(event StreamEvent) error {
content.WriteString(event.Content)
return nil
})
if err != nil {
t.Fatal(err)
}
if attempts != 2 {
t.Fatalf("attempts = %d, want 2", attempts)
}
if content.String() != "ok" {
t.Fatalf("content = %q", content.String())
}
}
func mustReadBody(t *testing.T, r *http.Request) string {
t.Helper()
data, err := io.ReadAll(r.Body)