@cleocode/lafs-protocol 1.1.0 → 1.2.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.
|
@@ -67,6 +67,12 @@
|
|
|
67
67
|
"type": "integer",
|
|
68
68
|
"minimum": 0
|
|
69
69
|
},
|
|
70
|
+
"sessionId": {
|
|
71
|
+
"type": "string",
|
|
72
|
+
"minLength": 1,
|
|
73
|
+
"maxLength": 256,
|
|
74
|
+
"description": "Session identifier for correlating multi-step agent workflows"
|
|
75
|
+
},
|
|
70
76
|
"warnings": {
|
|
71
77
|
"type": "array",
|
|
72
78
|
"items": {
|
|
@@ -2,6 +2,8 @@ import type { FlagInput } from "./types.js";
|
|
|
2
2
|
export interface FlagResolution {
|
|
3
3
|
format: "json" | "human";
|
|
4
4
|
source: "flag" | "project" | "user" | "default";
|
|
5
|
+
/** When true, suppress non-essential output for scripting */
|
|
6
|
+
quiet: boolean;
|
|
5
7
|
}
|
|
6
8
|
export declare class LAFSFlagError extends Error {
|
|
7
9
|
code: string;
|
|
@@ -10,20 +10,21 @@ export function resolveOutputFormat(input) {
|
|
|
10
10
|
if (input.humanFlag && input.jsonFlag) {
|
|
11
11
|
throw new LAFSFlagError("E_FORMAT_CONFLICT", "Cannot combine --human and --json in the same invocation.");
|
|
12
12
|
}
|
|
13
|
+
const quiet = input.quiet ?? false;
|
|
13
14
|
if (input.requestedFormat) {
|
|
14
|
-
return { format: input.requestedFormat, source: "flag" };
|
|
15
|
+
return { format: input.requestedFormat, source: "flag", quiet };
|
|
15
16
|
}
|
|
16
17
|
if (input.humanFlag) {
|
|
17
|
-
return { format: "human", source: "flag" };
|
|
18
|
+
return { format: "human", source: "flag", quiet };
|
|
18
19
|
}
|
|
19
20
|
if (input.jsonFlag) {
|
|
20
|
-
return { format: "json", source: "flag" };
|
|
21
|
+
return { format: "json", source: "flag", quiet };
|
|
21
22
|
}
|
|
22
23
|
if (input.projectDefault) {
|
|
23
|
-
return { format: input.projectDefault, source: "project" };
|
|
24
|
+
return { format: input.projectDefault, source: "project", quiet };
|
|
24
25
|
}
|
|
25
26
|
if (input.userDefault) {
|
|
26
|
-
return { format: input.userDefault, source: "user" };
|
|
27
|
+
return { format: input.userDefault, source: "user", quiet };
|
|
27
28
|
}
|
|
28
|
-
return { format: "json", source: "default" };
|
|
29
|
+
return { format: "json", source: "default", quiet };
|
|
29
30
|
}
|
package/dist/src/types.d.ts
CHANGED
|
@@ -17,6 +17,8 @@ export interface LAFSMeta {
|
|
|
17
17
|
strict: boolean;
|
|
18
18
|
mvi: 'minimal' | 'standard' | 'full' | 'custom';
|
|
19
19
|
contextVersion: number;
|
|
20
|
+
/** Session identifier for correlating multi-step agent workflows */
|
|
21
|
+
sessionId?: string;
|
|
20
22
|
warnings?: Warning[];
|
|
21
23
|
}
|
|
22
24
|
export interface LAFSError {
|
|
@@ -76,6 +78,8 @@ export interface FlagInput {
|
|
|
76
78
|
humanFlag?: boolean;
|
|
77
79
|
projectDefault?: "json" | "human";
|
|
78
80
|
userDefault?: "json" | "human";
|
|
81
|
+
/** Suppress non-essential output for scripting. When true, only essential data is returned. */
|
|
82
|
+
quiet?: boolean;
|
|
79
83
|
}
|
|
80
84
|
export interface ConformanceReport {
|
|
81
85
|
ok: boolean;
|
package/lafs.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# LAFS: LLM-Agent-First Specification
|
|
2
2
|
|
|
3
3
|
> 📚 **Documentation:** https://codluv.gitbook.io/lafs-protocol/
|
|
4
|
-
> **Version:** 1.
|
|
4
|
+
> **Version:** 1.2.0 | **Status:** Production Ready
|
|
5
5
|
|
|
6
6
|
## 1. Scope
|
|
7
7
|
|
|
@@ -67,6 +67,52 @@ The keywords MUST, MUST NOT, SHOULD, SHOULD NOT, and MAY are interpreted per RFC
|
|
|
67
67
|
3. Global/user config
|
|
68
68
|
4. Protocol default (`json`)
|
|
69
69
|
|
|
70
|
+
### 5.3 Supported formats
|
|
71
|
+
|
|
72
|
+
LAFS supports exactly two output formats:
|
|
73
|
+
|
|
74
|
+
- **`json`** (default) — Machine-readable JSON envelope for programmatic consumption
|
|
75
|
+
- **`human`** — Human-readable text output for terminal display
|
|
76
|
+
|
|
77
|
+
#### 5.3.1 Human format definition
|
|
78
|
+
|
|
79
|
+
The `human` format produces plain text output optimized for terminal display:
|
|
80
|
+
|
|
81
|
+
- Suitable for direct human consumption in CLI environments
|
|
82
|
+
- NOT markdown, NOT tables, NOT structured data
|
|
83
|
+
- May include ANSI colors (respect `NO_COLOR` environment variable)
|
|
84
|
+
- Example: Tabular data displayed with aligned columns using spaces
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
ID Name Status
|
|
88
|
+
---- ------------ --------
|
|
89
|
+
123 Alpha active
|
|
90
|
+
456 Beta pending
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
#### 5.3.2 Rejected formats
|
|
94
|
+
|
|
95
|
+
The following formats were explicitly rejected to maintain protocol minimalism:
|
|
96
|
+
|
|
97
|
+
| Format | Status | Rationale |
|
|
98
|
+
|--------|--------|-----------|
|
|
99
|
+
| `text` | ❌ Rejected | Ambiguous overlap with `human`. Use `human` format with `NO_COLOR=1` for plain text. |
|
|
100
|
+
| `markdown` | ❌ Rejected | Presentation format, not data format. Generate from JSON if markdown rendering is needed. |
|
|
101
|
+
| `table` | ❌ Rejected | Presentation concern. Use `jq` + `column` command or `human` format for tabular display. |
|
|
102
|
+
| `jsonl` | ❌ Rejected | Streaming format violates LAFS discrete envelope contract (see Section 2: Non-Goals). |
|
|
103
|
+
|
|
104
|
+
**Design principle:** LAFS is a response envelope contract, not a presentation layer. Six formats = format proliferation = protocol bloat.
|
|
105
|
+
|
|
106
|
+
#### 5.3.3 Achieving presentation goals with json format
|
|
107
|
+
|
|
108
|
+
Consumers needing presentation formats should:
|
|
109
|
+
|
|
110
|
+
1. Request `json` format from LAFS-compliant services
|
|
111
|
+
2. Transform JSON to desired presentation format using standard tools:
|
|
112
|
+
- **Markdown:** `jq` + template engine
|
|
113
|
+
- **Tables:** `jq` + `column` command
|
|
114
|
+
- **Plain text:** `jq` with `-r` (raw) output
|
|
115
|
+
|
|
70
116
|
---
|
|
71
117
|
|
|
72
118
|
## 6. Canonical Response Envelope
|
|
@@ -110,6 +156,144 @@ The envelope supports an optional `_extensions` object for vendor-specific metad
|
|
|
110
156
|
- Consumers MUST NOT rely on extension fields for protocol-required behavior.
|
|
111
157
|
- Producers MAY omit `_extensions` entirely; the field is always optional.
|
|
112
158
|
|
|
159
|
+
#### 6.2.1 Extension use cases
|
|
160
|
+
|
|
161
|
+
The following examples demonstrate common use cases for `_extensions`. These fields were rejected from the core protocol but are valid extension use cases.
|
|
162
|
+
|
|
163
|
+
**Example 1: Performance timing**
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
// Extension type definition
|
|
167
|
+
interface XTimingExtension {
|
|
168
|
+
"x-timing": {
|
|
169
|
+
executionMs: number; // Total request execution time
|
|
170
|
+
parseMs?: number; // Input parsing time
|
|
171
|
+
queryMs?: number; // Database query time
|
|
172
|
+
serializeMs?: number; // Response serialization time
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
```json
|
|
178
|
+
{
|
|
179
|
+
"_extensions": {
|
|
180
|
+
"x-timing": {
|
|
181
|
+
"executionMs": 42,
|
|
182
|
+
"queryMs": 15,
|
|
183
|
+
"serializeMs": 3
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**Example 2: Source metadata**
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
interface XSourceExtension {
|
|
193
|
+
"x-source": {
|
|
194
|
+
gitRef?: string; // Git commit SHA
|
|
195
|
+
apiVersion?: string; // API implementation version
|
|
196
|
+
buildTimestamp?: string; // ISO 8601 build time
|
|
197
|
+
deployment?: string; // Deployment environment (staging, prod)
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
```json
|
|
203
|
+
{
|
|
204
|
+
"_extensions": {
|
|
205
|
+
"x-source": {
|
|
206
|
+
"gitRef": "abc123def456",
|
|
207
|
+
"apiVersion": "2.1.0",
|
|
208
|
+
"deployment": "production"
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
**Example 3: Applied filters**
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
interface XFiltersExtension {
|
|
218
|
+
"x-filters": {
|
|
219
|
+
applied: Array<{
|
|
220
|
+
field: string;
|
|
221
|
+
operator: "eq" | "neq" | "gt" | "lt" | "contains";
|
|
222
|
+
value: unknown;
|
|
223
|
+
}>;
|
|
224
|
+
omitted: string[]; // Fields excluded due to permissions
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
```json
|
|
230
|
+
{
|
|
231
|
+
"_extensions": {
|
|
232
|
+
"x-filters": {
|
|
233
|
+
"applied": [
|
|
234
|
+
{ "field": "status", "operator": "eq", "value": "active" },
|
|
235
|
+
{ "field": "createdAt", "operator": "gt", "value": "2024-01-01" }
|
|
236
|
+
],
|
|
237
|
+
"omitted": ["internalNotes", "costCenter"]
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
**Example 4: Result summary**
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
interface XSummaryExtension {
|
|
247
|
+
"x-summary": {
|
|
248
|
+
totalCount: number; // Total matching records
|
|
249
|
+
returnedCount: number; // Records in this response
|
|
250
|
+
aggregated?: {
|
|
251
|
+
revenue?: number;
|
|
252
|
+
count?: number;
|
|
253
|
+
average?: number;
|
|
254
|
+
};
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
```json
|
|
260
|
+
{
|
|
261
|
+
"_extensions": {
|
|
262
|
+
"x-summary": {
|
|
263
|
+
"totalCount": 150,
|
|
264
|
+
"returnedCount": 25,
|
|
265
|
+
"aggregated": {
|
|
266
|
+
"revenue": 125000.00,
|
|
267
|
+
"average": 833.33
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
#### 6.2.2 Extension best practices
|
|
275
|
+
|
|
276
|
+
1. **Use x- prefix** — All extension keys MUST start with `x-` (e.g., `x-caamp-timing`)
|
|
277
|
+
2. **Document your schema** — Publish extension schemas separately from LAFS core
|
|
278
|
+
3. **Don't rely on extensions for core behavior** — Extensions are informational only
|
|
279
|
+
4. **Version your extensions** — Include version in extension key if schema may change (e.g., `x-vendor-v2-field`)
|
|
280
|
+
5. **Keep extensions optional** — Consumers MUST be able to operate without extension data
|
|
281
|
+
6. **Namespace by vendor** — Use vendor prefix to avoid collisions (e.g., `x-caamp-`, `x-acme-`)
|
|
282
|
+
|
|
283
|
+
#### 6.2.3 When to use extensions vs core protocol
|
|
284
|
+
|
|
285
|
+
| Use Case | Core Protocol | Extensions |
|
|
286
|
+
|----------|---------------|------------|
|
|
287
|
+
| Session correlation | ✅ sessionId | — |
|
|
288
|
+
| Soft warnings | ✅ warnings array | — |
|
|
289
|
+
| Performance timing | — | ✅ x-timing |
|
|
290
|
+
| Source/version metadata | — | ✅ x-source |
|
|
291
|
+
| Debug filters | — | ✅ x-filters |
|
|
292
|
+
| Derived summaries | — | ✅ x-summary |
|
|
293
|
+
| Data integrity (TLS covers) | — | ✅ x-checksum (if needed) |
|
|
294
|
+
|
|
295
|
+
**Guideline:** If a field is required for basic operation, it belongs in core. If it's useful for debugging, monitoring, or rich display, it belongs in extensions.
|
|
296
|
+
|
|
113
297
|
---
|
|
114
298
|
|
|
115
299
|
## 7. Error Contract
|
package/package.json
CHANGED
|
@@ -67,6 +67,12 @@
|
|
|
67
67
|
"type": "integer",
|
|
68
68
|
"minimum": 0
|
|
69
69
|
},
|
|
70
|
+
"sessionId": {
|
|
71
|
+
"type": "string",
|
|
72
|
+
"minLength": 1,
|
|
73
|
+
"maxLength": 256,
|
|
74
|
+
"description": "Session identifier for correlating multi-step agent workflows"
|
|
75
|
+
},
|
|
70
76
|
"warnings": {
|
|
71
77
|
"type": "array",
|
|
72
78
|
"items": {
|