agent-first-data 0.16.0 → 0.16.1

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.
@@ -47,13 +47,7 @@
47
47
  "type": "object",
48
48
  "properties": {
49
49
  "kind": {"const": "progress"},
50
- "progress": {
51
- "type": "object",
52
- "properties": {
53
- "message": {"type": "string", "minLength": 1}
54
- },
55
- "additionalProperties": true
56
- },
50
+ "progress": true,
57
51
  "trace": {"$ref": "#/$defs/trace"}
58
52
  },
59
53
  "required": ["kind", "progress"],
@@ -63,18 +57,7 @@
63
57
  "type": "object",
64
58
  "properties": {
65
59
  "kind": {"const": "log"},
66
- "log": {
67
- "type": "object",
68
- "properties": {
69
- "message": {"type": "string", "minLength": 1},
70
- "level": {"enum": ["debug", "info", "warn", "error"]},
71
- "code": false
72
- },
73
- "not": {
74
- "required": ["code"]
75
- },
76
- "additionalProperties": true
77
- },
60
+ "log": true,
78
61
  "trace": {"$ref": "#/$defs/trace"}
79
62
  },
80
63
  "required": ["kind", "log"],
@@ -258,7 +258,7 @@ Startup payload fields are tool-defined; `config` is recommended, while `version
258
258
 
259
259
  All use `kind` plus the same-named payload and optional `trace`. Do not split protocol events across `stdout` and `stderr`.
260
260
 
261
- Base validators enforce mandatory envelope/error/lifecycle rules. Strict validators additionally require object-valued `trace` on every event, complete log fields (`message`, `level`; `code` field MUST NOT appear in log payload), `retryable` on every error, and a non-empty progress `message`. Use strict validation before claiming compliance with all recommendations.
261
+ Base validators enforce mandatory envelope/error/lifecycle rules. Strict validators additionally require object-valued `trace` on every event and `retryable` on every error. Log and progress payloads remain tool-defined in both profiles. Use strict validation before claiming compliance with all recommendations.
262
262
 
263
263
  ---
264
264
 
@@ -298,11 +298,11 @@ let span = info_span!("request", request_id = %uuid);
298
298
  let _guard = span.enter();
299
299
  ```
300
300
 
301
- For Go, Python, and TypeScript: emit span fields explicitly in each log event via `.field()` or equivalent event construction.
301
+ For Go, Python, and TypeScript: emit span fields explicitly in each tool-defined log payload.
302
302
 
303
303
  ### Output fields
304
304
 
305
- Every log line contains `message`, `level` (debug/info/warn/error), plus span fields and event fields. Log payloads MUST NOT contain a `code` field. Do not use the log level as `code`; `code:"error"` is reserved for terminal protocol errors. Projects that need timestamps add them as extension fields (`timestamp_epoch_ms`) via emitter defaults or per-call `.field()`.
305
+ Log payloads have no required or reserved fields. Traditional logging adapters commonly add `message` and `level` (debug/info/warn/error), plus span and event fields, but those names and meanings are adapter conventions rather than AFDATA protocol requirements. Projects that need timestamps add `timestamp_epoch_ms` explicitly.
306
306
 
307
307
  Log redaction is **by field name** (the same `_secret`/`_url` rule as all output), applied when the line is emitted. Name the secret field — `info!(api_key_secret = %key)` — rather than logging a whole object by its `Debug`/string rendering, which hides the inner field names from redaction. For structured/nested secret-bearing data, build a value, apply redaction through output formatters or redacted_value(), then emit via the standard formatting helpers — do not pass the struct to a `?`/`%`-rendered log field.
308
308
 
package/dist/format.d.ts CHANGED
@@ -54,30 +54,19 @@ export declare class JsonErrorBuilder {
54
54
  build(): Event;
55
55
  }
56
56
  export declare class JsonProgressBuilder {
57
- private readonly message;
58
- private extensionFields;
57
+ private readonly payload;
59
58
  private traceValue;
60
59
  private issues;
61
- constructor(message: string);
62
- field(name: string, value: JsonValue): this;
63
- fields(obj: unknown): this;
64
- extend(obj: unknown): this;
60
+ constructor(payload: JsonValue);
65
61
  trace(value: Record<string, JsonValue> | undefined): this;
66
- private isReservedProgressField;
67
62
  build(): Event;
68
63
  }
