aap-agent-client 2.6.0 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/index.js +3 -0
  2. package/package.json +3 -2
  3. package/websocket.js +162 -0
package/index.js CHANGED
@@ -208,4 +208,7 @@ export function createClient(options) {
208
208
  // Re-export Prover
209
209
  export { Prover };
210
210
 
211
+ // WebSocket client (v2.7+)
212
+ export { AAPWebSocketClient, createSolver, verifyWithWebSocket } from './websocket.js';
213
+
211
214
  export default { AAPClient, createClient, Prover };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aap-agent-client",
3
- "version": "2.6.0",
3
+ "version": "2.7.0",
4
4
  "description": "Client library for Agent Attestation Protocol - prove your AI agent identity",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -20,7 +20,8 @@
20
20
  },
21
21
  "homepage": "https://github.com/ira-hash/agent-attestation-protocol#readme",
22
22
  "dependencies": {
23
- "aap-agent-core": "^2.6.0"
23
+ "aap-agent-core": "^2.6.0",
24
+ "ws": "^8.16.0"
24
25
  },
25
26
  "engines": {
26
27
  "node": ">=18.0.0"
package/websocket.js ADDED
@@ -0,0 +1,162 @@
1
+ /**
2
+ * AAP WebSocket Client v2.7
3
+ *
4
+ * Connects to AAP WebSocket server, receives sequential challenges,
5
+ * and responds in real-time.
6
+ */
7
+
8
+ import WebSocket from 'ws';
9
+ import { Identity } from 'aap-agent-core';
10
+
11
+ const PROTOCOL_VERSION = '2.7.0';
12
+
13
+ /**
14
+ * AAP WebSocket Client
15
+ */
16
+ export class AAPWebSocketClient {
17
+ constructor(options = {}) {
18
+ this.serverUrl = options.serverUrl || 'ws://localhost:3000/aap';
19
+ this.identity = options.identity || new Identity(options);
20
+ this.llmCallback = options.llmCallback || null;
21
+ this.autoSolve = options.autoSolve !== false;
22
+ }
23
+
24
+ /**
25
+ * Get public identity info
26
+ */
27
+ getIdentity() {
28
+ return this.identity.getPublic();
29
+ }
30
+
31
+ /**
32
+ * Connect and verify
33
+ * @param {Function} [llmCallback] - async (challengeString) => solutionObject
34
+ * @returns {Promise<Object>} Verification result
35
+ */
36
+ async verify(llmCallback) {
37
+ const solver = llmCallback || this.llmCallback;
38
+
39
+ return new Promise((resolve, reject) => {
40
+ const ws = new WebSocket(this.serverUrl);
41
+ let sessionId = null;
42
+ let result = null;
43
+
44
+ ws.on('open', () => {
45
+ // Wait for handshake
46
+ });
47
+
48
+ ws.on('message', async (data) => {
49
+ try {
50
+ const msg = JSON.parse(data.toString());
51
+
52
+ switch (msg.type) {
53
+ case 'handshake':
54
+ sessionId = msg.sessionId;
55
+ // Send ready with identity
56
+ const identity = this.identity.getPublic();
57
+ ws.send(JSON.stringify({
58
+ type: 'ready',
59
+ publicKey: identity.publicKey,
60
+ publicId: identity.publicId
61
+ }));
62
+ break;
63
+
64
+ case 'challenge':
65
+ // Solve challenge
66
+ if (!solver) {
67
+ ws.send(JSON.stringify({
68
+ type: 'answer',
69
+ answer: {} // Empty - will fail
70
+ }));
71
+ break;
72
+ }
73
+
74
+ try {
75
+ const answer = await solver(msg.challenge, msg.id);
76
+ ws.send(JSON.stringify({
77
+ type: 'answer',
78
+ answer
79
+ }));
80
+ } catch (e) {
81
+ ws.send(JSON.stringify({
82
+ type: 'answer',
83
+ answer: { error: e.message }
84
+ }));
85
+ }
86
+ break;
87
+
88
+ case 'ack':
89
+ // Challenge acknowledged, wait for next
90
+ break;
91
+
92
+ case 'timeout':
93
+ // Too slow
94
+ break;
95
+
96
+ case 'result':
97
+ result = msg;
98
+ ws.close();
99
+ break;
100
+
101
+ case 'error':
102
+ reject(new Error(msg.message));
103
+ ws.close();
104
+ break;
105
+ }
106
+ } catch (e) {
107
+ reject(e);
108
+ }
109
+ });
110
+
111
+ ws.on('close', () => {
112
+ if (result) {
113
+ resolve(result);
114
+ } else {
115
+ reject(new Error('Connection closed without result'));
116
+ }
117
+ });
118
+
119
+ ws.on('error', (err) => {
120
+ reject(err);
121
+ });
122
+ });
123
+ }
124
+ }
125
+
126
+ /**
127
+ * Create solver function from LLM
128
+ * @param {Function} llm - async (prompt) => response string
129
+ * @returns {Function} Solver function
130
+ */
131
+ export function createSolver(llm) {
132
+ return async (challengeString, challengeId) => {
133
+ const prompt = `Solve this challenge and respond with ONLY valid JSON (no markdown, no explanation):
134
+
135
+ ${challengeString}
136
+
137
+ Important:
138
+ - Include the exact salt from the challenge
139
+ - Follow the response format exactly
140
+ - Return ONLY the JSON object`;
141
+
142
+ const response = await llm(prompt);
143
+
144
+ // Parse JSON from response
145
+ const jsonMatch = response.match(/\{[\s\S]*\}/);
146
+ if (!jsonMatch) {
147
+ throw new Error('No JSON found in response');
148
+ }
149
+
150
+ return JSON.parse(jsonMatch[0]);
151
+ };
152
+ }
153
+
154
+ /**
155
+ * Quick verify helper
156
+ */
157
+ export async function verifyWithWebSocket(serverUrl, llmCallback) {
158
+ const client = new AAPWebSocketClient({ serverUrl, llmCallback });
159
+ return client.verify();
160
+ }
161
+
162
+ export default AAPWebSocketClient;