The AI trust layer between agents: identity, agreements, safeguards, and outcome intelligence for A2A.

Commit 04c17739

04c1773999ceMerged

aryaamin <[email protected]> · 2 months ago · 8 files · ~8 modified

Description

feat: automate provider interaction finalization

Details

Commit
04c1773999ce
Parent
18b70a0f11a5

apps/api/src/app.tsmodifiedView file

@@ -325,10 +325,16 @@
325325 return getOnboardingState(repository, owner);
326326 });
327327 router.get('/v0.1/runtime/bootstrap', async (request) => {
328- operatorId(request);
328+ const owner = operatorId(request);
329329 const agentId = boundAgentId(request);
330+ const rows = owner && repository ? await repository.list(owner) : [];
331+ const profile = rows.find((row) => row.kind === 'agent_profile' && row.recordId === agentId)
332+ ?.payload as AgentProfile | undefined;
330333 return {
331334 agentId,
335+ agentVersion: profile?.agentVersion ?? '1.0.0',
336+ capabilities: profile?.capabilities ?? [],
337+ limitations: profile?.limitations ?? [],
332338 openClaspUrl: publicBaseUrl(request),
333339 runtimeRegistrationEndpoint: `${publicBaseUrl(request)}/v0.1/runtime`,
334340 protocol: 'A2A/1.0',
@@ -356,6 +362,47 @@
356362 throw new Error('Agent presence is not configured');
357363 return repository.touchAgentPresence(owner, boundAgentId(request));
358364 });
365+ router.put('/v0.1/runtime/profile', async (request) => {
366+ const owner = operatorId(request);
367+ if (!repository || !owner) throw new Error('Hosted persistence is not configured');
368+ const agentId = boundAgentId(request);
369+ const value = z
370+ .object({
371+ description: z.string().trim().max(500).optional(),
372+ capabilities: z.array(z.string().trim().min(1).max(100)).min(1).max(100),
373+ limitations: z.array(z.string().trim().min(1).max(300)).max(100).default([]),
374+ })
375+ .strict()
376+ .parse(request.body);
377+ const rows = await repository.list(owner);
378+ const current = rows.find((row) => row.kind === 'agent_profile' && row.recordId === agentId)
379+ ?.payload as AgentProfile | undefined;
380+ if (!current || current.status !== 'active') throw new Error('Active owned agent not found');
381+ const profile: AgentProfile = {
382+ ...current,
383+ ...(value.description !== undefined ? { description: value.description } : {}),
384+ capabilities: [...new Set(value.capabilities)],
385+ limitations: [...new Set(value.limitations)],
386+ updatedAt: new Date().toISOString(),
387+ };
388+ await repository.upsert(owner, 'agent_profile', agentId, profile);
389+ const publication = rows.find((row) => row.kind === 'publication' && row.recordId === agentId)
390+ ?.payload as { published?: boolean } | undefined;
391+ if (profile.autoPublish || publication?.published) {
392+ const previous = await repository.getPublishedAgent(agentId);
393+ const card = await repository.publishAgent(
394+ owner,
395+ buildPublicAgentCard(profile, publicBaseUrl(request), previous),
396+ );
397+ await repository.upsert(owner, 'publication', agentId, {
398+ agentId,
399+ published: true,
400+ updatedAt: card.updatedAt,
401+ });
402+ return { profile, card };
403+ }
404+ return { profile };
405+ });
359406 router.post('/v0.1/onboarding/:id/approve', async (request) => {
360407 const owner = operatorId(request);
361408 if (!repository || !owner) throw new Error('Hosted persistence is not configured');
@@ -404,8 +451,8 @@
404451 provider: z.enum(['botpress', 'custom']),
405452 agentName: z.string().trim().min(1).max(100),
406453 projectName: z.string().trim().min(1).max(100),
407- description: z.string().trim().max(500).optional(),
408- capabilities: z.array(z.string().trim().min(1).max(100)).max(100).default([]),
454+ description: z.string().trim().min(1).max(500),
455+ capabilities: z.array(z.string().trim().min(1).max(100)).min(1).max(100),
409456 limitations: z.array(z.string().trim().min(1).max(300)).max(100).default([]),
410457 expiresInDays: z.number().int().min(1).max(365).default(365),
411458 })