Skip to content

Commit fb8fc36

Browse files
feat: add AdditionalInterfaces and PreferredTransport props (#34)
* add AdditionalInterfaces and PreferredTransport props * add converter and tests * address pr review comment
1 parent 12187a0 commit fb8fc36

File tree

8 files changed

+586
-0
lines changed

8 files changed

+586
-0
lines changed

src/A2A/Models/AgentCard.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,4 +118,22 @@ public class AgentCard
118118
/// </remarks>
119119
[JsonPropertyName("supportsAuthenticatedExtendedCard")]
120120
public bool SupportsAuthenticatedExtendedCard { get; set; } = false;
121+
122+
/// <summary>
123+
/// Announcement of additional supported transports.
124+
/// </summary>
125+
/// <remarks>
126+
/// The client can use any of the supported transports.
127+
/// </remarks>
128+
[JsonPropertyName("additionalInterfaces")]
129+
public List<AgentInterface>? AdditionalInterfaces { get; set; }
130+
131+
/// <summary>
132+
/// The transport of the preferred endpoint.
133+
/// </summary>
134+
/// <remarks>
135+
/// If empty, defaults to JSONRPC.
136+
/// </remarks>
137+
[JsonPropertyName("preferredTransport")]
138+
public AgentTransport? PreferredTransport { get; set; }
121139
}

src/A2A/Models/AgentInterface.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System.ComponentModel.DataAnnotations;
2+
using System.Text.Json.Serialization;
3+
4+
namespace A2A;
5+
6+
/// <summary>
7+
/// Provides a declaration of a combination of target URL and supported transport to interact with an agent.
8+
/// </summary>
9+
public class AgentInterface
10+
{
11+
/// <summary>
12+
/// The transport supported by this URL.
13+
/// </summary>
14+
/// <remarks>
15+
/// This is an open form string, to be easily extended for many transport protocols.
16+
/// The core ones officially supported are JSONRPC, GRPC, and HTTP+JSON.
17+
/// </remarks>
18+
[JsonPropertyName("transport")]
19+
[Required]
20+
public required AgentTransport Transport { get; set; }
21+
22+
/// <summary>
23+
/// The target URL for the agent interface.
24+
/// </summary>
25+
[JsonPropertyName("url")]
26+
[Required]
27+
public required string Url { get; set; }
28+
}

