inferencekit-cli 0.1.0__py3-none-any.whl

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.
Files changed (104) hide show
  1. inferencekit/__init__.py +9 -0
  2. inferencekit/__main__.py +5 -0
  3. inferencekit/analysis/__init__.py +1 -0
  4. inferencekit/analysis/ncu_csv.py +284 -0
  5. inferencekit/analysis/nsys_sqlite.py +518 -0
  6. inferencekit/canonical.py +104 -0
  7. inferencekit/checkpoint.py +396 -0
  8. inferencekit/cli.py +274 -0
  9. inferencekit/cuda/bw_peak.cu +252 -0
  10. inferencekit/cuda/torch_bw.py +60 -0
  11. inferencekit/engines/__init__.py +7 -0
  12. inferencekit/engines/adapters.py +190 -0
  13. inferencekit/engines/clip/__init__.py +13 -0
  14. inferencekit/engines/clip/comfyui.py +749 -0
  15. inferencekit/engines/clip/diffusers_ltx.py +601 -0
  16. inferencekit/engines/clip/noise.py +46 -0
  17. inferencekit/engines/clip/official_ltx.py +316 -0
  18. inferencekit/engines/clip/server.py +542 -0
  19. inferencekit/engines/clip/stepdump.py +182 -0
  20. inferencekit/engines/gates.py +94 -0
  21. inferencekit/engines/sglang_worker.py +86 -0
  22. inferencekit/engines/vllm_worker.py +129 -0
  23. inferencekit/evidence.py +427 -0
  24. inferencekit/gpuinfo.py +93 -0
  25. inferencekit/hardware.py +135 -0
  26. inferencekit/mcp_server.py +178 -0
  27. inferencekit/ops/__init__.py +30 -0
  28. inferencekit/ops/bench.py +184 -0
  29. inferencekit/ops/bench_audio.py +384 -0
  30. inferencekit/ops/bench_clip.py +819 -0
  31. inferencekit/ops/bench_image.py +393 -0
  32. inferencekit/ops/bench_rounds.py +297 -0
  33. inferencekit/ops/bench_serve.py +866 -0
  34. inferencekit/ops/ceiling.py +135 -0
  35. inferencekit/ops/compare.py +378 -0
  36. inferencekit/ops/correctness.py +153 -0
  37. inferencekit/ops/doctor.py +486 -0
  38. inferencekit/ops/gates.py +1772 -0
  39. inferencekit/ops/gates_clip.py +930 -0
  40. inferencekit/ops/intake.py +1321 -0
  41. inferencekit/ops/ledger.py +749 -0
  42. inferencekit/ops/manifest.py +309 -0
  43. inferencekit/ops/ncu.py +183 -0
  44. inferencekit/ops/nsys.py +224 -0
  45. inferencekit/ops/prompts.py +316 -0
  46. inferencekit/ops/quality.py +2161 -0
  47. inferencekit/ops/quality_clip.py +690 -0
  48. inferencekit/ops/quality_clip_steps.py +341 -0
  49. inferencekit/ops/report.py +317 -0
  50. inferencekit/ops/review.py +119 -0
  51. inferencekit/ops/rocprof.py +89 -0
  52. inferencekit/ops/roofline.py +392 -0
  53. inferencekit/ops/store.py +61 -0
  54. inferencekit/proc.py +172 -0
  55. inferencekit/prompts/ATTRIBUTION.md +56 -0
  56. inferencekit/prompts/__init__.py +167 -0
  57. inferencekit/prompts/build.py +518 -0
  58. inferencekit/prompts/dev-load.jsonl.gz +0 -0
  59. inferencekit/prompts/dev-load.manifest.json +212 -0
  60. inferencekit/prompts/dev.jsonl.gz +0 -0
  61. inferencekit/prompts/dev.manifest.json +214 -0
  62. inferencekit/prompts/exclusions.json +54 -0
  63. inferencekit/quality/__init__.py +23 -0
  64. inferencekit/quality/client.py +66 -0
  65. inferencekit/quality/data/gsm8k_LICENSE.txt +21 -0
  66. inferencekit/quality/fake.py +329 -0
  67. inferencekit/quality/gsm8k.py +224 -0
  68. inferencekit/quality/logprobs.py +106 -0
  69. inferencekit/quality/metrics.py +235 -0
  70. inferencekit/quality/niah.py +63 -0
  71. inferencekit/quality/parquet.py +296 -0
  72. inferencekit/quality/sampling.py +262 -0
  73. inferencekit/quality/step_replay.py +217 -0
  74. inferencekit/quality/video_metrics.py +304 -0
  75. inferencekit/registry.py +206 -0
  76. inferencekit/review/__init__.py +6 -0
  77. inferencekit/review/diff.py +163 -0
  78. inferencekit/review/media.py +181 -0
  79. inferencekit/review/page.py +920 -0
  80. inferencekit/review/rundir.py +844 -0
  81. inferencekit/roofline_headers.py +504 -0
  82. inferencekit/schemas/evidence.v1.json +130 -0
  83. inferencekit/schemas/evidence.v2.json +499 -0
  84. inferencekit/schemas/intake.v1.json +276 -0
  85. inferencekit/schemas/run-manifest.v1.json +118 -0
  86. inferencekit/serve/__init__.py +8 -0
  87. inferencekit/serve/audio_client.py +330 -0
  88. inferencekit/serve/client.py +446 -0
  89. inferencekit/serve/clip_client.py +351 -0
  90. inferencekit/serve/clip_rounds.py +429 -0
  91. inferencekit/serve/image_client.py +373 -0
  92. inferencekit/serve/loadgen.py +136 -0
  93. inferencekit/serve/metrics.py +203 -0
  94. inferencekit/serve/profiles.py +105 -0
  95. inferencekit/serve/prompts_io.py +125 -0
  96. inferencekit/serve/rounds.py +1111 -0
  97. inferencekit/serve/servers.py +897 -0
  98. inferencekit/stats.py +249 -0
  99. inferencekit_cli-0.1.0.dist-info/METADATA +233 -0
  100. inferencekit_cli-0.1.0.dist-info/RECORD +104 -0
  101. inferencekit_cli-0.1.0.dist-info/WHEEL +4 -0
  102. inferencekit_cli-0.1.0.dist-info/entry_points.txt +2 -0
  103. inferencekit_cli-0.1.0.dist-info/licenses/LICENSE +202 -0
  104. inferencekit_cli-0.1.0.dist-info/licenses/NOTICE +9 -0
