agent-first-data 0.1.3__tar.gz → 0.2.0__tar.gz

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.
@@ -0,0 +1,281 @@
1
+ Metadata-Version: 2.4
2
+ Name: agent-first-data
3
+ Version: 0.2.0
4
+ Summary: Agent-First Data (AFD) — suffix-driven output formatting and protocol templates for AI agents
5
+ License-Expression: MIT
6
+ Project-URL: Repository, https://github.com/cmnspore/agent-first-data
7
+ Requires-Python: >=3.9
8
+ Description-Content-Type: text/markdown
9
+
10
+ # agent-first-data
11
+
12
+ **Agent-First Data (AFD)** — Suffix-driven output formatting and protocol templates for AI agents.
13
+
14
+ The field name is the schema. Agents read `latency_ms` and know milliseconds, `api_key_secret` and know to redact, no external schema needed.
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ pip install agent-first-data
20
+ ```
21
+
22
+ ## API Reference
23
+
24
+ Total: **9 public APIs** (4 protocol builders + 3 output functions + 1 internal + 1 utility)
25
+
26
+ ### Protocol Builders (returns dict)
27
+
28
+ Build AFD protocol structures. Return dict objects for API responses.
29
+
30
+ ```python
31
+ # Startup (configuration)
32
+ build_json_startup(config: Any, args: Any, env: Any) -> dict
33
+
34
+ # Success (result)
35
+ build_json_ok(result: Any, trace: Any = None) -> dict
36
+
37
+ # Error (simple message)
38
+ build_json_error(message: str, trace: Any = None) -> dict
39
+
40
+ # Generic (any code + fields)
41
+ build_json(code: str, fields: Any, trace: Any = None) -> dict
42
+ ```
43
+
44
+ **Use case:** API responses (frameworks like FastAPI automatically serialize)
45
+
46
+ **Example:**
47
+ ```python
48
+ from agent_first_data import *
49
+
50
+ # Startup
51
+ startup = build_json_startup(
52
+ {"api_key_secret": "sk-123", "timeout_s": 30},
53
+ {"config_path": "config.yml"},
54
+ {"RUST_LOG": "info"},
55
+ )
56
+
57
+ # Success (always include trace)
58
+ response = build_json_ok(
59
+ {"user_id": 123},
60
+ trace={"duration_ms": 150, "source": "db"},
61
+ )
62
+
63
+ # Error
64
+ err = build_json_error("user not found", trace={"duration_ms": 5})
65
+
66
+ # Specific error code
67
+ not_found = build_json(
68
+ "not_found",
69
+ {"resource": "user", "id": 123},
70
+ trace={"duration_ms": 8},
71
+ )
72
+ ```
73
+
74
+ ### CLI/Log Output (returns str)
75
+
76
+ Format values for CLI output and logs. **All formats redact `_secret` fields.** YAML and Plain also strip suffixes from keys and format values for human readability.
77
+
78
+ ```python
79
+ output_json(value: Any) -> str # Single-line JSON, original keys, for programs/logs
80
+ output_yaml(value: Any) -> str # Multi-line YAML, keys stripped, values formatted
81
+ output_plain(value: Any) -> str # Single-line logfmt, keys stripped, values formatted
82
+ ```
83
+
84
+ **Example:**
85
+ ```python
86
+ from agent_first_data import *
87
+
88
+ data = {
89
+ "user_id": 123,
90
+ "api_key_secret": "sk-1234567890abcdef",
91
+ "created_at_epoch_ms": 1738886400000,
92
+ "file_size_bytes": 5242880,
93
+ }
94
+
95
+ # JSON (secrets redacted, original keys, raw values)
96
+ print(output_json(data))
97
+ # {"api_key_secret":"***","created_at_epoch_ms":1738886400000,"file_size_bytes":5242880,"user_id":123}
98
+
99
+ # YAML (keys stripped, values formatted, secrets redacted)
100
+ print(output_yaml(data))
101
+ # ---
102
+ # api_key: "***"
103
+ # created_at: "2025-02-07T00:00:00.000Z"
104
+ # file_size: "5.0MB"
105
+ # user_id: 123
106
+
107
+ # Plain logfmt (keys stripped, values formatted, secrets redacted)
108
+ print(output_plain(data))
109
+ # api_key=*** created_at=2025-02-07T00:00:00.000Z file_size=5.0MB user_id=123
110
+ ```
111
+
112
+ ### Internal Tools
113
+
114
+ ```python
115
+ internal_redact_secrets(value: Any) -> None # Manually redact secrets in-place
116
+ ```
117
+
118
+ Most users don't need this. Output functions automatically protect secrets.
119
+
120
+ ### Utility Functions
121
+
122
+ ```python
123
+ parse_size(s: str) -> int | None # Parse "10M" → bytes
124
+ ```
125
+
126
+ **Example:**
127
+ ```python
128
+ from agent_first_data import *
129
+
130
+ assert parse_size("10M") == 10485760
131
+ assert parse_size("1.5K") == 1536
132
+ assert parse_size("512") == 512
133
+ ```
134
+
135
+ ## Usage Examples
136
+
137
+ ### Example 1: REST API
138
+
139
+ ```python
140
+ from agent_first_data import *
141
+ from fastapi import FastAPI
142
+
143
+ app = FastAPI()
144
+
145
+ @app.get("/users/{user_id}")
146
+ async def get_user(user_id: int):
147
+ response = build_json_ok(
148
+ {"user_id": user_id, "name": "alice"},
149
+ trace={"duration_ms": 150, "source": "db"},
150
+ )
151
+ # API returns raw JSON — no output processing, no key stripping
152
+ return response
153
+ ```
154
+
155
+ ### Example 2: CLI Tool (Complete Lifecycle)
156
+
157
+ ```python
158
+ from agent_first_data import *
159
+
160
+ # 1. Startup
161
+ startup = build_json_startup(
162
+ {"api_key_secret": "sk-sensitive-key", "timeout_s": 30},
163
+ {"input_path": "data.json"},
164
+ {"RUST_LOG": "info"},
165
+ )
166
+ print(output_yaml(startup))
167
+ # ---
168
+ # code: "startup"
169
+ # args:
170
+ # input_path: "data.json"
171
+ # config:
172
+ # api_key: "***"
173
+ # timeout: "30s"
174
+ # env:
175
+ # RUST_LOG: "info"
176
+
177
+ # 2. Progress
178
+ progress = build_json(
179
+ "progress",
180
+ {"current": 3, "total": 10, "message": "processing"},
181
+ trace={"duration_ms": 1500},
182
+ )
183
+ print(output_plain(progress))
184
+ # code=progress current=3 message=processing total=10 trace.duration=1.5s
185
+
186
+ # 3. Result
187
+ result = build_json_ok(
188
+ {
189
+ "records_processed": 10,
190
+ "file_size_bytes": 5242880,
191
+ "created_at_epoch_ms": 1738886400000,
192
+ },
193
+ trace={"duration_ms": 3500, "source": "file"},
194
+ )
195
+ print(output_yaml(result))
196
+ # ---
197
+ # code: "ok"
198
+ # result:
199
+ # created_at: "2025-02-07T00:00:00.000Z"
200
+ # file_size: "5.0MB"
201
+ # records_processed: 10
202
+ # trace:
203
+ # duration: "3.5s"
204
+ # source: "file"
205
+ ```
206
+
207
+ ### Example 3: JSONL Output
208
+
209
+ ```python
210
+ from agent_first_data import *
211
+
212
+ result = build_json_ok(
213
+ {"status": "success"},
214
+ trace={"duration_ms": 250, "api_key_secret": "sk-123"},
215
+ )
216
+
217
+ # Print JSONL to stdout (secrets redacted, one JSON object per line)
218
+ print(output_json(result))
219
+ # {"code":"ok","result":{"status":"success"},"trace":{"api_key_secret":"***","duration_ms":250}}
220
+ ```
221
+
222
+ ## Complete Suffix Example
223
+
224
+ ```python
225
+ from agent_first_data import *
226
+
227
+ data = {
228
+ "created_at_epoch_ms": 1738886400000,
229
+ "request_timeout_ms": 5000,
230
+ "cache_ttl_s": 3600,
231
+ "file_size_bytes": 5242880,
232
+ "payment_msats": 50000000,
233
+ "price_usd_cents": 9999,
234
+ "success_rate_percent": 95.5,
235
+ "api_key_secret": "sk-1234567890abcdef",
236
+ "user_name": "alice",
237
+ "count": 42,
238
+ }
239
+
240
+ # YAML output (keys stripped, values formatted, secrets redacted)
241
+ print(output_yaml(data))
242
+ # ---
243
+ # api_key: "***"
244
+ # cache_ttl: "3600s"
245
+ # count: 42
246
+ # created_at: "2025-02-07T00:00:00.000Z"
247
+ # file_size: "5.0MB"
248
+ # payment: "50000000msats"
249
+ # price: "$99.99"
250
+ # request_timeout: "5.0s"
251
+ # success_rate: "95.5%"
252
+ # user_name: "alice"
253
+
254
+ # Plain logfmt output (same transformations, single line)
255
+ print(output_plain(data))
256
+ # api_key=*** cache_ttl=3600s count=42 created_at=2025-02-07T00:00:00.000Z file_size=5.0MB payment=50000000msats price=$99.99 request_timeout=5.0s success_rate=95.5% user_name=alice
257
+ ```
258
+
259
+ ## Output Formats
260
+
261
+ Three output formats for different use cases:
262
+
263
+ | Format | Structure | Keys | Values | Use case |
264
+ |:-------|:----------|:-----|:-------|:---------|
265
+ | **JSON** | single-line | original (with suffix) | raw | programs, logs |
266
+ | **YAML** | multi-line | stripped | formatted | human inspection |
267
+ | **Plain** | single-line logfmt | stripped | formatted | compact scanning |
268
+
269
+ All formats automatically redact `_secret` fields.
270
+
271
+ ## Supported Suffixes
272
+
273
+ - **Duration**: `_ms`, `_s`, `_ns`, `_us`, `_minutes`, `_hours`, `_days`
274
+ - **Timestamps**: `_epoch_ms`, `_epoch_s`, `_epoch_ns`, `_rfc3339`
275
+ - **Size**: `_bytes` (auto-scales to KB/MB/GB/TB), `_size` (config input, pass through)
276
+ - **Currency**: `_msats`, `_sats`, `_btc`, `_usd_cents`, `_eur_cents`, `_jpy`, `_{code}_cents`
277
+ - **Other**: `_percent`, `_secret` (auto-redacted in all formats)
278
+
279
+ ## License
280
+
281
+ MIT
@@ -0,0 +1,272 @@
1
+ # agent-first-data
2
+
3
+ **Agent-First Data (AFD)** — Suffix-driven output formatting and protocol templates for AI agents.
4
+
5
+ The field name is the schema. Agents read `latency_ms` and know milliseconds, `api_key_secret` and know to redact, no external schema needed.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ pip install agent-first-data
11
+ ```
12
+
13
+ ## API Reference
14
+
15
+ Total: **9 public APIs** (4 protocol builders + 3 output functions + 1 internal + 1 utility)
16
+
17
+ ### Protocol Builders (returns dict)
18
+
19
+ Build AFD protocol structures. Return dict objects for API responses.
20
+
21
+ ```python
22
+ # Startup (configuration)
23
+ build_json_startup(config: Any, args: Any, env: Any) -> dict
24
+
25
+ # Success (result)
26
+ build_json_ok(result: Any, trace: Any = None) -> dict
27
+
28
+ # Error (simple message)
29
+ build_json_error(message: str, trace: Any = None) -> dict
30
+
31
+ # Generic (any code + fields)
32
+ build_json(code: str, fields: Any, trace: Any = None) -> dict
33
+ ```
34
+
35
+ **Use case:** API responses (frameworks like FastAPI automatically serialize)
36
+
37
+ **Example:**
38
+ ```python
39
+ from agent_first_data import *
40
+
41
+ # Startup
42
+ startup = build_json_startup(
43
+ {"api_key_secret": "sk-123", "timeout_s": 30},
44
+ {"config_path": "config.yml"},
45
+ {"RUST_LOG": "info"},
46
+ )
47
+
48
+ # Success (always include trace)
49
+ response = build_json_ok(
50
+ {"user_id": 123},
51
+ trace={"duration_ms": 150, "source": "db"},
52
+ )
53
+
54
+ # Error
55
+ err = build_json_error("user not found", trace={"duration_ms": 5})
56
+
57
+ # Specific error code
58
+ not_found = build_json(
59
+ "not_found",
60
+ {"resource": "user", "id": 123},
61
+ trace={"duration_ms": 8},
62
+ )
63
+ ```
64
+
65
+ ### CLI/Log Output (returns str)
66
+
67
+ Format values for CLI output and logs. **All formats redact `_secret` fields.** YAML and Plain also strip suffixes from keys and format values for human readability.
68
+
69
+ ```python
70
+ output_json(value: Any) -> str # Single-line JSON, original keys, for programs/logs
71
+ output_yaml(value: Any) -> str # Multi-line YAML, keys stripped, values formatted
72
+ output_plain(value: Any) -> str # Single-line logfmt, keys stripped, values formatted
73
+ ```
74
+
75
+ **Example:**
76
+ ```python
77
+ from agent_first_data import *
78
+
79
+ data = {
80
+ "user_id": 123,
81
+ "api_key_secret": "sk-1234567890abcdef",
82
+ "created_at_epoch_ms": 1738886400000,
83
+ "file_size_bytes": 5242880,
84
+ }
85
+
86
+ # JSON (secrets redacted, original keys, raw values)
87
+ print(output_json(data))
88
+ # {"api_key_secret":"***","created_at_epoch_ms":1738886400000,"file_size_bytes":5242880,"user_id":123}
89
+
90
+ # YAML (keys stripped, values formatted, secrets redacted)
91
+ print(output_yaml(data))
92
+ # ---
93
+ # api_key: "***"
94
+ # created_at: "2025-02-07T00:00:00.000Z"
95
+ # file_size: "5.0MB"
96
+ # user_id: 123
97
+
98
+ # Plain logfmt (keys stripped, values formatted, secrets redacted)
99
+ print(output_plain(data))
100
+ # api_key=*** created_at=2025-02-07T00:00:00.000Z file_size=5.0MB user_id=123
101
+ ```
102
+
103
+ ### Internal Tools
104
+
105
+ ```python
106
+ internal_redact_secrets(value: Any) -> None # Manually redact secrets in-place
107
+ ```
108
+
109
+ Most users don't need this. Output functions automatically protect secrets.
110
+
111
+ ### Utility Functions
112
+
113
+ ```python
114
+ parse_size(s: str) -> int | None # Parse "10M" → bytes
115
+ ```
116
+
117
+ **Example:**
118
+ ```python
119
+ from agent_first_data import *
120
+
121
+ assert parse_size("10M") == 10485760
122
+ assert parse_size("1.5K") == 1536
123
+ assert parse_size("512") == 512
124
+ ```
125
+
126
+ ## Usage Examples
127
+
128
+ ### Example 1: REST API
129
+
130
+ ```python
131
+ from agent_first_data import *
132
+ from fastapi import FastAPI
133
+
134
+ app = FastAPI()
135
+
136
+ @app.get("/users/{user_id}")
137
+ async def get_user(user_id: int):
138
+ response = build_json_ok(
139
+ {"user_id": user_id, "name": "alice"},
140
+ trace={"duration_ms": 150, "source": "db"},
141
+ )
142
+ # API returns raw JSON — no output processing, no key stripping
143
+ return response
144
+ ```
145
+
146
+ ### Example 2: CLI Tool (Complete Lifecycle)
147
+
148
+ ```python
149
+ from agent_first_data import *
150
+
151
+ # 1. Startup
152
+ startup = build_json_startup(
153
+ {"api_key_secret": "sk-sensitive-key", "timeout_s": 30},
154
+ {"input_path": "data.json"},
155
+ {"RUST_LOG": "info"},
156
+ )
157
+ print(output_yaml(startup))
158
+ # ---
159
+ # code: "startup"
160
+ # args:
161
+ # input_path: "data.json"
162
+ # config:
163
+ # api_key: "***"
164
+ # timeout: "30s"
165
+ # env:
166
+ # RUST_LOG: "info"
167
+
168
+ # 2. Progress
169
+ progress = build_json(
170
+ "progress",
171
+ {"current": 3, "total": 10, "message": "processing"},
172
+ trace={"duration_ms": 1500},
173
+ )
174
+ print(output_plain(progress))
175
+ # code=progress current=3 message=processing total=10 trace.duration=1.5s
176
+
177
+ # 3. Result
178
+ result = build_json_ok(
179
+ {
180
+ "records_processed": 10,
181
+ "file_size_bytes": 5242880,
182
+ "created_at_epoch_ms": 1738886400000,
183
+ },
184
+ trace={"duration_ms": 3500, "source": "file"},
185
+ )
186
+ print(output_yaml(result))
187
+ # ---
188
+ # code: "ok"
189
+ # result:
190
+ # created_at: "2025-02-07T00:00:00.000Z"
191
+ # file_size: "5.0MB"
192
+ # records_processed: 10
193
+ # trace:
194
+ # duration: "3.5s"
195
+ # source: "file"
196
+ ```
197
+
198
+ ### Example 3: JSONL Output
199
+
200
+ ```python
201
+ from agent_first_data import *
202
+
203
+ result = build_json_ok(
204
+ {"status": "success"},
205
+ trace={"duration_ms": 250, "api_key_secret": "sk-123"},
206
+ )
207
+
208
+ # Print JSONL to stdout (secrets redacted, one JSON object per line)
209
+ print(output_json(result))
210
+ # {"code":"ok","result":{"status":"success"},"trace":{"api_key_secret":"***","duration_ms":250}}
211
+ ```
212
+
213
+ ## Complete Suffix Example
214
+
215
+ ```python
216
+ from agent_first_data import *
217
+
218
+ data = {
219
+ "created_at_epoch_ms": 1738886400000,
220
+ "request_timeout_ms": 5000,
221
+ "cache_ttl_s": 3600,
222
+ "file_size_bytes": 5242880,
223
+ "payment_msats": 50000000,
224
+ "price_usd_cents": 9999,
225
+ "success_rate_percent": 95.5,
226
+ "api_key_secret": "sk-1234567890abcdef",
227
+ "user_name": "alice",
228
+ "count": 42,
229
+ }
230
+
231
+ # YAML output (keys stripped, values formatted, secrets redacted)
232
+ print(output_yaml(data))
233
+ # ---
234
+ # api_key: "***"
235
+ # cache_ttl: "3600s"
236
+ # count: 42
237
+ # created_at: "2025-02-07T00:00:00.000Z"
238
+ # file_size: "5.0MB"
239
+ # payment: "50000000msats"
240
+ # price: "$99.99"
241
+ # request_timeout: "5.0s"
242
+ # success_rate: "95.5%"
243
+ # user_name: "alice"
244
+
245
+ # Plain logfmt output (same transformations, single line)
246
+ print(output_plain(data))
247
+ # api_key=*** cache_ttl=3600s count=42 created_at=2025-02-07T00:00:00.000Z file_size=5.0MB payment=50000000msats price=$99.99 request_timeout=5.0s success_rate=95.5% user_name=alice
248
+ ```
249
+
250
+ ## Output Formats
251
+
252
+ Three output formats for different use cases:
253
+
254
+ | Format | Structure | Keys | Values | Use case |
255
+ |:-------|:----------|:-----|:-------|:---------|
256
+ | **JSON** | single-line | original (with suffix) | raw | programs, logs |
257
+ | **YAML** | multi-line | stripped | formatted | human inspection |
258
+ | **Plain** | single-line logfmt | stripped | formatted | compact scanning |
259
+
260
+ All formats automatically redact `_secret` fields.
261
+
262
+ ## Supported Suffixes
263
+
264
+ - **Duration**: `_ms`, `_s`, `_ns`, `_us`, `_minutes`, `_hours`, `_days`
265
+ - **Timestamps**: `_epoch_ms`, `_epoch_s`, `_epoch_ns`, `_rfc3339`
266
+ - **Size**: `_bytes` (auto-scales to KB/MB/GB/TB), `_size` (config input, pass through)
267
+ - **Currency**: `_msats`, `_sats`, `_btc`, `_usd_cents`, `_eur_cents`, `_jpy`, `_{code}_cents`
268
+ - **Other**: `_percent`, `_secret` (auto-redacted in all formats)
269
+
270
+ ## License
271
+
272
+ MIT
@@ -0,0 +1,25 @@
1
+ """Agent-First Data (AFD) — suffix-driven output formatting and protocol templates."""
2
+
3
+ from agent_first_data.format import (
4
+ build_json_startup,
5
+ build_json_ok,
6
+ build_json_error,
7
+ build_json,
8
+ output_json,
9
+ output_yaml,
10
+ output_plain,
11
+ internal_redact_secrets,
12
+ parse_size,
13
+ )
14
+
15
+ __all__ = [
16
+ "build_json_startup",
17
+ "build_json_ok",
18
+ "build_json_error",
19
+ "build_json",
20
+ "output_json",
21
+ "output_yaml",
22
+ "output_plain",
23
+ "internal_redact_secrets",
24
+ "parse_size",
25
+ ]