@cleocode/lafs-protocol 0.5.0 → 1.0.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 +0 -0
- 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/budgetEnforcement.d.ts +84 -0
- package/dist/src/budgetEnforcement.js +328 -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/index.d.ts +4 -0
- package/dist/src/index.js +4 -0
- package/dist/src/mcpAdapter.d.ts +28 -0
- package/dist/src/mcpAdapter.js +281 -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 +164 -0
- package/package.json +8 -3
- 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
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* MCP-LAFS Server Example
|
|
4
|
+
*
|
|
5
|
+
* A working MCP server that wraps all tool responses in LAFS-compliant envelopes.
|
|
6
|
+
* Demonstrates how LAFS complements MCP by adding structured metadata and budget enforcement.
|
|
7
|
+
*
|
|
8
|
+
* Usage: npx ts-node examples/mcp-lafs-server.ts
|
|
9
|
+
*/
|
|
10
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
11
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
12
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
13
|
+
import { wrapMCPResult } from "../src/mcpAdapter.js";
|
|
14
|
+
const simulatedDatabase = new Map([
|
|
15
|
+
["1", { id: "1", name: "Product A", value: 100, createdAt: new Date().toISOString() }],
|
|
16
|
+
["2", { id: "2", name: "Product B", value: 200, createdAt: new Date().toISOString() }],
|
|
17
|
+
["3", { id: "3", name: "Product C", value: 300, createdAt: new Date().toISOString() }],
|
|
18
|
+
]);
|
|
19
|
+
// Tool definitions
|
|
20
|
+
const TOOLS = [
|
|
21
|
+
{
|
|
22
|
+
name: "weather",
|
|
23
|
+
description: "Get current weather for a location",
|
|
24
|
+
inputSchema: {
|
|
25
|
+
type: "object",
|
|
26
|
+
properties: {
|
|
27
|
+
location: {
|
|
28
|
+
type: "string",
|
|
29
|
+
description: "City name or coordinates",
|
|
30
|
+
},
|
|
31
|
+
units: {
|
|
32
|
+
type: "string",
|
|
33
|
+
enum: ["celsius", "fahrenheit"],
|
|
34
|
+
description: "Temperature units",
|
|
35
|
+
default: "celsius",
|
|
36
|
+
},
|
|
37
|
+
_budget: {
|
|
38
|
+
type: "number",
|
|
39
|
+
description: "Token budget for response (LAFS extension)",
|
|
40
|
+
minimum: 10,
|
|
41
|
+
maximum: 10000,
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
required: ["location"],
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: "calculator",
|
|
49
|
+
description: "Perform mathematical calculations",
|
|
50
|
+
inputSchema: {
|
|
51
|
+
type: "object",
|
|
52
|
+
properties: {
|
|
53
|
+
operation: {
|
|
54
|
+
type: "string",
|
|
55
|
+
enum: ["add", "subtract", "multiply", "divide", "power", "sqrt"],
|
|
56
|
+
description: "Mathematical operation to perform",
|
|
57
|
+
},
|
|
58
|
+
a: {
|
|
59
|
+
type: "number",
|
|
60
|
+
description: "First operand",
|
|
61
|
+
},
|
|
62
|
+
b: {
|
|
63
|
+
type: "number",
|
|
64
|
+
description: "Second operand (not needed for sqrt)",
|
|
65
|
+
},
|
|
66
|
+
_budget: {
|
|
67
|
+
type: "number",
|
|
68
|
+
description: "Token budget for response (LAFS extension)",
|
|
69
|
+
minimum: 10,
|
|
70
|
+
maximum: 1000,
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
required: ["operation", "a"],
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: "database_query",
|
|
78
|
+
description: "Query the simulated database",
|
|
79
|
+
inputSchema: {
|
|
80
|
+
type: "object",
|
|
81
|
+
properties: {
|
|
82
|
+
action: {
|
|
83
|
+
type: "string",
|
|
84
|
+
enum: ["get", "list", "search"],
|
|
85
|
+
description: "Query action to perform",
|
|
86
|
+
},
|
|
87
|
+
id: {
|
|
88
|
+
type: "string",
|
|
89
|
+
description: "Record ID (for get action)",
|
|
90
|
+
},
|
|
91
|
+
query: {
|
|
92
|
+
type: "string",
|
|
93
|
+
description: "Search query (for search action)",
|
|
94
|
+
},
|
|
95
|
+
limit: {
|
|
96
|
+
type: "number",
|
|
97
|
+
description: "Maximum results to return",
|
|
98
|
+
default: 10,
|
|
99
|
+
},
|
|
100
|
+
_budget: {
|
|
101
|
+
type: "number",
|
|
102
|
+
description: "Token budget for response (LAFS extension)",
|
|
103
|
+
minimum: 10,
|
|
104
|
+
maximum: 5000,
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
required: ["action"],
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
];
|
|
111
|
+
// Weather simulation
|
|
112
|
+
async function getWeather(location, units) {
|
|
113
|
+
// Simulate API call delay
|
|
114
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
115
|
+
// Generate deterministic but varied weather based on location
|
|
116
|
+
const hash = location.split("").reduce((acc, char) => acc + char.charCodeAt(0), 0);
|
|
117
|
+
const conditions = ["sunny", "cloudy", "rainy", "partly cloudy", "clear"];
|
|
118
|
+
const condition = conditions[hash % conditions.length];
|
|
119
|
+
// Temperature based on condition and some randomness
|
|
120
|
+
let baseTemp = 20; // celsius
|
|
121
|
+
if (condition === "sunny")
|
|
122
|
+
baseTemp = 25;
|
|
123
|
+
if (condition === "rainy")
|
|
124
|
+
baseTemp = 15;
|
|
125
|
+
if (condition === "clear")
|
|
126
|
+
baseTemp = 22;
|
|
127
|
+
const tempC = baseTemp + (hash % 10) - 5;
|
|
128
|
+
const tempF = Math.round((tempC * 9) / 5 + 32);
|
|
129
|
+
return {
|
|
130
|
+
location,
|
|
131
|
+
temperature: units === "fahrenheit" ? tempF : tempC,
|
|
132
|
+
temperatureUnit: units,
|
|
133
|
+
conditions: condition,
|
|
134
|
+
humidity: 40 + (hash % 50),
|
|
135
|
+
windSpeed: 5 + (hash % 20),
|
|
136
|
+
windUnit: "km/h",
|
|
137
|
+
forecast: [
|
|
138
|
+
{ day: "Today", high: tempC + 2, low: tempC - 3, condition },
|
|
139
|
+
{ day: "Tomorrow", high: tempC + 1, low: tempC - 4, condition: conditions[(hash + 1) % conditions.length] },
|
|
140
|
+
{ day: "Day after", high: tempC + 3, low: tempC - 2, condition: conditions[(hash + 2) % conditions.length] },
|
|
141
|
+
],
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
// Calculator implementation
|
|
145
|
+
function calculate(operation, a, b) {
|
|
146
|
+
let result;
|
|
147
|
+
let expression;
|
|
148
|
+
switch (operation) {
|
|
149
|
+
case "add":
|
|
150
|
+
if (b === undefined)
|
|
151
|
+
throw new Error("Second operand (b) required for addition");
|
|
152
|
+
result = a + b;
|
|
153
|
+
expression = `${a} + ${b}`;
|
|
154
|
+
break;
|
|
155
|
+
case "subtract":
|
|
156
|
+
if (b === undefined)
|
|
157
|
+
throw new Error("Second operand (b) required for subtraction");
|
|
158
|
+
result = a - b;
|
|
159
|
+
expression = `${a} - ${b}`;
|
|
160
|
+
break;
|
|
161
|
+
case "multiply":
|
|
162
|
+
if (b === undefined)
|
|
163
|
+
throw new Error("Second operand (b) required for multiplication");
|
|
164
|
+
result = a * b;
|
|
165
|
+
expression = `${a} * ${b}`;
|
|
166
|
+
break;
|
|
167
|
+
case "divide":
|
|
168
|
+
if (b === undefined)
|
|
169
|
+
throw new Error("Second operand (b) required for division");
|
|
170
|
+
if (b === 0)
|
|
171
|
+
throw new Error("Cannot divide by zero");
|
|
172
|
+
result = a / b;
|
|
173
|
+
expression = `${a} / ${b}`;
|
|
174
|
+
break;
|
|
175
|
+
case "power":
|
|
176
|
+
if (b === undefined)
|
|
177
|
+
throw new Error("Second operand (b) required for power operation");
|
|
178
|
+
result = Math.pow(a, b);
|
|
179
|
+
expression = `${a} ^ ${b}`;
|
|
180
|
+
break;
|
|
181
|
+
case "sqrt":
|
|
182
|
+
if (a < 0)
|
|
183
|
+
throw new Error("Cannot calculate square root of negative number");
|
|
184
|
+
result = Math.sqrt(a);
|
|
185
|
+
expression = `sqrt(${a})`;
|
|
186
|
+
break;
|
|
187
|
+
default:
|
|
188
|
+
throw new Error(`Unknown operation: ${operation}`);
|
|
189
|
+
}
|
|
190
|
+
return {
|
|
191
|
+
operation,
|
|
192
|
+
expression,
|
|
193
|
+
operands: { a, b },
|
|
194
|
+
result,
|
|
195
|
+
resultType: Number.isInteger(result) ? "integer" : "float",
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
// Database operations
|
|
199
|
+
function databaseQuery(action, id, query, limit) {
|
|
200
|
+
switch (action) {
|
|
201
|
+
case "get": {
|
|
202
|
+
if (!id) {
|
|
203
|
+
throw new Error("ID required for get action");
|
|
204
|
+
}
|
|
205
|
+
const record = simulatedDatabase.get(id);
|
|
206
|
+
if (!record) {
|
|
207
|
+
throw new Error(`Record with ID '${id}' not found`);
|
|
208
|
+
}
|
|
209
|
+
return {
|
|
210
|
+
action,
|
|
211
|
+
record,
|
|
212
|
+
found: true,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
case "list": {
|
|
216
|
+
const records = Array.from(simulatedDatabase.values()).slice(0, limit ?? 10);
|
|
217
|
+
return {
|
|
218
|
+
action,
|
|
219
|
+
records,
|
|
220
|
+
count: records.length,
|
|
221
|
+
total: simulatedDatabase.size,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
case "search": {
|
|
225
|
+
if (!query) {
|
|
226
|
+
throw new Error("Query required for search action");
|
|
227
|
+
}
|
|
228
|
+
const queryLower = query.toLowerCase();
|
|
229
|
+
const records = Array.from(simulatedDatabase.values())
|
|
230
|
+
.filter((r) => r.name.toLowerCase().includes(queryLower))
|
|
231
|
+
.slice(0, limit ?? 10);
|
|
232
|
+
return {
|
|
233
|
+
action,
|
|
234
|
+
query,
|
|
235
|
+
records,
|
|
236
|
+
count: records.length,
|
|
237
|
+
total: simulatedDatabase.size,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
default:
|
|
241
|
+
throw new Error(`Unknown action: ${action}`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
// Create MCP server
|
|
245
|
+
const server = new Server({
|
|
246
|
+
name: "lafs-mcp-server",
|
|
247
|
+
version: "1.0.0",
|
|
248
|
+
}, {
|
|
249
|
+
capabilities: {
|
|
250
|
+
tools: {},
|
|
251
|
+
},
|
|
252
|
+
});
|
|
253
|
+
// Handle tool listing
|
|
254
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
255
|
+
return {
|
|
256
|
+
tools: TOOLS,
|
|
257
|
+
};
|
|
258
|
+
});
|
|
259
|
+
// Handle tool calls
|
|
260
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
261
|
+
const { name, arguments: args } = request.params;
|
|
262
|
+
const budget = typeof args?._budget === "number" ? args._budget : undefined;
|
|
263
|
+
try {
|
|
264
|
+
let result;
|
|
265
|
+
switch (name) {
|
|
266
|
+
case "weather": {
|
|
267
|
+
const location = String(args?.location ?? "");
|
|
268
|
+
const units = String(args?.units ?? "celsius");
|
|
269
|
+
if (!location) {
|
|
270
|
+
throw new Error("Location is required");
|
|
271
|
+
}
|
|
272
|
+
result = await getWeather(location, units);
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
case "calculator": {
|
|
276
|
+
const operation = String(args?.operation ?? "");
|
|
277
|
+
const a = Number(args?.a);
|
|
278
|
+
const b = args?.b !== undefined ? Number(args?.b) : undefined;
|
|
279
|
+
if (!operation || Number.isNaN(a)) {
|
|
280
|
+
throw new Error("Operation and operand 'a' are required");
|
|
281
|
+
}
|
|
282
|
+
result = calculate(operation, a, b);
|
|
283
|
+
break;
|
|
284
|
+
}
|
|
285
|
+
case "database_query": {
|
|
286
|
+
const action = String(args?.action ?? "");
|
|
287
|
+
const id = args?.id !== undefined ? String(args?.id) : undefined;
|
|
288
|
+
const query = args?.query !== undefined ? String(args?.query) : undefined;
|
|
289
|
+
const limit = args?.limit !== undefined ? Number(args?.limit) : undefined;
|
|
290
|
+
if (!action) {
|
|
291
|
+
throw new Error("Action is required");
|
|
292
|
+
}
|
|
293
|
+
result = databaseQuery(action, id, query, limit);
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
296
|
+
default:
|
|
297
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
298
|
+
}
|
|
299
|
+
// Create MCP result
|
|
300
|
+
const mcpResult = {
|
|
301
|
+
content: [
|
|
302
|
+
{
|
|
303
|
+
type: "text",
|
|
304
|
+
text: JSON.stringify(result, null, 2),
|
|
305
|
+
},
|
|
306
|
+
],
|
|
307
|
+
isError: false,
|
|
308
|
+
};
|
|
309
|
+
// Wrap in LAFS envelope
|
|
310
|
+
const envelope = wrapMCPResult(mcpResult, `tools/${name}`, budget);
|
|
311
|
+
// Return the LAFS envelope as text content
|
|
312
|
+
return {
|
|
313
|
+
content: [
|
|
314
|
+
{
|
|
315
|
+
type: "text",
|
|
316
|
+
text: JSON.stringify(envelope),
|
|
317
|
+
},
|
|
318
|
+
],
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
catch (error) {
|
|
322
|
+
// Create error MCP result
|
|
323
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
324
|
+
const mcpResult = {
|
|
325
|
+
content: [
|
|
326
|
+
{
|
|
327
|
+
type: "text",
|
|
328
|
+
text: errorMessage,
|
|
329
|
+
},
|
|
330
|
+
],
|
|
331
|
+
isError: true,
|
|
332
|
+
};
|
|
333
|
+
// Wrap in LAFS error envelope
|
|
334
|
+
const envelope = wrapMCPResult(mcpResult, `tools/${name}`, budget);
|
|
335
|
+
return {
|
|
336
|
+
content: [
|
|
337
|
+
{
|
|
338
|
+
type: "text",
|
|
339
|
+
text: JSON.stringify(envelope),
|
|
340
|
+
},
|
|
341
|
+
],
|
|
342
|
+
isError: true,
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
// Start server
|
|
347
|
+
async function main() {
|
|
348
|
+
const transport = new StdioServerTransport();
|
|
349
|
+
console.error("LAFS-MCP Server starting...");
|
|
350
|
+
console.error("Available tools: weather, calculator, database_query");
|
|
351
|
+
console.error("All responses are wrapped in LAFS-compliant envelopes");
|
|
352
|
+
await server.connect(transport);
|
|
353
|
+
console.error("LAFS-MCP Server running on stdio");
|
|
354
|
+
}
|
|
355
|
+
main().catch((error) => {
|
|
356
|
+
console.error("Fatal error:", error);
|
|
357
|
+
process.exit(1);
|
|
358
|
+
});
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LAFS Budget Enforcement
|
|
3
|
+
*
|
|
4
|
+
* Middleware for enforcing MVI (Minimal Viable Interface) token budgets on LAFS envelopes.
|
|
5
|
+
* Provides budget checking, truncation, and error generation for exceeded budgets.
|
|
6
|
+
*/
|
|
7
|
+
import type { LAFSEnvelope } from "./types.js";
|
|
8
|
+
import type { BudgetEnforcementOptions, TokenEstimate, BudgetEnforcementResult } from "./types.js";
|
|
9
|
+
import { TokenEstimator } from "./tokenEstimator.js";
|
|
10
|
+
/**
|
|
11
|
+
* Budget exceeded error code from LAFS error registry
|
|
12
|
+
*/
|
|
13
|
+
declare const BUDGET_EXCEEDED_CODE = "E_MVI_BUDGET_EXCEEDED";
|
|
14
|
+
/**
|
|
15
|
+
* Apply budget enforcement to an envelope.
|
|
16
|
+
*
|
|
17
|
+
* @param envelope - The LAFS envelope to check
|
|
18
|
+
* @param budget - Maximum allowed tokens
|
|
19
|
+
* @param options - Budget enforcement options
|
|
20
|
+
* @returns Enforce result with potentially modified envelope
|
|
21
|
+
*/
|
|
22
|
+
export declare function applyBudgetEnforcement(envelope: LAFSEnvelope, budget: number, options?: BudgetEnforcementOptions): BudgetEnforcementResult;
|
|
23
|
+
/**
|
|
24
|
+
* Type for middleware function
|
|
25
|
+
*/
|
|
26
|
+
type EnvelopeMiddleware = (envelope: LAFSEnvelope, next: () => LAFSEnvelope | Promise<LAFSEnvelope>) => Promise<LAFSEnvelope> | LAFSEnvelope;
|
|
27
|
+
/**
|
|
28
|
+
* Create a budget enforcement middleware function.
|
|
29
|
+
*
|
|
30
|
+
* @param budget - Maximum allowed tokens for response
|
|
31
|
+
* @param options - Budget enforcement options
|
|
32
|
+
* @returns Middleware function that enforces budget
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* const middleware = withBudget(1000, { truncateOnExceed: true });
|
|
37
|
+
* const result = await middleware(envelope, async () => nextEnvelope);
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export declare function withBudget(budget: number, options?: BudgetEnforcementOptions): EnvelopeMiddleware;
|
|
41
|
+
/**
|
|
42
|
+
* Check if an envelope has exceeded its budget without modifying it.
|
|
43
|
+
*
|
|
44
|
+
* @param envelope - The LAFS envelope to check
|
|
45
|
+
* @param budget - Maximum allowed tokens
|
|
46
|
+
* @returns Budget check result
|
|
47
|
+
*/
|
|
48
|
+
export declare function checkBudget(envelope: LAFSEnvelope, budget: number): {
|
|
49
|
+
exceeded: boolean;
|
|
50
|
+
estimated: number;
|
|
51
|
+
remaining: number;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Synchronous version of withBudget for non-async contexts.
|
|
55
|
+
*
|
|
56
|
+
* @param budget - Maximum allowed tokens for response
|
|
57
|
+
* @param options - Budget enforcement options
|
|
58
|
+
* @returns Middleware function that enforces budget synchronously
|
|
59
|
+
*/
|
|
60
|
+
export declare function withBudgetSync(budget: number, options?: BudgetEnforcementOptions): (envelope: LAFSEnvelope, next: () => LAFSEnvelope) => LAFSEnvelope;
|
|
61
|
+
/**
|
|
62
|
+
* Higher-order function that wraps a handler with budget enforcement.
|
|
63
|
+
*
|
|
64
|
+
* @param handler - The handler function to wrap
|
|
65
|
+
* @param budget - Maximum allowed tokens
|
|
66
|
+
* @param options - Budget enforcement options
|
|
67
|
+
* @returns Wrapped handler with budget enforcement
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```typescript
|
|
71
|
+
* const myHandler = async (request: Request) => ({ success: true, result: { data } });
|
|
72
|
+
* const budgetedHandler = wrapWithBudget(myHandler, 1000, { truncateOnExceed: true });
|
|
73
|
+
* const result = await budgetedHandler(request);
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export declare function wrapWithBudget<TArgs extends unknown[], TResult extends LAFSEnvelope>(handler: (...args: TArgs) => TResult | Promise<TResult>, budget: number, options?: BudgetEnforcementOptions): (...args: TArgs) => Promise<LAFSEnvelope>;
|
|
77
|
+
/**
|
|
78
|
+
* Compose multiple middleware functions into a single middleware.
|
|
79
|
+
* Middleware is executed in order (left to right).
|
|
80
|
+
*/
|
|
81
|
+
export declare function composeMiddleware(...middlewares: EnvelopeMiddleware[]): EnvelopeMiddleware;
|
|
82
|
+
export type { BudgetEnforcementOptions, TokenEstimate, BudgetEnforcementResult };
|
|
83
|
+
export { TokenEstimator };
|
|
84
|
+
export { BUDGET_EXCEEDED_CODE };
|