69
64
  export declare class JsonLogBuilder {
70
- private readonly level;
71
- private readonly message;
72
- private extensionFields;
65
+ private readonly payload;
73
66
  private traceValue;
74
67
  private issues;
75
- constructor(level: LogLevel, message: string);
76
- field(name: string, value: JsonValue): this;
77
- fields(obj: unknown): this;
78
- extend(obj: unknown): this;
68
+ constructor(payload: JsonValue);
79
69
  trace(value: Record<string, JsonValue> | undefined): this;
80
- private isReservedLogField;
81
70
  build(): Event;
82
71
  }
83
72
  /** Fluent builder for result events. */
@@ -85,9 +74,9 @@ export declare function jsonResult(payload: JsonValue): JsonResultBuilder;
85
74
  /** Fluent builder for error events. */
86
75
  export declare function jsonError(code: string, message: string): JsonErrorBuilder;
87
76
  /** Fluent builder for progress events. */
88
- export declare function jsonProgress(message: string): JsonProgressBuilder;
77
+ export declare function jsonProgress(payload: JsonValue): JsonProgressBuilder;
89
78
  /** Fluent builder for log events. */
90
- export declare function jsonLog(level: LogLevel, message: string): JsonLogBuilder;
79
+ export declare function jsonLog(payload: JsonValue): JsonLogBuilder;
91
80
  /** Validate one protocol event envelope. `strict` also enforces the recommended strict protocol profile (default true). */
92
81
  export declare function validateProtocolEvent(event: unknown, strict?: boolean): void;
93
82
  /** Validate finite CLI lifecycle: (log | progress)* -> exactly one terminal. `strict` also enforces the recommended strict protocol profile (default true). */
@@ -108,15 +97,12 @@ export type DecodedError = {
108
97
  };
109
98
  export type DecodedProgress = {
110
99
  kind: "progress";
111
- message: string;
112
- fields: Record<string, JsonValue>;
100
+ progress: JsonValue;
113
101
  trace?: Record<string, JsonValue>;
114
102
  };
115
103
  export type DecodedLog = {
116
104
  kind: "log";
117
- level: LogLevel;
118
- message: string;
119
- fields: Record<string, JsonValue>;
105
+ log: JsonValue;
120
106
  trace?: Record<string, JsonValue>;
121
107
  };
122
108
  /** Discriminated union of decoded protocol events, narrow on `kind`. */
@@ -127,8 +113,7 @@ export declare class EventDecodeError extends Error {
127
113
  }
128
114
  /**
129
115
  * Parse one protocol line (a single JSON text value), strict-validate it, and
130
- * return a typed decoded event. Extension fields are every payload key beyond
131
- * the required ones, collected into `fields`.
116
+ * return a typed decoded event.
132
117
  */
133
118
  export declare function decodeProtocolEvent(text: string): DecodedEvent;
134
119
  export declare enum RedactionPolicy {
package/dist/format.js CHANGED
@@ -176,53 +176,11 @@ export class JsonErrorBuilder {
176
176
  }
177
177
  }