@@ -0,0 +1,276 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "urn:inferencekit:schema:intake:v1",
4
+ "title": "inferencekit intake v1",
5
+ "description": "Input of the optimizing-inference flow: what to make fast, on what, for which goal, inside which budget. Written as YAML (intake.yaml); JSON works too. Validate with `inferencekit intake validate <file>`. Unknown keys are reported as warnings (probably typos), not errors.",
6
+ "type": "object",
7
+ "required": ["model", "modality", "hardware"],
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "intake_version": {"const": 1},
11
+ "run_id": {"type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,79}$",
12
+ "description": "Directory name under runs/. Default: <model>-<gpu>-<UTC date>."},
13
+ "model": {
14
+ "type": "object",
15
+ "required": ["id"],
16
+ "additionalProperties": false,
17
+ "properties": {
18
+ "id": {"type": "string", "minLength": 1, "description": "Hugging Face id (org/name) or a local path."},
19
+ "revision": {"type": "string", "minLength": 1,
20
+ "description": "Commit sha to pin. A branch name (main) is resolved to a sha at stage 1 and recorded."},
21
+ "precision": {"type": "string", "minLength": 1,
22
+ "description": "Precision the checkpoint is stored in, e.g. nvfp4, fp8, bf16, q8_0."},
23
+ "architecture_changes": {"enum": ["forbid", "allow", "ask"], "default": "forbid", "description": "Separate permission for pruning, distillation, skipped model components or replacement. A lossy quality preference does not grant this permission."},
24
+ "precision_allowed": {"type": "array", "minItems": 1, "uniqueItems": true,
25
+ "items": {"type": "string", "minLength": 1},
26
+ "description": "Weight/activation precisions engines may run. Default: [precision]. Rows outside the checkpoint's own precision are a separate track."},
27
+ "kv_cache_dtype_allowed": {"type": "array", "minItems": 1, "uniqueItems": true,
28
+ "items": {"type": "string", "minLength": 1},
29
+ "description": "KV cache dtypes allowed. Default: [checkpoint_default] (what the checkpoint config specifies, else the activation dtype)."},
30
+ "tokenizer": {"type": "string", "minLength": 1, "description": "Default: model.id."}
31
+ }
32
+ },
33
+ "modality": {"enum": ["llm", "tts", "stt", "video", "image"]},
34
+ "hardware": {
35
+ "type": "object",
36
+ "required": ["gpu"],
37
+ "additionalProperties": false,
38
+ "properties": {
39
+ "gpu": {"type": "string", "minLength": 1, "description": "GPU model, e.g. RTX 5090."},
40
+ "count": {"type": "integer", "minimum": 1, "default": 1},
41
+ "price_usd_h": {"type": "number", "exclusiveMinimum": 0,
42
+ "description": "Hourly price of the whole host (all `count` GPUs) in USD."},
43
+ "access": {
44
+ "type": "object",
45
+ "required": ["kind"],
46
+ "additionalProperties": false,
47
+ "properties": {
48
+ "kind": {"enum": ["ssh", "local"]},
49
+ "host": {"type": "string", "minLength": 1},
50
+ "port": {"type": "integer", "minimum": 1, "maximum": 65535},
51
+ "user": {"type": "string", "minLength": 1},
52
+ "key_path": {"type": "string", "minLength": 1}
53
+ },
54
+ "if": {"properties": {"kind": {"const": "ssh"}}},
55
+ "then": {"required": ["host", "user"]}
56
+ }
57
+ }
58
+ },
59
+ "goals": {
60
+ "type": "object",
61
+ "additionalProperties": false,
62
+ "properties": {
63
+ "lead": {"enum": ["single_user", "capacity", "affordability"], "default": "single_user"},
64
+ "affordability": {
65
+ "type": "object", "additionalProperties": false,
66
+ "required": ["memory_gb_max", "memory_kind"],
67
+ "description": "Minimize memory while meeting latency and quality gates; compare with each baseline tuned for minimum memory under the same gates. GB means decimal GB; record observed bytes too.",
68
+ "properties": {
69
+ "memory_gb_max": {"type": "number", "exclusiveMinimum": 0},
70
+ "stretch_memory_gb_max": {"type": "number", "exclusiveMinimum": 0},
71
+ "memory_kind": {"enum": ["vram", "unified", "host"]},
72
+ "host_memory_gb_max": {"type": "number", "exclusiveMinimum": 0},
73
+ "offload_allowed": {"type": "boolean", "default": false}
74
+ }
75
+ },
76
+ "targets": {
77
+ "type": "object",
78
+ "additionalProperties": false,
79
+ "description": "Optional. A missed target means continue (within budget). What happens once every target is met is goals.after_target. Without a target, an interactive run asks at the stop point unless after_target keep_climbing is written; a non_interactive run keeps climbing while budget remains, or stops after the stop-point ranking when after_target stop is written.",
80
+ "properties": {
81
+ "decode_tok_s": {"type": "number", "exclusiveMinimum": 0},
82
+ "ttft_ms": {"type": "number", "exclusiveMinimum": 0},
83
+ "n_star": {"type": "integer", "minimum": 1},
84
+ "decode_ceiling_fraction": {"type": "number", "exclusiveMinimum": 0, "maximum": 1,
85
+ "description": "Decode tok/s as a fraction of the measured-bandwidth roofline ceiling."},
86
+ "ttfa_ms": {"type": "number", "exclusiveMinimum": 0, "description": "TTS: time to first audio."},
87
+ "ttfa_p95_ms": {"type": "number", "exclusiveMinimum": 0, "description": "TTS: p95 client time to first playable audio, including preprocessing and buffering."},
88
+ "image_ms": {"type": "number", "exclusiveMinimum": 0, "description": "Image: client time to final decoded image."},
89
+ "images_per_hour": {"type": "number", "exclusiveMinimum": 0},
90
+ "rtf": {"type": "number", "exclusiveMinimum": 0, "description": "TTS/STT: real-time factor (compute time / audio time; lower is better)."},
91
+ "usd_per_1m": {"type": "number", "exclusiveMinimum": 0, "description": "Cost per 1M output units (tokens, characters, audio-seconds)."},
92
+ "clip_ms": {"type": "number", "exclusiveMinimum": 0, "description": "Video: client-timed end-to-end ms per clip at the intake's clip set (bench clip clip_ms; lower is better)."},
93
+ "clips_per_hour": {"type": "number", "exclusiveMinimum": 0, "description": "Video: clips per hour, one clip at a time (bench clip clips_per_hour; higher is better)."},
94
+ "buckets": {"type": "array", "minItems": 1, "uniqueItems": true,
95
+ "items": {"enum": ["very_short", "short", "medium", "long"]},
96
+ "description": "Buckets the target must hold in (all of them). Default: every intake bucket."}
97
+ }
98
+ },
99
+ "slo": {
100
+ "type": "object",
101
+ "additionalProperties": false,
102
+ "properties": {
103
+ "ttft_p95_ms": {"type": "number", "exclusiveMinimum": 0},
104
+ "tpot_p95_ms": {"type": "number", "exclusiveMinimum": 0},
105
+ "max_fail": {"type": "integer", "minimum": 0, "default": 0}
106
+ }
107
+ },
108
+ "after_target": {"enum": ["stop", "keep_climbing"],
109
+ "description": "What the flow does once every target is met: stop (and write the report) or keep_climbing (keep improving until the budget ends, recording the best result over time, screened or verified). Default: keep_climbing when non_interactive or when budget.gpu_hours, usd or wall_clock_h is set; else stop. budget.usd ends a climbing run only with hardware.price_usd_h (validate warns otherwise). The constraint string 'after_target: <value>' is still accepted; when both are given they must agree."},
110
+ "traffic": {
111
+ "type": "object",
112
+ "additionalProperties": false,
113
+ "description": "Capacity goal: expected traffic shape.",
114
+ "properties": {
115
+ "arrival_rate_rps": {"type": "number", "exclusiveMinimum": 0},
116
+ "burstiness": {"type": "string"},
117
+ "session_len": {"type": "string"}
118
+ }
119
+ }
120
+ }
121
+ },
122
+ "io_modes": {
123
+ "type": "object",
124
+ "additionalProperties": false,
125
+ "properties": {
126
+ "input": {"enum": ["complete", "streaming"], "default": "complete"},
127
+ "output": {"enum": ["complete", "streaming"], "default": "streaming"},
128
+ "input_rate": {"type": "string", "description": "Streaming input pace, e.g. '30 tok/s' or '40 ms audio chunks at 1x'."},
129
+ "latency_focus": {"type": "string", "description": "Which latency matters most, in the user's words."}
130
+ }
131
+ },
132
+ "buckets": {"type": "array", "minItems": 1, "uniqueItems": true,
133
+ "items": {"enum": ["very_short", "short", "medium", "long"]}},
134
+ "workload": {
135
+ "type": "object",
136
+ "additionalProperties": false,
137
+ "properties": {
138
+ "max_tokens": {"type": "integer", "minimum": 2, "default": 256},
139
+ "rounds": {"type": "integer", "minimum": 3, "default": 5},
140
+ "concurrency": {"type": "array", "minItems": 1, "items": {"type": "integer", "minimum": 1}},
141
+ "prompt_set": {"type": "string", "default": "dev"},
142
+ "chat_template_kwargs": {"type": "object", "description": "Pre-registered template settings, e.g. {\"enable_thinking\": false} for a reasoning model. The intake itself sends nothing: intake validate records the pin in intake.normalized.json and state.json; manifest validate and bench rounds refuse a run manifest whose workload.chat_template_kwargs leaves out or changes a pinned key; bench serve, gates run and quality trajectory/gsm8k/niah with --run-dir add the pinned keys to every chat request and refuse a different value."}
143
+ }
144
+ },
145
+ "budget": {
146
+ "type": "object",
147
+ "additionalProperties": false,
148
+ "properties": {
149
+ "gpu_hours": {"type": "number", "exclusiveMinimum": 0, "description": "GPU-hours (host hours x count)."},
150
+ "usd": {"type": "number", "exclusiveMinimum": 0},
151
+ "wall_clock_h": {"type": "number", "exclusiveMinimum": 0},
152
+ "approved": {"type": "boolean", "default": false},
153
+ "spend_cap": {"enum": ["bounded", "none"], "default": "bounded",
154
+ "description": "Explicit run-scoped uncapped-spend approval. none requires approved:true plus a finite deadline or wall_clock_h, and conflicts with usd/gpu_hours. Null numeric caps mean uncapped; never use a huge numeric sentinel."},
155
+ "deadline": {"type": "string", "minLength": 1, "description": "Absolute ISO8601 deadline with timezone; enforced even when spending is uncapped."},
156
+ "stage_timeboxes": {"type": "boolean", "default": true, "description": "false explicitly disables per-stage time cutoffs for this run; the overall deadline still applies."},
157
+ "report_reserve_h": {"type": "number", "minimum": 0, "description": "Explicit run-scoped reporting reserve; zero disables the automatic early reporting/freeze cutoff. Validate continuously and keep artifacts ready through the deadline."}
158
+ }
159
+ },
160
+ "fidelity": {"enum": ["lossless", "lossy"], "default": "lossless",
161
+ "description": "lossless (default): numerics stay as shipped (weights and activations in model.precision; no KV cache below 16 bits unless the checkpoint ships one); other entries of precision_allowed / kv_cache_dtype_allowed are reported as levers, not run or ranked. Only changes that leave the output distribution unchanged count. lossy: changes that alter numerics are allowed when every bound in quality.budget holds against the reference; they are a separate track, reported as speed at a stated quality cost and never ranked against lossless results. The constraint string 'fidelity: <value>' is still accepted; when both are given they must agree."},
162
+ "interaction": {
163
+ "type": "object", "additionalProperties": false,
164
+ "properties": {
165
+ "checkpoints": {"enum": ["required", "quality", "milestones"], "default": "required", "description": "Pause only for new required decisions, also for human quality review, or at major milestones. Never waives spending/scope or quality requirements."},
166
+ "show_plan": {"type": "boolean", "default": false, "description": "Show a plan only when requested; does not by itself require plan approval."}
167
+ }
168
+ },
169
+ "quality": {
170
+ "type": "object",
171
+ "additionalProperties": false,
172
+ "properties": {
173
+ "preference": {"enum": ["exact", "balanced", "speed"], "description": "Simple opening choice: identical declared deterministic/seeded outputs; small numerical differences with task quality preserved; or prioritize speed within an agreed quality budget. exact resolves fidelity to lossless, others to lossy. Does not itself prove equality, fill quality bounds, allow formats or authorize model changes."},
174
+ "reference": {
175
+ "oneOf": [
176
+ {"const": "none"},
177
+ {"type": "object", "required": ["kind"], "additionalProperties": false,
178
+ "properties": {"kind": {"const": "none"}}},
179
+ {"type": "object", "required": ["kind", "base_url"], "additionalProperties": false,
180
+ "properties": {"kind": {"const": "endpoint"}, "base_url": {"type": "string", "minLength": 1},
181
+ "model": {"type": "string"}}}
182
+ ]
183
+ },
184
+ "acceptance": {"enum": ["perceptual_and_task_noninferiority"], "description": "Explicit image/TTS acceptance through hash-bound external blinded perceptual plus task-quality proof. Requires typed relative task/perceptual bounds. Numerical similarity and cross-engine equality are diagnostic; historical gates/results are not rewritten."},
185
+ "diagnostic_only": {"type": "array", "minItems": 1, "uniqueItems": true,
186
+ "items": {"enum": ["lpips", "ssim", "psnr", "cross_engine_byte_identity", "cross_engine_tensor_equality", "rounding_drift", "eager_compiled_drift", "repeated_run_variation", "cross_engine_pcm_equality", "cross_engine_generated_code_equality"]},
187
+ "description": "Declared diagnostic comparisons, never acceptance thresholds. Requires explicit perceptual/task acceptance; only image/TTS-applicable keys are accepted. Own output integrity and finite/shape contracts remain hard requirements."},
188
+ "protocol": {"type": "string", "minLength": 1, "description": "Pre-registered modality quality protocol: dataset, seeds, reference, metrics/margins, A/A floor and CI decision rules; external evidence is required where the CLI has no modality adapter."},
189
+ "protocol_sha256": {"type": "string", "pattern": "^[0-9a-f]{64}$", "description": "SHA256 of the external quality protocol bytes; required for quality.budget.relative. Intake validation checks the declaration, not external evidence."},
190
+ "noise_floor": {"oneOf": [{"const": "measure"}, {"type": "number", "minimum": 0, "maximum": 1}],
191
+ "description": "'measure' (A/A run of the reference) or a fixed agreement floor in [0, 1]."},
192
+ "budget": {
193
+ "type": "object",
194
+ "additionalProperties": false,
195
+ "minProperties": 1,
196
+ "description": "The quality budget of a lossy run, declared before any measurement: every bound given must hold against the reference. Required when fidelity is lossy (an error in a non_interactive run; an interactive run warns and agrees it before ranking a lossy change). Legacy absolute budgets are ignored, with a warning, when fidelity is lossless; relative budgets require fidelity lossy.",
197
+ "properties": {
198
+ "gsm8k_drop_pts_max": {"type": "number", "minimum": 0,
199
+ "description": "Largest acceptable GSM8K accuracy drop against the reference, in percentage points (paired, judged on the CI)."},
200
+ "top1_agreement_min": {"type": "number", "minimum": 0, "maximum": 1,
201
+ "description": "Lowest acceptable next-token (top-1) agreement with the reference, a fraction in [0, 1]."},
202
+ "kl_max": {"type": "number", "minimum": 0,
203
+ "description": "Largest acceptable mean KL divergence per token from the reference's next-token distribution, in nats."},
204
+ "nll_increase_max": {"type": "number", "minimum": 0,
205
+ "description": "Largest acceptable increase in the reference's NLL per token on the candidate's outputs, in nats."},
206
+ "tv_max": {"type": "number", "minimum": 0, "maximum": 1,
207
+ "description": "Largest acceptable mean total variation distance between the reference's and the candidate's next-token distributions (top-k with the tail imputed), in [0, 1]."},
208
+ "wer_max": {"type": "number", "minimum": 0, "description": "TTS/STT: maximum word error rate as a fraction."},
209
+ "cer_max": {"type": "number", "minimum": 0, "description": "TTS/STT: maximum character error rate as a fraction."},
210
+ "speaker_similarity_min": {"type": "number", "minimum": -1, "maximum": 1, "description": "TTS: minimum speaker embedding cosine similarity."},
211
+ "psnr_db_min": {"type": "number", "description": "Video (quality clip, lossy): minimum mean PSNR vs the reference, dB."},
212
+ "ssim_min": {"type": "number", "minimum": 0, "maximum": 1, "description": "Video (quality clip, lossy): minimum mean SSIM vs the reference."},
213
+ "lpips_max": {"type": "number", "minimum": 0, "description": "Video (quality clip, lossy): maximum mean LPIPS vs the reference."},
214
+ "relative": {
215
+ "type": "object", "additionalProperties": false, "required": ["modality"], "minProperties": 2,
216
+ "description": "Typed relative degradation bounds for a hash-bound external image/TTS/STT quality protocol. Positive increase/drop is worse; these are not absolute scorer thresholds. Only metric keys for the declared intake modality are valid; unknown keys are errors. Protocol defines reference/A/A adjustment, units, cohort and CI rules. Finite values only.",
217
+ "allOf": [
218
+ {"if": {"properties": {"modality": {"const": "image"}}}, "then": {"propertyNames": {"enum": ["modality", "lpips_excess_max", "ssim_loss_max", "ocr_cer_increase_max", "semantic_score_drop_max", "new_severe_regressions_max"]}}},
219
+ {"if": {"properties": {"modality": {"const": "tts"}}}, "then": {"propertyNames": {"enum": ["modality", "wer_increase_max", "cer_increase_max", "completion_failure_increase_max", "speaker_similarity_drop_max", "perceptual_score_drop_max", "new_severe_regressions_max"]}}},
220
+ {"if": {"properties": {"modality": {"const": "stt"}}}, "then": {"propertyNames": {"enum": ["modality", "wer_increase_max", "cer_increase_max", "completion_failure_increase_max", "new_severe_regressions_max"]}}}
221
+ ],
222
+ "properties": {
223
+ "modality": {"enum": ["image", "tts", "stt"]},
224
+ "lpips_excess_max": {"type": "number", "minimum": 0, "description": "Image: maximum protocol-defined excess LPIPS over the reference/A/A floor; lower is better."},
225
+ "ssim_loss_max": {"type": "number", "minimum": 0, "maximum": 2, "description": "Image: maximum protocol-defined SSIM loss relative to reference/A/A; lower is better, not absolute SSIM."},
226
+ "ocr_cer_increase_max": {"type": "number", "minimum": 0, "description": "Image: maximum OCR CER increase, as a fraction; lower is better. CER can exceed one."},
227
+ "semantic_score_drop_max": {"type": "number", "minimum": 0, "maximum": 1, "description": "Image: maximum drop on a normalized [0,1] semantic score; lower degradation is better."},
228
+ "wer_increase_max": {"type": "number", "minimum": 0, "description": "TTS/STT: maximum WER increase as a fraction; lower is better. WER can exceed one."},
229
+ "cer_increase_max": {"type": "number", "minimum": 0, "description": "TTS/STT: maximum CER increase as a fraction; lower is better. CER can exceed one."},
230
+ "completion_failure_increase_max": {"type": "number", "minimum": 0, "maximum": 1, "description": "TTS/STT: maximum increase in completion failure rate, an absolute fraction; lower is better."},
231
+ "speaker_similarity_drop_max": {"type": "number", "minimum": 0, "maximum": 2, "description": "TTS: maximum drop in speaker cosine similarity in [-1,1]; lower degradation is better."},
232
+ "perceptual_score_drop_max": {"type": "number", "minimum": 0, "description": "TTS: maximum perceptual score drop in the external protocol's declared units; lower degradation is better."},
233
+ "new_severe_regressions_max": {"type": "integer", "minimum": 0, "description": "Image/TTS/STT: maximum count of new severe regressions; lower is better. Zero forbids new severe regressions."}
234
+ }
235
+ }
236
+ }
237
+ }
238
+ }
239
+ },
240
+ "repo": {
241
+ "type": "object",
242
+ "additionalProperties": false,
243
+ "properties": {
244
+ "path": {"type": "string", "minLength": 1},
245
+ "branch": {"type": "string", "minLength": 1},
246
+ "push": {"enum": ["ask", "never"], "default": "ask"}
247
+ }
248
+ },
249
+ "constraints": {"oneOf": [{"type": "string"}, {"type": "array", "items": {"type": "string"}}],
250
+ "description": "Free text, one quoted string per entry (an unquoted 'a: b' is a YAML mapping, which is refused). Validate reads these conventions (several in one entry when separated by ';'): 'after_target: stop|keep_climbing', 'fidelity: lossless|lossy', 'speculation: off|auto', 'route: build|patch'."},
251
+ "rule_sources": {"type": "object", "additionalProperties": false,
252
+ "description": "Written by intake validate into the normalized intake; leave it out of a hand-written one. Where each run rule came from: its field name, 'constraints' or 'default: ...'. A filled-in default keeps its source when a normalized intake is checked again.",
253
+ "properties": {"after_target": {"type": "string"}, "fidelity": {"type": "string"},
254
+ "speculation": {"type": "string"}, "route": {"type": "string"}}},
255
+ "non_interactive": {"type": "boolean", "default": false},
256
+ "harness": {
257
+ "type": "object",
258
+ "additionalProperties": false,
259
+ "description": "How to install inferencekit on the GPU host (ssh access).",
260
+ "properties": {
261
+ "wheel": {"type": "string", "minLength": 1},
262
+ "wheel_sha256": {"type": "string", "pattern": "^[0-9a-f]{64}$"},
263
+ "requirements": {"type": "string", "minLength": 1}
264
+ }
265
+ },
266
+ "candidates": {
267
+ "type": "object",
268
+ "additionalProperties": false,
269
+ "properties": {
270
+ "include": {"type": "array", "items": {"type": "string"}},
271
+ "exclude": {"type": "array", "items": {"type": "string"}},
272
+ "max_engines": {"type": "integer", "minimum": 1, "maximum": 8, "default": 5}
273
+ }
274
+ }
275
+ }
276
+ }
@@ -0,0 +1,118 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://inferencekit.dev/schemas/run-manifest.v1.json",
4
+ "title": "inferencekit run manifest v1",
5
+ "description": "What an agent ran: model at a pinned revision, hardware, every engine with its install and launch commands, the workload and the frozen harness. A re-run of the manifest replays exactly this on a clean host. Semantic rules that JSON Schema cannot express (unique engine labels, distinct ports, no secret values in env) are checked by `inferencekit manifest validate`.",
6
+ "type": "object",
7
+ "required": ["manifest_version", "model", "hardware", "engines", "workload", "harness", "agent_run"],
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "manifest_version": {"const": 1},
11
+ "model": {
12
+ "type": "object",
13
+ "required": ["id", "revision"],
14
+ "additionalProperties": false,
15
+ "properties": {
16
+ "id": {"type": "string", "minLength": 1, "description": "Hugging Face repo id (org/name)."},
17
+ "revision": {"type": "string", "description": "Full 40-character commit sha of the model repo (a branch or tag can move)."},
18
+ "precision": {"type": "string", "description": "Weight precision class, e.g. bf16, fp8, nvfp4, q8_0."},
19
+ "tokenizer": {"type": "string", "description": "Tokenizer repo id, when it differs from the model."},
20
+ "tokenizer_revision": {"type": "string"},
21
+ "local_dir": {"type": "string", "pattern": "^(?!/)(?!~)(?!.*(^|/)\\.\\.(/|$)).+$", "description": "Where launch commands expect the weights, relative to the re-run's working directory (the uploaded copy of the agent's run directory), e.g. models/qwen3-8b. A re-run runs `hf download <id> --revision <revision> --local-dir <local_dir>`. Without it the model goes to the HF cache and launch commands must name the repo id and the revision."}
22
+ }
23
+ },
24
+ "hardware": {
25
+ "type": "object",
26
+ "required": ["gpu", "count"],
27
+ "additionalProperties": false,
28
+ "properties": {
29
+ "gpu": {"type": "string", "minLength": 1, "description": "GPU model as nvidia-smi names it, or a substring of that name (e.g. 'RTX 5090')."},
30
+ "count": {"type": "integer", "minimum": 1},
31
+ "price_usd_h": {"type": ["number", "null"], "minimum": 0}
32
+ }
33
+ },
34
+ "engines": {
35
+ "type": "array",
36
+ "minItems": 1,
37
+ "items": {
38
+ "type": "object",
39
+ "required": ["name", "label", "install", "launch", "port"],
40
+ "additionalProperties": false,
41
+ "properties": {
42
+ "name": {"type": "string", "minLength": 1, "description": "Engine family: vllm, sglang, llamacpp, trtllm, custom..."},
43
+ "label": {"type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$", "description": "Unique label for this engine + configuration; used as a directory name."},
44
+ "version": {"type": "string"},
45
+ "install": {"type": "array", "minItems": 1, "items": {"type": "string", "minLength": 1}, "description": "Shell commands run in order inside this engine's own venv (VIRTUAL_ENV is set)."},
46
+ "launch": {"type": "array", "minItems": 1, "items": {"type": "string"}, "description": "Server argv (no shell)."},
47
+ "env": {"type": "object", "additionalProperties": {"type": ["string", "null"]}, "description": "Environment for the server. null = inherit that variable from the caller (e.g. a token). Never secret values: name secrets in a re-run instead."},
48
+ "port": {"type": "integer", "minimum": 1, "maximum": 65535},
49
+ "host": {"type": "string", "minLength": 1, "description": "Address the harness connects to (default 127.0.0.1). A re-run runs every engine on the host it measures, so it must be a loopback address."},
50
+ "cwd": {"type": "string", "pattern": "^(?!/)(?!~)(?!.*(^|/)\\.\\.(/|$)).+$", "description": "Working directory of the server, relative to the re-run's working directory (the uploaded copy of the agent's run directory). Default: that directory."},
51
+ "ready_check": {"type": "string", "description": "HTTP path polled until it returns 200, e.g. /v1/models or /health."},
52
+ "resolved_config": {"type": "object", "description": "What the engine logged it actually used."},
53
+ "role": {"enum": ["baseline-recipe", "tuned", "custom"]},
54
+ "endpoint_kind": {"enum": ["clip_http", "comfyui"], "description": "bench rounds --mode clip: how bench clip reaches the engine (default clip_http)."},
55
+ "workflow": {"type": "string", "description": "comfyui: the API-format workflow JSON (a path relative to the manifest is resolved there)."}
56
+ }
57
+ }
58
+ },
59
+ "workload": {
60
+ "type": "object",
61
+ "required": ["modes"],
62
+ "if": {"properties": {"modes": {"contains": {"const": "clip"}}}, "required": ["modes"]},
63
+ "then": {"required": ["clips"]},
64
+ "else": {"required": ["buckets", "max_tokens"]},
65
+ "additionalProperties": false,
66
+ "properties": {
67
+ "modes": {"type": "array", "minItems": 1, "uniqueItems": true, "items": {"enum": ["single", "load", "clip"]}},
68
+ "clips": {"type": "string", "description": "Clip set JSONL for --mode clip (sha256 pinned by bench clip records)."},
69
+ "buckets": {"type": "array", "minItems": 1, "uniqueItems": true, "items": {"enum": ["very_short", "short", "medium", "long"]}},
70
+ "max_tokens": {"type": "integer", "minimum": 1},
71
+ "slo": {
72
+ "type": "object",
73
+ "additionalProperties": false,
74
+ "properties": {
75
+ "ttft_p95_ms": {"type": ["number", "null"], "exclusiveMinimum": 0},
76
+ "tpot_p95_ms": {"type": ["number", "null"], "exclusiveMinimum": 0},
77
+ "max_fail": {"type": ["number", "null"], "minimum": 0}
78
+ }
79
+ },
80
+ "concurrency": {"type": "array", "items": {"type": "integer", "minimum": 1}},
81
+ "rate_rps": {"type": "array", "items": {"type": "number", "exclusiveMinimum": 0}},
82
+ "seed": {"type": "integer"},
83
+ "chat_template_kwargs": {"type": "object", "description": "Sent as chat_template_kwargs on every chat request to every engine (bench serve, bench rounds, gates run, quality trajectory), e.g. {\"enable_thinking\": false} to pin a reasoning model's template; a prompt record's own chat_template_kwargs field is merged over it per key. When the run's intake pins workload.chat_template_kwargs (intake.normalized.json next to the manifest), every pinned key must be here with the pinned value (manifest validate, bench rounds and a re-run refuse otherwise)."},
84
+ "extra_body": {
85
+ "type": "object",
86
+ "description": "Merged last into the body of every timed request to every engine: bench rounds passes it to each bench serve call as --extra-body (bench rounds --extra-body overrides it). Use it to time sampling instead of greedy decoding, e.g. {\"temperature\": 1.0, \"top_k\": 64, \"top_p\": 0.95, \"seed\": 1234}. Absent: bench serve times greedy decoding (temperature 0) on every engine. manifest validate refuses fields that change what is timed or how it is read (model, messages, prompt, stream, stream_options, max_tokens, max_completion_tokens, n, best_of, ignore_eos, min_tokens, stop, stop_token_ids, logit_bias, return_token_ids, return_tokens_as_token_ids, logprobs, top_logprobs, echo, suffix), chat_template_kwargs (use workload.chat_template_kwargs) and secret-looking keys; it warns when top_k, top_p, min_p or seed come without a temperature above 0 (bench serve stays greedy).",
87
+ "properties": {
88
+ "temperature": {"type": "number", "minimum": 0},
89
+ "top_p": {"type": "number", "exclusiveMinimum": 0, "maximum": 1},
90
+ "top_k": {"type": "integer", "minimum": -1, "description": "-1 (or 0 on some engines) disables top-k."},
91
+ "min_p": {"type": "number", "minimum": 0, "maximum": 1},
92
+ "seed": {"type": "integer"}
93
+ }
94
+ }
95
+ }
96
+ },
97
+ "harness": {
98
+ "type": "object",
99
+ "required": ["inferencekit_version", "wheel_sha256"],
100
+ "additionalProperties": false,
101
+ "properties": {
102
+ "inferencekit_version": {"type": "string", "minLength": 1},
103
+ "wheel_sha256": {"type": "string", "description": "sha256 of the inferencekit-cli wheel the agent ran (64 hex). Empty only while drafting; a re-run refuses it."},
104
+ "dev_prompt_set_sha256": {"type": "string"}
105
+ }
106
+ },
107
+ "agent_run": {
108
+ "type": "object",
109
+ "required": ["run_id"],
110
+ "additionalProperties": false,
111
+ "properties": {
112
+ "run_id": {"type": "string"},
113
+ "started": {"type": "string"},
114
+ "ended": {"type": "string"}
115
+ }
116
+ }
117
+ }
118
+ }
@@ -0,0 +1,8 @@
1
+ """bench serve: a client-side timer for OpenAI-compatible inference servers.
2
+
3
+ prompts_io read a prompt set (JSONL, as ``prompts build`` writes it) and its sha256
4
+ profiles per-engine request bodies: ignore_eos / min_tokens, token ids, usage
5
+ client async streaming SSE client on raw asyncio sockets, timed with perf_counter_ns
6
+ metrics per-request numbers, per-bucket summaries with bootstrap CIs over rounds
7
+ loadgen open-loop seeded Poisson load at a concurrency or rate grid; N* and cost
8
+ """