cog
484a30a0 - feat: build-time schema generation in Go (tree-sitter) (#2782)

Commit
131 days ago
feat: build-time schema generation in Go (tree-sitter) (#2782) * feat: add static Python schema parser using tree-sitter Implement pkg/schema/ package for build-time extraction of Cog predictor signatures via tree-sitter (smacker/go-tree-sitter, CGo). Replaces runtime Python-based schema generation with static analysis. - pkg/schema/types.go: core type system (OrderedMap, PrimitiveType, FieldType, InputField, OutputType, TypeAnnotation, etc.) - pkg/schema/errors.go: typed SchemaError with error kinds - pkg/schema/python/parser.go: tree-sitter AST walker that extracts imports, module-scope constants, BaseModel subclasses, InputRegistry patterns, function signatures, Input() metadata, and type annotations - pkg/schema/python/parser_test.go: 50 tests covering basic predictors, Input() constraints, choices (literal, module var, dict keys/values, concat), optional/list/iterator/BaseModel outputs, train mode, InputRegistry (attribute + method), default_factory hard error, and error cases * feat: add OpenAPI 3.0.2 schema generation from PredictorInfo Port schema.rs to Go: GenerateOpenAPISchema() produces a complete OpenAPI spec from parsed predictor info. Includes input schema with constraints, choices/enums, output types (single/list/iterator/concat/ object), fixed components (request/response/status/validation), and post-processing (removeTitleNextToRef, fixNullableAnyOf). Also adds OutputType.JSONType() to types.go, fixes pre-existing lint issues in parser.go and errors.go. * feat: add schema Generate() public API with COG_OPENAPI_SCHEMA support Generate() reads a predict ref (e.g. predict.py:Predictor), loads the source file, parses it, and produces OpenAPI JSON. Uses a Parser function type to avoid import cycle between schema and schema/python. COG_OPENAPI_SCHEMA env var allows bringing a pre-built schema file, skipping all parsing and generation. * feat: wire static schema gen into build pipeline and add cogEnvVars - Pre-build static schema gen (Go tree-sitter) for SDK >= 0.17.0 - Post-build legacy schema gen (container) for SDK < 0.17.0 - Add cogEnvVars() to Dockerfile: COG_PREDICT_TYPE_STUB, COG_TRAIN_TYPE_STUB, COG_MAX_CONCURRENCY - Add isLegacySDKVersion() and conditional coglet install (SDK dep handles it when unpinned) - Add GenerateCombined() and MergeSchemas() for predict+train schemas - Export BaseVersionRe and add DetectLocalSDKVersion() to wheels package - Update test expectations for new ENV lines and coglet install behavior * chore: fix clippy manual_str_repeat warning in protocol.rs * feat: load bundled schema from disk, remove runtime Python schema gen - Replace handler.schema() with load_bundled_schema() reading .cog/openapi_schema.json - Remove schema() from PredictHandler trait (coglet-core) - Remove schema() impl from PythonPredictHandler (worker_bridge.rs) - Remove schema() method from PythonPredictor (predictor.rs) - Read COG_MAX_CONCURRENCY from env instead of importing cog.config - Update SDK detection to check cog.BasePredictor instead of cog._adt * chore: enable CGo for go-tree-sitter with zig cross-compilation - CGO_ENABLED=1 globally (goreleaser, mise.toml, CI env) - goreleaser overrides: zig cc for linux/amd64 and linux/arm64 - darwin targets use native clang (zig lacks macOS SDK stubs) - CI: mlugg/setup-zig@v2 in build-cog and release-dry-run jobs * chore: update Cargo.lock for 0.17.0-rc.1 * test: add ITs for static/legacy schema gen and parser edge cases - legacy_sdk_schema IT: verifies SDK < 0.17.0 falls back to runtime schema gen - static_schema_gen IT: verifies Go tree-sitter schema in Docker label end-to-end - Parser tests: falsy defaults (False, 0, 0.0, ""), no-input predictor, async iterators, typing.List, typing.Union[X, None], list[Path], all-optional - Support typing.Union[X, None] via comma-aware generic parsing - Compact JSON for schema output (no wasted bytes in Docker labels) * feat: add input validation at HTTP edge using bundled schema Validates prediction and training inputs against the OpenAPI schema at the Rust HTTP layer before dispatching to the Python worker. This catches missing required fields and unknown fields early with pydantic-compatible error responses (422 with detail array). - Add InputValidator with jsonschema validation, inlining, and additionalProperties enforcement - Wire validators into PredictionService (separate Input/TrainingInput) - Validate in create_prediction_with_id before slot acquisition - Rewrite training routes with proper idempotency handling (ID mismatch check, existing state return) instead of delegating to prediction routes - Add 7 unit tests for InputValidator, 2 for training idempotency * chore: allow MIT-0 license for borrow-or-share (jsonschema transitive dep) * fix: resolve allOf/$ref wrappers in CLI input type coercion The CLI sends all -i values as strings and relies on the schema to coerce them to the correct types (integer, number, etc.). The static schema gen emits allOf:[{$ref: ...}] for enum/choices fields, where the referenced schema carries the concrete type but the wrapper does not. Without resolving these wrappers, the CLI sends string '42' for integer fields and '3' for integer enum choices, which the edge validator correctly rejects. Also adds NewInputsForMode() to look up TrainingInput schema for train mode, with fallback to Input for legacy schemas.
Author
Parents
Loading