178
178
  export class JsonProgressBuilder {
179
- message;
180
- extensionFields = {};
179
+ payload;
181
180
  traceValue = {};
182
181
  issues = [];
183
- constructor(message) {
184
- this.message = message;
185
- if (!message || message === "")
186
- this.issues.push("message must be a non-empty string");
187
- }
188
- field(name, value) {
189
- if (this.isReservedProgressField(name)) {
190
- this.issues.push(`cannot write reserved progress field ${JSON.stringify(name)}`);
191
- }
192
- else {
193
- this.extensionFields[name] = value;
194
- }
195
- return this;
196
- }
197
- fields(obj) {
198
- if (!isObject(obj)) {
199
- this.issues.push("fields must be a JSON object");
200
- return this;
201
- }
202
- for (const [key, val] of Object.entries(obj)) {
203
- if (this.isReservedProgressField(key)) {
204
- this.issues.push(`cannot write reserved progress field ${JSON.stringify(key)}`);
205
- }
206
- else {
207
- this.extensionFields[key] = val;
208
- }
209
- }
210
- return this;
211
- }
212
- extend(obj) {
213
- if (!isObject(obj)) {
214
- this.issues.push("extend must be a JSON object");
215
- return this;
216
- }
217
- for (const [key, val] of Object.entries(obj)) {
218
- if (this.isReservedProgressField(key)) {
219
- this.issues.push(`cannot write reserved progress field ${JSON.stringify(key)}`);
220
- }
221
- else {
222
- this.extensionFields[key] = val;
223
- }
224
- }
225
- return this;
182
+ constructor(payload) {
183
+ this.payload = payload;
226
184
  }
227
185
  trace(value) {
228
186
  if (value !== undefined) {
@@ -235,71 +193,20 @@ export class JsonProgressBuilder {
235
193
  }
236
194
  return this;
237
195
  }
238
- isReservedProgressField(name) {
239
- return name === "message";
240
- }
241
196
  build() {
242
197
  if (this.issues.length > 0) {
243
198
  throw new EventBuildError(`Failed to build progress event: ${this.issues.join("; ")}`, this.issues);
244
199
  }
245
- const progress = { ...this.extensionFields };
246
- progress.message = this.message;
247
- const m = { kind: "progress", progress, trace: this.traceValue };
200
+ const m = { kind: "progress", progress: this.payload, trace: this.traceValue };
248
201
  return new Event(m);
249
202
  }
250
203
  }
251
204
  export class JsonLogBuilder {
252
- level;
253
- message;
254
- extensionFields = {};
205
+ payload;
255
206
  traceValue = {};
256
207
  issues = [];
257
- constructor(level, message) {
258
- this.level = level;
259
- this.message = message;
260
- if (!message || message === "")
261
- this.issues.push("message must be a non-empty string");
262
- if (!isValidLogLevel(level))
263
- this.issues.push(`level must be one of debug, info, warn, error`);
264
- }
265
- field(name, value) {
266
- if (this.isReservedLogField(name)) {
267
- this.issues.push(`cannot write reserved log field ${JSON.stringify(name)}`);
268
- }
269
- else {
270
- this.extensionFields[name] = value;
271
- }
272
- return this;
273
- }
274
- fields(obj) {
275
- if (!isObject(obj)) {
276
- this.issues.push("fields must be a JSON object");
277
- return this;
278
- }
279
- for (const [key, val] of Object.entries(obj)) {
280
- if (this.isReservedLogField(key)) {
281
- this.issues.push(`cannot write reserved log field ${JSON.stringify(key)}`);
282
- }
283
- else {
284
- this.extensionFields[key] = val;
285
- }
286
- }
287
- return this;
288
- }
289
- extend(obj) {
290
- if (!isObject(obj)) {
291
- this.issues.push("extend must be a JSON object");
292
- return this;
293
- }
294
- for (const [key, val] of Object.entries(obj)) {
295
- if (this.isReservedLogField(key)) {
296
- this.issues.push(`cannot write reserved log field ${JSON.stringify(key)}`);
297
- }
298
- else {
299
- this.extensionFields[key] = val;
300
- }
301
- }
302
- return this;
208
+ constructor(payload) {
209
+ this.payload = payload;
303
210
  }
304
211
  trace(value) {
305
212
  if (value !== undefined) {
@@ -312,17 +219,11 @@ export class JsonLogBuilder {
312
219
  }
313
220
  return this;
314
221
  }
315
- isReservedLogField(name) {
316
- return name === "message" || name === "level" || name === "code";
317
- }
318
222
  build() {
319
223
  if (this.issues.length > 0) {
320
224
  throw new EventBuildError(`Failed to build log event: ${this.issues.join("; ")}`, this.issues);
321
225
  }
322
- const log = { ...this.extensionFields };
323
- log.level = this.level;
324
- log.message = this.message;
325
- const m = { kind: "log", log, trace: this.traceValue };
226
+ const m = { kind: "log", log: this.payload, trace: this.traceValue };
326
227
  return new Event(m);
327
228
  }
328
229
  }
@@ -335,15 +236,12 @@ export function jsonError(code, message) {
335
236
  return new JsonErrorBuilder(code, message);
336
237
  }
337
238
  /** Fluent builder for progress events. */
338
- export function jsonProgress(message) {
339
- return new JsonProgressBuilder(message);
239
+ export function jsonProgress(payload) {
240
+ return new JsonProgressBuilder(payload);
340
241
  }
341
242
  /** Fluent builder for log events. */
342
- export function jsonLog(level, message) {
343
- return new JsonLogBuilder(level, message);
344
- }
345
- function isValidLogLevel(level) {
346
- return level === "debug" || level === "info" || level === "warn" || level === "error";
243
+ export function jsonLog(payload) {
244
+ return new JsonLogBuilder(payload);
347
245
  }
348
246
  /** Validate one protocol event envelope. `strict` also enforces the recommended strict protocol profile (default true). */
349
247
  export function validateProtocolEvent(event, strict = true) {
@@ -372,10 +270,6 @@ export function validateProtocolEvent(event, strict = true) {
372
270
  return;
373
271
  if (!isObject(event.trace))
374
272
  throw new Error("event.trace is required in strict mode");
375
- if (kind === "log")
376
- validateStrictLog(event.log);
377
- if (kind === "progress")
378
- validateStrictProgress(event.progress);
379
273
  if (kind === "error")
380
274
  validateStrictError(event.error);
381
275
  }
@@ -418,25 +312,6 @@ export function validateProtocolStream(events, strict = true) {
418
312
  throw new Error("event stream must contain exactly one terminal result or error");
419
313
  }
420
314
  }
421
- function validateStrictLog(payload) {
422
- if (!isObject(payload))
423
- throw new Error("event.log must be a JSON object in strict mode");
424
- // 0.16: log payload MUST NOT contain code field
425
- if ("code" in payload) {
426
- throw new Error("event.log.code is not allowed in strict mode");
427
- }
428
- if (typeof payload.message !== "string" || payload.message === "") {
429
- throw new Error("event.log.message must be a non-empty string in strict mode");
430
- }
431
- if (!['debug', 'info', 'warn', 'error'].includes(payload.level)) {
432
- throw new Error("event.log.level must be one of debug, info, warn, error in strict mode");
433
- }
434
- }
435
- function validateStrictProgress(payload) {
436
- if (!isObject(payload) || typeof payload.message !== "string" || payload.message === "") {
437
- throw new Error("event.progress.message must be a non-empty string in strict mode");
438
- }
439
- }
440
315
  function validateStrictError(error) {
441
316
  if (!isObject(error))
442
317
  throw new Error("event.error must be a JSON object in strict mode");
@@ -461,12 +336,9 @@ export class EventDecodeError extends Error {
461
336
  }
462
337
  }
463
338
  const ERROR_RESERVED_FIELDS = new Set(["code", "message", "hint", "retryable"]);
464
- const PROGRESS_RESERVED_FIELDS = new Set(["message"]);
465
- const LOG_RESERVED_FIELDS = new Set(["level", "message"]);
466
339
  /**
467
340
  * Parse one protocol line (a single JSON text value), strict-validate it, and
468
- * return a typed decoded event. Extension fields are every payload key beyond
469
- * the required ones, collected into `fields`.
341
+ * return a typed decoded event.
470
342
  */
471
343
  export function decodeProtocolEvent(text) {
472
344
  let parsed;
@@ -506,24 +378,10 @@ export function decodeProtocolEvent(text) {
506
378
  decoded.hint = error.hint;
507
379
  return decoded;
508
380
  }
509
- case "progress": {
510
- const progress = event.progress;
511
- const fields = {};
512
- for (const [k, v] of Object.entries(progress)) {
513
- if (!PROGRESS_RESERVED_FIELDS.has(k))
514
- fields[k] = v;
515
- }
516
- return { kind: "progress", message: progress.message, fields, trace };
517
- }
518
- case "log": {
519
- const log = event.log;
520
- const fields = {};
521
- for (const [k, v] of Object.entries(log)) {
522
- if (!LOG_RESERVED_FIELDS.has(k))
523
- fields[k] = v;
524
- }
525
- return { kind: "log", level: log.level, message: log.message, fields, trace };
526
- }
381
+ case "progress":
382
+ return { kind: "progress", progress: event.progress, trace };
383
+ case "log":
384
+ return { kind: "log", log: event.log, trace };
527
385
  default:
528
386
  // Unreachable: validateProtocolEvent already constrains event.kind.
529
387
  throw new EventDecodeError(`unsupported event kind ${JSON.stringify(event.kind)}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-first-data",
3
- "version": "0.16.0",
3
+ "version": "0.16.1",
4
4
  "description": "A naming convention that lets AI agents understand your data without being told what it means.",
5
5
  "license": "MIT",
6
6
  "repository": {