llama-stack-api 0.4.3__py3-none-any.whl → 0.5.0rc1__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.
- llama_stack_api/__init__.py +1100 -0
- llama_stack_api/admin/__init__.py +45 -0
- llama_stack_api/admin/api.py +72 -0
- llama_stack_api/admin/fastapi_routes.py +117 -0
- llama_stack_api/admin/models.py +113 -0
- llama_stack_api/agents/__init__.py +38 -0
- llama_stack_api/agents/api.py +52 -0
- llama_stack_api/agents/fastapi_routes.py +268 -0
- llama_stack_api/agents/models.py +181 -0
- llama_stack_api/batches/__init__.py +40 -0
- llama_stack_api/batches/api.py +53 -0
- llama_stack_api/batches/fastapi_routes.py +113 -0
- llama_stack_api/batches/models.py +78 -0
- llama_stack_api/benchmarks/__init__.py +43 -0
- llama_stack_api/benchmarks/api.py +39 -0
- llama_stack_api/benchmarks/fastapi_routes.py +109 -0
- llama_stack_api/benchmarks/models.py +109 -0
- llama_stack_api/common/__init__.py +5 -0
- llama_stack_api/common/content_types.py +101 -0
- llama_stack_api/common/errors.py +110 -0
- llama_stack_api/common/job_types.py +38 -0
- llama_stack_api/common/responses.py +77 -0
- llama_stack_api/common/training_types.py +47 -0
- llama_stack_api/common/type_system.py +146 -0
- llama_stack_api/connectors/__init__.py +38 -0
- llama_stack_api/connectors/api.py +50 -0
- llama_stack_api/connectors/fastapi_routes.py +103 -0
- llama_stack_api/connectors/models.py +103 -0
- llama_stack_api/conversations/__init__.py +61 -0
- llama_stack_api/conversations/api.py +44 -0
- llama_stack_api/conversations/fastapi_routes.py +177 -0
- llama_stack_api/conversations/models.py +245 -0
- llama_stack_api/datasetio/__init__.py +34 -0
- llama_stack_api/datasetio/api.py +42 -0
- llama_stack_api/datasetio/fastapi_routes.py +94 -0
- llama_stack_api/datasetio/models.py +48 -0
- llama_stack_api/datasets/__init__.py +61 -0
- llama_stack_api/datasets/api.py +35 -0
- llama_stack_api/datasets/fastapi_routes.py +104 -0
- llama_stack_api/datasets/models.py +152 -0
- llama_stack_api/datatypes.py +373 -0
- llama_stack_api/eval/__init__.py +55 -0
- llama_stack_api/eval/api.py +51 -0
- llama_stack_api/eval/compat.py +300 -0
- llama_stack_api/eval/fastapi_routes.py +126 -0
- llama_stack_api/eval/models.py +141 -0
- llama_stack_api/file_processors/__init__.py +27 -0
- llama_stack_api/file_processors/api.py +64 -0
- llama_stack_api/file_processors/fastapi_routes.py +78 -0
- llama_stack_api/file_processors/models.py +42 -0
- llama_stack_api/files/__init__.py +35 -0
- llama_stack_api/files/api.py +51 -0
- llama_stack_api/files/fastapi_routes.py +124 -0
- llama_stack_api/files/models.py +107 -0
- llama_stack_api/inference/__init__.py +207 -0
- llama_stack_api/inference/api.py +93 -0
- llama_stack_api/inference/fastapi_routes.py +243 -0
- llama_stack_api/inference/models.py +1035 -0
- llama_stack_api/inspect_api/__init__.py +37 -0
- llama_stack_api/inspect_api/api.py +25 -0
- llama_stack_api/inspect_api/fastapi_routes.py +76 -0
- llama_stack_api/inspect_api/models.py +28 -0
- llama_stack_api/internal/__init__.py +9 -0
- llama_stack_api/internal/kvstore.py +28 -0
- llama_stack_api/internal/sqlstore.py +81 -0
- llama_stack_api/models/__init__.py +47 -0
- llama_stack_api/models/api.py +38 -0
- llama_stack_api/models/fastapi_routes.py +104 -0
- llama_stack_api/models/models.py +157 -0
- llama_stack_api/openai_responses.py +1494 -0
- llama_stack_api/post_training/__init__.py +73 -0
- llama_stack_api/post_training/api.py +36 -0
- llama_stack_api/post_training/fastapi_routes.py +116 -0
- llama_stack_api/post_training/models.py +339 -0
- llama_stack_api/prompts/__init__.py +47 -0
- llama_stack_api/prompts/api.py +44 -0
- llama_stack_api/prompts/fastapi_routes.py +163 -0
- llama_stack_api/prompts/models.py +177 -0
- llama_stack_api/providers/__init__.py +33 -0
- llama_stack_api/providers/api.py +16 -0
- llama_stack_api/providers/fastapi_routes.py +57 -0
- llama_stack_api/providers/models.py +24 -0
- llama_stack_api/rag_tool.py +168 -0
- llama_stack_api/resource.py +36 -0
- llama_stack_api/router_utils.py +160 -0
- llama_stack_api/safety/__init__.py +37 -0
- llama_stack_api/safety/api.py +29 -0
- llama_stack_api/safety/datatypes.py +83 -0
- llama_stack_api/safety/fastapi_routes.py +55 -0
- llama_stack_api/safety/models.py +38 -0
- llama_stack_api/schema_utils.py +251 -0
- llama_stack_api/scoring/__init__.py +66 -0
- llama_stack_api/scoring/api.py +35 -0
- llama_stack_api/scoring/fastapi_routes.py +67 -0
- llama_stack_api/scoring/models.py +81 -0
- llama_stack_api/scoring_functions/__init__.py +50 -0
- llama_stack_api/scoring_functions/api.py +39 -0
- llama_stack_api/scoring_functions/fastapi_routes.py +108 -0
- llama_stack_api/scoring_functions/models.py +214 -0
- llama_stack_api/shields/__init__.py +41 -0
- llama_stack_api/shields/api.py +39 -0
- llama_stack_api/shields/fastapi_routes.py +104 -0
- llama_stack_api/shields/models.py +74 -0
- llama_stack_api/tools.py +226 -0
- llama_stack_api/validators.py +46 -0
- llama_stack_api/vector_io/__init__.py +88 -0
- llama_stack_api/vector_io/api.py +234 -0
- llama_stack_api/vector_io/fastapi_routes.py +447 -0
- llama_stack_api/vector_io/models.py +663 -0
- llama_stack_api/vector_stores.py +53 -0
- llama_stack_api/version.py +9 -0
- {llama_stack_api-0.4.3.dist-info → llama_stack_api-0.5.0rc1.dist-info}/METADATA +1 -1
- llama_stack_api-0.5.0rc1.dist-info/RECORD +115 -0
- llama_stack_api-0.5.0rc1.dist-info/top_level.txt +1 -0
- llama_stack_api-0.4.3.dist-info/RECORD +0 -4
- llama_stack_api-0.4.3.dist-info/top_level.txt +0 -1
- {llama_stack_api-0.4.3.dist-info → llama_stack_api-0.5.0rc1.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
#
|
|
4
|
+
# This source code is licensed under the terms described in the LICENSE file in
|
|
5
|
+
# the root directory of this source tree.
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
Backward compatibility helpers for the Eval API.
|
|
9
|
+
|
|
10
|
+
This module provides utilities to support both the old-style (individual parameters)
|
|
11
|
+
and new-style (request objects) calling conventions for Eval API methods.
|
|
12
|
+
|
|
13
|
+
The old-style parameters are deprecated and will be removed in a future release.
|
|
14
|
+
|
|
15
|
+
Note: When both a request object AND individual parameters are provided, the request
|
|
16
|
+
object takes precedence and individual parameters are ignored.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
import warnings
|
|
20
|
+
from typing import Any
|
|
21
|
+
|
|
22
|
+
from .models import (
|
|
23
|
+
BenchmarkConfig,
|
|
24
|
+
EvaluateRowsRequest,
|
|
25
|
+
JobCancelRequest,
|
|
26
|
+
JobResultRequest,
|
|
27
|
+
JobStatusRequest,
|
|
28
|
+
RunEvalRequest,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
_DEPRECATION_TARGET = "0.6.0"
|
|
32
|
+
|
|
33
|
+
_DEPRECATION_MESSAGE = (
|
|
34
|
+
"Passing individual parameters to {method_name}() is deprecated. "
|
|
35
|
+
"Please use {request_class}(benchmark_id=..., ...) instead. "
|
|
36
|
+
"This will be removed in version {target}."
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _emit_deprecation_warning(method_name: str, request_class: str) -> None:
|
|
41
|
+
"""Emit a deprecation warning for old-style parameter usage."""
|
|
42
|
+
warnings.warn(
|
|
43
|
+
_DEPRECATION_MESSAGE.format(method_name=method_name, request_class=request_class, target=_DEPRECATION_TARGET),
|
|
44
|
+
DeprecationWarning,
|
|
45
|
+
stacklevel=4,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _format_missing_params(required: list[str], provided: dict[str, Any]) -> str:
|
|
50
|
+
"""Format error message showing which parameters are missing."""
|
|
51
|
+
missing = [p for p in required if provided.get(p) is None]
|
|
52
|
+
provided_names = [p for p in required if provided.get(p) is not None]
|
|
53
|
+
|
|
54
|
+
parts = []
|
|
55
|
+
if missing:
|
|
56
|
+
parts.append(f"missing: {', '.join(missing)}")
|
|
57
|
+
if provided_names:
|
|
58
|
+
parts.append(f"provided: {', '.join(provided_names)}")
|
|
59
|
+
|
|
60
|
+
return "; ".join(parts)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _validate_not_empty(value: Any, name: str) -> None:
|
|
64
|
+
"""Validate that a value is not None, empty string, or empty list."""
|
|
65
|
+
if not value:
|
|
66
|
+
raise ValueError(f"'{name}' cannot be None or empty. Provided: {value}")
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def resolve_run_eval_request(
|
|
70
|
+
request: RunEvalRequest | None = None,
|
|
71
|
+
*,
|
|
72
|
+
benchmark_id: str | None = None,
|
|
73
|
+
benchmark_config: BenchmarkConfig | None = None,
|
|
74
|
+
) -> RunEvalRequest:
|
|
75
|
+
"""
|
|
76
|
+
Resolve run_eval parameters to a RunEvalRequest object.
|
|
77
|
+
|
|
78
|
+
Supports both new-style (request object) and old-style (individual parameters).
|
|
79
|
+
Old-style usage emits a DeprecationWarning.
|
|
80
|
+
|
|
81
|
+
Note: If both request object and individual parameters are provided, the request
|
|
82
|
+
object takes precedence and individual parameters are ignored.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
request: The new-style request object (preferred)
|
|
86
|
+
benchmark_id: (Deprecated) The benchmark ID
|
|
87
|
+
benchmark_config: (Deprecated) The benchmark configuration
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
RunEvalRequest object
|
|
91
|
+
"""
|
|
92
|
+
if request is not None:
|
|
93
|
+
_validate_not_empty(request.benchmark_id, "benchmark_id")
|
|
94
|
+
_validate_not_empty(request.benchmark_config, "benchmark_config")
|
|
95
|
+
return request
|
|
96
|
+
|
|
97
|
+
# Old-style parameters
|
|
98
|
+
if benchmark_id and benchmark_config:
|
|
99
|
+
_emit_deprecation_warning("run_eval", "RunEvalRequest")
|
|
100
|
+
return RunEvalRequest(
|
|
101
|
+
benchmark_id=benchmark_id,
|
|
102
|
+
benchmark_config=benchmark_config,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
required = ["benchmark_id", "benchmark_config"]
|
|
106
|
+
provided = {"benchmark_id": benchmark_id, "benchmark_config": benchmark_config}
|
|
107
|
+
raise ValueError(
|
|
108
|
+
f"Either 'request' (RunEvalRequest) or both 'benchmark_id' and 'benchmark_config' "
|
|
109
|
+
f"must be provided. {_format_missing_params(required, provided)}"
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def resolve_evaluate_rows_request(
|
|
114
|
+
request: EvaluateRowsRequest | None = None,
|
|
115
|
+
*,
|
|
116
|
+
benchmark_id: str | None = None,
|
|
117
|
+
input_rows: list[dict[str, Any]] | None = None,
|
|
118
|
+
scoring_functions: list[str] | None = None,
|
|
119
|
+
benchmark_config: BenchmarkConfig | None = None,
|
|
120
|
+
) -> EvaluateRowsRequest:
|
|
121
|
+
"""
|
|
122
|
+
Resolve evaluate_rows parameters to an EvaluateRowsRequest object.
|
|
123
|
+
|
|
124
|
+
Supports both new-style (request object) and old-style (individual parameters).
|
|
125
|
+
Old-style usage emits a DeprecationWarning.
|
|
126
|
+
|
|
127
|
+
Note: If both request object and individual parameters are provided, the request
|
|
128
|
+
object takes precedence and individual parameters are ignored.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
request: The new-style request object (preferred)
|
|
132
|
+
benchmark_id: (Deprecated) The benchmark ID
|
|
133
|
+
input_rows: (Deprecated) The rows to evaluate
|
|
134
|
+
scoring_functions: (Deprecated) The scoring functions to use
|
|
135
|
+
benchmark_config: (Deprecated) The benchmark configuration
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
EvaluateRowsRequest object
|
|
139
|
+
"""
|
|
140
|
+
if request is not None:
|
|
141
|
+
_validate_not_empty(request.benchmark_id, "benchmark_id")
|
|
142
|
+
_validate_not_empty(request.input_rows, "input_rows")
|
|
143
|
+
_validate_not_empty(request.scoring_functions, "scoring_functions")
|
|
144
|
+
_validate_not_empty(request.benchmark_config, "benchmark_config")
|
|
145
|
+
return request
|
|
146
|
+
|
|
147
|
+
# Old-style parameters
|
|
148
|
+
if benchmark_id and input_rows and scoring_functions and benchmark_config:
|
|
149
|
+
_emit_deprecation_warning("evaluate_rows", "EvaluateRowsRequest")
|
|
150
|
+
return EvaluateRowsRequest(
|
|
151
|
+
benchmark_id=benchmark_id,
|
|
152
|
+
input_rows=input_rows,
|
|
153
|
+
scoring_functions=scoring_functions,
|
|
154
|
+
benchmark_config=benchmark_config,
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
required = ["benchmark_id", "input_rows", "scoring_functions", "benchmark_config"]
|
|
158
|
+
provided = {
|
|
159
|
+
"benchmark_id": benchmark_id,
|
|
160
|
+
"input_rows": input_rows,
|
|
161
|
+
"scoring_functions": scoring_functions,
|
|
162
|
+
"benchmark_config": benchmark_config,
|
|
163
|
+
}
|
|
164
|
+
raise ValueError(
|
|
165
|
+
f"Either 'request' (EvaluateRowsRequest) or all of 'benchmark_id', 'input_rows', "
|
|
166
|
+
f"'scoring_functions', and 'benchmark_config' must be provided. "
|
|
167
|
+
f"{_format_missing_params(required, provided)}"
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def resolve_job_status_request(
|
|
172
|
+
request: JobStatusRequest | None = None,
|
|
173
|
+
*,
|
|
174
|
+
benchmark_id: str | None = None,
|
|
175
|
+
job_id: str | None = None,
|
|
176
|
+
) -> JobStatusRequest:
|
|
177
|
+
"""
|
|
178
|
+
Resolve job_status parameters to a JobStatusRequest object.
|
|
179
|
+
|
|
180
|
+
Supports both new-style (request object) and old-style (individual parameters).
|
|
181
|
+
Old-style usage emits a DeprecationWarning.
|
|
182
|
+
|
|
183
|
+
Note: If both request object and individual parameters are provided, the request
|
|
184
|
+
object takes precedence and individual parameters are ignored.
|
|
185
|
+
|
|
186
|
+
Args:
|
|
187
|
+
request: The new-style request object (preferred)
|
|
188
|
+
benchmark_id: (Deprecated) The benchmark ID
|
|
189
|
+
job_id: (Deprecated) The job ID
|
|
190
|
+
|
|
191
|
+
Returns:
|
|
192
|
+
JobStatusRequest object
|
|
193
|
+
"""
|
|
194
|
+
if request is not None:
|
|
195
|
+
_validate_not_empty(request.benchmark_id, "benchmark_id")
|
|
196
|
+
_validate_not_empty(request.job_id, "job_id")
|
|
197
|
+
return request
|
|
198
|
+
|
|
199
|
+
# Old-style parameters
|
|
200
|
+
if benchmark_id and job_id:
|
|
201
|
+
_emit_deprecation_warning("job_status", "JobStatusRequest")
|
|
202
|
+
return JobStatusRequest(
|
|
203
|
+
benchmark_id=benchmark_id,
|
|
204
|
+
job_id=job_id,
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
required = ["benchmark_id", "job_id"]
|
|
208
|
+
provided = {"benchmark_id": benchmark_id, "job_id": job_id}
|
|
209
|
+
raise ValueError(
|
|
210
|
+
f"Either 'request' (JobStatusRequest) or both 'benchmark_id' and 'job_id' "
|
|
211
|
+
f"must be provided. {_format_missing_params(required, provided)}"
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def resolve_job_cancel_request(
|
|
216
|
+
request: JobCancelRequest | None = None,
|
|
217
|
+
*,
|
|
218
|
+
benchmark_id: str | None = None,
|
|
219
|
+
job_id: str | None = None,
|
|
220
|
+
) -> JobCancelRequest:
|
|
221
|
+
"""
|
|
222
|
+
Resolve job_cancel parameters to a JobCancelRequest object.
|
|
223
|
+
|
|
224
|
+
Supports both new-style (request object) and old-style (individual parameters).
|
|
225
|
+
Old-style usage emits a DeprecationWarning.
|
|
226
|
+
|
|
227
|
+
Note: If both request object and individual parameters are provided, the request
|
|
228
|
+
object takes precedence and individual parameters are ignored.
|
|
229
|
+
|
|
230
|
+
Args:
|
|
231
|
+
request: The new-style request object (preferred)
|
|
232
|
+
benchmark_id: (Deprecated) The benchmark ID
|
|
233
|
+
job_id: (Deprecated) The job ID
|
|
234
|
+
|
|
235
|
+
Returns:
|
|
236
|
+
JobCancelRequest object
|
|
237
|
+
"""
|
|
238
|
+
if request is not None:
|
|
239
|
+
_validate_not_empty(request.benchmark_id, "benchmark_id")
|
|
240
|
+
_validate_not_empty(request.job_id, "job_id")
|
|
241
|
+
return request
|
|
242
|
+
|
|
243
|
+
# Old-style parameters
|
|
244
|
+
if benchmark_id and job_id:
|
|
245
|
+
_emit_deprecation_warning("job_cancel", "JobCancelRequest")
|
|
246
|
+
return JobCancelRequest(
|
|
247
|
+
benchmark_id=benchmark_id,
|
|
248
|
+
job_id=job_id,
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
required = ["benchmark_id", "job_id"]
|
|
252
|
+
provided = {"benchmark_id": benchmark_id, "job_id": job_id}
|
|
253
|
+
raise ValueError(
|
|
254
|
+
f"Either 'request' (JobCancelRequest) or both 'benchmark_id' and 'job_id' "
|
|
255
|
+
f"must be provided. {_format_missing_params(required, provided)}"
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def resolve_job_result_request(
|
|
260
|
+
request: JobResultRequest | None = None,
|
|
261
|
+
*,
|
|
262
|
+
benchmark_id: str | None = None,
|
|
263
|
+
job_id: str | None = None,
|
|
264
|
+
) -> JobResultRequest:
|
|
265
|
+
"""
|
|
266
|
+
Resolve job_result parameters to a JobResultRequest object.
|
|
267
|
+
|
|
268
|
+
Supports both new-style (request object) and old-style (individual parameters).
|
|
269
|
+
Old-style usage emits a DeprecationWarning.
|
|
270
|
+
|
|
271
|
+
Note: If both request object and individual parameters are provided, the request
|
|
272
|
+
object takes precedence and individual parameters are ignored.
|
|
273
|
+
|
|
274
|
+
Args:
|
|
275
|
+
request: The new-style request object (preferred)
|
|
276
|
+
benchmark_id: (Deprecated) The benchmark ID
|
|
277
|
+
job_id: (Deprecated) The job ID
|
|
278
|
+
|
|
279
|
+
Returns:
|
|
280
|
+
JobResultRequest object
|
|
281
|
+
"""
|
|
282
|
+
if request is not None:
|
|
283
|
+
_validate_not_empty(request.benchmark_id, "benchmark_id")
|
|
284
|
+
_validate_not_empty(request.job_id, "job_id")
|
|
285
|
+
return request
|
|
286
|
+
|
|
287
|
+
# Old-style parameters
|
|
288
|
+
if benchmark_id and job_id:
|
|
289
|
+
_emit_deprecation_warning("job_result", "JobResultRequest")
|
|
290
|
+
return JobResultRequest(
|
|
291
|
+
benchmark_id=benchmark_id,
|
|
292
|
+
job_id=job_id,
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
required = ["benchmark_id", "job_id"]
|
|
296
|
+
provided = {"benchmark_id": benchmark_id, "job_id": job_id}
|
|
297
|
+
raise ValueError(
|
|
298
|
+
f"Either 'request' (JobResultRequest) or both 'benchmark_id' and 'job_id' "
|
|
299
|
+
f"must be provided. {_format_missing_params(required, provided)}"
|
|
300
|
+
)
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
#
|
|
4
|
+
# This source code is licensed under the terms described in the LICENSE file in
|
|
5
|
+
# the root directory of this source tree.
|
|
6
|
+
|
|
7
|
+
from typing import Annotated
|
|
8
|
+
|
|
9
|
+
from fastapi import APIRouter, Body, Depends
|
|
10
|
+
|
|
11
|
+
from llama_stack_api.common.job_types import Job
|
|
12
|
+
from llama_stack_api.router_utils import create_path_dependency, standard_responses
|
|
13
|
+
from llama_stack_api.version import LLAMA_STACK_API_V1ALPHA
|
|
14
|
+
|
|
15
|
+
from .api import Eval
|
|
16
|
+
from .models import (
|
|
17
|
+
BenchmarkIdRequest,
|
|
18
|
+
EvaluateResponse,
|
|
19
|
+
EvaluateRowsBodyRequest,
|
|
20
|
+
EvaluateRowsRequest,
|
|
21
|
+
JobCancelRequest,
|
|
22
|
+
JobResultRequest,
|
|
23
|
+
JobStatusRequest,
|
|
24
|
+
RunEvalBodyRequest,
|
|
25
|
+
RunEvalRequest,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
get_benchmark_id_request = create_path_dependency(BenchmarkIdRequest)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def create_router(impl: Eval) -> APIRouter:
|
|
32
|
+
"""Create a FastAPI router for the Eval API."""
|
|
33
|
+
router = APIRouter(
|
|
34
|
+
prefix=f"/{LLAMA_STACK_API_V1ALPHA}",
|
|
35
|
+
tags=["Eval"],
|
|
36
|
+
responses=standard_responses,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
@router.post(
|
|
40
|
+
"/eval/benchmarks/{benchmark_id}/jobs",
|
|
41
|
+
response_model=Job,
|
|
42
|
+
summary="Run Eval",
|
|
43
|
+
description="Run an evaluation on a benchmark.",
|
|
44
|
+
responses={
|
|
45
|
+
200: {"description": "The job that was created to run the evaluation."},
|
|
46
|
+
},
|
|
47
|
+
)
|
|
48
|
+
async def run_eval(
|
|
49
|
+
benchmark_id_request: Annotated[BenchmarkIdRequest, Depends(get_benchmark_id_request)],
|
|
50
|
+
body_request: Annotated[RunEvalBodyRequest, Body(...)],
|
|
51
|
+
) -> Job:
|
|
52
|
+
request = RunEvalRequest(
|
|
53
|
+
benchmark_id=benchmark_id_request.benchmark_id,
|
|
54
|
+
benchmark_config=body_request.benchmark_config,
|
|
55
|
+
)
|
|
56
|
+
return await impl.run_eval(request)
|
|
57
|
+
|
|
58
|
+
@router.post(
|
|
59
|
+
"/eval/benchmarks/{benchmark_id}/evaluations",
|
|
60
|
+
response_model=EvaluateResponse,
|
|
61
|
+
summary="Evaluate Rows",
|
|
62
|
+
description="Evaluate a list of rows on a benchmark.",
|
|
63
|
+
responses={
|
|
64
|
+
200: {"description": "EvaluateResponse object containing generations and scores."},
|
|
65
|
+
},
|
|
66
|
+
)
|
|
67
|
+
async def evaluate_rows(
|
|
68
|
+
benchmark_id_request: Annotated[BenchmarkIdRequest, Depends(get_benchmark_id_request)],
|
|
69
|
+
body_request: Annotated[EvaluateRowsBodyRequest, Body(...)],
|
|
70
|
+
) -> EvaluateResponse:
|
|
71
|
+
request = EvaluateRowsRequest(
|
|
72
|
+
benchmark_id=benchmark_id_request.benchmark_id,
|
|
73
|
+
input_rows=body_request.input_rows,
|
|
74
|
+
scoring_functions=body_request.scoring_functions,
|
|
75
|
+
benchmark_config=body_request.benchmark_config,
|
|
76
|
+
)
|
|
77
|
+
return await impl.evaluate_rows(request)
|
|
78
|
+
|
|
79
|
+
@router.get(
|
|
80
|
+
"/eval/benchmarks/{benchmark_id}/jobs/{job_id}",
|
|
81
|
+
response_model=Job,
|
|
82
|
+
summary="Job Status",
|
|
83
|
+
description="Get the status of a job.",
|
|
84
|
+
responses={
|
|
85
|
+
200: {"description": "The status of the evaluation job."},
|
|
86
|
+
},
|
|
87
|
+
)
|
|
88
|
+
async def job_status(
|
|
89
|
+
benchmark_id: str,
|
|
90
|
+
job_id: str,
|
|
91
|
+
) -> Job:
|
|
92
|
+
request = JobStatusRequest(benchmark_id=benchmark_id, job_id=job_id)
|
|
93
|
+
return await impl.job_status(request)
|
|
94
|
+
|
|
95
|
+
@router.delete(
|
|
96
|
+
"/eval/benchmarks/{benchmark_id}/jobs/{job_id}",
|
|
97
|
+
summary="Job Cancel",
|
|
98
|
+
description="Cancel a job.",
|
|
99
|
+
responses={
|
|
100
|
+
200: {"description": "Successful Response"},
|
|
101
|
+
},
|
|
102
|
+
)
|
|
103
|
+
async def job_cancel(
|
|
104
|
+
benchmark_id: str,
|
|
105
|
+
job_id: str,
|
|
106
|
+
) -> None:
|
|
107
|
+
request = JobCancelRequest(benchmark_id=benchmark_id, job_id=job_id)
|
|
108
|
+
return await impl.job_cancel(request)
|
|
109
|
+
|
|
110
|
+
@router.get(
|
|
111
|
+
"/eval/benchmarks/{benchmark_id}/jobs/{job_id}/result",
|
|
112
|
+
response_model=EvaluateResponse,
|
|
113
|
+
summary="Job Result",
|
|
114
|
+
description="Get the result of a job.",
|
|
115
|
+
responses={
|
|
116
|
+
200: {"description": "The result of the job."},
|
|
117
|
+
},
|
|
118
|
+
)
|
|
119
|
+
async def job_result(
|
|
120
|
+
benchmark_id: str,
|
|
121
|
+
job_id: str,
|
|
122
|
+
) -> EvaluateResponse:
|
|
123
|
+
request = JobResultRequest(benchmark_id=benchmark_id, job_id=job_id)
|
|
124
|
+
return await impl.job_result(request)
|
|
125
|
+
|
|
126
|
+
return router
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
#
|
|
4
|
+
# This source code is licensed under the terms described in the LICENSE file in
|
|
5
|
+
# the root directory of this source tree.
|
|
6
|
+
|
|
7
|
+
from typing import Any, Literal
|
|
8
|
+
|
|
9
|
+
from pydantic import BaseModel, Field
|
|
10
|
+
|
|
11
|
+
from llama_stack_api.inference import SamplingParams, SystemMessage
|
|
12
|
+
from llama_stack_api.schema_utils import json_schema_type
|
|
13
|
+
from llama_stack_api.scoring import ScoringResult
|
|
14
|
+
from llama_stack_api.scoring_functions import ScoringFnParams
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@json_schema_type
|
|
18
|
+
class ModelCandidate(BaseModel):
|
|
19
|
+
"""A model candidate for evaluation."""
|
|
20
|
+
|
|
21
|
+
type: Literal["model"] = "model"
|
|
22
|
+
model: str = Field(..., description="The model ID to evaluate", min_length=1)
|
|
23
|
+
sampling_params: SamplingParams = Field(..., description="The sampling parameters for the model")
|
|
24
|
+
system_message: SystemMessage | None = Field(
|
|
25
|
+
None, description="The system message providing instructions or context to the model"
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
EvalCandidate = ModelCandidate
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@json_schema_type
|
|
33
|
+
class BenchmarkConfig(BaseModel):
|
|
34
|
+
"""A benchmark configuration for evaluation."""
|
|
35
|
+
|
|
36
|
+
eval_candidate: EvalCandidate = Field(..., description="The candidate to evaluate")
|
|
37
|
+
scoring_params: dict[str, ScoringFnParams] = Field(
|
|
38
|
+
default_factory=dict,
|
|
39
|
+
description="Map between scoring function id and parameters for each scoring function you want to run",
|
|
40
|
+
)
|
|
41
|
+
num_examples: int | None = Field(
|
|
42
|
+
None,
|
|
43
|
+
description="Number of examples to evaluate (useful for testing), if not provided, all examples in the dataset will be evaluated",
|
|
44
|
+
ge=1,
|
|
45
|
+
)
|
|
46
|
+
# we could optinally add any specific dataset config here
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@json_schema_type
|
|
50
|
+
class EvaluateResponse(BaseModel):
|
|
51
|
+
"""The response from an evaluation."""
|
|
52
|
+
|
|
53
|
+
generations: list[dict[str, Any]] = Field(..., description="The generations from the evaluation")
|
|
54
|
+
scores: dict[str, ScoringResult] = Field(
|
|
55
|
+
..., description="The scores from the evaluation. Each key in the dict is a scoring function name"
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@json_schema_type
|
|
60
|
+
class BenchmarkIdRequest(BaseModel):
|
|
61
|
+
"""Request model containing benchmark_id path parameter."""
|
|
62
|
+
|
|
63
|
+
benchmark_id: str = Field(..., description="The ID of the benchmark", min_length=1)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@json_schema_type
|
|
67
|
+
class RunEvalRequest(BaseModel):
|
|
68
|
+
"""Request model for running an evaluation on a benchmark."""
|
|
69
|
+
|
|
70
|
+
benchmark_id: str = Field(..., description="The ID of the benchmark to run the evaluation on", min_length=1)
|
|
71
|
+
benchmark_config: BenchmarkConfig = Field(..., description="The configuration for the benchmark")
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@json_schema_type
|
|
75
|
+
class RunEvalBodyRequest(BaseModel):
|
|
76
|
+
"""Request body model for running an evaluation (without path parameter)."""
|
|
77
|
+
|
|
78
|
+
benchmark_config: BenchmarkConfig = Field(..., description="The configuration for the benchmark")
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@json_schema_type
|
|
82
|
+
class EvaluateRowsRequest(BaseModel):
|
|
83
|
+
"""Request model for evaluating a list of rows on a benchmark."""
|
|
84
|
+
|
|
85
|
+
benchmark_id: str = Field(..., description="The ID of the benchmark to run the evaluation on", min_length=1)
|
|
86
|
+
input_rows: list[dict[str, Any]] = Field(..., description="The rows to evaluate", min_length=1)
|
|
87
|
+
scoring_functions: list[str] = Field(
|
|
88
|
+
..., description="The scoring functions to use for the evaluation", min_length=1
|
|
89
|
+
)
|
|
90
|
+
benchmark_config: BenchmarkConfig = Field(..., description="The configuration for the benchmark")
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@json_schema_type
|
|
94
|
+
class EvaluateRowsBodyRequest(BaseModel):
|
|
95
|
+
"""Request body model for evaluating rows (without path parameter)."""
|
|
96
|
+
|
|
97
|
+
input_rows: list[dict[str, Any]] = Field(..., description="The rows to evaluate", min_length=1)
|
|
98
|
+
scoring_functions: list[str] = Field(
|
|
99
|
+
..., description="The scoring functions to use for the evaluation", min_length=1
|
|
100
|
+
)
|
|
101
|
+
benchmark_config: BenchmarkConfig = Field(..., description="The configuration for the benchmark")
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@json_schema_type
|
|
105
|
+
class JobStatusRequest(BaseModel):
|
|
106
|
+
"""Request model for getting the status of a job."""
|
|
107
|
+
|
|
108
|
+
benchmark_id: str = Field(..., description="The ID of the benchmark associated with the job", min_length=1)
|
|
109
|
+
job_id: str = Field(..., description="The ID of the job to get the status of", min_length=1)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
@json_schema_type
|
|
113
|
+
class JobCancelRequest(BaseModel):
|
|
114
|
+
"""Request model for canceling a job."""
|
|
115
|
+
|
|
116
|
+
benchmark_id: str = Field(..., description="The ID of the benchmark associated with the job", min_length=1)
|
|
117
|
+
job_id: str = Field(..., description="The ID of the job to cancel", min_length=1)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
@json_schema_type
|
|
121
|
+
class JobResultRequest(BaseModel):
|
|
122
|
+
"""Request model for getting the result of a job."""
|
|
123
|
+
|
|
124
|
+
benchmark_id: str = Field(..., description="The ID of the benchmark associated with the job", min_length=1)
|
|
125
|
+
job_id: str = Field(..., description="The ID of the job to get the result of", min_length=1)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
__all__ = [
|
|
129
|
+
"ModelCandidate",
|
|
130
|
+
"EvalCandidate",
|
|
131
|
+
"BenchmarkConfig",
|
|
132
|
+
"EvaluateResponse",
|
|
133
|
+
"BenchmarkIdRequest",
|
|
134
|
+
"RunEvalRequest",
|
|
135
|
+
"RunEvalBodyRequest",
|
|
136
|
+
"EvaluateRowsRequest",
|
|
137
|
+
"EvaluateRowsBodyRequest",
|
|
138
|
+
"JobStatusRequest",
|
|
139
|
+
"JobCancelRequest",
|
|
140
|
+
"JobResultRequest",
|
|
141
|
+
]
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
#
|
|
4
|
+
# This source code is licensed under the terms described in the LICENSE file in
|
|
5
|
+
# the root directory of this source tree.
|
|
6
|
+
|
|
7
|
+
"""File Processors API protocol and models.
|
|
8
|
+
|
|
9
|
+
This module contains the File Processors protocol definition.
|
|
10
|
+
Pydantic models are defined in llama_stack_api.file_processors.models.
|
|
11
|
+
The FastAPI router is defined in llama_stack_api.file_processors.fastapi_routes.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
# Import fastapi_routes for router factory access
|
|
15
|
+
from . import fastapi_routes
|
|
16
|
+
|
|
17
|
+
# Import protocol for re-export
|
|
18
|
+
from .api import FileProcessors
|
|
19
|
+
|
|
20
|
+
# Import models for re-export
|
|
21
|
+
from .models import ProcessFileResponse
|
|
22
|
+
|
|
23
|
+
__all__ = [
|
|
24
|
+
"FileProcessors",
|
|
25
|
+
"ProcessFileResponse",
|
|
26
|
+
"fastapi_routes",
|
|
27
|
+
]
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
#
|
|
4
|
+
# This source code is licensed under the terms described in the LICENSE file in
|
|
5
|
+
# the root directory of this source tree.
|
|
6
|
+
|
|
7
|
+
from typing import Any, Protocol, runtime_checkable
|
|
8
|
+
|
|
9
|
+
from fastapi import UploadFile
|
|
10
|
+
|
|
11
|
+
from llama_stack_api.vector_io import VectorStoreChunkingStrategy
|
|
12
|
+
|
|
13
|
+
from .models import ProcessFileResponse
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@runtime_checkable
|
|
17
|
+
class FileProcessors(Protocol):
|
|
18
|
+
"""
|
|
19
|
+
File Processor API for converting files into structured, processable content.
|
|
20
|
+
|
|
21
|
+
This API provides a flexible interface for processing various file formats
|
|
22
|
+
(PDFs, documents, images, etc.) into normalized text content that can be used for
|
|
23
|
+
vector store ingestion, RAG applications, or standalone content extraction.
|
|
24
|
+
|
|
25
|
+
The API focuses on parsing and normalization:
|
|
26
|
+
- Multiple file formats through extensible provider architecture
|
|
27
|
+
- Multipart form uploads or file ID references
|
|
28
|
+
- Configurable processing options per provider
|
|
29
|
+
- Optional chunking using provider's native capabilities
|
|
30
|
+
- Rich metadata about processing results
|
|
31
|
+
|
|
32
|
+
For embedding generation, use the chunks from this API with the separate
|
|
33
|
+
embedding API to maintain clean separation of concerns.
|
|
34
|
+
|
|
35
|
+
Future providers can extend this interface to support additional formats,
|
|
36
|
+
processing capabilities, and optimization strategies.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
async def process_file(
|
|
40
|
+
self,
|
|
41
|
+
file: UploadFile | None = None,
|
|
42
|
+
file_id: str | None = None,
|
|
43
|
+
options: dict[str, Any] | None = None,
|
|
44
|
+
chunking_strategy: VectorStoreChunkingStrategy | None = None,
|
|
45
|
+
) -> ProcessFileResponse:
|
|
46
|
+
"""
|
|
47
|
+
Process a file into chunks ready for vector database storage.
|
|
48
|
+
|
|
49
|
+
This method supports two modes of operation via multipart form request:
|
|
50
|
+
1. Direct upload: Upload and process a file directly (file parameter)
|
|
51
|
+
2. File storage: Process files already uploaded to file storage (file_id parameter)
|
|
52
|
+
|
|
53
|
+
Exactly one of file or file_id must be provided.
|
|
54
|
+
|
|
55
|
+
If no chunking_strategy is provided, the entire file content is returned as a single chunk.
|
|
56
|
+
If chunking_strategy is provided, the file is split according to the strategy.
|
|
57
|
+
|
|
58
|
+
:param file: The uploaded file object containing content and metadata (filename, content_type, etc.). Mutually exclusive with file_id.
|
|
59
|
+
:param file_id: ID of file already uploaded to file storage. Mutually exclusive with file.
|
|
60
|
+
:param options: Provider-specific processing options (e.g., OCR settings, output format).
|
|
61
|
+
:param chunking_strategy: Optional strategy for splitting content into chunks.
|
|
62
|
+
:returns: ProcessFileResponse with chunks ready for vector database storage.
|
|
63
|
+
"""
|
|
64
|
+
...
|