a2aproject / a2aproject/a2a-dotnet

[Feat]: Enforce required Message fields at compile-time or runtime to ensure A2A spec compliance

Đang mở
#198 0 bình luận 1 reaction 0 người được giao Xem trên GitHub
Ngôn ngữ chính
C#
Star
262
Fork
64
Merge trung bình
5 ngày 2 giờ
Pull request đã merge (30 ngày)
31

Mô tả

### Is your feature request related to a problem? Please describe.

The A2A specification (v0.3.0) defines `Message.messageId` as a **required field** (Section 6.4):

```typescript
export interface Message {
readonly role: "user" | "agent";
parts: Part[];
messageId: string; // Required - must be a UUID
taskId?: string; // Optional
contextId?: string; // Optional
kind: "message";
}
```

However, the current C# SDK allows developers to construct `AgentMessage` (or `Message`) objects without providing a `messageId`, which results in **spec non-compliant responses** that may be rejected by clients or cause interoperability issues.

### Example of Current Problematic Code

```csharp
await _taskManager.UpdateStatusAsync(taskId, TaskState.InputRequired, new AgentMessage()
{
Parts = [new TextPart() { Text = "When ready say go ahead" }],
},
cancellationToken: cancellationToken);
```

This compiles and runs without errors, but produces a message with a missing or empty `messageId`, violating the A2A spec.

## Impact

- **Spec non-compliance**: Messages without `messageId` violate the A2A protocol
- **Interoperability issues**: Clients expecting spec-compliant messages may reject responses
- **Developer confusion**: No indication that a required field is missing until runtime testing
- **Inconsistent examples**: Some SDK examples (like `EchoAgent.cs`) include `MessageId`, while developers writing new agents may forget to include it

### Describe the solution you'd like

Add compile-time or runtime enforcement for required Message fields. Consider one or more of these approaches:

### Option 1: Use C# 11 `required` Keyword (Preferred)

```csharp
public class AgentMessage
{
public required string MessageId { get; init; }
public required MessageRole Role { get; init; }
public required Part[] Parts { get; init; }
public string? TaskId { get; init; }
public string? ContextId { get; init; }
public string Kind { get; init; } = "message";
}
```

**Benefits:**
- ✅ Compile-time errors when required fields are missing
- ✅ Clear intent in the type system
- ✅ IDE support (IntelliSense shows required fields)
- ✅ No runtime overhead

**Requirement:** Requires C# 11+ (.NET 7+), which the SDK already targets (.NET 8/9)

### Describe alternatives you've considered

### Option 2: Runtime Validation

Add validation in the `TaskManager` or serialization layer:

```csharp
private void ValidateMessage(AgentMessage message)
{
if (string.IsNullOrWhiteSpace(message.MessageId))
{
throw new ArgumentException(
"Message.MessageId is required by A2A specification (Section 6.4). " +
"Assign a unique identifier using: MessageId = Guid.NewGuid().ToString()",
nameof(message));
}

// Validate other required fields...
}
```

### Option 3: Builder Pattern with Validation

Provide a fluent builder that ensures required fields:

```csharp
var message = AgentMessage.Create()
.WithMessageId(Guid.NewGuid().ToString()) // Required
.WithRole(MessageRole.Agent) // Required
.WithParts(new TextPart { Text = "..." }) // Required
.WithTaskId(taskId) // Optional
.WithContextId(contextId) // Optional
.Build();
```

### Option 4: Analyzer Package (Advanced)

Create a Roslyn analyzer that warns at compile-time when `MessageId` is not set during object initialization.

## Recommended Approach

**Combination of Option 1 + Option 2:**
1. Use `required` keyword for compile-time safety (Option 1)
2. Add runtime validation as a safety net (Option 2)
3. Update all SDK examples and documentation to show the correct pattern

This provides defense-in-depth and matches the strictness of the Node.js SDK while leveraging C#'s type system.

## Additional Recommendations

### Also Consider for Optional But Recommended Fields

While `taskId` and `contextId` are optional per the spec schema, **all official spec examples include them** (Section 9.4). Consider:

- Adding XML documentation comments indicating these are "optional but recommended"
- Providing helper methods that make it easy to include them
- Adding analyzer warnings (not errors) when they're omitted

```csharp
///
/// Optional but recommended: Links this message to its parent task.
/// All A2A specification examples include this field.
///
public string? TaskId { get; init; }
```

### Additional context

Used GitHub Copilot for analysis

### Code of Conduct

- [x] I agree to follow this project's Code of Conduct

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Hướng nghiên cứu

The issue is about the AgentMessage class and the A2A spec. Start by examining the AgentMessage definition in the codebase, likely in a file like AgentMessage.cs. Review how messages are currently constructed and serialized. The goal is to modify the class to enforce required fields, possibly using the 'required' keyword, and add validation. Check existing tests for message creation to understand the current behavior and update them.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
csharp
Lĩnh vực
backend-api-design
Loại issue
Tính năng
Độ khó
3/5
Thời gian dự kiến
1-2 ngày
Mức độ hoạt động
Đình trệ
Độ rõ ràng
Đặc tả rõ ràng
Mức phù hợp với người mới
45/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.