@@ -11,13 +11,19 @@ namespace SkillServer.Services;
1111public sealed class NativeManifestGenerator
1212{
1313 private const string SkillsPageRange = "all" ;
14+ private const string SubAgentsPageRange = "all" ;
1415
15- private readonly SkillRepository _repository ;
16+ private readonly SkillRepository _skillRepository ;
17+ private readonly SubAgentRepository _subAgentRepository ;
1618 private readonly IConfiguration _configuration ;
1719
18- public NativeManifestGenerator ( SkillRepository repository , IConfiguration configuration )
20+ public NativeManifestGenerator (
21+ SkillRepository skillRepository ,
22+ SubAgentRepository subAgentRepository ,
23+ IConfiguration configuration )
1924 {
20- _repository = repository ;
25+ _skillRepository = skillRepository ;
26+ _subAgentRepository = subAgentRepository ;
2127 _configuration = configuration ;
2228 }
2329
@@ -30,7 +36,8 @@ public Task<NativeRootManifest> GenerateRootAsync(CancellationToken ct = default
3036 {
3137 Self = Link ( "/manifest.json" ) ,
3238 RfcSkills = Link ( "/.well-known/agent-skills/index.json" ) ,
33- Skills = Link ( "/manifest/skills/index.json" )
39+ Skills = Link ( "/manifest/skills/index.json" ) ,
40+ SubAgents = Link ( "/manifest/subagents/index.json" )
3441 }
3542 } ;
3643
@@ -57,12 +64,12 @@ public Task<NativeSkillCollectionIndex> GenerateSkillIndexAsync(CancellationToke
5764 if ( ! page . Equals ( SkillsPageRange , StringComparison . OrdinalIgnoreCase ) )
5865 return null ;
5966
60- var latestVersions = await _repository . GetAllLatestVersionsWithMetadataAsync ( ct : ct ) ;
67+ var latestVersions = await _skillRepository . GetAllLatestVersionsWithMetadataAsync ( ct : ct ) ;
6168 var items = new List < NativeSkillPageItem > ( latestVersions . Count ) ;
6269
6370 foreach ( var latest in latestVersions )
6471 {
65- var versions = await _repository . GetAllVersionsAsync ( latest . SkillId , ct ) ;
72+ var versions = await _skillRepository . GetAllVersionsAsync ( latest . SkillId , ct ) ;
6673 if ( versions . Count == 0 )
6774 continue ;
6875
@@ -91,11 +98,11 @@ public Task<NativeSkillCollectionIndex> GenerateSkillIndexAsync(CancellationToke
9198
9299 public async Task < NativeSkillIdentityIndex ? > GenerateSkillIdentityAsync ( string skillName , CancellationToken ct = default )
93100 {
94- var skill = await _repository . GetSkillByNameAsync ( skillName , ct ) ;
101+ var skill = await _skillRepository . GetSkillByNameAsync ( skillName , ct ) ;
95102 if ( skill is null )
96103 return null ;
97104
98- var versions = await _repository . GetAllVersionsAsync ( skill . Id , ct ) ;
105+ var versions = await _skillRepository . GetAllVersionsAsync ( skill . Id , ct ) ;
99106 if ( versions . Count == 0 )
100107 return null ;
101108
@@ -117,11 +124,11 @@ public Task<NativeSkillCollectionIndex> GenerateSkillIndexAsync(CancellationToke
117124
118125 public async Task < NativeSkillVersionDetail ? > GenerateSkillVersionAsync ( string skillName , string version , CancellationToken ct = default )
119126 {
120- var skill = await _repository . GetSkillByNameAsync ( skillName , ct ) ;
127+ var skill = await _skillRepository . GetSkillByNameAsync ( skillName , ct ) ;
121128 if ( skill is null )
122129 return null ;
123130
124- var skillVersion = await _repository . GetVersionAsync ( skill . Id , version , ct ) ;
131+ var skillVersion = await _skillRepository . GetVersionAsync ( skill . Id , version , ct ) ;
125132 if ( skillVersion is null )
126133 return null ;
127134
@@ -139,6 +146,106 @@ public Task<NativeSkillCollectionIndex> GenerateSkillIndexAsync(CancellationToke
139146 } ;
140147 }
141148
149+ public Task < NativeSubAgentCollectionIndex > GenerateSubAgentIndexAsync ( CancellationToken ct = default )
150+ {
151+ var index = new NativeSubAgentCollectionIndex
152+ {
153+ Links = SelfLinks ( "/manifest/subagents/index.json" ) ,
154+ Pages = [ new NativeManifestPageLink
155+ {
156+ Range = SubAgentsPageRange ,
157+ Href = "/manifest/subagents/pages/all.json"
158+ } ]
159+ } ;
160+
161+ return Task . FromResult ( index ) ;
162+ }
163+
164+ public async Task < NativeSubAgentCollectionPage ? > GenerateSubAgentPageAsync ( string page , CancellationToken ct = default )
165+ {
166+ if ( ! page . Equals ( SubAgentsPageRange , StringComparison . OrdinalIgnoreCase ) )
167+ return null ;
168+
169+ var latestVersions = await _subAgentRepository . GetAllLatestVersionsWithMetadataAsync ( ct ) ;
170+ var items = new List < NativeSubAgentPageItem > ( latestVersions . Count ) ;
171+
172+ foreach ( var latest in latestVersions )
173+ {
174+ var versions = await _subAgentRepository . GetAllVersionsAsync ( latest . SubAgentId , ct ) ;
175+ if ( versions . Count == 0 )
176+ continue ;
177+
178+ var oldest = versions [ ^ 1 ] ;
179+ items . Add ( new NativeSubAgentPageItem
180+ {
181+ Name = latest . SubAgentName ,
182+ LatestVersion = latest . Version ,
183+ VersionRange = new NativeVersionRange
184+ {
185+ Min = oldest . Version ,
186+ Max = latest . Version ,
187+ Count = versions . Count
188+ } ,
189+ Href = $ "/manifest/subagents/{ latest . SubAgentName } /index.json"
190+ } ) ;
191+ }
192+
193+ return new NativeSubAgentCollectionPage
194+ {
195+ Range = SubAgentsPageRange ,
196+ Items = items ,
197+ Links = SelfLinks ( "/manifest/subagents/pages/all.json" )
198+ } ;
199+ }
200+
201+ public async Task < NativeSubAgentIdentityIndex ? > GenerateSubAgentIdentityAsync ( string subAgentName , CancellationToken ct = default )
202+ {
203+ var subAgent = await _subAgentRepository . GetSubAgentByNameAsync ( subAgentName , ct ) ;
204+ if ( subAgent is null )
205+ return null ;
206+
207+ var versions = await _subAgentRepository . GetAllVersionsAsync ( subAgent . Id , ct ) ;
208+ if ( versions . Count == 0 )
209+ return null ;
210+
211+ var latest = versions . FirstOrDefault ( v => v . IsLatest ) ?? versions [ 0 ] ;
212+ return new NativeSubAgentIdentityIndex
213+ {
214+ Name = subAgent . Name ,
215+ LatestVersion = latest . Version ,
216+ Versions = versions . Select ( v => new NativeSubAgentVersionLink
217+ {
218+ Version = v . Version ,
219+ PublishedAt = v . PublishedAt ,
220+ Digest = Sha256Digest . Create ( v . Sha256 ) . Value ,
221+ Href = $ "/manifest/subagents/{ subAgent . Name } /versions/{ v . Version } .json"
222+ } ) . ToList ( ) ,
223+ Links = SelfLinks ( $ "/manifest/subagents/{ subAgent . Name } /index.json")
224+ } ;
225+ }
226+
227+ public async Task < NativeSubAgentVersionDetail ? > GenerateSubAgentVersionAsync ( string subAgentName , string version , CancellationToken ct = default )
228+ {
229+ var subAgent = await _subAgentRepository . GetSubAgentByNameAsync ( subAgentName , ct ) ;
230+ if ( subAgent is null )
231+ return null ;
232+
233+ var subAgentVersion = await _subAgentRepository . GetVersionAsync ( subAgent . Id , version , ct ) ;
234+ if ( subAgentVersion is null )
235+ return null ;
236+
237+ var baseUrl = GetBaseUrl ( ) ;
238+ return new NativeSubAgentVersionDetail
239+ {
240+ Name = subAgent . Name ,
241+ Version = subAgentVersion . Version ,
242+ Description = subAgentVersion . Description ,
243+ Url = $ "{ baseUrl } /subagents/{ subAgent . Name } /{ subAgentVersion . Version } /agent.md",
244+ Digest = Sha256Digest . Create ( subAgentVersion . Sha256 ) . Value ,
245+ Links = SelfLinks ( $ "/manifest/subagents/{ subAgent . Name } /versions/{ subAgentVersion . Version } .json")
246+ } ;
247+ }
248+
142249 private NativeSkillArtifact CreateArtifact ( string skillName , SkillVersion version )
143250 {
144251 var baseUrl = GetBaseUrl ( ) ;
0 commit comments