micro--go-micro
929cd1ab1d
Co-authored-by: Codex <codex@openai.com>
113 行
3.2 KiB
Go
113 行
3.2 KiB
Go
package a2a
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// An agent that embeds NewAgentHandler is directly A2A-queryable — no
|
|
// gateway, no registry — and the client talks to it the same way.
|
|
func TestEmbeddedAgentHandler(t *testing.T) {
|
|
card := Card("solo", "http://localhost:4000", "", []string{"task"})
|
|
h := NewAgentHandler(card, func(_ context.Context, text string) (string, error) {
|
|
return "echo:" + text, nil
|
|
})
|
|
ts := httptest.NewServer(h)
|
|
defer ts.Close()
|
|
|
|
cl := NewClient(ts.URL)
|
|
got, err := cl.Card(context.Background())
|
|
if err != nil || got.Name != "solo" {
|
|
t.Fatalf("Card() = %+v, err %v", got, err)
|
|
}
|
|
reply, err := cl.Send(context.Background(), "hi")
|
|
if err != nil || reply != "echo:hi" {
|
|
t.Fatalf("Send = %q, err %v", reply, err)
|
|
}
|
|
}
|
|
|
|
// The client fetches a card and sends a message to an agent served by the
|
|
// gateway — A2A end to end, both directions, in one process.
|
|
func TestClientSendAndCard(t *testing.T) {
|
|
ts, cleanup := newGatewayWithAgent(t)
|
|
defer cleanup()
|
|
|
|
cl := NewClient(ts.URL + "/agents/echo")
|
|
|
|
card, err := cl.Card(context.Background())
|
|
if err != nil || card.Name != "echo" {
|
|
t.Fatalf("Card() = %+v, err %v", card, err)
|
|
}
|
|
|
|
reply, err := cl.Send(context.Background(), "ping")
|
|
if err != nil {
|
|
t.Fatalf("Send: %v", err)
|
|
}
|
|
if reply != "pong" {
|
|
t.Errorf("Send reply = %q, want pong", reply)
|
|
}
|
|
}
|
|
|
|
func TestClientContinuesTaskAndConfiguresPush(t *testing.T) {
|
|
card := Card("solo", "http://localhost:4000", "", []string{"task"})
|
|
h := NewAgentHandler(card, func(_ context.Context, text string) (string, error) {
|
|
return "echo:" + text, nil
|
|
})
|
|
ts := httptest.NewServer(h)
|
|
defer ts.Close()
|
|
|
|
updates := make(chan Task, 1)
|
|
push := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
var task Task
|
|
if err := json.NewDecoder(r.Body).Decode(&task); err != nil {
|
|
t.Errorf("decode push task: %v", err)
|
|
return
|
|
}
|
|
updates <- task
|
|
w.WriteHeader(http.StatusAccepted)
|
|
}))
|
|
defer push.Close()
|
|
|
|
cl := NewClient(ts.URL)
|
|
first, err := cl.SendMessage(context.Background(), Message{
|
|
Parts: []Part{{Kind: "text", Text: "one"}},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("first SendMessage: %v", err)
|
|
}
|
|
second, err := cl.SendMessage(context.Background(), Message{
|
|
TaskID: first.ID,
|
|
ContextID: first.ContextID,
|
|
Parts: []Part{{Kind: "text", Text: "two"}},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("second SendMessage: %v", err)
|
|
}
|
|
if second.ID != first.ID || second.ContextID != first.ContextID || len(second.History) != 4 {
|
|
t.Fatalf("continued task = %+v, first %+v", second, first)
|
|
}
|
|
cfg := PushNotificationConfig{URL: push.URL}
|
|
if err := cl.SetPushNotificationConfig(context.Background(), second.ID, cfg); err != nil {
|
|
t.Fatalf("SetPushNotificationConfig: %v", err)
|
|
}
|
|
got, err := cl.PushNotificationConfig(context.Background(), second.ID)
|
|
if err != nil {
|
|
t.Fatalf("PushNotificationConfig: %v", err)
|
|
}
|
|
if got.URL != push.URL {
|
|
t.Fatalf("PushNotificationConfig URL = %q, want %q", got.URL, push.URL)
|
|
}
|
|
select {
|
|
case update := <-updates:
|
|
if update.ID != second.ID {
|
|
t.Fatalf("push update ID = %q, want %q", update.ID, second.ID)
|
|
}
|
|
case <-time.After(2 * time.Second):
|
|
t.Fatal("timed out waiting for push update")
|
|
}
|
|
}
|