clinch-core 0.5.0 → 0.6.1
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.
- package/README.md +124 -102
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,109 +1,121 @@
|
|
|
1
1
|
# Clinch Core (`clinch-core`)
|
|
2
2
|
|
|
3
|
-
> **
|
|
3
|
+
> **Agent Negotiation Protocol (ANP) — Edge Client & Seller SDK**
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Once an agreement is reached, Clinch issues a **cryptographically co-signed deal artifact** held by both parties. This SDK provides the complete network client, state-isolated session management, cryptographic signing engines, an optional out-of-the-box local LLM bargaining sandbox, and the server-side Seller SDK.
|
|
5
|
+
`clinch-core` is the programmatic engine of the Clinch Protocol. It provides the state machine, cryptographic signing interfaces, local LLM sandbox adapters, and server-side utilities required to implement both buyer and seller agents conforming to the **Agent Negotiation Protocol (ANP)**.
|
|
8
6
|
|
|
9
7
|
---
|
|
10
8
|
|
|
11
|
-
##
|
|
9
|
+
## 1. Protocol Architecture & Mechanics
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
The Agent Negotiation Protocol (ANP) governs how two autonomous software agents establish identity, declare capabilities, and reach a cryptographically verifiable agreement on price and terms.
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
* **Enterprise Concurrency**: Complete session isolation allows scaling horizontally. You can run hundreds of concurrent negotiations on a single server, serialize state, and resume negotiations across pod restarts or delayed webhooks.
|
|
18
|
-
* **Cryptographic Accountability**: Identity is proven via Ed25519 keys and Proof-of-Work (PoW). The final co-signed deal artifact is self-verifying against the Registry's daily rotating key chain. Zero-trust machine-to-machine updates are enforced without centralized JWT expirations.
|
|
13
|
+
### 1.1 Address Formatting & Routing
|
|
14
|
+
All destination routing in Clinch relies on strict, structured addressing:
|
|
19
15
|
|
|
20
|
-
|
|
16
|
+
$$\text{PROTOCOL\_MODE} \mathbin{.} \text{domain} \mathbin{.} \text{TLD}$$
|
|
21
17
|
|
|
22
|
-
|
|
18
|
+
*Example:* `ANP/C.amazon.anp`
|
|
23
19
|
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
npm install clinch-core
|
|
27
|
-
```
|
|
20
|
+
The SDK parses the address to extract the negotiated **Protocol Mode** and target namespace domain before dispatching the initialization request.
|
|
28
21
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
*
|
|
22
|
+
### 1.2 Protocol Modes
|
|
23
|
+
Sellers declare which execution profiles they support. The SDK maps these mode flags to session parameters during handshake:
|
|
24
|
+
|
|
25
|
+
* **`ANP/A`**: Standard native execution. Both buyer and seller agents run the local Clinch edge model. Best suited for high-volume, low-friction commodity exchanges.
|
|
26
|
+
* **`ANP/B`**: Mixed execution. One side uses the native edge model, while the other runs a custom model or external API adapter.
|
|
27
|
+
* **`ANP/C`**: Custom integration. Both agents run custom decision engines (e.g., GPT-4o, Claude 3.5, or proprietary heuristics).
|
|
34
28
|
|
|
35
29
|
---
|
|
36
30
|
|
|
37
|
-
##
|
|
31
|
+
## 2. State Machine & Event Architecture
|
|
38
32
|
|
|
39
|
-
|
|
33
|
+
The SDK maintains an isolated, turn-based state machine for each active session.
|
|
40
34
|
|
|
41
35
|
### Core Statuses (`CoreStatus`)
|
|
42
|
-
* `OFFLINE`: Client is disconnected.
|
|
43
|
-
* `CONNECTING`:
|
|
44
|
-
* `IDLE`: Connected and authenticated.
|
|
45
|
-
* `
|
|
46
|
-
* `
|
|
47
|
-
* `
|
|
48
|
-
* `
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
### Event Emitters
|
|
36
|
+
* `OFFLINE`: Client is completely disconnected.
|
|
37
|
+
* `CONNECTING`: Authenticating identity and performing local Proof-of-Work (PoW) verification.
|
|
38
|
+
* `IDLE`: Connected and authenticated. Ready to initialize new sessions.
|
|
39
|
+
* `NEGOTIATING`: Active, turn-based bargaining sequence in progress.
|
|
40
|
+
* `CONVERGED`: Mathematical convergence reached; agreement co-signed.
|
|
41
|
+
* `STALEMATE`: Handshake or negotiation sequence aborted or timed out.
|
|
42
|
+
* `ERROR`: Internal network, compilation, or cryptographic validation failure.
|
|
43
|
+
|
|
44
|
+
### Developer Event Subscriptions
|
|
52
45
|
```typescript
|
|
46
|
+
// Track the operational status of the client
|
|
53
47
|
core.on('status_changed', (status: CoreStatus) => {
|
|
54
|
-
console.log(`
|
|
48
|
+
console.log(`[Status] Client changed to: ${status}`);
|
|
55
49
|
});
|
|
56
50
|
|
|
51
|
+
// Fired when a new negotiation handshake is completed
|
|
57
52
|
core.on('session_started', ({ sessionId, sellerId }) => {
|
|
58
|
-
console.log(`
|
|
53
|
+
console.log(`[Session Started] Active ID: ${sessionId} targeting ${sellerId}`);
|
|
59
54
|
});
|
|
60
55
|
|
|
56
|
+
// Fired when a session reaches terminal state (deal converged or stalemate)
|
|
61
57
|
core.on('session_closed', ({ sessionId, outcome, finalPrice }) => {
|
|
62
|
-
console.log(`Session ${sessionId}
|
|
58
|
+
console.log(`[Session Closed] ID: ${sessionId} | Outcome: ${outcome} | Price: $${finalPrice}`);
|
|
63
59
|
});
|
|
64
60
|
|
|
61
|
+
// Fired when an out-of-band message is received via the WS callback channel
|
|
65
62
|
core.on('callback_received', ({ sessionId, payload }) => {
|
|
66
|
-
|
|
63
|
+
console.log(`[Callback] Re-engagement for session ${sessionId} received`);
|
|
67
64
|
});
|
|
68
65
|
```
|
|
69
66
|
|
|
70
67
|
---
|
|
71
68
|
|
|
72
|
-
##
|
|
69
|
+
## 3. Installation
|
|
73
70
|
|
|
74
|
-
|
|
71
|
+
Install the library using your package manager:
|
|
72
|
+
```bash
|
|
73
|
+
npm install clinch-core
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
To run the local autonomous **Sandbox engine**, install the required peer dependency:
|
|
77
|
+
```bash
|
|
78
|
+
npm install node-llama-cpp
|
|
79
|
+
```
|
|
80
|
+
*(Note: `node-llama-cpp` is dynamically imported at runtime. Web builds or headless environments will not fail if this dependency is omitted, provided `.sandbox()` is not invoked).*
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## 4. Integration Guide: Buyer Agents
|
|
85
|
+
|
|
86
|
+
### 4.1 Running the On-Device Sandbox
|
|
87
|
+
The local Sandbox runs an optimized **Qwen 2.5 1.5B Q4_K_M** model on local hardware resources. It automatically handles handshake math and turn-based counter-offers based on your strict constraints.
|
|
75
88
|
|
|
76
89
|
```javascript
|
|
77
90
|
const { ClinchCore } = require('clinch-core');
|
|
78
91
|
|
|
79
|
-
async function
|
|
92
|
+
async function runAutonomousSession() {
|
|
80
93
|
const core = new ClinchCore();
|
|
81
94
|
|
|
82
95
|
core.on('log', (msg) => console.log(msg));
|
|
83
|
-
core.on('session_closed', ({ finalPrice }) =>
|
|
96
|
+
core.on('session_closed', ({ finalPrice }) => {
|
|
97
|
+
console.log(`✓ Negotiation completed at $${finalPrice}`);
|
|
98
|
+
});
|
|
84
99
|
|
|
85
|
-
// 1. Initialize
|
|
100
|
+
// 1. Initialize local LLM, solve PoW, and connect WebSocket
|
|
86
101
|
await core.sandbox({ downloadLLM: true });
|
|
87
102
|
|
|
88
|
-
// 2.
|
|
103
|
+
// 2. Begin autonomous negotiation
|
|
89
104
|
const sessionId = await core.negotiate('ANP/C.amazon.anp', {
|
|
90
105
|
intent: 'purchase',
|
|
91
106
|
category: 'electronics',
|
|
92
107
|
item: 'Ninja Blender',
|
|
93
|
-
max_budget: 85.00
|
|
108
|
+
max_budget: 85.00
|
|
94
109
|
});
|
|
95
110
|
|
|
96
|
-
console.log(
|
|
111
|
+
console.log(`Session active: ${sessionId}`);
|
|
97
112
|
}
|
|
98
113
|
|
|
99
|
-
|
|
114
|
+
runAutonomousSession();
|
|
100
115
|
```
|
|
101
116
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
## 🔌 Quickstart: Bring Your Own AI & Webhook Persistence
|
|
105
|
-
|
|
106
|
-
If you are running in a cloud environment (e.g., handling webhooks) and want to leverage high-end hosted APIs (e.g. Claude 3.5 Sonnet or OpenAI GPT-4o), bypass the sandbox. The Core provides **State Serialization** to survive server restarts.
|
|
117
|
+
### 4.2 Cloud Webhook & Horizontal Scale Pattern
|
|
118
|
+
For enterprise cloud environments where processes must remain stateless or scale horizontally across server pods, you must serialize and rehydrate active sessions dynamically. This ensures that when an asynchronous callback arrives, any pod can load the session state and use the matching ephemeral key to sign the next turn.
|
|
107
119
|
|
|
108
120
|
```javascript
|
|
109
121
|
import { ClinchCore } from 'clinch-core';
|
|
@@ -112,53 +124,59 @@ import Anthropic from '@anthropic-ai/sdk';
|
|
|
112
124
|
const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
|
|
113
125
|
const core = new ClinchCore();
|
|
114
126
|
|
|
115
|
-
await core.initialize();
|
|
127
|
+
await core.initialize();
|
|
116
128
|
|
|
117
|
-
// 1. Start session
|
|
129
|
+
// 1. Start session
|
|
118
130
|
const sessionId = await core.negotiate('ANP/C.amazon.anp', {
|
|
119
131
|
intent: 'purchase',
|
|
120
132
|
item: 'Ninja Blender',
|
|
121
133
|
max_budget: 85.00
|
|
122
134
|
});
|
|
123
|
-
const savedState = core.exportSessionState(sessionId);
|
|
124
|
-
await db.save(sessionId, savedState);
|
|
125
135
|
|
|
126
|
-
//
|
|
136
|
+
// 2. Serialize and persist the state to your DB (Redis, Postgres, etc.)
|
|
137
|
+
const exportedState = core.exportSessionState(sessionId);
|
|
138
|
+
await db.saveSession(sessionId, exportedState);
|
|
139
|
+
|
|
140
|
+
// --- LATER, ON A DIFFERENT POD OR ASYNCHRONOUS WEBHOOK TRIGGER --- //
|
|
127
141
|
|
|
128
142
|
const webhookCore = new ClinchCore();
|
|
129
|
-
webhookCore.importSessionState(
|
|
143
|
+
webhookCore.importSessionState(exportedState);
|
|
130
144
|
|
|
131
145
|
webhookCore.on('callback_received', async (event) => {
|
|
132
|
-
//
|
|
146
|
+
// 3. Generate system prompt using rehydrated session data
|
|
133
147
|
const systemPrompt = webhookCore.buildAgentPrompt(event.sessionId, event.payload.message);
|
|
134
148
|
|
|
135
|
-
//
|
|
149
|
+
// 4. Evaluate with hosted LLM
|
|
136
150
|
const msg = await anthropic.messages.create({
|
|
137
151
|
model: "claude-3-5-sonnet-20241022",
|
|
138
152
|
maxTokens: 150,
|
|
139
153
|
system: systemPrompt,
|
|
140
|
-
messages: [{ role: "user", content: "
|
|
154
|
+
messages: [{ role: "user", content: "Calculate next move." }]
|
|
141
155
|
});
|
|
142
156
|
|
|
143
|
-
const
|
|
157
|
+
const decision = JSON.parse(msg.content[0].text);
|
|
144
158
|
|
|
145
|
-
//
|
|
146
|
-
if (
|
|
147
|
-
console.log("
|
|
159
|
+
// 5. Submit cryptographic counter-offer
|
|
160
|
+
if (decision.action === 'accept') {
|
|
161
|
+
console.log("Agreement reached!");
|
|
148
162
|
} else {
|
|
149
|
-
await webhookCore.sendCounter(event.sessionId,
|
|
150
|
-
|
|
163
|
+
await webhookCore.sendCounter(event.sessionId, decision.price, decision.message);
|
|
164
|
+
// 6. Update DB with new turn state and counters
|
|
165
|
+
await db.updateSession(event.sessionId, webhookCore.exportSessionState(event.sessionId));
|
|
151
166
|
}
|
|
152
167
|
});
|
|
153
168
|
```
|
|
154
169
|
|
|
155
170
|
---
|
|
156
171
|
|
|
157
|
-
##
|
|
172
|
+
## 5. Integration Guide: Seller Nodes
|
|
158
173
|
|
|
159
|
-
|
|
174
|
+
Sellers use the `ClinchSeller` class to build compliant, automated endpoints.
|
|
160
175
|
|
|
161
|
-
|
|
176
|
+
### 5.1 Decoupled Routing Architecture
|
|
177
|
+
To prevent centralized token expiration failures, Clinch separates ownership from routing:
|
|
178
|
+
1. **The Control Plane**: The merchant claims their domain name (e.g., `amazon.anp`) and binds their permanent public key to it once using the dashboard.
|
|
179
|
+
2. **The Data Plane**: The actual seller server is initialized with the matching permanent private key. On boot, the machine signs its dynamic endpoint configuration locally and publishes it to the registry. No JWTs are used on-wire for machine routing.
|
|
162
180
|
|
|
163
181
|
```javascript
|
|
164
182
|
import { ClinchSeller } from 'clinch-core';
|
|
@@ -167,10 +185,12 @@ import express from 'express';
|
|
|
167
185
|
const app = express();
|
|
168
186
|
app.use(express.json());
|
|
169
187
|
|
|
170
|
-
// Initialize with
|
|
171
|
-
const seller = new ClinchSeller({
|
|
188
|
+
// 1. Initialize seller with the permanent cryptographic key
|
|
189
|
+
const seller = new ClinchSeller({
|
|
190
|
+
privateKeyHex: process.env.SELLER_PRIVATE_KEY
|
|
191
|
+
});
|
|
172
192
|
|
|
173
|
-
// Publish
|
|
193
|
+
// 2. Publish endpoint to the registry on boot (Self-Signing)
|
|
174
194
|
await seller.registerEndpoint({
|
|
175
195
|
agent_id: 'amazon.anp',
|
|
176
196
|
endpoint: 'https://your-seller-api.com/anp/v1',
|
|
@@ -179,21 +199,21 @@ await seller.registerEndpoint({
|
|
|
179
199
|
capabilities: ['price_flex']
|
|
180
200
|
});
|
|
181
201
|
|
|
182
|
-
//
|
|
202
|
+
// 3. Implement the standard ANP counter-offer endpoint
|
|
183
203
|
app.post('/anp/v1/counter', (req, res) => {
|
|
184
204
|
const { session_id, turn, price, reason, buyer_sig } = req.body;
|
|
185
205
|
|
|
186
|
-
//
|
|
206
|
+
// Cryptographically verify the buyer's ephemeral signature
|
|
187
207
|
const isValid = seller.verifyBuyerSignature(
|
|
188
208
|
{ session_id, turn, price, reason },
|
|
189
209
|
buyer_sig,
|
|
190
210
|
req.headers['x-buyer-pubkey']
|
|
191
211
|
);
|
|
192
212
|
|
|
193
|
-
if (!isValid) return res.status(401).
|
|
213
|
+
if (!isValid) return res.status(401).json({ error: "Invalid signature" });
|
|
194
214
|
|
|
195
|
-
//
|
|
196
|
-
res.json({ msg_type: 'counter', price: 95.00, reason: "Best
|
|
215
|
+
// Execute bargaining logic and respond
|
|
216
|
+
res.json({ msg_type: 'counter', price: 95.00, reason: "Best we can offer is $95." });
|
|
197
217
|
});
|
|
198
218
|
|
|
199
219
|
app.listen(8080);
|
|
@@ -201,53 +221,55 @@ app.listen(8080);
|
|
|
201
221
|
|
|
202
222
|
---
|
|
203
223
|
|
|
204
|
-
##
|
|
224
|
+
## 6. API Reference
|
|
205
225
|
|
|
206
|
-
###
|
|
226
|
+
### 6.1 `ClinchCore` (Buyer Client)
|
|
207
227
|
|
|
208
228
|
#### `new ClinchCore(config)`
|
|
209
|
-
* `config.registryUrl` *(string)*:
|
|
210
|
-
* `config.timeoutMs` *(number)*:
|
|
229
|
+
* `config.registryUrl` *(string)*: Optional. Direct override pointing to a local development registry.
|
|
230
|
+
* `config.timeoutMs` *(number)*: Network connection timeout limit (Default: `5000`ms).
|
|
211
231
|
|
|
212
232
|
#### `async initialize(cachedToken?)`
|
|
213
|
-
|
|
233
|
+
Resolves network configurations, computes Proof-of-Work proof, and opens active WebSocket channels.
|
|
234
|
+
* `cachedToken` *(string)*: Optional. Pastes a previous registry authorization token to skip PoW calculations on startup.
|
|
214
235
|
|
|
215
236
|
#### `async negotiate(address, constraints)`
|
|
216
|
-
|
|
217
|
-
* `address` *(string)*: e.g
|
|
218
|
-
* `constraints` *(ConstraintVector)*:
|
|
237
|
+
Initializes the cryptographic handshake with a seller. Returns `sessionId`.
|
|
238
|
+
* `address` *(string)*: Target address formatted strictly as `PROTOCOL_MODE.domain` (e.g., `ANP/C.amazon.anp`).
|
|
239
|
+
* `constraints` *(ConstraintVector)*: Schema requiring `max_budget` (number) and `item` (string).
|
|
219
240
|
|
|
220
241
|
#### `exportSessionState(sessionId)` / `importSessionState(serializedData)`
|
|
221
|
-
Serializes
|
|
242
|
+
Serializes or de-serializes all in-flight state for a given session, including ephemeral Ed25519 keys, state metrics, and local sandbox parameters, into an exchangeable JSON string.
|
|
222
243
|
|
|
223
244
|
#### `buildAgentPrompt(sessionId, incomingMessage)`
|
|
224
|
-
|
|
245
|
+
Assembles a contextual, structure-compliant system prompt for external LLMs to ensure compliant JSON execution.
|
|
225
246
|
|
|
226
247
|
#### `async sendCounter(sessionId, price, reason)`
|
|
227
|
-
Signs and dispatches a counter-offer to the seller
|
|
248
|
+
Signs and dispatches a standard counter-offer to the seller endpoint.
|
|
228
249
|
|
|
229
250
|
#### `async exitSession(sessionId)`
|
|
230
|
-
|
|
251
|
+
Stops the live execution channel and requests a callback token.
|
|
231
252
|
|
|
232
|
-
|
|
233
|
-
Initializes the edge-AI execution context, downloads the GGUF, and auto-listens.
|
|
253
|
+
---
|
|
234
254
|
|
|
235
|
-
###
|
|
255
|
+
### 6.2 `ClinchSeller` (Seller Client)
|
|
236
256
|
|
|
237
257
|
#### `new ClinchSeller(config)`
|
|
238
|
-
* `config.privateKeyHex` *(string)*: The Ed25519 private key generated
|
|
258
|
+
* `config.privateKeyHex` *(string)*: The permanent Ed25519 private key generated via the registration interface.
|
|
259
|
+
* `config.registryUrl` *(string)*: Optional. Point to a dev registry for local testing.
|
|
239
260
|
|
|
240
261
|
#### `async registerEndpoint(record)`
|
|
241
|
-
|
|
262
|
+
Locally signs and publishes dynamic endpoint mappings and categories to the discovery registry.
|
|
242
263
|
|
|
243
|
-
#### `verifyBuyerSignature(payload, signatureHex,
|
|
244
|
-
|
|
264
|
+
#### `verifyBuyerSignature(payload, signatureHex, buyerPubKeyHex)`
|
|
265
|
+
Verifies that the provided turn payload matches the cryptographic signature produced by the session's ephemeral public key.
|
|
245
266
|
|
|
246
267
|
---
|
|
247
268
|
|
|
248
|
-
##
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
269
|
+
## 7. Cryptographic Properties
|
|
270
|
+
|
|
271
|
+
Clinch relies entirely on zero-trust cryptography to maintain buyer privacy and seller authenticity:
|
|
272
|
+
|
|
273
|
+
1. **Proof-of-Work Binding**: The PoW challenge solution includes the client's public key hash, ensuring challenges cannot be pre-computed or farmed.
|
|
274
|
+
2. **Ephemeral Session Keypairs**: Calling `negotiate()` generates a single-use keypair (`nacl.sign.keyPair()`). This ephemeral key signs every message sent within the session context. In the event of a key compromise, your permanent global identity remains secure, and historical session logs are completely unlinkable.
|
|
275
|
+
3. **Decoupled Verification**: Agreement artifacts are sequentially co-signed by the buyer's session key, the seller's verified identity key, and countersigned by the active registry key. This provides independent verification offline using only the registry's public key chain.
|