pipelex-api 0.76.0__tar.gz → 0.78.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.
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/PKG-INFO +2 -2
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/error_types.py +4 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/main.py +2 -1
- pipelex_api-0.78.0/pipelex_api/routes/pipelex/agent/models.py +121 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/schemas/models.py +3 -2
- pipelex_api-0.76.0/pipelex_api/routes/pipelex/agent/models.py +0 -49
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/.gitignore +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/LICENSE +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/README.md +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/hatch_build.py +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/__init__.py +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/api.toml +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/api_config.py +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/bundle.py +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/disclosure.py +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/error_uri.py +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/errors.py +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/exception_handlers.py +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/json_body.py +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/limits.py +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/method_cache.py +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/method_source.py +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/middleware.py +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/openapi_responses.py +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/openapi_schema.py +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/problem_document.py +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/py.typed +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/routes/__init__.py +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/routes/health.py +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/routes/pipelex/__init__.py +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/routes/pipelex/agent/__init__.py +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/routes/pipelex/codegen.py +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/routes/pipelex/crate_ops.py +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/routes/pipelex/pipe_io.py +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/routes/pipelex/pipeline.py +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/routes/pipelex/resolve.py +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/routes/pipelex/tools.py +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/routes/pipelex/utils.py +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/routes/pipelex/validate.py +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/routes/version.py +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/schemas/__init__.py +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/security.py +0 -0
- {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pyproject.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: pipelex-api
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.78.0
|
|
4
4
|
Summary: Pipelex API
|
|
5
5
|
Project-URL: Homepage, https://pipelex.com
|
|
6
6
|
Project-URL: Repository, https://github.com/Pipelex/pipelex
|
|
@@ -16,7 +16,7 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.14
|
|
17
17
|
Requires-Python: <3.15,>=3.11
|
|
18
18
|
Requires-Dist: fastapi<0.142,>=0.118.0
|
|
19
|
-
Requires-Dist: pipelex[anthropic,bedrock,fal,google,google-genai,mistralai]==0.
|
|
19
|
+
Requires-Dist: pipelex[anthropic,bedrock,fal,google,google-genai,mistralai]==0.78.0
|
|
20
20
|
Requires-Dist: pyjwt>=2.10.1
|
|
21
21
|
Requires-Dist: uvicorn>=0.37.0
|
|
22
22
|
Provides-Extra: dev
|
|
@@ -52,6 +52,10 @@ class ErrorType(StrEnum):
|
|
|
52
52
|
# the runtime's charset and entry cap (`pipelex.system.run_extras`).
|
|
53
53
|
INVALID_ANALYTICS_GROUPS = "InvalidAnalyticsGroups"
|
|
54
54
|
INVALID_MODEL_CATEGORY = "InvalidModelCategory"
|
|
55
|
+
# `GET /v1/models/check` was given a `reference` it cannot check: blank once trimmed, a sigil or a
|
|
56
|
+
# namespace with nothing after it, or longer than the route's bound. A reference that parses and
|
|
57
|
+
# resolves nowhere is never refused: it is the `not_found` verdict.
|
|
58
|
+
INVALID_MODEL_REFERENCE = "InvalidModelReference"
|
|
55
59
|
INVALID_BASE64 = "InvalidBase64"
|
|
56
60
|
PAYLOAD_TOO_LARGE = "PayloadTooLarge"
|
|
57
61
|
# A run request carried a malformed method bundle (`bundle_b64` / `files`): a corrupt zip, an
|
|
@@ -150,7 +150,8 @@ fastapi_app = PipelexFastAPI(
|
|
|
150
150
|
f"This server implements the [MTHDS Protocol](https://mthds.ai) v{PROTOCOL_VERSION} "
|
|
151
151
|
"(`POST /execute`, `POST /start`, `POST /validate`, `GET /models`, `GET /version` — "
|
|
152
152
|
"marked `x-mthds-protocol: true`) plus the Pipelex API extensions: resolve and codegen "
|
|
153
|
-
"(`/resolve`, `/codegen`), the pipe I/O route (`/pipe-io`),
|
|
153
|
+
"(`/resolve`, `/codegen`), the pipe I/O route (`/pipe-io`), the model reference check (`/models/check`), "
|
|
154
|
+
"and editor tooling (`/lint`, `/format`). "
|
|
154
155
|
"Contract layering: MTHDS Protocol ⊂ Pipelex API (this server) ⊂ Pipelex hosted API. "
|
|
155
156
|
"All endpoints are served under the `/v1` base path; "
|
|
156
157
|
"every error is an RFC 7807 `application/problem+json` problem document, documented per "
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"""Models endpoints — the MTHDS Protocol model deck this runner routes to, and the model reference check."""
|
|
2
|
+
|
|
3
|
+
from typing import Annotated
|
|
4
|
+
|
|
5
|
+
from fastapi import APIRouter, Query, Request
|
|
6
|
+
from mthds.protocol.models import ModelCategory
|
|
7
|
+
from pipelex.cogt.models.exceptions import ModelReferenceParseError
|
|
8
|
+
from pipelex.cogt.models.model_reference import ModelReference
|
|
9
|
+
from pipelex.cogt.models.model_reference_check import ModelCheckCategory, ModelReferenceVerdict, check_model_reference
|
|
10
|
+
from pipelex.pipeline.runner import PipelexModelDeck
|
|
11
|
+
from pipelex.runtime_hub import get_model_deck
|
|
12
|
+
|
|
13
|
+
from pipelex_api.error_types import ErrorType
|
|
14
|
+
from pipelex_api.errors import raise_validation_error
|
|
15
|
+
from pipelex_api.routes.pipelex.pipeline import ApiRunner
|
|
16
|
+
|
|
17
|
+
router = APIRouter(tags=["agent"])
|
|
18
|
+
|
|
19
|
+
# The longest reference the check accepts once trimmed; one character more is refused with `InvalidModelReference`.
|
|
20
|
+
MAX_MODEL_REFERENCE_LENGTH = 199
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@router.get("/models", openapi_extra={"x-mthds-protocol": True})
|
|
24
|
+
async def get_models(
|
|
25
|
+
request: Request,
|
|
26
|
+
model_type: Annotated[
|
|
27
|
+
str | None,
|
|
28
|
+
Query(alias="type", description="Filter by model category: llm, extract, img_gen, search, judgment. Single value (protocol arity)."),
|
|
29
|
+
] = None,
|
|
30
|
+
) -> PipelexModelDeck:
|
|
31
|
+
"""List the model deck this runner can route to (MTHDS Protocol `GET /models`).
|
|
32
|
+
|
|
33
|
+
Answers the protocol `ModelDeck` as produced by `PipelexMTHDSProtocol.models` —
|
|
34
|
+
the flat `models` list (`{name, type}` entries) plus this implementation's
|
|
35
|
+
category-keyed routing extensions (`aliases`, `waterfalls`). The `type` query
|
|
36
|
+
param is a SINGLE protocol `ModelCategory` value: repeated `?type=` values
|
|
37
|
+
(arity, `ValidationError`) and unknown categories (`InvalidModelCategory`) are
|
|
38
|
+
both 422s (RFC 7807).
|
|
39
|
+
"""
|
|
40
|
+
# Protocol arity: `type` is a plain single-value enum. FastAPI silently keeps one of
|
|
41
|
+
# several repeated scalar query params, so the multi-value rejection must be explicit.
|
|
42
|
+
# Generic ValidationError, not InvalidModelCategory: the values may all be valid —
|
|
43
|
+
# what's wrong is the arity.
|
|
44
|
+
if len(request.query_params.getlist("type")) > 1:
|
|
45
|
+
raise_validation_error(message="The `type` query parameter accepts a single value")
|
|
46
|
+
category: ModelCategory | None = None
|
|
47
|
+
if model_type is not None:
|
|
48
|
+
try:
|
|
49
|
+
category = ModelCategory(model_type)
|
|
50
|
+
except ValueError:
|
|
51
|
+
valid = ", ".join(sorted(member.value for member in ModelCategory))
|
|
52
|
+
raise_validation_error(
|
|
53
|
+
message=f"Invalid model category. Valid values: {valid}",
|
|
54
|
+
error_type=ErrorType.INVALID_MODEL_CATEGORY,
|
|
55
|
+
)
|
|
56
|
+
return await ApiRunner().models(category=category)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
# NOT tagged `x-mthds-protocol`: the check is a Pipelex API extension, and the flag marks the
|
|
60
|
+
# standard's own operations alone. Its refusals are the composite router's shared problem+json 422.
|
|
61
|
+
@router.get("/models/check")
|
|
62
|
+
async def check_model(
|
|
63
|
+
request: Request,
|
|
64
|
+
reference: Annotated[
|
|
65
|
+
str,
|
|
66
|
+
Query(
|
|
67
|
+
description=(
|
|
68
|
+
"The model reference as a method's `model` field writes it: `$preset`, `@alias`, `~waterfall`, a bare model handle, "
|
|
69
|
+
"or one of the namespaces `preset:`, `alias:`, `waterfall:` and `handle:`. Surrounding whitespace is ignored, "
|
|
70
|
+
f"and the trimmed reference holds at most {MAX_MODEL_REFERENCE_LENGTH} characters. Single value."
|
|
71
|
+
),
|
|
72
|
+
),
|
|
73
|
+
],
|
|
74
|
+
model_type: Annotated[
|
|
75
|
+
str | None,
|
|
76
|
+
Query(
|
|
77
|
+
alias="type",
|
|
78
|
+
description=(
|
|
79
|
+
"The category to check in: llm, extract, img_gen, search, judgment or doc_gen. "
|
|
80
|
+
"When absent, the check is made in every one of them. Single value."
|
|
81
|
+
),
|
|
82
|
+
),
|
|
83
|
+
] = None,
|
|
84
|
+
) -> ModelReferenceVerdict:
|
|
85
|
+
"""Check whether one model reference resolves on this runner, as what, to which model (Pipelex API extension).
|
|
86
|
+
|
|
87
|
+
Answers from pipelex's own reference parser and deck lookups, the ones a validation runs, so a
|
|
88
|
+
reference found `resolved` in a category is one a pipe of that category may name, and one found
|
|
89
|
+
`not_found` is one a validation refuses. A verdict is a `200` whatever the resolution, and on
|
|
90
|
+
`not_found` it carries the suggestions a failing validation of the same reference offers. A
|
|
91
|
+
request that cannot produce a verdict is an input `422`: `ValidationError` for a missing or
|
|
92
|
+
repeated `reference` or a repeated `type`, `InvalidModelReference` for a reference that is blank,
|
|
93
|
+
a sigil or a namespace alone, or too long, and `InvalidModelCategory` for an unknown `type`.
|
|
94
|
+
"""
|
|
95
|
+
for parameter_name in ("reference", "type"):
|
|
96
|
+
if len(request.query_params.getlist(parameter_name)) > 1:
|
|
97
|
+
raise_validation_error(message=f"The `{parameter_name}` query parameter accepts a single value")
|
|
98
|
+
|
|
99
|
+
# The parser trims the reference itself, and its `raw` is the trimmed text the length limit measures.
|
|
100
|
+
try:
|
|
101
|
+
parsed_reference = ModelReference.parse(reference)
|
|
102
|
+
except ModelReferenceParseError as exc:
|
|
103
|
+
raise_validation_error(message=exc.message, error_type=ErrorType.INVALID_MODEL_REFERENCE)
|
|
104
|
+
if len(parsed_reference.raw) > MAX_MODEL_REFERENCE_LENGTH:
|
|
105
|
+
too_long_message = (
|
|
106
|
+
f"The model reference holds {len(parsed_reference.raw)} characters once trimmed, more than the {MAX_MODEL_REFERENCE_LENGTH} accepted"
|
|
107
|
+
)
|
|
108
|
+
raise_validation_error(message=too_long_message, error_type=ErrorType.INVALID_MODEL_REFERENCE)
|
|
109
|
+
|
|
110
|
+
category: ModelCheckCategory | None = None
|
|
111
|
+
if model_type is not None:
|
|
112
|
+
try:
|
|
113
|
+
category = ModelCheckCategory(model_type)
|
|
114
|
+
except ValueError:
|
|
115
|
+
valid = ", ".join(sorted(member.value for member in ModelCheckCategory))
|
|
116
|
+
raise_validation_error(
|
|
117
|
+
message=f"Invalid model category. Valid values: {valid}",
|
|
118
|
+
error_type=ErrorType.INVALID_MODEL_CATEGORY,
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
return check_model_reference(model_deck=get_model_deck(), reference=parsed_reference, category=category)
|
|
@@ -53,8 +53,9 @@ class RunRequest(BaseModel):
|
|
|
53
53
|
deliberately open (`extra="allow"`): a caller may send extra request
|
|
54
54
|
properties, and they are kept rather than silently dropped. Openness is not
|
|
55
55
|
a waiver, though — an unknown key never satisfies the run-source
|
|
56
|
-
precondition. Under the layered extension policy
|
|
57
|
-
|
|
56
|
+
precondition. Under the layered extension policy
|
|
57
|
+
(`conformance/specs/pipelex-platform-api.md` → "Layered extension policy",
|
|
58
|
+
in the `conformance` repo beside the tests that verify it), an
|
|
58
59
|
extension-borne method selector is resolved by the layer that owns it
|
|
59
60
|
BEFORE the request reaches this one, so a body arriving here with no source
|
|
60
61
|
this server understands is an error whatever else it carries.
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
"""Models endpoint — the MTHDS Protocol model deck this runner routes to."""
|
|
2
|
-
|
|
3
|
-
from typing import Annotated
|
|
4
|
-
|
|
5
|
-
from fastapi import APIRouter, Query, Request
|
|
6
|
-
from mthds.protocol.models import ModelCategory
|
|
7
|
-
from pipelex.pipeline.runner import PipelexModelDeck
|
|
8
|
-
|
|
9
|
-
from pipelex_api.error_types import ErrorType
|
|
10
|
-
from pipelex_api.errors import raise_validation_error
|
|
11
|
-
from pipelex_api.routes.pipelex.pipeline import ApiRunner
|
|
12
|
-
|
|
13
|
-
router = APIRouter(tags=["agent"])
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
@router.get("/models", openapi_extra={"x-mthds-protocol": True})
|
|
17
|
-
async def get_models(
|
|
18
|
-
request: Request,
|
|
19
|
-
model_type: Annotated[
|
|
20
|
-
str | None,
|
|
21
|
-
Query(alias="type", description="Filter by model category: llm, extract, img_gen, search, judgment. Single value (protocol arity)."),
|
|
22
|
-
] = None,
|
|
23
|
-
) -> PipelexModelDeck:
|
|
24
|
-
"""List the model deck this runner can route to (MTHDS Protocol `GET /models`).
|
|
25
|
-
|
|
26
|
-
Answers the protocol `ModelDeck` as produced by `PipelexMTHDSProtocol.models` —
|
|
27
|
-
the flat `models` list (`{name, type}` entries) plus this implementation's
|
|
28
|
-
category-keyed routing extensions (`aliases`, `waterfalls`). The `type` query
|
|
29
|
-
param is a SINGLE protocol `ModelCategory` value: repeated `?type=` values
|
|
30
|
-
(arity, `ValidationError`) and unknown categories (`InvalidModelCategory`) are
|
|
31
|
-
both 422s (RFC 7807).
|
|
32
|
-
"""
|
|
33
|
-
# Protocol arity: `type` is a plain single-value enum. FastAPI silently keeps one of
|
|
34
|
-
# several repeated scalar query params, so the multi-value rejection must be explicit.
|
|
35
|
-
# Generic ValidationError, not InvalidModelCategory: the values may all be valid —
|
|
36
|
-
# what's wrong is the arity.
|
|
37
|
-
if len(request.query_params.getlist("type")) > 1:
|
|
38
|
-
raise_validation_error(message="The `type` query parameter accepts a single value")
|
|
39
|
-
category: ModelCategory | None = None
|
|
40
|
-
if model_type is not None:
|
|
41
|
-
try:
|
|
42
|
-
category = ModelCategory(model_type)
|
|
43
|
-
except ValueError:
|
|
44
|
-
valid = ", ".join(sorted(member.value for member in ModelCategory))
|
|
45
|
-
raise_validation_error(
|
|
46
|
-
message=f"Invalid model category. Valid values: {valid}",
|
|
47
|
-
error_type=ErrorType.INVALID_MODEL_CATEGORY,
|
|
48
|
-
)
|
|
49
|
-
return await ApiRunner().models(category=category)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|