@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/LICENSE
CHANGED
|
File without changes
|
package/README.md
CHANGED
|
@@ -4,7 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
LAFS defines a standard envelope format for structured responses from LLM-powered agents and tools. It complements transport protocols like [MCP](https://modelcontextprotocol.io/) and [A2A](https://github.com/google/A2A) by standardizing what comes back — not how it gets there.
|
|
6
6
|
|
|
7
|
-
**Current version:** 0.
|
|
7
|
+
**Current version:** 1.0.0 | [📚 Documentation](https://codluv.gitbook.io/lafs-protocol/) | [Spec](lafs.md) | [Migration Guides](migrations/)
|
|
8
|
+
|
|
9
|
+
[](https://codluv.gitbook.io/lafs-protocol/)
|
|
10
|
+
[](https://www.npmjs.com/package/@cleocode/lafs-protocol)
|
|
8
11
|
|
|
9
12
|
## What LAFS provides
|
|
10
13
|
|
|
@@ -17,7 +20,7 @@ LAFS defines a standard envelope format for structured responses from LLM-powere
|
|
|
17
20
|
| **Tooling** | `src/` | TypeScript validation, conformance runner, CLI diagnostic tool |
|
|
18
21
|
| **Tests** | `tests/` | 31 tests covering envelope, pagination, strict mode, error handling |
|
|
19
22
|
| **Fixtures** | `fixtures/` | 14 JSON fixtures (valid + invalid) for conformance testing |
|
|
20
|
-
| **Docs** | `docs/` |
|
|
23
|
+
| **Docs** | `docs/` | [GitBook documentation](https://codluv.gitbook.io/lafs-protocol/) with guides, SDK reference, and specs |
|
|
21
24
|
|
|
22
25
|
## Install
|
|
23
26
|
|
|
@@ -64,7 +67,7 @@ npm run typecheck
|
|
|
64
67
|
{
|
|
65
68
|
"$schema": "https://lafs.dev/schemas/v1/envelope.schema.json",
|
|
66
69
|
"_meta": {
|
|
67
|
-
"specVersion": "0.
|
|
70
|
+
"specVersion": "1.0.0",
|
|
68
71
|
"schemaVersion": "1.0.0",
|
|
69
72
|
"timestamp": "2026-02-13T00:00:00Z",
|
|
70
73
|
"operation": "example.list",
|
|
@@ -139,6 +142,7 @@ CONTRIBUTING.md # Contributor guidelines, RFC process
|
|
|
139
142
|
|
|
140
143
|
| Version | Phase | Description |
|
|
141
144
|
|---------|-------|-------------|
|
|
145
|
+
| **v1.0.0** | **3** | **Production release: Token budgets, agent discovery, MCP integration, complete SDKs** |
|
|
142
146
|
| v0.5.0 | 2B | Conditional pagination, MVI field selection/expansion, context ledger schema |
|
|
143
147
|
| v0.4.0 | 2A | Optional page/error, extensions, strict/lenient mode, warnings |
|
|
144
148
|
| v0.3.0 | 1 | Strategic positioning, vision alignment, adoption tiers |
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LAFS Discovery Example Server
|
|
3
|
+
*
|
|
4
|
+
* Run with: npx tsx examples/discovery-server.ts
|
|
5
|
+
* Or: npm run build && node dist/examples/discovery-server.js
|
|
6
|
+
*/
|
|
7
|
+
import express from "express";
|
|
8
|
+
import { discoveryMiddleware } from "../src/discovery.js";
|
|
9
|
+
const app = express();
|
|
10
|
+
const PORT = process.env.PORT || 3000;
|
|
11
|
+
/**
|
|
12
|
+
* LAFS-compliant envelope endpoint handler
|
|
13
|
+
* Demonstrates proper LAFS envelope processing
|
|
14
|
+
*/
|
|
15
|
+
app.post("/api/v1/envelope", express.json(), (req, res) => {
|
|
16
|
+
const envelope = req.body;
|
|
17
|
+
// Validate basic envelope structure
|
|
18
|
+
if (!envelope._meta) {
|
|
19
|
+
return res.status(400).json({
|
|
20
|
+
success: false,
|
|
21
|
+
error: {
|
|
22
|
+
code: "INVALID_ENVELOPE",
|
|
23
|
+
message: "Missing _meta field",
|
|
24
|
+
category: "VALIDATION",
|
|
25
|
+
retryable: false,
|
|
26
|
+
retryAfterMs: null,
|
|
27
|
+
details: { missing: ["_meta"] }
|
|
28
|
+
},
|
|
29
|
+
result: null
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
// Process the request (simplified example)
|
|
33
|
+
const operation = envelope._meta.operation;
|
|
34
|
+
// Echo back with success
|
|
35
|
+
res.json({
|
|
36
|
+
$schema: "https://lafs.dev/schemas/v1/envelope.schema.json",
|
|
37
|
+
_meta: {
|
|
38
|
+
specVersion: envelope._meta.specVersion || "1.0.0",
|
|
39
|
+
schemaVersion: envelope._meta.schemaVersion || "1.0.0",
|
|
40
|
+
timestamp: new Date().toISOString(),
|
|
41
|
+
operation: `${operation}:response`,
|
|
42
|
+
requestId: envelope._meta.requestId || crypto.randomUUID(),
|
|
43
|
+
transport: "http",
|
|
44
|
+
strict: envelope._meta.strict ?? true,
|
|
45
|
+
mvi: envelope._meta.mvi || "standard",
|
|
46
|
+
contextVersion: (envelope._meta.contextVersion || 0) + 1
|
|
47
|
+
},
|
|
48
|
+
success: true,
|
|
49
|
+
result: {
|
|
50
|
+
received: true,
|
|
51
|
+
operation: operation,
|
|
52
|
+
data: envelope.payload || null
|
|
53
|
+
},
|
|
54
|
+
error: null
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
/**
|
|
58
|
+
* Context ledger endpoint
|
|
59
|
+
* Demonstrates context management capability
|
|
60
|
+
*/
|
|
61
|
+
app.get("/api/v1/context/:ledgerId", (req, res) => {
|
|
62
|
+
const ledgerId = req.params.ledgerId;
|
|
63
|
+
// Return mock context ledger
|
|
64
|
+
res.json({
|
|
65
|
+
$schema: "https://lafs.dev/schemas/v1/context-ledger.schema.json",
|
|
66
|
+
ledgerId,
|
|
67
|
+
version: 1,
|
|
68
|
+
createdAt: new Date().toISOString(),
|
|
69
|
+
updatedAt: new Date().toISOString(),
|
|
70
|
+
entries: [],
|
|
71
|
+
checksum: "sha256:mock",
|
|
72
|
+
maxEntries: 1000
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
app.post("/api/v1/context/:ledgerId/entries", express.json(), (req, res) => {
|
|
76
|
+
const ledgerId = req.params.ledgerId;
|
|
77
|
+
const entry = req.body;
|
|
78
|
+
res.json({
|
|
79
|
+
$schema: "https://lafs.dev/schemas/v1/envelope.schema.json",
|
|
80
|
+
_meta: {
|
|
81
|
+
specVersion: "1.0.0",
|
|
82
|
+
schemaVersion: "1.0.0",
|
|
83
|
+
timestamp: new Date().toISOString(),
|
|
84
|
+
operation: "context:append",
|
|
85
|
+
requestId: crypto.randomUUID(),
|
|
86
|
+
transport: "http",
|
|
87
|
+
strict: true,
|
|
88
|
+
mvi: "standard",
|
|
89
|
+
contextVersion: 2
|
|
90
|
+
},
|
|
91
|
+
success: true,
|
|
92
|
+
result: {
|
|
93
|
+
ledgerId,
|
|
94
|
+
entryId: crypto.randomUUID(),
|
|
95
|
+
committed: true,
|
|
96
|
+
timestamp: new Date().toISOString()
|
|
97
|
+
},
|
|
98
|
+
error: null
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
/**
|
|
102
|
+
* Discovery configuration
|
|
103
|
+
* Advertises all LAFS capabilities and endpoints
|
|
104
|
+
*/
|
|
105
|
+
const discoveryConfig = {
|
|
106
|
+
service: {
|
|
107
|
+
name: "example-lafs-service",
|
|
108
|
+
version: "1.0.0",
|
|
109
|
+
description: "Example LAFS-compliant API service demonstrating discovery protocol"
|
|
110
|
+
},
|
|
111
|
+
capabilities: [
|
|
112
|
+
{
|
|
113
|
+
name: "envelope-processor",
|
|
114
|
+
version: "1.0.0",
|
|
115
|
+
description: "Process and validate LAFS envelopes",
|
|
116
|
+
operations: ["process", "validate", "transform"]
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
name: "context-ledger",
|
|
120
|
+
version: "1.0.0",
|
|
121
|
+
description: "Manage context ledgers for stateful operations",
|
|
122
|
+
operations: ["read", "append", "query"]
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
name: "pagination-provider",
|
|
126
|
+
version: "1.0.0",
|
|
127
|
+
description: "Provide cursor and offset pagination for list endpoints",
|
|
128
|
+
operations: ["cursor", "offset", "none"],
|
|
129
|
+
optional: true
|
|
130
|
+
}
|
|
131
|
+
],
|
|
132
|
+
endpoints: {
|
|
133
|
+
envelope: "/api/v1/envelope",
|
|
134
|
+
context: "/api/v1/context",
|
|
135
|
+
discovery: "https://lafs.dev/schemas/v1/discovery.schema.json"
|
|
136
|
+
},
|
|
137
|
+
cacheMaxAge: 3600,
|
|
138
|
+
lafsVersion: "1.0.0"
|
|
139
|
+
};
|
|
140
|
+
// Mount discovery middleware BEFORE other routes
|
|
141
|
+
// This ensures /.well-known/lafs.json is served at the root
|
|
142
|
+
app.use(discoveryMiddleware(discoveryConfig));
|
|
143
|
+
/**
|
|
144
|
+
* Health check endpoint
|
|
145
|
+
*/
|
|
146
|
+
app.get("/health", (req, res) => {
|
|
147
|
+
res.json({
|
|
148
|
+
status: "healthy",
|
|
149
|
+
service: discoveryConfig.service.name,
|
|
150
|
+
version: discoveryConfig.service.version,
|
|
151
|
+
timestamp: new Date().toISOString()
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
/**
|
|
155
|
+
* Error handling middleware
|
|
156
|
+
*/
|
|
157
|
+
app.use((err, req, res, next) => {
|
|
158
|
+
console.error("Error:", err);
|
|
159
|
+
res.status(500).json({
|
|
160
|
+
success: false,
|
|
161
|
+
error: {
|
|
162
|
+
code: "INTERNAL_ERROR",
|
|
163
|
+
message: err.message || "Internal server error",
|
|
164
|
+
category: "INTERNAL",
|
|
165
|
+
retryable: false,
|
|
166
|
+
retryAfterMs: null,
|
|
167
|
+
details: process.env.NODE_ENV === "development" ? { stack: err.stack } : {}
|
|
168
|
+
},
|
|
169
|
+
result: null
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
/**
|
|
173
|
+
* Start server
|
|
174
|
+
*/
|
|
175
|
+
const server = app.listen(PORT, () => {
|
|
176
|
+
console.log(`
|
|
177
|
+
╔════════════════════════════════════════════════════════╗
|
|
178
|
+
║ LAFS Discovery Server Running ║
|
|
179
|
+
╠════════════════════════════════════════════════════════╣
|
|
180
|
+
║ Service: ${discoveryConfig.service.name.padEnd(43)}║
|
|
181
|
+
║ Version: ${discoveryConfig.service.version.padEnd(43)}║
|
|
182
|
+
║ Port: ${String(PORT).padEnd(43)}║
|
|
183
|
+
╠════════════════════════════════════════════════════════╣
|
|
184
|
+
║ Endpoints: ║
|
|
185
|
+
║ GET /.well-known/lafs.json (Discovery document) ║
|
|
186
|
+
║ POST /api/v1/envelope (Envelope processor) ║
|
|
187
|
+
║ GET /api/v1/context/:id (Context ledger) ║
|
|
188
|
+
║ GET /health (Health check) ║
|
|
189
|
+
╚════════════════════════════════════════════════════════╝
|
|
190
|
+
|
|
191
|
+
Test with:
|
|
192
|
+
curl http://localhost:${PORT}/.well-known/lafs.json | jq
|
|
193
|
+
curl http://localhost:${PORT}/health | jq
|
|
194
|
+
curl -X POST http://localhost:${PORT}/api/v1/envelope \
|
|
195
|
+
-H "Content-Type: application/json" \
|
|
196
|
+
-d '{"_meta":{"operation":"test","requestId":"123"},"payload":{"hello":"world"}}'
|
|
197
|
+
`);
|
|
198
|
+
});
|
|
199
|
+
/**
|
|
200
|
+
* Graceful shutdown
|
|
201
|
+
*/
|
|
202
|
+
process.on("SIGTERM", () => {
|
|
203
|
+
console.log("\nShutting down gracefully...");
|
|
204
|
+
server.close(() => {
|
|
205
|
+
console.log("Server closed");
|
|
206
|
+
process.exit(0);
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
process.on("SIGINT", () => {
|
|
210
|
+
console.log("\nShutting down gracefully...");
|
|
211
|
+
server.close(() => {
|
|
212
|
+
console.log("Server closed");
|
|
213
|
+
process.exit(0);
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
export default app;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* MCP-LAFS Client Example
|
|
4
|
+
*
|
|
5
|
+
* A client that connects to the MCP-LAFS server and validates responses
|
|
6
|
+
* are LAFS-compliant. Demonstrates budget negotiation and envelope validation.
|
|
7
|
+
*
|
|
8
|
+
* Usage: npx ts-node examples/mcp-lafs-client.ts
|
|
9
|
+
*/
|
|
10
|
+
export {};
|