### Run HelloWorld Example Source: https://github.com/a2aserver/a2a-go/blob/main/README.md Execute the HelloWorld example server. ```bash go run ./examples/helloworld/main.go # or ./helloworld ``` -------------------------------- ### Build Example Servers Source: https://github.com/a2aserver/a2a-go/blob/main/README.md Compile the example servers using the Go toolchain. ```bash go build ./cmd/a2aserver/... go build ./examples/.../... ``` -------------------------------- ### Run Simple Streaming Example Source: https://github.com/a2aserver/a2a-go/blob/main/README.md Execute the simple streaming example server. ```bash go run ./examples/simple/main.go # or ./simple ``` -------------------------------- ### Initialize and start an A2A server Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/README.md Configures a new server instance with custom handlers and options, then starts the HTTP listener. ```go server, err := a2a.NewServer( a2a.HandlerFuncs{ GetAgentCardFunc: getAgentCard, SendTaskFunc: handleTask, }, a2a.WithAddress(":8080"), a2a.WithStore(a2a.NewInMemoryTaskStore()), ) if err != nil { log.Fatal(err) } if err := server.Serve(); err != nil { log.Fatal(err) } ``` -------------------------------- ### Server.Serve Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/server.md Starts the server and begins listening on the configured address. ```APIDOC ## func (s *Server) Serve() error ### Description Starts the server and begins listening. This is a blocking call that returns when the server stops or encounters a fatal error. ### Returns - **error** - Any error encountered during server operation. ``` -------------------------------- ### Initialize Artifact instance Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/types.md Example of creating an Artifact instance with parts and metadata flags. ```go artifact := a2a.Artifact{ Name: "processing_result", Description: "Final output", Parts: []a2a.Part{a2a.TextPart{Text: "Result data"}}, Index: 0, LastChunk: true, } ``` -------------------------------- ### Initialize DataPart instance Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/types.md Example of creating a DataPart instance with a map and MIME type. ```go dataPart := a2a.DataPart{ Data: map[string]interface{}{ "key": "value", "number": 42, }, MimeType: "application/json", } ``` -------------------------------- ### Initialize A2A Server Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/configuration.md Demonstrates the complete setup process including logger, file storage, handler registration, and server startup. ```go package main import ( "log" "os" "github.com/a2aserver/a2a-go" ) func main() { // 1. Configure logger logger := log.New(os.Stderr, "[MyAgent] ", log.LstdFlags|log.Lshortfile) // 2. Configure storage fileStore, err := a2a.NewFileTaskStore("./tasks") if err != nil { log.Fatalf("Failed to create store: %v", err) } // 3. Define handlers handlerFuncs := a2a.HandlerFuncs{ GetAgentCardFunc: getAgentCard, SendTaskFunc: handleTask, } // 4. Create server with all options server, err := a2a.NewServer( handlerFuncs, a2a.WithAddress(":9000"), a2a.WithLogger(logger), a2a.WithStore(fileStore), a2a.WithBasePath("/api/tasks"), ) if err != nil { logger.Fatalf("Failed to create server: %v", err) } // 5. Start server logger.Println("Starting server...") if err := server.Serve(); err != nil { logger.Fatalf("Server failed: %v", err) } } ``` -------------------------------- ### Implement Agent Handlers Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/quick-start.md Example implementation of agent card configuration and task handling logic in Go. ```go package main import ( "time" "github.com/a2aserver/a2a-go" ) func getAgentCard() (*a2a.AgentCard, error) { return &a2a.AgentCard{ Name: "My Agent", URL: "http://localhost:8080", Version: "1.0.0", Capabilities: a2a.AgentCapabilities{Streaming: true}, Authentication: a2a.AgentAuthentication{Schemes: []string{"None"}}, }, nil } func handleTask(ctx *a2a.TaskContext) (*a2a.Task, error) { task := ctx.CurrentTask task.Status.State = a2a.StateCompleted task.Status.Message = &a2a.Message{ Role: a2a.RoleAgent, Parts: []a2a.Part{a2a.TextPart{Text: "Done"}}, } task.Status.SetTimestamp(time.Now()) return task, nil } func handleStreamingTask(ctx *a2a.TaskContext) (*a2a.Task, error) { go func() { ctx.UpdateFn(a2a.TaskStatus{State: a2a.StateProcessing}) time.Sleep(1 * time.Second) ctx.UpdateFn(a2a.TaskStatus{State: a2a.StateCompleted}) }() return ctx.CurrentTask, nil } ``` -------------------------------- ### Start A2A Server Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/server.md Starts the server on the configured address. This is a blocking call that should be checked for errors other than http.ErrServerClosed. ```go func (s *Server) Serve() error ``` ```go if err := server.Serve(); err != nil && err != http.ErrServerClosed { log.Fatalf("Server failed: %v", err) } ``` -------------------------------- ### Implement Custom TaskStore Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/task-store.md Example implementation of a TaskStore using a database, including the required Save, Load, and Delete methods. ```go type MyDatabaseStore struct { db *sql.DB } func (m *MyDatabaseStore) Save(data *TaskAndHistory) error { // Save to database return m.db.QueryRow(...).Scan(...) } func (m *MyDatabaseStore) Load(taskID string) (*TaskAndHistory, error) { // Load from database // Return (nil, nil) if not found return &TaskAndHistory{...}, nil } func (m *MyDatabaseStore) Delete(taskID string) error { // Delete from database return m.db.Exec(...).Err } // Use it store := &MyDatabaseStore{db: myDB} server, err := a2a.NewServer(handlerFuncs, a2a.WithStore(store)) ``` -------------------------------- ### RPC Result Event Format and Example Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/streaming.md The initial event sent at the start of the stream containing the task response. ```text event: rpc_result data: {"jsonrpc":"2.0","result":{task},"id":} ``` ```text event: rpc_result data: {"jsonrpc":"2.0","result":{"id":"abc123","status":{"state":"pending"},"artifacts":[]},"id":1} ``` -------------------------------- ### Implement SendTaskSubscribeFunc Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/handlers.md Example implementation of a streaming task handler that sends progress and artifacts asynchronously. ```go handlerFuncs.SendTaskSubscribeFunc = func(ctx *a2a.TaskContext) (*a2a.Task, error) { // Spawn async work go func() { // Send progress ctx.UpdateFn(a2a.TaskStatus{State: a2a.StateProcessing}) // Do work time.Sleep(2 * time.Second) // Send artifact ctx.UpdateFn(a2a.Artifact{ Name: "result", Parts: []a2a.Part{a2a.TextPart{Text: "Complete"}}, }) // Send completion ctx.UpdateFn(a2a.TaskStatus{ State: a2a.StateCompleted, Message: &a2a.Message{ Role: a2a.RoleAgent, Parts: []a2a.Part{a2a.TextPart{Text: "Done streaming"}}, }, }) }() return ctx.CurrentTask, nil } ``` -------------------------------- ### Define and Initialize AgentSkill Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/types.md Defines the structure for agent skills and provides an example of how to instantiate one. ```go type AgentSkill struct { ID string `json:"id"` Name string `json:"name"` Description string `json:"description,omitempty"` Tags []string `json:"tags,omitempty"` Examples []string `json:"examples,omitempty"` } ``` ```go skill := a2a.AgentSkill{ ID: "document_analysis", Name: "Document Analysis", Description: "Analyzes uploaded documents and extracts key information", Tags: []string{"analysis", "text"}, Examples: []string{"Analyze this PDF", "Extract tables from document"}, } ``` -------------------------------- ### Implementing GetAgentCardFunc Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/handlers.md Example implementation of the mandatory GetAgentCardFunc within the HandlerFuncs struct. ```go handlerFuncs := a2a.HandlerFuncs{ GetAgentCardFunc: func() (*a2a.AgentCard, error) { return &a2a.AgentCard{ Name: "My Agent", Description: "Does important work", URL: "http://localhost:8080", Version: "1.0.0", Capabilities: a2a.AgentCapabilities{ Streaming: true, PushNotifications: false, }, Authentication: a2a.AgentAuthentication{ Schemes: []string{"None"}, }, }, nil }, } ``` -------------------------------- ### Initialize A2A Server Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/server.md Defines the signature for creating a new server instance and provides a usage example with mandatory handler functions and optional configurations. ```go func NewServer(funcs HandlerFuncs, opts ...Option) (*Server, error) ``` ```go handlerFuncs := a2a.HandlerFuncs{ GetAgentCardFunc: getMyAgentCard, SendTaskFunc: handleMyTask, } server, err := a2a.NewServer( handlerFuncs, a2a.WithAddress(":8080"), a2a.WithLogger(logger), a2a.WithStore(fileStore), ) if err != nil { log.Fatalf("Failed to create server: %v", err) } ``` -------------------------------- ### Create a new RPC error instance Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/errors.md Example of instantiating an RPCError using the provided constructor. ```go rpcErr := a2a.NewRPCError( a2a.TaskNotFoundCode, "Task not found", "task '12345' does not exist", ) ``` -------------------------------- ### Retrieve Task Success Response Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/endpoints.md Example successful response for the tasks/get method. ```json { "jsonrpc": "2.0", "result": { "id": "task-uuid", "status": { "state": "completed" } }, "id": 2 } ``` -------------------------------- ### Implement SendTaskFunc Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/handlers.md Example implementation of a non-streaming task handler that updates task state to completed. ```go handlerFuncs.SendTaskFunc = func(ctx *a2a.TaskContext) (*a2a.Task, error) { log.Printf("Handling task %s", ctx.ID) // Do work finalTask := ctx.CurrentTask finalTask.Status.State = a2a.StateCompleted finalTask.Status.Message = &a2a.Message{ Role: a2a.RoleAgent, Parts: []a2a.Part{a2a.TextPart{Text: "Done!"}}, } return finalTask, nil } ``` -------------------------------- ### Task Subscription SSE Events Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/endpoints.md Example SSE event stream output for task subscription. ```text event: rpc_result data: {"jsonrpc":"2.0","result":{"id":"task-uuid","status":{"state":"pending"}},"id":4} ``` ```text event: task_status_update data: {"id":"task-uuid","status":{"state":"processing"},"final":false} event: task_artifact_update data: {"id":"task-uuid","artifact":{"name":"result","parts":[...] },"final":false} event: task_status_update data: {"id":"task-uuid","status":{"state":"completed",...},"final":true} ``` -------------------------------- ### Get a Task Source: https://github.com/a2aserver/a2a-go/blob/main/docs/A2A文档.md Retrieves task artifacts and optionally the task history. ```json //Request { "jsonrpc": "0", "id": 1, "method":"tasks/get", "params": { "id": "de38c76d-d54c-436c-8b9f-4c2703648d64", "historyLength": 10, "metadata": {} } } //Response { "jsonrpc": "0", "id": 1, "result": { "id": "de38c76d-d54c-436c-8b9f-4c2703648d64", "sessionId": "c295ea44-7543-4f78-b524-7a38915ad6e4", "status": { "state": "completed" }, "artifacts": [{ "parts": [{ "type":"text", "text":"Why did the chicken cross the road? To get to the other side!" }] }], "history":[ { "role": "user", "parts": [ { "type": "text", "text": "tell me a joke" } ] } ], "metadata": {} } } ``` -------------------------------- ### Configure RPC Base Path with WithBasePath Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/options.md Defines the base path for JSON-RPC requests. Paths not starting with '/' are automatically corrected. ```go func WithBasePath(path string) Option ``` ```go server, err := a2a.NewServer( handlerFuncs, a2a.WithBasePath("/myagent/rpc"), ) // RPC requests to: POST /myagent/rpc // Agent card at: GET /.well-known/agent.json ``` -------------------------------- ### Configure Base Path Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/configuration.md Defines the base path for RPC endpoints. The path must start with a forward slash. ```go a2a.WithBasePath("/myagent/rpc") ``` ```go server, err := a2a.NewServer( handlerFuncs, a2a.WithBasePath("/v1/rpc"), ) ``` -------------------------------- ### GetAgentCardFunc Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/handlers.md Returns the agent's metadata card describing its capabilities, authentication, and skills. This function is mandatory for the server to start. ```APIDOC ## GetAgentCardFunc ### Description Returns the agent's metadata card describing its capabilities, authentication, and skills. ### Signature `func GetAgentCardFunc() (*AgentCard, error)` ### Returns - **AgentCard** (object) - The agent's metadata. - **error** (error) - An error if the metadata is unavailable. ### Mandatory Yes. The server will not start if this is nil. ### Example ```go handlerFuncs := a2a.HandlerFuncs{ GetAgentCardFunc: func() (*a2a.AgentCard, error) { return &a2a.AgentCard{ Name: "My Agent", Description: "Does important work", URL: "http://localhost:8080", Version: "1.0.0", Capabilities: a2a.AgentCapabilities{ Streaming: true, PushNotifications: false, }, Authentication: a2a.AgentAuthentication{ Schemes: []string{"None"}, }, }, nil }, } ``` ``` -------------------------------- ### Task Status Update Event Format and Examples Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/streaming.md Events triggered by changes in task state, including a final flag to indicate completion. ```text event: task_status_update data: {"id":"","status":{status},"final":false} ``` ```text event: task_status_update data: {"id":"abc123","status":{"state":"processing","timestamp":"2026-07-18T12:34:56.789Z"},"final":false} event: task_status_update data: {"id":"abc123","status":{"state":"completed","message":{"role":"agent","parts":[{"type":"text","text":"Done"}]},"timestamp":"2026-07-18T12:34:57.123Z"},"final":true} ``` -------------------------------- ### GET /.well-known/agent.json Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/MANIFEST.txt Retrieves the agent metadata card. ```APIDOC ## GET /.well-known/agent.json ### Description Retrieves the agent's configuration and metadata card. ### Method GET ### Endpoint /.well-known/agent.json ``` -------------------------------- ### Cancel Task Success Response Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/endpoints.md Example successful response for the tasks/cancel method. ```json { "jsonrpc": "2.0", "result": { "id": "task-uuid", "status": { "state": "canceled", "message": { "role": "agent", "parts": [{"type": "text", "text": "Task canceled by request."}] } } }, "id": 3 } ``` -------------------------------- ### Configure Server via Environment Variables Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/configuration.md Since the library does not read environment variables automatically, use os.Getenv to retrieve values and pass them to the server constructor. ```go addr := os.Getenv("A2A_ADDRESS") if addr == "" { addr = ":8080" } storeDir := os.Getenv("A2A_STORE_DIR") if storeDir == "" { storeDir = ".a2a-tasks" } store, err := a2a.NewFileTaskStore(storeDir) server, err := a2a.NewServer( handlerFuncs, a2a.WithAddress(addr), a2a.WithStore(store), ) ``` -------------------------------- ### Initialize FileTaskStore Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/task-store.md Creates a file-based task store using a specified base directory. Files are stored as JSON. ```go func NewFileTaskStore(baseDir string) (*FileTaskStore, error) ``` ```go fileStore, err := a2a.NewFileTaskStore("./tasks") if err != nil { log.Fatalf("Failed to create store: %v", err) } server, err := a2a.NewServer( handlerFuncs, a2a.WithStore(fileStore), ) ``` -------------------------------- ### Test HelloWorld Endpoints Source: https://github.com/a2aserver/a2a-go/blob/main/README.md Verify the HelloWorld server by retrieving the agent card and sending a task via JSON-RPC. ```bash # Get Agent Card curl http://localhost:8080/.well-known/agent.json | jq . # Send Task (assuming default base path /) curl -X POST http://localhost:8080/ -d '{"jsonrpc":"2.0","method":"tasks/send","params":{"message":{"role":"user","parts":[{"type":"text","text":"Hi"}]}},"id":1}' | jq . ``` -------------------------------- ### Configure Server Address with WithAddress Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/options.md Sets the network address for the server. Requires a non-empty string. ```go func WithAddress(addr string) Option ``` ```go server, err := a2a.NewServer( handlerFuncs, a2a.WithAddress(":8080"), ) ``` -------------------------------- ### Implement complete streaming task handler Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/streaming.md A full implementation showing how to return the initial task and process updates asynchronously in a separate function. ```go func handleStreamingTask(ctx *a2a.TaskContext) (*a2a.Task, error) { log.Printf("Streaming task %s started", ctx.ID) // Return initial task immediately go processAsync(ctx) return ctx.CurrentTask, nil } func processAsync(ctx *a2a.TaskContext) { // Simulate work with progress updates for i := 1; i <= 3; i++ { time.Sleep(1 * time.Second) // Send progress status := a2a.TaskStatus{ State: a2a.StateProcessing, } if i == 1 { status.Message = &a2a.Message{ Role: a2a.RoleAgent, Parts: []a2a.Part{ a2a.TextPart{Text: fmt.Sprintf("Processing step %d/3", i)}, }, } } err := ctx.UpdateFn(status) if err != nil { log.Printf("Update error: %v", err) return } } // Send final artifact artifact := a2a.Artifact{ Name: "completion", Parts: []a2a.Part{ a2a.TextPart{Text: "All steps completed"}, }, LastChunk: true, } ctx.UpdateFn(artifact) // Send completion status ctx.UpdateFn(a2a.TaskStatus{ State: a2a.StateCompleted, Message: &a2a.Message{ Role: a2a.RoleAgent, Parts: []a2a.Part{ a2a.TextPart{Text: "Task completed successfully"}, }, }, }) log.Printf("Streaming task %s completed", ctx.ID) } ``` -------------------------------- ### Implement Custom Agent Server Source: https://github.com/a2aserver/a2a-go/blob/main/README.md Basic implementation of an agent server using a2a-go, including custom handler functions and file-based task storage. ```go package main import ( "log" "github.com/a2aserver/a2a-go"// Adjust import path "os" ) // 1. Implement required GetAgentCardFunc func myAgentCard() (*a2a.AgentCard, error) { // ... return your agent card ... return &a2a.AgentCard{ Name: "My Custom Agent", // ... other fields ... }, nil } // 2. Implement optional handler funcs (e.g., SendTaskFunc) // Access the current task state via ctx.CurrentTask // For streaming (SendTaskSubscribeFunc), use ctx.UpdateFn to send updates. func mySendTask(ctx *a2a.TaskContext) (*a2a.Task, error) { log.Printf("Handling task %s", ctx.ID) // ... your logic here, potentially modifying ctx.CurrentTask ... finalTask := ctx.CurrentTask // Use provided task as base finalTask.Status.State = a2a.StateCompleted // ... set status message/artifacts ... log.Printf("Task %s completed by custom handler.", ctx.ID) return finalTask, nil } func main() { logger := log.New(os.Stderr, "[MyAgent] ", log.LstdFlags) // 3. Define HandlerFuncs handlerFuncs := a2a.HandlerFuncs{ GetAgentCardFunc: myAgentCard, SendTaskFunc: mySendTask, // Other funcs like SendTaskSubscribeFunc, GetTaskFunc, CancelTaskFunc // left nil will use server defaults (interacting with TaskStore). } // 4. Create and configure the server store, err := a2a.NewFileTaskStore("my_agent_tasks") // Use file store if err != nil { logger.Fatalf("Failed to create file store: %v", err) } server, err := a2a.NewServer( handlerFuncs, a2a.WithAddress(":8080"), a2a.WithLogger(logger), a2a.WithStore(store), // a2a.WithBasePath("/myagent/rpc"), // Optional: Set custom RPC base path ) if err != nil { logger.Fatalf("Failed to create server: %v", err) } // 5. Start the server (add graceful shutdown if needed) logger.Println("Starting server...") if err := server.Serve(); err != nil { logger.Fatalf("Server failed: %v", err) } } ``` -------------------------------- ### Configure Task Persistence with WithStore Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/options.md Sets the TaskStore implementation for persistence. Defaults to an in-memory store if omitted. ```go func WithStore(store TaskStore) Option ``` ```go fileStore, err := a2a.NewFileTaskStore("./tasks") if err != nil { log.Fatalf("Failed to create file store: %v", err) } server, err := a2a.NewServer( handlerFuncs, a2a.WithStore(fileStore), ) ``` -------------------------------- ### Implement TextPart Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/types.md Structure for plain text content with a corresponding Type method implementation. ```go type TextPart struct { Text string `json:"text"` } func (t TextPart) Type() string { return "text" } ``` ```go part := a2a.TextPart{Text: "Hello, world!"} ``` -------------------------------- ### RPC Result Event Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/streaming.md The initial event sent at the start of the stream containing the task object. ```APIDOC ## Event: rpc_result ### Description Sent once at the start of the stream, containing the initial task. ### Structure - **jsonrpc** (string) - "2.0" - **result** (Task) - The initial pending task - **id** (any) - Request ID from original RPC call ### Example ``` event: rpc_result data: {"jsonrpc":"2.0","result":{"id":"abc123","status":{"state":"pending"},"artifacts":[]},"id":1} ``` ``` -------------------------------- ### Get Task Push Notifications Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/endpoints.md Retrieves the current push notification configuration for a task by its ID. ```json { "jsonrpc": "2.0", "method": "tasks/pushNotification/get", "params": { "id": "task-uuid" }, "id": 7 } ``` ```json { "jsonrpc": "2.0", "result": { "url": "https://client.example.com/webhook", "token": "secret-token" }, "id": 7 } ``` -------------------------------- ### Implement FilePart Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/types.md Structure for file attachments supporting either raw bytes or URI references. ```go type FilePart struct { File FileData `json:"file"` MimeType string `json:"mimeType,omitempty"` } func (f FilePart) Type() string { return "file" } ``` ```go type FileData struct { Bytes *[]byte `json:"bytes,omitempty"` URI *string `json:"uri,omitempty"` } ``` ```go filePart := a2a.FilePart{ File: a2a.FileData{ URI: stringPtr("https://example.com/document.pdf"), }, MimeType: "application/pdf", } ``` -------------------------------- ### NewFileTaskStore Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/task-store.md Creates a new file-based task store. ```APIDOC ## func NewFileTaskStore(baseDir string) ### Description Creates a new file-based task store. Stores each task as a JSON file in a base directory. ### Parameters - **baseDir** (string) - Optional - Base directory for task files. Defaults to `.a2a-tasks`. ``` -------------------------------- ### JSON-RPC Error Response Format Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/errors.md Example of a structured JSON-RPC 2.0 error response returned by the server. ```json { "jsonrpc": "2.0", "error": { "code": -32001, "message": "Task not found", "data": "task 'abc123' not found in store" }, "id": 1 } ``` -------------------------------- ### NewServer Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/server.md Creates and configures a new A2A Server instance with required handler functions and optional configuration. ```APIDOC ## func NewServer(funcs HandlerFuncs, opts ...Option) (*Server, error) ### Description Initializes a new A2A Server. Requires a set of handler functions, specifically `GetAgentCardFunc`. ### Parameters - **funcs** (HandlerFuncs) - Required - Handler function implementations. - **opts** (...Option) - Optional - Functional options for server configuration. ### Returns - **(*Server, error)** - A configured server instance or an error if initialization fails. ``` -------------------------------- ### Task Artifact Update Event Format and Examples Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/streaming.md Events sent when artifacts are generated or updated during the task lifecycle. ```text event: task_artifact_update data: {"id":"","artifact":{artifact},"final":false} ``` ```text event: task_artifact_update data: {"id":"abc123","artifact":{"name":"output","parts":[{"type":"text","text":"Intermediate result"}],"index":0,"lastChunk":false},"final":false} event: task_artifact_update data: {"id":"abc123","artifact":{"name":"output","parts":[{"type":"text","text":"Final result"}],"index":0,"lastChunk":true},"final":true} ``` -------------------------------- ### Initialize InMemoryTaskStore Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/task-store.md Creates a new in-memory task store instance. Suitable for development or testing where persistence is not required. ```go func NewInMemoryTaskStore() *InMemoryTaskStore ``` ```go store := a2a.NewInMemoryTaskStore() server, err := a2a.NewServer( handlerFuncs, a2a.WithStore(store), ) ``` -------------------------------- ### Configure Agent with Custom Logger and Base Path Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/quick-start.md Initializes an a2a server instance with a custom logger, file store, and specific base path configuration. ```go package main import ( "log" "os" "github.com/a2aserver/a2a-go" ) func main() { // Custom logger logFile, _ := os.OpenFile("agent.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) defer logFile.Close() logger := log.New(logFile, "[MyAgent] ", log.LstdFlags|log.Lshortfile) // File store store, _ := a2a.NewFileTaskStore("./data/tasks") handlerFuncs := a2a.HandlerFuncs{ GetAgentCardFunc: func() (*a2a.AgentCard, error) { return &a2a.AgentCard{ Name: "Configured Agent", URL: "http://localhost:9000", Version: "1.0.0", Capabilities: a2a.AgentCapabilities{}, Authentication: a2a.AgentAuthentication{Schemes: []string{"None"}}, }, nil }, } server, _ := a2a.NewServer( handlerFuncs, a2a.WithAddress(":9000"), a2a.WithLogger(logger), a2a.WithStore(store), a2a.WithBasePath("/api/a2a"), ) logger.Println("Agent configured:") logger.Println(" - Listening on :9000") logger.Println(" - RPC endpoint: /api/a2a") logger.Println(" - Agent card: /.well-known/agent.json") logger.Println(" - Task storage: ./data/tasks") server.Serve() } ``` -------------------------------- ### Configure Server Address Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/configuration.md Sets the network address for the server. Requires a non-empty string in [host]:port format. ```go a2a.WithAddress(":8080") ``` ```go server, err := a2a.NewServer( handlerFuncs, a2a.WithAddress(":9000"), ) ``` -------------------------------- ### Configure Task Store Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/configuration.md Sets the storage backend for tasks. Supports in-memory, file-based, or custom implementations of the TaskStore interface. ```go a2a.WithStore(store) ``` ```go store := a2a.NewInMemoryTaskStore() ``` ```go store, err := a2a.NewFileTaskStore("./tasks") ``` ```go type MyStore struct {} func (m *MyStore) Save(data *TaskAndHistory) error { ... } func (m *MyStore) Load(taskID string) (*TaskAndHistory, error) { ... } func (m *MyStore) Delete(taskID string) error { ... } ``` ```go fileStore, err := a2a.NewFileTaskStore("./agent_tasks") if err != nil { log.Fatalf("Failed to create store: %v", err) } server, err := a2a.NewServer( handlerFuncs, a2a.WithStore(fileStore), ) ``` -------------------------------- ### Implement Agent with Persistent Storage Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/quick-start.md Uses FileTaskStore to persist task data to the local filesystem. Requires a directory path for storage initialization. ```go package main import ( "log" "os" "github.com/a2aserver/a2a-go" ) func main() { logger := log.New(os.Stderr, "[File Agent] ", log.LstdFlags) // Create file store store, err := a2a.NewFileTaskStore("./tasks") if err != nil { logger.Fatalf("Failed to create store: %v", err) } handlerFuncs := a2a.HandlerFuncs{ GetAgentCardFunc: func() (*a2a.AgentCard, error) { return &a2a.AgentCard{ Name: "File Agent", URL: "http://localhost:8080", Version: "1.0.0", Capabilities: a2a.AgentCapabilities{}, Authentication: a2a.AgentAuthentication{Schemes: []string{"None"}}, }, nil }, // No SendTaskFunc = default: create pending task and save } server, _ := a2a.NewServer( handlerFuncs, a2a.WithAddress(":8080"), a2a.WithStore(store), a2a.WithLogger(logger), ) logger.Println("Listening on :8080, storing tasks in ./tasks") server.Serve() } ``` -------------------------------- ### tasks/send Source: https://github.com/a2aserver/a2a-go/blob/main/docs/A2A文档.md Allows a client to send content to a remote agent to start a new Task, resume an interrupted Task, or reopen a completed Task. ```APIDOC ## tasks/send ### Description Allows a client to send content to a remote agent to start a new Task, resume an interrupted Task or reopen a completed Task. ### Request Example { "jsonrpc": "0", "id": 1, "method": "tasks/send", "params": { "id": "de38c76d-d54c-436c-8b9f-4c2703648d64", "message": { "role": "user", "parts": [{ "type": "text", "text": "tell me a joke" }] }, "metadata": {} } } ### Response Example { "jsonrpc": "0", "id": 1, "result": { "id": "de38c76d-d54c-436c-8b9f-4c2703648d64", "sessionId": "c295ea44-7543-4f78-b524-7a38915ad6e4", "status": { "state": "completed" }, "artifacts": [{ "name": "joke", "parts": [{ "type": "text", "text": "Why did the chicken cross the road? To get to the other side!" }] }], "metadata": {} } } ``` -------------------------------- ### WithStore Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/options.md Sets a custom TaskStore implementation for task persistence. ```APIDOC ## func WithStore(store TaskStore) Option ### Description Sets a custom TaskStore for task persistence. If not provided, the server defaults to an InMemoryTaskStore. ### Parameters - **store** (TaskStore) - Required - A TaskStore implementation (e.g., InMemoryTaskStore, FileTaskStore). ### Returns - **Option** - A functional option that configures the server. ### Error Conditions - Returns an error if store is nil. ### Example ```go fileStore, err := a2a.NewFileTaskStore("./tasks") server, err := a2a.NewServer( handlerFuncs, a2a.WithStore(fileStore), ) ``` ``` -------------------------------- ### Recommended Project Structure Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/quick-start.md Standard directory layout for organizing A2A agent projects. ```text my-agent/ ├── main.go # Server entrypoint ├── handlers.go # Handler implementations ├── config.go # Configuration management ├── go.mod ├── go.sum ├── data/ │ └── tasks/ # Task storage (if using FileTaskStore) ├── logs/ # Log files └── README.md ``` -------------------------------- ### Handle ErrTaskNotFound Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/errors.md Demonstrates checking for ErrTaskNotFound during store load operations. ```go data, err := store.Load(taskID) if err != nil && errors.Is(err, a2a.ErrTaskNotFound) { // Task not found } else if err != nil { // Other error (e.g., read failure) } ``` -------------------------------- ### Load task from file Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/task-store.md Loads a task and its history from JSON files. Returns nil if the task file does not exist. ```go func (fs *FileTaskStore) Load(taskID string) (*TaskAndHistory, error) ``` -------------------------------- ### Configure Server Logger Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/configuration.md Provides a custom logger instance. Defaults to os.Stderr with a specific prefix if not provided. ```go a2a.WithLogger(logger) ``` ```go log.New(os.Stderr, "[A2A Server] ", log.LstdFlags|log.Lshortfile) ``` ```go customLogger := log.New(os.Stderr, "[MyAgent] ", log.LstdFlags|log.Lshortfile) server, err := a2a.NewServer( handlerFuncs, a2a.WithLogger(customLogger), ) ``` -------------------------------- ### Implement ResubscribeFunc in Go Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/streaming.md Server-side handler logic to verify task existence before initiating a new SSE stream. ```go ResubscribeFunc: func(params *a2a.TaskGetParams) error { // Verify task exists data, err := store.Load(params.ID) if err != nil { return err } if data == nil { return a2a.ErrTaskNotFound } // Optionally replay recent events here return nil } ``` -------------------------------- ### POST /api/tasks Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/streaming.md Initiates a task subscription using Server-Sent Events (SSE) via a JSON-RPC request. ```APIDOC ## POST /api/tasks ### Description Initiates a task subscription. The client sends a JSON-RPC request to subscribe to task updates, which are then streamed back via SSE events. ### Method POST ### Endpoint /api/tasks ### Request Body - **jsonrpc** (string) - Required - Version of the JSON-RPC protocol (e.g., "2.0") - **method** (string) - Required - The method name, set to "tasks/sendSubscribe" - **params** (object) - Required - Parameters containing the message object - **id** (number) - Required - Request identifier ### Response - **rpc_result** (event) - Initial task response data - **task_status_update** (event) - Updates regarding the task status - **task_artifact_update** (event) - Updates regarding task artifacts ``` -------------------------------- ### Implement UpdateFn callback usage Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/streaming.md Demonstrates sending task status and artifacts within a SendTaskSubscribeFunc handler using a goroutine. ```go handlerFuncs.SendTaskSubscribeFunc = func(ctx *a2a.TaskContext) (*a2a.Task, error) { go func() { // Send progress err := ctx.UpdateFn(a2a.TaskStatus{ State: a2a.StateProcessing, }) if err != nil { log.Printf("Failed to send status: %v", err) } // Do work... time.Sleep(2 * time.Second) // Send artifact err = ctx.UpdateFn(a2a.Artifact{ Name: "result", Parts: []a2a.Part{ a2a.TextPart{Text: "Processing complete"}, }, }) // Send completion ctx.UpdateFn(a2a.TaskStatus{ State: a2a.StateCompleted, Message: &a2a.Message{ Role: a2a.RoleAgent, Parts: []a2a.Part{ a2a.TextPart{Text: "Task finished"}, }, }, }) }() return ctx.CurrentTask, nil } ``` -------------------------------- ### Define Handler Functions Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/configuration.md Shows how to implement the mandatory GetAgentCardFunc and optional custom handlers within the HandlerFuncs struct. ```go handlerFuncs := a2a.HandlerFuncs{ // Mandatory GetAgentCardFunc: func() (*a2a.AgentCard, error) { return &a2a.AgentCard{ Name: "My Agent", // ... }, nil }, // Optional: Custom send handler SendTaskFunc: func(ctx *a2a.TaskContext) (*a2a.Task, error) { // Custom logic return ctx.CurrentTask, nil }, // Remaining handlers use defaults } ``` -------------------------------- ### Handle ErrUnsupportedOperation Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/errors.md Demonstrates checking for ErrUnsupportedOperation when calling handler methods. ```go task, err := handler.SendTask(ctx) if errors.Is(err, a2a.ErrUnsupportedOperation) { // Method not implemented, server will return error code -32004 } ``` -------------------------------- ### ResubscribeFunc Signature and Implementation Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/handlers.md Defines the signature for validating task resubscription and provides a standard implementation pattern using the task store. ```go func ResubscribeFunc(params *TaskGetParams) error ``` ```go handlerFuncs.ResubscribeFunc = func(params *a2a.TaskGetParams) error { data, err := store.Load(params.ID) if err != nil { return err } if data == nil { return a2a.ErrTaskNotFound } return nil } ``` -------------------------------- ### Configure Custom Logger with WithLogger Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/options.md Provides a custom log.Logger instance. Defaults to os.Stderr if not specified. ```go func WithLogger(logger *log.Logger) Option ``` ```go customLogger := log.New(os.Stderr, "[MyAgent] ", log.LstdFlags|log.Lshortfile) server, err := a2a.NewServer( handlerFuncs, a2a.WithLogger(customLogger), ) ``` -------------------------------- ### WithAddress Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/options.md Sets the listening address for the server. ```APIDOC ## func WithAddress(addr string) Option ### Description Sets the network address the server will listen on. ### Parameters - **addr** (string) - Required - Network address to listen on (e.g., :8080, 127.0.0.1:9000). ### Returns - **Option** - A functional option that configures the server. ### Error Conditions - Returns an error if addr is an empty string. ### Example ```go server, err := a2a.NewServer( handlerFuncs, a2a.WithAddress(":8080"), ) ``` ``` -------------------------------- ### Test Agent via CLI Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/quick-start.md Commands to verify agent metadata and send a task request using curl. ```bash # Get agent info curl http://localhost:8080/.well-known/agent.json | jq . # Send task curl -X POST http://localhost:8080 \ -d '{"jsonrpc":"2.0","method":"tasks/send","params":{"message":{"role":"user","parts":[{"type":"text","text":"Hello"}]}},"id":1}' \ | jq . ``` -------------------------------- ### FileTaskStore.Load Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/task-store.md Loads a task from JSON files. ```APIDOC ## func (fs *FileTaskStore) Load(taskID string) ### Description Loads a task from JSON files. Returns nil if the task file does not exist. ``` -------------------------------- ### InMemoryTaskStore.Load Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/task-store.md Retrieves a task from memory. ```APIDOC ## func (ms *InMemoryTaskStore) Load(taskID string) ### Description Retrieves a task from memory, returning a copy. Returns nil and nil if the task is not found. ``` -------------------------------- ### Implement Agent with Multiple Skills Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/quick-start.md Defines an agent with distinct capabilities and skills in the AgentCard. Requires implementing SendTaskFunc to handle incoming task requests. ```go package main import ( "fmt" "log" "os" "github.com/a2aserver/a2a-go" ) func main() { logger := log.New(os.Stderr, "[Multi-Skill] ", log.LstdFlags) handlerFuncs := a2a.HandlerFuncs{ GetAgentCardFunc: func() (*a2a.AgentCard, error) { return &a2a.AgentCard{ Name: "Multi-Skill Agent", URL: "http://localhost:8080", Version: "1.0.0", Capabilities: a2a.AgentCapabilities{Streaming: true}, Authentication: a2a.AgentAuthentication{Schemes: []string{"None"}}, Skills: []a2a.AgentSkill{ { ID: "analyze", Name: "Document Analysis", Description: "Analyzes uploaded documents", Examples: []string{"Analyze this PDF", "Extract data from document"}, }, { ID: "summarize", Name: "Summarization", Description: "Summarizes text content", Examples: []string{"Summarize this text", "Give me a brief summary"}, }, }, }, nil }, SendTaskFunc: func(ctx *a2a.TaskContext) (*a2a.Task, error) { task := ctx.CurrentTask task.Status.State = a2a.StateCompleted // In real implementation, route by skill or input type task.Status.Message = &a2a.Message{ Role: a2a.RoleAgent, Parts: []a2a.Part{ a2a.TextPart{Text: fmt.Sprintf("Processed: %d parts", len(ctx.Message.Parts))}, }, } return task, nil }, } server, _ := a2a.NewServer(handlerFuncs, a2a.WithAddress(":8080")) logger.Println("Listening on :8080") server.Serve() } ``` -------------------------------- ### POST {basePath}/tasks/send Source: https://github.com/a2aserver/a2a-go/blob/main/_autodocs/MANIFEST.txt Sends a new task to the server. ```APIDOC ## POST {basePath}/tasks/send ### Description Submits a new task for processing via JSON-RPC. ### Method POST ### Endpoint {basePath}/tasks/send ```