src/A2A/Models/AgentTransport.cs

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
using System.Text.Json;
2+
using System.Text.Json.Serialization;
3+
4+
namespace A2A;
5+
6+
/// <summary>
7+
/// Represents the transport protocol for an AgentInterface.
8+
/// </summary>
9+
[JsonConverter(typeof(AgentTransportConverter))]
10+
public readonly struct AgentTransport : IEquatable<AgentTransport>
11+
{
12+
/// <summary>
13+
/// JSON-RPC transport.
14+
/// </summary>
15+
public static AgentTransport JsonRpc { get; } = new("JSONRPC");
16+
17+
/// <summary>
18+
/// Gets the label associated with this <see cref="AgentTransport"/>.
19+
/// </summary>
20+
public string Label { get; }
21+
22+
/// <summary>
23+
/// Creates a new <see cref="AgentTransport"/> instance with the provided label.
24+
/// </summary>
25+
/// <param name="label">The label to associate with this <see cref="AgentTransport"/>.</param>
26+
[JsonConstructor]
27+
public AgentTransport(string label)
28+
{
29+
if (string.IsNullOrWhiteSpace(label))
30+
throw new ArgumentException("Transport label cannot be null or whitespace.", nameof(label));
31+
this.Label = label;
32+
}
33+
34+
/// <summary>
35+
/// Determines whether two <see cref="AgentTransport"/> instances are equal.
36+
/// </summary>
37+
/// <param name="left">The first <see cref="AgentTransport"/> to compare.</param>
38+
/// <param name="right">The second <see cref="AgentTransport"/> to compare.</param>
39+
/// <returns><c>true</c> if the instances are equal; otherwise, <c>false</c>.</returns>
40+
public static bool operator ==(AgentTransport left, AgentTransport right)
41+
=> left.Equals(right);
42+
43+
/// <summary>
44+
/// Determines whether two <see cref="AgentTransport"/> instances are not equal.
45+
/// </summary>
46+
/// <param name="left">The first <see cref="AgentTransport"/> to compare.</param>
47+
/// <param name="right">The second <see cref="AgentTransport"/> to compare.</param>
48+
/// <returns><c>true</c> if the instances are not equal; otherwise, <c>false</c>.</returns>
49+
public static bool operator !=(AgentTransport left, AgentTransport right)
50+
=> !(left == right);
51+
52+
/// <summary>
53+
/// Determines whether the specified object is equal to the current <see cref="AgentTransport"/>.
54+
/// </summary>
55+
/// <param name="obj">The object to compare with the current <see cref="AgentTransport"/>.</param>
56+
/// <returns><c>true</c> if the specified object is equal to the current <see cref="AgentTransport"/>; otherwise, <c>false</c>.</returns>
57+
public override bool Equals(object? obj)
58+
=> obj is AgentTransport other && this == other;
59+
60+
/// <summary>
61+
/// Determines whether the specified <see cref="AgentTransport"/> is equal to the current <see cref="AgentTransport"/>.
62+
/// </summary>
63+
/// <param name="other">The <see cref="AgentTransport"/> to compare with the current <see cref="AgentTransport"/>.</param>
64+
/// <returns><c>true</c> if the specified <see cref="AgentTransport"/> is equal to the current <see cref="AgentTransport"/>; otherwise, <c>false</c>.</returns>
65+
public bool Equals(AgentTransport other)
66+
=> string.Equals(this.Label, other.Label, StringComparison.OrdinalIgnoreCase);
67+
68+
/// <summary>
69+
/// Returns the hash code for this <see cref="AgentTransport"/>.
70+
/// </summary>
71+
/// <returns>A hash code for the current <see cref="AgentTransport"/>.</returns>
72+
public override int GetHashCode()
73+
=> StringComparer.OrdinalIgnoreCase.GetHashCode(this.Label);
74+
75+
/// <summary>
76+
/// Returns the string representation of this <see cref="AgentTransport"/>.
77+
/// </summary>
78+
/// <returns>The label of this <see cref="AgentTransport"/>.</returns>
79+
public override string ToString() => this.Label;
80+
81+
/// <summary>
82+
/// Custom JSON converter for <see cref="AgentTransport"/> that serializes it as a simple string value.
83+
/// </summary>
84+
internal sealed class AgentTransportConverter : JsonConverter<AgentTransport>
85+
{
86+
/// <summary>
87+
/// Reads and converts the JSON to <see cref="AgentTransport"/>.
88+
/// </summary>
89+
/// <param name="reader">The reader to read from.</param>
90+
/// <param name="typeToConvert">The type to convert.</param>
91+
/// <param name="options">Serializer options.</param>
92+
/// <returns>The converted <see cref="AgentTransport"/>.</returns>
93+
public override AgentTransport Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
94+
{
95+
if (reader.TokenType != JsonTokenType.String)
96+
{
97+
throw new JsonException("Expected a string for AgentTransport.");
98+
}
99+
100+
var label = reader.GetString();
101+
if (string.IsNullOrWhiteSpace(label))
102+
{
103+
throw new JsonException("AgentTransport string value cannot be null or whitespace.");
104+
}
105+
106+
return new AgentTransport(label!);
107+
}
108+
109+
/// <summary>
110+
/// Writes the <see cref="AgentTransport"/> as a JSON string.
111+
/// </summary>
112+
/// <param name="writer">The writer to write to.</param>
113+
/// <param name="value">The value to convert.</param>
114+
/// <param name="options">Serializer options.</param>
115+
public override void Write(Utf8JsonWriter writer, AgentTransport value, JsonSerializerOptions options)
116+
{
117+
writer.WriteStringValue(value.Label);
118+
}
119+
}
120+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
#if !NETCOREAPP
5+
namespace System.Runtime.CompilerServices;
6+
7+
[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)]
8+
internal sealed class CompilerFeatureRequiredAttribute : Attribute
9+
{
10+
public CompilerFeatureRequiredAttribute(string featureName)
11+
{
12+
this.FeatureName = featureName;
13+
}
14+
15+
/// <summary>
16+
/// The name of the compiler feature.
17+
/// </summary>
18+
public string FeatureName { get; }
19+
20+
/// <summary>
21+
/// If true, the compiler can choose to allow access to the location where this attribute is applied if it does not understand <see cref="FeatureName"/>.
22+
/// </summary>
23+
public bool IsOptional { get; init; }
24+
25+
/// <summary>
26+
/// The <see cref="FeatureName"/> used for the ref structs C# feature.
27+
/// </summary>
28+
public const string RefStructs = nameof(RefStructs);
29+
30+
/// <summary>
31+
/// The <see cref="FeatureName"/> used for the required members C# feature.
32+
/// </summary>
33+
public const string RequiredMembers = nameof(RequiredMembers);
34+
}
35+
#endif
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
#if !NETCOREAPP
5+
namespace System.Runtime.CompilerServices;
6+
7+
/// <summary>
8+
/// Reserved to be used by the compiler for tracking metadata.
9+
/// This class should not be used by developers in source code.
10+
/// </summary>
11+
internal static class IsExternalInit;
12+
#endif
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
#if !NETCOREAPP
5+
namespace System.Runtime.CompilerServices;
6+
7+
/// <summary>
8+
/// Specifies that a type has required members or that a member is required.
9+
/// </summary>
10+
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
11+
internal sealed class RequiredMemberAttribute : Attribute;
12+
#endif

0 commit comments

Comments
 (0)