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

Viewing files at commit c2c9d5ba27afCommit detailsView latest

packages/sdk/src/index.ts 121 lines · 4.1 KB · typescript
1
import {
2
  canonicalHash,
3
  signObject,
4
  type InteractionEvent,
5
  type KeyPair,
6
  type TrustEnvelope,
7
  type FederatedInteraction,
8
  type PublicAgentCard,
9
} from '../../protocol/src/index.js';
10
export { createIdentity } from '../../core/src/index.js';
11
export * from '../../protocol/src/index.js';
12
13
export class OpenClaspClient {
14
  constructor(
15
    readonly baseUrl = 'http://localhost:3100/v0.1',
16
    readonly accessToken?: string,
17
  ) {}
18
  private async request<T>(path: string, init?: RequestInit): Promise<T> {
19
    const response = await fetch(`${this.baseUrl}${path}`, {
20
      ...init,
21
      headers: {
22
        'content-type': 'application/json',
23
        ...(this.accessToken ? { authorization: `Bearer ${this.accessToken}` } : {}),
24
        ...init?.headers,
25
      },
26
    });
27
    const body = (await response.json()) as any;
28
    if (!response.ok) throw new Error(body.error ?? `OpenClasp request failed: ${response.status}`);
29
    return body as T;
30
  }
31
  registerAgent(identity: unknown) {
32
    return this.request('/agents', { method: 'POST', body: JSON.stringify(identity) });
33
  }
34
  getProfile(agentId: string, version: string, taskCategory: string) {
35
    return this.request(
36
      `/profiles/${encodeURIComponent(agentId)}?version=${encodeURIComponent(version)}&taskCategory=${encodeURIComponent(taskCategory)}`,
37
    );
38
  }
39
  saveContract(contract: unknown) {
40
    return this.request('/interactions/contracts', {
41
      method: 'POST',
42
      body: JSON.stringify(contract),
43
    });
44
  }
45
  assess(input: unknown) {
46
    return this.request('/risk/assess', { method: 'POST', body: JSON.stringify(input) });
47
  }
48
  recordEvent(event: unknown) {
49
    return this.request('/events', { method: 'POST', body: JSON.stringify(event) });
50
  }
51
  checkClaim(claim: string) {
52
    return this.request('/claims/check', { method: 'POST', body: JSON.stringify({ claim }) });
53
  }
54
  submitReceipt(receipt: unknown) {
55
    return this.request('/receipts', { method: 'POST', body: JSON.stringify(receipt) });
56
  }
57
  verifyReceipt(receipt: unknown) {
58
    return this.request('/receipts/verify', { method: 'POST', body: JSON.stringify(receipt) });
59
  }
60
  submitFeedback(feedback: unknown) {
61
    return this.request('/feedback', { method: 'POST', body: JSON.stringify(feedback) });
62
  }
63
  setContributionConsent(agentId: string, enabled: boolean) {
64
    return this.request('/contributions/consent', {
65
      method: 'POST',
66
      body: JSON.stringify({ agentId, enabled }),
67
    });
68
  }
69
  getPublicAgentCard(agentId: string): Promise<PublicAgentCard> {
70
    const root = this.baseUrl.replace(/\/v0\.1\/?$/, '');
71
    return fetch(`${root}/agents/${encodeURIComponent(agentId)}/card.json`).then(
72
      async (response) => {
73
        const body = (await response.json()) as any;
74
        if (!response.ok)
75
          throw new Error(body.error ?? `OpenClasp request failed: ${response.status}`);
76
        return body as PublicAgentCard;
77
      },
78
    );
79
  }
80
  createFederatedInteraction(value: FederatedInteraction) {
81
    return this.request<FederatedInteraction>('/federated-interactions', {
82
      method: 'POST',
83
      body: JSON.stringify(value),
84
    });
85
  }
86
  listFederatedInteractions() {
87
    return this.request<FederatedInteraction[]>('/federated-interactions');
88
  }
89
  getFederatedInteraction(interactionId: string) {
90
    return this.request<FederatedInteraction>(
91
      `/federated-interactions/${encodeURIComponent(interactionId)}`,
92
    );
93
  }
94
  respondToFederatedInteraction(
95
    interactionId: string,
96
    agentId: string,
97
    decision: 'accept' | 'reject',
98
  ) {
99
    return this.request<FederatedInteraction>(
100
      `/federated-interactions/${encodeURIComponent(interactionId)}/respond`,
101
      { method: 'POST', body: JSON.stringify({ agentId, decision }) },
102
    );
103
  }
104
}
105
106
export function createSignedEvent(
107
  input: Omit<InteractionEvent, 'payloadHash' | 'signature'>,
108
  key: KeyPair,
109
): InteractionEvent {
110
  return signObject(
111
    { ...input, payloadHash: canonicalHash(input.payload) },
112
    key,
113
  ) as InteractionEvent;
114
}
115
116
export function createSignedEnvelope(
117
  input: Omit<TrustEnvelope, 'signature'>,
118
  key: KeyPair,
119
): TrustEnvelope {
120
  return signObject(input, key) as TrustEnvelope;
121
}