@cleocode/lafs-protocol 0.5.0 → 1.1.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.
- package/LICENSE +0 -0
- package/README.md +7 -3
- package/dist/examples/discovery-server.d.ts +8 -0
- package/dist/examples/discovery-server.js +216 -0
- package/dist/examples/mcp-lafs-client.d.ts +10 -0
- package/dist/examples/mcp-lafs-client.js +427 -0
- package/dist/examples/mcp-lafs-server.d.ts +10 -0
- package/dist/examples/mcp-lafs-server.js +358 -0
- package/dist/schemas/v1/envelope.schema.json +0 -0
- package/dist/schemas/v1/error-registry.json +0 -0
- package/dist/src/a2a/bridge.d.ts +129 -0
- package/dist/src/a2a/bridge.js +173 -0
- package/dist/src/a2a/index.d.ts +36 -0
- package/dist/src/a2a/index.js +36 -0
- package/dist/src/budgetEnforcement.d.ts +84 -0
- package/dist/src/budgetEnforcement.js +328 -0
- package/dist/src/circuit-breaker/index.d.ts +121 -0
- package/dist/src/circuit-breaker/index.js +249 -0
- package/dist/src/cli.d.ts +0 -0
- package/dist/src/cli.js +0 -0
- package/dist/src/conformance.d.ts +0 -0
- package/dist/src/conformance.js +0 -0
- package/dist/src/discovery.d.ts +127 -0
- package/dist/src/discovery.js +304 -0
- package/dist/src/errorRegistry.d.ts +0 -0
- package/dist/src/errorRegistry.js +0 -0
- package/dist/src/flagSemantics.d.ts +0 -0
- package/dist/src/flagSemantics.js +0 -0
- package/dist/src/health/index.d.ts +105 -0
- package/dist/src/health/index.js +211 -0
- package/dist/src/index.d.ts +8 -0
- package/dist/src/index.js +10 -0
- package/dist/src/mcpAdapter.d.ts +28 -0
- package/dist/src/mcpAdapter.js +281 -0
- package/dist/src/shutdown/index.d.ts +69 -0
- package/dist/src/shutdown/index.js +160 -0
- package/dist/src/tokenEstimator.d.ts +87 -0
- package/dist/src/tokenEstimator.js +238 -0
- package/dist/src/types.d.ts +25 -0
- package/dist/src/types.js +0 -0
- package/dist/src/validateEnvelope.d.ts +0 -0
- package/dist/src/validateEnvelope.js +0 -0
- package/lafs.md +167 -0
- package/package.json +10 -4
- package/schemas/v1/context-ledger.schema.json +0 -0
- package/schemas/v1/discovery.schema.json +132 -0
- package/schemas/v1/envelope.schema.json +0 -0
- package/schemas/v1/error-registry.json +0 -0
package/lafs.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# LAFS: LLM-Agent-First Specification
|
|
2
2
|
|
|
3
|
+
> 📚 **Documentation:** https://codluv.gitbook.io/lafs-protocol/
|
|
4
|
+
> **Version:** 1.0.0 | **Status:** Production Ready
|
|
5
|
+
|
|
3
6
|
## 1. Scope
|
|
4
7
|
|
|
5
8
|
LAFS is a **response envelope contract specification**. It defines the canonical shape of structured responses — success envelopes, error envelopes, pagination metadata, and context preservation — for software systems whose primary consumer is an LLM agent or AI-driven tool.
|
|
@@ -176,6 +179,56 @@ Rules:
|
|
|
176
179
|
- Decisions affecting output MUST be represented in ledger state.
|
|
177
180
|
- Missing required context for a mutating step MUST fail with structured error.
|
|
178
181
|
|
|
182
|
+
### 8.1 Context Retrieval
|
|
183
|
+
|
|
184
|
+
Agents MAY retrieve context ledger state via `GET /_lafs/context/{ledgerId}` with projection modes.
|
|
185
|
+
|
|
186
|
+
#### 8.1.1 Projection Modes
|
|
187
|
+
|
|
188
|
+
**Full Mode (`mode=full`):**
|
|
189
|
+
Returns complete ledger including all entries.
|
|
190
|
+
- Use for: Initial loads, recovery scenarios
|
|
191
|
+
- Supports: Offset-based pagination
|
|
192
|
+
- Response includes: All ledger fields
|
|
193
|
+
|
|
194
|
+
**Delta Mode (`mode=delta&sinceVersion=N`):**
|
|
195
|
+
Returns only entries added since version N.
|
|
196
|
+
- Use for: Active workflows (efficient sync)
|
|
197
|
+
- Response includes:
|
|
198
|
+
```json
|
|
199
|
+
{
|
|
200
|
+
"ledgerId": "ctx_abc123",
|
|
201
|
+
"mode": "delta",
|
|
202
|
+
"fromVersion": 10,
|
|
203
|
+
"toVersion": 15,
|
|
204
|
+
"entries": [/* new entries only */],
|
|
205
|
+
"removedConstraints": [/* constraints no longer active */],
|
|
206
|
+
"checksum": "sha256:..."
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
**Summary Mode (`mode=summary`):**
|
|
211
|
+
Returns checksum and version for validation.
|
|
212
|
+
- Use for: Quick sync validation
|
|
213
|
+
- Response includes only: `ledgerId`, `version`, `checksum`, `entryCount`
|
|
214
|
+
|
|
215
|
+
#### 8.1.2 Query Parameters
|
|
216
|
+
|
|
217
|
+
| Parameter | Type | Description |
|
|
218
|
+
|-----------|------|-------------|
|
|
219
|
+
| `mode` | enum | `full`, `delta`, `summary` |
|
|
220
|
+
| `sinceVersion` | integer | For delta mode: return entries after this version |
|
|
221
|
+
| `filterByOperation` | string[] | Filter entries by operation name(s) |
|
|
222
|
+
| `limit` | integer | Max entries (1-1000, default 100) |
|
|
223
|
+
| `includeChecksum` | boolean | Include integrity checksum (default true) |
|
|
224
|
+
|
|
225
|
+
#### 8.1.3 Agent Guidance
|
|
226
|
+
|
|
227
|
+
- **Initial load**: Use `mode=full` once
|
|
228
|
+
- **Active workflows**: Use `mode=delta` with last known version
|
|
229
|
+
- **Validation**: Use `mode=summary` to verify sync state
|
|
230
|
+
- **Default recommendation**: `delta` mode for agent-optimal behavior
|
|
231
|
+
|
|
179
232
|
---
|
|
180
233
|
|
|
181
234
|
## 9. MVI and Progressive Disclosure
|
|
@@ -212,6 +265,120 @@ Clients MAY request expanded/nested data via the `_expand` request parameter.
|
|
|
212
265
|
- Pagination mode (offset or cursor) MUST be documented.
|
|
213
266
|
- Mixed pagination modes in one request MUST fail validation.
|
|
214
267
|
|
|
268
|
+
### 9.5 Token Budget Signaling
|
|
269
|
+
|
|
270
|
+
Token budget signaling enables clients to declare resource constraints that servers MUST respect when generating responses. This mechanism prevents context window overflow in LLM-driven workflows.
|
|
271
|
+
|
|
272
|
+
#### 9.5.1 Budget Declaration (`_budget`)
|
|
273
|
+
|
|
274
|
+
Clients MAY declare resource constraints via the `_budget` request parameter:
|
|
275
|
+
|
|
276
|
+
```json
|
|
277
|
+
{
|
|
278
|
+
"_budget": {
|
|
279
|
+
"maxTokens": 4000,
|
|
280
|
+
"maxBytes": 32768,
|
|
281
|
+
"maxItems": 100
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
**Fields:**
|
|
287
|
+
- `maxTokens` (integer) - Maximum approximate tokens
|
|
288
|
+
- `maxBytes` (integer) - Maximum byte size
|
|
289
|
+
- `maxItems` (integer) - Maximum items in lists
|
|
290
|
+
|
|
291
|
+
**Constraints:**
|
|
292
|
+
- At least one field MUST be present
|
|
293
|
+
- All values MUST be positive integers
|
|
294
|
+
- Servers MAY reject budgets exceeding implementation limits
|
|
295
|
+
|
|
296
|
+
#### 9.5.2 Server Behavior
|
|
297
|
+
|
|
298
|
+
Servers MUST:
|
|
299
|
+
1. Parse `_budget` from incoming requests
|
|
300
|
+
2. Estimate/measure response size
|
|
301
|
+
3. Return response within budget OR fail with `E_MVI_BUDGET_EXCEEDED`
|
|
302
|
+
|
|
303
|
+
Servers MAY truncate responses using:
|
|
304
|
+
- **Depth-first**: Remove deepest nested fields
|
|
305
|
+
- **Field priority**: Remove non-essential fields first
|
|
306
|
+
- **Hybrid**: Combine both strategies
|
|
307
|
+
|
|
308
|
+
When truncation occurs, servers MUST include:
|
|
309
|
+
```json
|
|
310
|
+
{
|
|
311
|
+
"_meta": {
|
|
312
|
+
"warnings": [{
|
|
313
|
+
"code": "E_MVI_BUDGET_TRUNCATED",
|
|
314
|
+
"message": "Response truncated to fit token budget"
|
|
315
|
+
}],
|
|
316
|
+
"_tokenEstimate": {
|
|
317
|
+
"estimated": 2847,
|
|
318
|
+
"budget": 4000,
|
|
319
|
+
"method": "character_based"
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
#### 9.5.3 Error Specification
|
|
326
|
+
|
|
327
|
+
**E_MVI_BUDGET_EXCEEDED:**
|
|
328
|
+
- **Category:** `VALIDATION`
|
|
329
|
+
- **Retryable:** `true`
|
|
330
|
+
- **Details:** `estimatedTokens`, `budget`, `excessTokens`, `constraint`
|
|
331
|
+
|
|
332
|
+
```json
|
|
333
|
+
{
|
|
334
|
+
"error": {
|
|
335
|
+
"code": "E_MVI_BUDGET_EXCEEDED",
|
|
336
|
+
"message": "Response exceeds declared token budget",
|
|
337
|
+
"category": "VALIDATION",
|
|
338
|
+
"retryable": true,
|
|
339
|
+
"details": {
|
|
340
|
+
"estimatedTokens": 5234,
|
|
341
|
+
"budget": 4000,
|
|
342
|
+
"excessTokens": 1234,
|
|
343
|
+
"constraint": "maxTokens"
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
#### 9.5.4 Token Estimation Algorithm (Normative)
|
|
350
|
+
|
|
351
|
+
Servers MUST implement this algorithm or equivalent (within +/- 10%):
|
|
352
|
+
|
|
353
|
+
```
|
|
354
|
+
FUNCTION estimate_tokens(value, depth = 0):
|
|
355
|
+
IF depth > 20: RETURN INFINITY
|
|
356
|
+
IF value IS null: RETURN 1
|
|
357
|
+
IF value IS boolean: RETURN 1
|
|
358
|
+
IF value IS number: RETURN max(1, len(stringify(value)) / 4)
|
|
359
|
+
IF value IS string:
|
|
360
|
+
graphemes = count_grapheme_clusters(value)
|
|
361
|
+
RETURN max(1, graphemes / 4.0)
|
|
362
|
+
IF value IS array:
|
|
363
|
+
tokens = 2 // []
|
|
364
|
+
FOR item IN value:
|
|
365
|
+
tokens += estimate_tokens(item, depth + 1) + 1
|
|
366
|
+
RETURN tokens
|
|
367
|
+
IF value IS object:
|
|
368
|
+
tokens = 2 // {}
|
|
369
|
+
FOR key, val IN value:
|
|
370
|
+
tokens += estimate_tokens(key, depth + 1)
|
|
371
|
+
tokens += 2 // : and ,
|
|
372
|
+
tokens += estimate_tokens(val, depth + 1)
|
|
373
|
+
RETURN tokens
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
**Requirements:**
|
|
377
|
+
- Count grapheme clusters (not bytes) for unicode
|
|
378
|
+
- Enforce max depth of 20
|
|
379
|
+
- Handle circular references
|
|
380
|
+
- Complete within 10ms for 100KB payloads
|
|
381
|
+
|
|
215
382
|
---
|
|
216
383
|
|
|
217
384
|
## 10. Strictness
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cleocode/lafs-protocol",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "LLM-Agent-First Specification schemas and conformance tooling",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"type": "git",
|
|
24
24
|
"url": "git+https://github.com/kryptobaseddev/lafs-protocol.git"
|
|
25
25
|
},
|
|
26
|
-
"homepage": "https://
|
|
26
|
+
"homepage": "https://codluv.gitbook.io/lafs-protocol/",
|
|
27
27
|
"bugs": {
|
|
28
28
|
"url": "https://github.com/kryptobaseddev/lafs-protocol/issues"
|
|
29
29
|
},
|
|
@@ -50,13 +50,19 @@
|
|
|
50
50
|
],
|
|
51
51
|
"license": "MIT",
|
|
52
52
|
"devDependencies": {
|
|
53
|
+
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
54
|
+
"@types/express": "^5.0.6",
|
|
53
55
|
"@types/node": "^24.3.0",
|
|
56
|
+
"@types/supertest": "^6.0.3",
|
|
57
|
+
"supertest": "^7.2.2",
|
|
54
58
|
"tsx": "^4.20.5",
|
|
55
59
|
"typescript": "^5.9.2",
|
|
56
60
|
"vitest": "^2.1.9"
|
|
57
61
|
},
|
|
58
62
|
"dependencies": {
|
|
59
|
-
"
|
|
60
|
-
"ajv
|
|
63
|
+
"@a2a-js/sdk": "^0.3.10",
|
|
64
|
+
"ajv": "^8.18.0",
|
|
65
|
+
"ajv-formats": "^3.0.1",
|
|
66
|
+
"express": "^5.2.1"
|
|
61
67
|
}
|
|
62
68
|
}
|
|
File without changes
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://lafs.dev/schemas/v1/discovery.schema.json",
|
|
4
|
+
"title": "LAFS Discovery Document",
|
|
5
|
+
"description": "Schema for LAFS agent discovery documents served at /.well-known/lafs.json",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": [
|
|
8
|
+
"$schema",
|
|
9
|
+
"lafs_version",
|
|
10
|
+
"service",
|
|
11
|
+
"capabilities",
|
|
12
|
+
"endpoints"
|
|
13
|
+
],
|
|
14
|
+
"properties": {
|
|
15
|
+
"$schema": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"format": "uri",
|
|
18
|
+
"description": "URL of the schema this document conforms to"
|
|
19
|
+
},
|
|
20
|
+
"lafs_version": {
|
|
21
|
+
"type": "string",
|
|
22
|
+
"pattern": "^\\d+\\.\\d+\\.\\d+$",
|
|
23
|
+
"description": "LAFS protocol version (semantic versioning)"
|
|
24
|
+
},
|
|
25
|
+
"service": {
|
|
26
|
+
"type": "object",
|
|
27
|
+
"description": "Service identification and metadata",
|
|
28
|
+
"required": [
|
|
29
|
+
"name",
|
|
30
|
+
"version"
|
|
31
|
+
],
|
|
32
|
+
"properties": {
|
|
33
|
+
"name": {
|
|
34
|
+
"type": "string",
|
|
35
|
+
"minLength": 1,
|
|
36
|
+
"maxLength": 100,
|
|
37
|
+
"description": "Unique service name (kebab-case recommended)"
|
|
38
|
+
},
|
|
39
|
+
"version": {
|
|
40
|
+
"type": "string",
|
|
41
|
+
"pattern": "^\\d+\\.\\d+\\.\\d+$",
|
|
42
|
+
"description": "Service version (semantic versioning)"
|
|
43
|
+
},
|
|
44
|
+
"description": {
|
|
45
|
+
"type": "string",
|
|
46
|
+
"maxLength": 500,
|
|
47
|
+
"description": "Human-readable service description"
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"additionalProperties": false
|
|
51
|
+
},
|
|
52
|
+
"capabilities": {
|
|
53
|
+
"type": "array",
|
|
54
|
+
"description": "List of LAFS capabilities this service provides",
|
|
55
|
+
"minItems": 1,
|
|
56
|
+
"items": {
|
|
57
|
+
"type": "object",
|
|
58
|
+
"required": [
|
|
59
|
+
"name",
|
|
60
|
+
"version",
|
|
61
|
+
"operations"
|
|
62
|
+
],
|
|
63
|
+
"properties": {
|
|
64
|
+
"name": {
|
|
65
|
+
"type": "string",
|
|
66
|
+
"minLength": 1,
|
|
67
|
+
"maxLength": 100,
|
|
68
|
+
"description": "Capability identifier (kebab-case recommended)"
|
|
69
|
+
},
|
|
70
|
+
"version": {
|
|
71
|
+
"type": "string",
|
|
72
|
+
"pattern": "^\\d+\\.\\d+\\.\\d+$",
|
|
73
|
+
"description": "Capability version (semantic versioning)"
|
|
74
|
+
},
|
|
75
|
+
"description": {
|
|
76
|
+
"type": "string",
|
|
77
|
+
"maxLength": 500,
|
|
78
|
+
"description": "Human-readable capability description"
|
|
79
|
+
},
|
|
80
|
+
"operations": {
|
|
81
|
+
"type": "array",
|
|
82
|
+
"description": "List of operations this capability supports",
|
|
83
|
+
"minItems": 1,
|
|
84
|
+
"items": {
|
|
85
|
+
"type": "string",
|
|
86
|
+
"minLength": 1,
|
|
87
|
+
"maxLength": 50
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
"optional": {
|
|
91
|
+
"type": "boolean",
|
|
92
|
+
"default": false,
|
|
93
|
+
"description": "Whether this capability is optional for clients"
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
"additionalProperties": false
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
"endpoints": {
|
|
100
|
+
"type": "object",
|
|
101
|
+
"description": "URL endpoints for LAFS operations",
|
|
102
|
+
"required": [
|
|
103
|
+
"envelope",
|
|
104
|
+
"discovery"
|
|
105
|
+
],
|
|
106
|
+
"properties": {
|
|
107
|
+
"envelope": {
|
|
108
|
+
"type": "string",
|
|
109
|
+
"minLength": 1,
|
|
110
|
+
"description": "URL for envelope submission (POST)"
|
|
111
|
+
},
|
|
112
|
+
"context": {
|
|
113
|
+
"type": "string",
|
|
114
|
+
"minLength": 1,
|
|
115
|
+
"description": "URL for context ledger operations"
|
|
116
|
+
},
|
|
117
|
+
"discovery": {
|
|
118
|
+
"type": "string",
|
|
119
|
+
"minLength": 1,
|
|
120
|
+
"description": "URL of this discovery document"
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
"additionalProperties": false
|
|
124
|
+
},
|
|
125
|
+
"extensions": {
|
|
126
|
+
"type": "object",
|
|
127
|
+
"description": "Extension fields for vendor-specific metadata",
|
|
128
|
+
"additionalProperties": true
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
"additionalProperties": false
|
|
132
|
+
}
|
|
File without changes
|
|
File without changes
|