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.
Files changed (43) hide show
  1. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/PKG-INFO +2 -2
  2. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/error_types.py +4 -0
  3. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/main.py +2 -1
  4. pipelex_api-0.78.0/pipelex_api/routes/pipelex/agent/models.py +121 -0
  5. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/schemas/models.py +3 -2
  6. pipelex_api-0.76.0/pipelex_api/routes/pipelex/agent/models.py +0 -49
  7. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/.gitignore +0 -0
  8. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/LICENSE +0 -0
  9. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/README.md +0 -0
  10. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/hatch_build.py +0 -0
  11. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/__init__.py +0 -0
  12. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/api.toml +0 -0
  13. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/api_config.py +0 -0
  14. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/bundle.py +0 -0
  15. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/disclosure.py +0 -0
  16. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/error_uri.py +0 -0
  17. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/errors.py +0 -0
  18. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/exception_handlers.py +0 -0
  19. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/json_body.py +0 -0
  20. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/limits.py +0 -0
  21. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/method_cache.py +0 -0
  22. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/method_source.py +0 -0
  23. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/middleware.py +0 -0
  24. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/openapi_responses.py +0 -0
  25. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/openapi_schema.py +0 -0
  26. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/problem_document.py +0 -0
  27. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/py.typed +0 -0
  28. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/routes/__init__.py +0 -0
  29. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/routes/health.py +0 -0
  30. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/routes/pipelex/__init__.py +0 -0
  31. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/routes/pipelex/agent/__init__.py +0 -0
  32. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/routes/pipelex/codegen.py +0 -0
  33. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/routes/pipelex/crate_ops.py +0 -0
  34. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/routes/pipelex/pipe_io.py +0 -0
  35. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/routes/pipelex/pipeline.py +0 -0
  36. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/routes/pipelex/resolve.py +0 -0
  37. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/routes/pipelex/tools.py +0 -0
  38. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/routes/pipelex/utils.py +0 -0
  39. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/routes/pipelex/validate.py +0 -0
  40. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/routes/version.py +0 -0
  41. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/schemas/__init__.py +0 -0
  42. {pipelex_api-0.76.0 → pipelex_api-0.78.0}/pipelex_api/security.py +0 -0
  43. {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.76.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.76.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`), and editor tooling (`/lint`, `/format`). "
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 (the Pipelex workspace
57
- spec `docs/specs/pipelex-platform-api.md` → "Layered extension policy"), an
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