@cleocode/lafs 1.8.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 +21 -0
- package/README.md +235 -0
- package/dist/schemas/v1/conformance-profiles.json +39 -0
- package/dist/schemas/v1/envelope.schema.json +306 -0
- package/dist/schemas/v1/error-registry.json +162 -0
- package/dist/src/a2a/bindings/grpc.d.ts +67 -0
- package/dist/src/a2a/bindings/grpc.js +148 -0
- package/dist/src/a2a/bindings/http.d.ts +102 -0
- package/dist/src/a2a/bindings/http.js +120 -0
- package/dist/src/a2a/bindings/index.d.ts +35 -0
- package/dist/src/a2a/bindings/index.js +79 -0
- package/dist/src/a2a/bindings/jsonrpc.d.ts +77 -0
- package/dist/src/a2a/bindings/jsonrpc.js +114 -0
- package/dist/src/a2a/bridge.d.ts +175 -0
- package/dist/src/a2a/bridge.js +286 -0
- package/dist/src/a2a/extensions.d.ts +121 -0
- package/dist/src/a2a/extensions.js +205 -0
- package/dist/src/a2a/index.d.ts +40 -0
- package/dist/src/a2a/index.js +76 -0
- package/dist/src/a2a/streaming.d.ts +74 -0
- package/dist/src/a2a/streaming.js +265 -0
- package/dist/src/a2a/task-lifecycle.d.ts +109 -0
- package/dist/src/a2a/task-lifecycle.js +313 -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 +16 -0
- package/dist/src/cli.js +63 -0
- package/dist/src/compliance.d.ts +31 -0
- package/dist/src/compliance.js +89 -0
- package/dist/src/conformance.d.ts +7 -0
- package/dist/src/conformance.js +248 -0
- package/dist/src/conformanceProfiles.d.ts +11 -0
- package/dist/src/conformanceProfiles.js +34 -0
- package/dist/src/deprecationRegistry.d.ts +13 -0
- package/dist/src/deprecationRegistry.js +39 -0
- package/dist/src/discovery.d.ts +286 -0
- package/dist/src/discovery.js +350 -0
- package/dist/src/envelope.d.ts +60 -0
- package/dist/src/envelope.js +136 -0
- package/dist/src/errorRegistry.d.ts +28 -0
- package/dist/src/errorRegistry.js +36 -0
- package/dist/src/fieldExtraction.d.ts +67 -0
- package/dist/src/fieldExtraction.js +133 -0
- package/dist/src/flagResolver.d.ts +46 -0
- package/dist/src/flagResolver.js +47 -0
- package/dist/src/flagSemantics.d.ts +16 -0
- package/dist/src/flagSemantics.js +45 -0
- package/dist/src/health/index.d.ts +105 -0
- package/dist/src/health/index.js +220 -0
- package/dist/src/index.d.ts +24 -0
- package/dist/src/index.js +34 -0
- package/dist/src/mcpAdapter.d.ts +28 -0
- package/dist/src/mcpAdapter.js +281 -0
- package/dist/src/mviProjection.d.ts +19 -0
- package/dist/src/mviProjection.js +116 -0
- package/dist/src/problemDetails.d.ts +34 -0
- package/dist/src/problemDetails.js +45 -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 +135 -0
- package/dist/src/types.js +12 -0
- package/dist/src/validateEnvelope.d.ts +15 -0
- package/dist/src/validateEnvelope.js +31 -0
- package/lafs.md +819 -0
- package/package.json +88 -0
- package/schemas/v1/agent-card.schema.json +230 -0
- package/schemas/v1/conformance-profiles.json +39 -0
- package/schemas/v1/context-ledger.schema.json +70 -0
- package/schemas/v1/discovery.schema.json +132 -0
- package/schemas/v1/envelope.schema.json +306 -0
- package/schemas/v1/error-registry.json +162 -0
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A2A Task Lifecycle Management
|
|
3
|
+
*
|
|
4
|
+
* State machine enforcement, task CRUD, and LAFS integration
|
|
5
|
+
* for A2A Protocol v1.0+ compliance.
|
|
6
|
+
*
|
|
7
|
+
* Reference: A2A spec Section 6 (Task Lifecycle)
|
|
8
|
+
*/
|
|
9
|
+
import { createLafsArtifact } from './bridge.js';
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// State Constants
|
|
12
|
+
// ============================================================================
|
|
13
|
+
/** States from which no further transitions are possible */
|
|
14
|
+
export const TERMINAL_STATES = new Set([
|
|
15
|
+
'completed',
|
|
16
|
+
'failed',
|
|
17
|
+
'canceled',
|
|
18
|
+
'rejected',
|
|
19
|
+
]);
|
|
20
|
+
/** States where the task is paused awaiting external input */
|
|
21
|
+
export const INTERRUPTED_STATES = new Set([
|
|
22
|
+
'input-required',
|
|
23
|
+
'auth-required',
|
|
24
|
+
]);
|
|
25
|
+
/** Valid state transitions (adjacency map). Terminal states have empty outgoing sets. */
|
|
26
|
+
export const VALID_TRANSITIONS = new Map([
|
|
27
|
+
['submitted', new Set(['working', 'canceled', 'rejected', 'failed'])],
|
|
28
|
+
['working', new Set(['completed', 'failed', 'canceled', 'input-required', 'auth-required'])],
|
|
29
|
+
['input-required', new Set(['working', 'canceled', 'failed'])],
|
|
30
|
+
['auth-required', new Set(['working', 'canceled', 'failed'])],
|
|
31
|
+
['completed', new Set()],
|
|
32
|
+
['failed', new Set()],
|
|
33
|
+
['canceled', new Set()],
|
|
34
|
+
['rejected', new Set()],
|
|
35
|
+
['unknown', new Set(['submitted', 'working', 'input-required', 'completed', 'canceled', 'failed', 'rejected', 'auth-required'])],
|
|
36
|
+
]);
|
|
37
|
+
// ============================================================================
|
|
38
|
+
// State Functions
|
|
39
|
+
// ============================================================================
|
|
40
|
+
/** Check if a transition from one state to another is valid */
|
|
41
|
+
export function isValidTransition(from, to) {
|
|
42
|
+
const allowed = VALID_TRANSITIONS.get(from);
|
|
43
|
+
return allowed ? allowed.has(to) : false;
|
|
44
|
+
}
|
|
45
|
+
/** Check if a state is terminal (no further transitions allowed) */
|
|
46
|
+
export function isTerminalState(state) {
|
|
47
|
+
return TERMINAL_STATES.has(state);
|
|
48
|
+
}
|
|
49
|
+
/** Check if a state is interrupted (paused awaiting input) */
|
|
50
|
+
export function isInterruptedState(state) {
|
|
51
|
+
return INTERRUPTED_STATES.has(state);
|
|
52
|
+
}
|
|
53
|
+
// ============================================================================
|
|
54
|
+
// Error Classes
|
|
55
|
+
// ============================================================================
|
|
56
|
+
/** Thrown when attempting an invalid state transition */
|
|
57
|
+
export class InvalidStateTransitionError extends Error {
|
|
58
|
+
taskId;
|
|
59
|
+
fromState;
|
|
60
|
+
toState;
|
|
61
|
+
constructor(taskId, fromState, toState) {
|
|
62
|
+
super(`Invalid transition for task ${taskId}: ${fromState} -> ${toState}`);
|
|
63
|
+
this.name = 'InvalidStateTransitionError';
|
|
64
|
+
this.taskId = taskId;
|
|
65
|
+
this.fromState = fromState;
|
|
66
|
+
this.toState = toState;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/** Thrown when attempting to modify a task in a terminal state */
|
|
70
|
+
export class TaskImmutabilityError extends Error {
|
|
71
|
+
taskId;
|
|
72
|
+
terminalState;
|
|
73
|
+
constructor(taskId, terminalState) {
|
|
74
|
+
super(`Task ${taskId} is in terminal state ${terminalState} and cannot be modified`);
|
|
75
|
+
this.name = 'TaskImmutabilityError';
|
|
76
|
+
this.taskId = taskId;
|
|
77
|
+
this.terminalState = terminalState;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/** Thrown when a task is not found */
|
|
81
|
+
export class TaskNotFoundError extends Error {
|
|
82
|
+
taskId;
|
|
83
|
+
constructor(taskId) {
|
|
84
|
+
super(`Task not found: ${taskId}`);
|
|
85
|
+
this.name = 'TaskNotFoundError';
|
|
86
|
+
this.taskId = taskId;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/** Thrown when a refinement/follow-up task references invalid parent tasks */
|
|
90
|
+
export class TaskRefinementError extends Error {
|
|
91
|
+
referenceTaskIds;
|
|
92
|
+
constructor(message, referenceTaskIds) {
|
|
93
|
+
super(message);
|
|
94
|
+
this.name = 'TaskRefinementError';
|
|
95
|
+
this.referenceTaskIds = referenceTaskIds;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// ============================================================================
|
|
99
|
+
// ID Generation
|
|
100
|
+
// ============================================================================
|
|
101
|
+
function generateId() {
|
|
102
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
|
103
|
+
const r = (Math.random() * 16) | 0;
|
|
104
|
+
const v = c === 'x' ? r : (r & 0x3) | 0x8;
|
|
105
|
+
return v.toString(16);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* In-memory task manager implementing A2A task lifecycle.
|
|
110
|
+
* Enforces valid state transitions and terminal state immutability.
|
|
111
|
+
*/
|
|
112
|
+
export class TaskManager {
|
|
113
|
+
tasks = new Map();
|
|
114
|
+
contextIndex = new Map();
|
|
115
|
+
/** Create a new task in the submitted state */
|
|
116
|
+
createTask(options) {
|
|
117
|
+
const id = generateId();
|
|
118
|
+
const resolvedContextId = options?.contextId ?? this.resolveContextForReferenceTasks(options?.referenceTaskIds) ?? generateId();
|
|
119
|
+
const contextId = resolvedContextId;
|
|
120
|
+
const referenceTaskIds = options?.referenceTaskIds ?? [];
|
|
121
|
+
this.validateReferenceTasks(referenceTaskIds, contextId);
|
|
122
|
+
const metadata = {
|
|
123
|
+
...(options?.metadata ?? {}),
|
|
124
|
+
...(referenceTaskIds.length > 0 ? { referenceTaskIds } : {}),
|
|
125
|
+
...(options?.parallelFollowUp ? { parallelFollowUp: true } : {}),
|
|
126
|
+
};
|
|
127
|
+
const task = {
|
|
128
|
+
id,
|
|
129
|
+
contextId,
|
|
130
|
+
kind: 'task',
|
|
131
|
+
status: {
|
|
132
|
+
state: 'submitted',
|
|
133
|
+
timestamp: new Date().toISOString(),
|
|
134
|
+
},
|
|
135
|
+
...(Object.keys(metadata).length > 0 && { metadata }),
|
|
136
|
+
};
|
|
137
|
+
this.tasks.set(id, task);
|
|
138
|
+
// Index by contextId
|
|
139
|
+
let contextTasks = this.contextIndex.get(contextId);
|
|
140
|
+
if (!contextTasks) {
|
|
141
|
+
contextTasks = new Set();
|
|
142
|
+
this.contextIndex.set(contextId, contextTasks);
|
|
143
|
+
}
|
|
144
|
+
contextTasks.add(id);
|
|
145
|
+
return structuredClone(task);
|
|
146
|
+
}
|
|
147
|
+
/** Create a refinement/follow-up task referencing existing task(s). */
|
|
148
|
+
createRefinedTask(referenceTaskIds, options) {
|
|
149
|
+
return this.createTask({
|
|
150
|
+
...options,
|
|
151
|
+
referenceTaskIds,
|
|
152
|
+
parallelFollowUp: options?.parallelFollowUp,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
/** Get a task by ID. Throws TaskNotFoundError if not found. */
|
|
156
|
+
getTask(taskId) {
|
|
157
|
+
const task = this.tasks.get(taskId);
|
|
158
|
+
if (!task) {
|
|
159
|
+
throw new TaskNotFoundError(taskId);
|
|
160
|
+
}
|
|
161
|
+
return structuredClone(task);
|
|
162
|
+
}
|
|
163
|
+
/** List tasks with optional filtering and pagination */
|
|
164
|
+
listTasks(options) {
|
|
165
|
+
let taskIds;
|
|
166
|
+
if (options?.contextId) {
|
|
167
|
+
const contextTasks = this.contextIndex.get(options.contextId);
|
|
168
|
+
taskIds = contextTasks ? [...contextTasks] : [];
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
taskIds = [...this.tasks.keys()];
|
|
172
|
+
}
|
|
173
|
+
// Filter by state
|
|
174
|
+
if (options?.state) {
|
|
175
|
+
taskIds = taskIds.filter(id => {
|
|
176
|
+
const task = this.tasks.get(id);
|
|
177
|
+
return task && task.status.state === options.state;
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
// Sort for deterministic pagination
|
|
181
|
+
taskIds.sort();
|
|
182
|
+
// Apply page token (cursor-based: token is the last seen task ID)
|
|
183
|
+
if (options?.pageToken) {
|
|
184
|
+
const startIdx = taskIds.indexOf(options.pageToken);
|
|
185
|
+
if (startIdx >= 0) {
|
|
186
|
+
taskIds = taskIds.slice(startIdx + 1);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
// Apply limit
|
|
190
|
+
const limit = options?.limit ?? taskIds.length;
|
|
191
|
+
const pageTaskIds = taskIds.slice(0, limit);
|
|
192
|
+
const hasMore = taskIds.length > limit;
|
|
193
|
+
const tasks = pageTaskIds.map(id => structuredClone(this.tasks.get(id)));
|
|
194
|
+
const nextPageToken = hasMore ? pageTaskIds[pageTaskIds.length - 1] : undefined;
|
|
195
|
+
return { tasks, nextPageToken };
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Update task status. Enforces valid transitions and terminal state immutability.
|
|
199
|
+
* @throws InvalidStateTransitionError if the transition is not valid
|
|
200
|
+
* @throws TaskImmutabilityError if the task is in a terminal state
|
|
201
|
+
*/
|
|
202
|
+
updateTaskStatus(taskId, state, message) {
|
|
203
|
+
const task = this.tasks.get(taskId);
|
|
204
|
+
if (!task) {
|
|
205
|
+
throw new TaskNotFoundError(taskId);
|
|
206
|
+
}
|
|
207
|
+
const currentState = task.status.state;
|
|
208
|
+
if (isTerminalState(currentState)) {
|
|
209
|
+
throw new TaskImmutabilityError(taskId, currentState);
|
|
210
|
+
}
|
|
211
|
+
if (!isValidTransition(currentState, state)) {
|
|
212
|
+
throw new InvalidStateTransitionError(taskId, currentState, state);
|
|
213
|
+
}
|
|
214
|
+
const status = {
|
|
215
|
+
state,
|
|
216
|
+
timestamp: new Date().toISOString(),
|
|
217
|
+
...(message && { message }),
|
|
218
|
+
};
|
|
219
|
+
task.status = status;
|
|
220
|
+
return structuredClone(task);
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Add an artifact to a task.
|
|
224
|
+
* @throws TaskImmutabilityError if the task is in a terminal state
|
|
225
|
+
*/
|
|
226
|
+
addArtifact(taskId, artifact) {
|
|
227
|
+
const task = this.tasks.get(taskId);
|
|
228
|
+
if (!task) {
|
|
229
|
+
throw new TaskNotFoundError(taskId);
|
|
230
|
+
}
|
|
231
|
+
if (isTerminalState(task.status.state)) {
|
|
232
|
+
throw new TaskImmutabilityError(taskId, task.status.state);
|
|
233
|
+
}
|
|
234
|
+
if (!task.artifacts) {
|
|
235
|
+
task.artifacts = [];
|
|
236
|
+
}
|
|
237
|
+
task.artifacts.push(artifact);
|
|
238
|
+
return structuredClone(task);
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Add a message to task history.
|
|
242
|
+
* @throws TaskImmutabilityError if the task is in a terminal state
|
|
243
|
+
*/
|
|
244
|
+
addHistory(taskId, message) {
|
|
245
|
+
const task = this.tasks.get(taskId);
|
|
246
|
+
if (!task) {
|
|
247
|
+
throw new TaskNotFoundError(taskId);
|
|
248
|
+
}
|
|
249
|
+
if (isTerminalState(task.status.state)) {
|
|
250
|
+
throw new TaskImmutabilityError(taskId, task.status.state);
|
|
251
|
+
}
|
|
252
|
+
if (!task.history) {
|
|
253
|
+
task.history = [];
|
|
254
|
+
}
|
|
255
|
+
task.history.push(message);
|
|
256
|
+
return structuredClone(task);
|
|
257
|
+
}
|
|
258
|
+
/** Cancel a task by transitioning to canceled state */
|
|
259
|
+
cancelTask(taskId) {
|
|
260
|
+
return this.updateTaskStatus(taskId, 'canceled');
|
|
261
|
+
}
|
|
262
|
+
/** Get all tasks in a given context */
|
|
263
|
+
getTasksByContext(contextId) {
|
|
264
|
+
const taskIds = this.contextIndex.get(contextId);
|
|
265
|
+
if (!taskIds)
|
|
266
|
+
return [];
|
|
267
|
+
return [...taskIds].map(id => structuredClone(this.tasks.get(id)));
|
|
268
|
+
}
|
|
269
|
+
/** Check if a task is in a terminal state */
|
|
270
|
+
isTerminal(taskId) {
|
|
271
|
+
const task = this.tasks.get(taskId);
|
|
272
|
+
if (!task) {
|
|
273
|
+
throw new TaskNotFoundError(taskId);
|
|
274
|
+
}
|
|
275
|
+
return isTerminalState(task.status.state);
|
|
276
|
+
}
|
|
277
|
+
resolveContextForReferenceTasks(referenceTaskIds) {
|
|
278
|
+
if (!referenceTaskIds || referenceTaskIds.length === 0) {
|
|
279
|
+
return undefined;
|
|
280
|
+
}
|
|
281
|
+
const firstId = referenceTaskIds[0];
|
|
282
|
+
if (!firstId) {
|
|
283
|
+
return undefined;
|
|
284
|
+
}
|
|
285
|
+
const first = this.tasks.get(firstId);
|
|
286
|
+
return first?.contextId;
|
|
287
|
+
}
|
|
288
|
+
validateReferenceTasks(referenceTaskIds, contextId) {
|
|
289
|
+
if (referenceTaskIds.length === 0) {
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
for (const refId of referenceTaskIds) {
|
|
293
|
+
const refTask = this.tasks.get(refId);
|
|
294
|
+
if (!refTask) {
|
|
295
|
+
throw new TaskRefinementError(`Referenced task not found: ${refId}`, referenceTaskIds);
|
|
296
|
+
}
|
|
297
|
+
if (refTask.contextId !== contextId) {
|
|
298
|
+
throw new TaskRefinementError(`Referenced task ${refId} has different contextId (${refTask.contextId}) than refinement (${contextId})`, referenceTaskIds);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
// ============================================================================
|
|
304
|
+
// LAFS Integration
|
|
305
|
+
// ============================================================================
|
|
306
|
+
/**
|
|
307
|
+
* Attach a LAFS envelope as an artifact to an A2A task.
|
|
308
|
+
* Uses createLafsArtifact() from bridge.ts to wrap the envelope.
|
|
309
|
+
*/
|
|
310
|
+
export function attachLafsEnvelope(manager, taskId, envelope) {
|
|
311
|
+
const artifact = createLafsArtifact(envelope);
|
|
312
|
+
return manager.addArtifact(taskId, artifact);
|
|
313
|
+
}
|
|
@@ -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 };
|