Repository navigation
v1.6.1
🚀 Added
✂️ Instance segmentation from the OpenAI block
roboflow_core/open_ai@v7 gains a new task type, instance-segmentation: name the classes, and the model returns one outline polygon per instance, which the block turns into real segmentation predictions that feed mask, polygon and halo visualizations, crops and dataset upload. It is the first VLM block that produces masks. classes is required for the task, and when you do not set model_version the block picks gpt-6-astra for it; an explicit value or a selector is always honoured, and the block-wide default stays gpt-5.1 for every other task. The image is uploaded at its original resolution (not the 2048 px downscale used for object detection), and the answer is enforced through OpenAI structured outputs as absolute-pixel vertex lists. All thanks to @Erol444
{
"type": "roboflow_core/open_ai@v7",
"name": "segmentation",
"images": "$inputs.image",
"task_type": "instance-segmentation",
"classes": ["chip", "connector"],
"api_key": "$inputs.openai_api_key"
}🪪 Responses say which model actually served them
HTTP inference responses gain an optional top-level resolved_model object, so a client can see what ran instead of assuming it was the id it sent: model_id (the canonical id of the loaded model), model_package_id (the package that loaded successfully and produced the result, including after a loading fallback), backend (onnx, trt, torch, ...) and quantization (fp32, fp16 or unknown; this describes the package, not the input tensor dtype or the precision of every operator). The field sits on the base InferenceResponse, so object detection, classification, instance and semantic segmentation, keypoints, LMM, OCR, depth estimation, action recognition, CLIP, Perception Encoder, Grounding DINO, YOLO-World and the SAM, SAM2 and SAM3 responses all carry it (@leeclemnet, #2999).
{
"inference_id": "...",
"time": 0.087,
"resolved_model": {"model_id": "my-workspace/my-project-131", "model_package_id": "c70f32369a54d61e06ef4e6b56c82524", "backend": "trt", "quantization": "fp16"},
"image": {"width": 2048, "height": 1371},
"predictions": []
}🧬 Anomaly detection with PatchCore and FoundAD
Anomaly-detection models trained on Roboflow can now be served by inference. Two architectures are supported, PatchCore and FoundAD, both fitted on images of your normal product only, and both addressed like any other custom model (my-project/2). They are registered as classification models with the two fixed classes normal and anomalous, so they work on POST /infer/classification, on the legacy /{dataset_id}/{version_id} route and through inference_models.AutoModel.from_pretrained(...). Next to the usual classification fields the response carries anomaly_score (the raw score), anomaly_threshold (the threshold stored with the model at training time), is_anomalous (the decision) and, on request, anomaly_map, a per-pixel heatmap resized to the input image (@probicheaux, #3007).
How to use it. Send include_anomaly_map: true in the classification request (or ?include_anomaly_map=true on the legacy route, or InferenceConfiguration(include_anomaly_map=True) in inference_sdk) only when you are going to render the heatmap: it is a full-resolution float array and it is large. Both classes are always returned and confidence filtering does not apply; confidence is a monotonic transform of the score margin where the threshold maps to exactly 0.5, not a probability.
{
"predictions": [{"class": "anomalous", "class_id": 1, "confidence": 0.73}, {"class": "normal", "class_id": 0, "confidence": 0.27}],
"top": "anomalous",
"confidence": 0.73,
"anomaly_score": 1.42,
"anomaly_threshold": 1.10,
"is_anomalous": true,
"anomaly_map": null
}📨 Kafka Producer and Kafka Consumer blocks
Two new enterprise blocks connect Workflows to Apache Kafka - producer and consumer. Make your workflow connected today 🛜 (@tewanchia, #3008).
At this moment, Kafka blocks are not available on the serverless platform
🔒 Security hardening
🪝 Webhook sink validates where it connects
roboflow_core/webhook_sink@v1 used to hand the workflow-supplied URL straight to requests, redirects included. It now sends through a guarded transport: only http and https URLs with a real host are accepted, a backslash in the URL authority is refused, the hostname is resolved once and the connection is pinned to the validated address (with the original name kept for TLS SNI, certificate checks and the Host header, which closes DNS rebinding), and redirects are never followed: any 3xx answer is reported as a failed notification with Webhook redirects are not allowed. A new switch, ALLOW_WEBHOOK_WORKFLOWS_SINK_TO_NON_GLOBAL_ADDRESSES, controls whether the sink may reach non-global destinations: loopback, RFC 1918 private ranges, link-local including the cloud metadata address 169.254.169.254, CGNAT, IPv6 ULA, reserved, unspecified and multicast addresses, including IPv4-mapped IPv6 forms. When it is False, every A/AAAA record of the target must be global, so a mixed public/private DNS answer is rejected outright (@grzegorz-roboflow, #2995).
What administrators should do.
- The switch ships as
True(permissive), so webhooks pointing at LAN and private addresses keep working after the upgrade. Servers that execute workflows written by people you do not fully trust should setALLOW_WEBHOOK_WORKFLOWS_SINK_TO_NON_GLOBAL_ADDRESSES=False. - Webhook endpoints that answer with a redirect now fail. Point the block at the final URL.
🔧 Fixed
- Two video sources opening at once no longer hang the first one — the helper that captures OpenCV/FFmpeg error text redirected the process-wide stderr around each
cv2.VideoCaptureopen with no synchronisation. When two opens overlapped (two pipelines starting together is enough), one thread saved the other's pipe as "the real stderr": the first source sat inINITIALISINGat 0 fps with no error, forever, the process lost its real stderr, and a restart re-ran the race. A backend writing more than 64 KiB during one open could block the same way. Capture is now a single reference-counted, continuously drained redirect shared by all overlapping opens, with an at-fork reset and a graceful no-capture fallback when stderr is closed.DISABLE_NATIVE_STDERR_CAPTURE=True(new, defaultFalse) leaves stderr untouched, at the cost of less detailedSourceConnectionErrormessages. Unchanged and worth knowing: while a source is opening, anything the process writes to stderr is captured rather than logged (@alexnorell, #3014). - YOLO-NAS on TensorRT no longer returns phantom detections under GPU load —
YOLONasForObjectDetectionTRTconcatenated the engine outputs on the default CUDA stream while NMS ran on the post-processing stream, with nothing ordering the two, so NMS could read a half-written buffer and emit extra boxes non-deterministically when several workers shared a GPU. The concatenation now runs on the inference stream and is synchronised before post-processing. The ONNX backend was never affected. Shipped ininference-models0.37.2(@grzegorz-roboflow, #3009). - Usage is recorded for requests authenticated only by the
Authorizationheader — on routes that resolve the key inside the handler, such as the legacy/{dataset_id}/{version_id}route, a request carrying its key only asAuthorization: Bearer <api_key>passed authentication but its usage row was silently dropped, because the collector looked for the key in bound call arguments only. It now falls back to the request-scoped header key. Expect reported usage of header-authenticated clients to rise to its true level after the upgrade (@grzegorz-roboflow, #3020). - Workspaces whose id starts with
-or_can use inference again — the workspace id pattern required an alphanumeric first character, so a real workspace such as-li3oefailed validation: serverless authorization answered 500 ("workspace lookup returned an invalid identity"), routes resolving the workspace answered 502, and theX-Roboflow-Workspace-Idheader was dropped. The pattern is now[A-Za-z0-9_-]+; everything else is still rejected (@mkaic, #3027). - Polygon, halo and label visualizations draw RLE masks — RLE-first segmentation predictions (the new
open_ai@v7task above, and therle_instance_segmentation_predictionkind in general) carry their masks indata["rle_mask"]withmask=None, and onlymask_visualization@v1decoded them.label_visualization@v1/@v2andrich_label_visualization@v1withtext_position: CENTER_OF_MASSfailed with "Cannot use Position.CENTER_OF_MASS without a detection mask", andpolygon_visualization@v1/@v2andhalo_visualization@v1/@v2silently drew the bounding box. A sharedensure_dense_maskshelper now decodes the masks on a shallow copy in all of them. Note the visible change: polygon and halo now draw the real contour where they used to draw a box (@SkalskiP, #3013). - Empty detections keep their image dimensions in two more places — v1.6.0 taught seven VLM parsers and the serialiser to carry
image.width/image.heighton a zero-detection result. Two gaps remained. The Florence-2 object-detection parser inroboflow_core/vlm_as_detector@v1and@v2has its own code path and still produced{"width": null, "height": null}; it now stores the dimensions in object-levelmetadatalike the others (@davidnichols-ops, #2983). And two consumers dropped what the producers had stored: the deserialiser returned early for zero rows, so an empty result lost its dimensions on a serialise/deserialise round trip (custom Python blocks, Modal and remote execution), and the numpy-to-tensor converter rebuilt image metadata from per-row columns only. Both now read the object-levelmetadata(@L4XB, #2982). describe_interfaceaccepts outputs that pass an input through — a workflow with an output such as{"name": "img", "selector": "$inputs.image"}executed correctly, butPOST /workflows/describe_interfaceandPOST /{workspace_name}/workflows/{workflow_id}/describe_interfaceanswered 400 with "Could not find step referred in outputs (inputs)". Output discovery now resolves input selectors and reports the input's kinds; a selector that names a missing input still returns a clear 400 (@atirna, #2936).- Detection filters accept
class_namestored as a NumPy object array — a custom Python block that filledsv.Detections.data["class_name"]with adtype=objectarray made every downstreamclass_nameexpression (detections filter, property extraction, conditions) crash withAttributeError: 'str' object has no attribute 'item'. Plain Python strings are now accepted next tonumpy.str_(@hansent, #3022). - Track Class Lock bounds its state per track — the caps added in v1.6.0 limit the number of tracks, but a single tracker id that carried a new class name on every detection grew its vote tables without bound and re-sorted them on every detection, which is quadratic.
roboflow_core/track_class_lock@v1now admits at most 256 distinct class names per track (classes already tallied always count, new ones beyond the cap are ignored), sweeps unreachable class ids at the cap, and ranks with a top-2 selection instead of a full sort. Real objects flicker between a handful of classes, so legitimate use is unaffected (@alexeialexandrovich, #2981). - The landing page hides the builder link when the builder is off — a self-hosted server always showed "Start building locally", which led to a 404 unless
ENABLE_BUILDER=True. The page now probesGET /buildonce and shows the link only when the builder is mounted. Defaults are unchanged: the builder is still enabled withENABLE_BUILDER=Trueorinference server start --dev, and the--devhelp text now says that it setsENABLE_BUILDERandNOTEBOOK_ENABLED(@mstevens843, #3001). - Model blocks say that the recommended confidence thresholds are per class — the
Best (Recommended)option ofconfidence_modenow reads "Use F1-optimal per-class thresholds from model evaluation" inroboflow_object_detection_model@v3,roboflow_instance_segmentation_model@v3/@v4,roboflow_multi_label_classification_model@v3androboflow_semantic_segmentation_model@v2. Wording only (@leeclemnet, #2998).
🚧 Maintenance
- Security dependency refresh (2026-09-18) —
fastapimoves from>=0.100,<0.129to>=0.134,<0.142, and the Workflows lockfile resolves Starlette1.6.0, in response to Dependabot alerts on Starlette (@grzegorz-roboflow, #3024).inference-modelsmoves to0.37.4, which adds ananyio>=4.14.2,<5.0.0floor for security reasons; every requirements file pinsinference-models~=0.37.4(@PawelPeczek-Roboflow, #3029). - Packaging after the Workflows split —
requirements/requirements.workflows.txtis new and pinsroboflow-workflows[enterprise]==0.1.1. The industrial and database client libraries (asyncua,paho-mqtt,pylogix,pymodbus,psycopg[binary]) left the shared requirements and now arrive through thatenterpriseextra, so the installed set is the same.inference-sdkis no longer bundled inside theinferencewheels; they depend oninference-sdk==1.6.1instead, which removes overlapping files between the two distributions. Every Docker image builds the Workflows wheel from source, and the macOS and Windows app bundles collectroboflow_workflows(#3004). - Compatibility repairs made along the way — two regressions introduced by the refactor were fixed before any release carried them. Segmentation converters briefly returned dataclasses, breaking
model_dump()for callers;InferenceResponseImage,InferenceResponse,CvInferenceResponse,WithVisualizationResponseandInstanceSegmentationInferenceResponseare Pydantic models again, defined inroboflow-workflowsand re-exported frominference.core.entities.responses.inference(#2991). And direct Python users buildingWorkflowImageDatafrom a file path or URL outside an engine lost image loading;inferencenow registers its guarded image codec lazily at import (#2996). - JetPack 5.1.1 image builds again — the Workflows install step re-resolved
transformersabove the5.7.0that the JetPack 5 PyTorch can run; the downgrade now happens after that step. Onlymainbuilds between 2026-09-16 and 2026-09-18 were affected (@grzegorz-roboflow, #3030). - CI for the new package —
roboflow-workflowsis published through PyPI trusted publishing on release, with a build-only manual dispatch (#3003); theinference-modelsintegration tests install the Workflows wheel (#3019); a test import that still used the legacy path inside the standalone package was corrected (#3023); the TensorRT CUDA-graph cache-reuse test builds its batch through the real pre-processing path (#3002); linters after #2936 (#3021); a direct changelog commit was reverted and its text re-landed underinference-models0.37.2(#3011). - Version —
inference1.6.1,inference-models0.37.4,roboflow-workflows0.1.1(@PawelPeczek-Roboflow, #3026).
📓 Side-notes
📦 Workflows ships as a standalone roboflow-workflows package
Marching towards new server we needed to make Workflows detached from the old inference. It's still fully compatible and imports are re-mapped within inference package. The change is purely tactical for now, the new package is not intended to be installed stand-alone for now.
🏅 New Contributors
- @mstevens843 made their first contribution in #3001
- @tewanchia made their first contribution in #3008
- @L4XB made their first contribution in #2982
- @atirna made their first contribution in #2936
Full Changelog: v1.6.0...v1.6.1