annotide 0.1.0__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.
annotide/models.py ADDED
@@ -0,0 +1,2683 @@
1
+ """Wire types of the Annotide API — generated, do not edit.
2
+
3
+ Regenerate with `make openapi` from the repository root. Every model is a
4
+ `TypedDict`: API responses are plain dicts, typed for editors and mypy.
5
+ """
6
+
7
+ from __future__ import annotations
8
+ from typing import Any, Literal, NotRequired, TypedDict
9
+
10
+
11
+ class AgreementAnnotator(TypedDict):
12
+ """
13
+ One annotator's footprint in a `ProjectAgreement` (how many items they touched).
14
+ """
15
+
16
+ display_name: str
17
+ email: str
18
+ items: int
19
+ user_id: str
20
+
21
+
22
+ type AnnotationKind = Literal["primary", "consensus", "gold"]
23
+
24
+
25
+ class AnnotationRead(TypedDict):
26
+ """
27
+ One annotation version as returned by the API.
28
+ """
29
+
30
+ author_model_version_id: str | None
31
+ author_user_id: str | None
32
+ blob_path: NotRequired[str | None]
33
+ duration_ms: int | None
34
+ id: str
35
+ item_id: str
36
+ kind: NotRequired[AnnotationKind]
37
+ label_schema_version_id: str
38
+ result: dict[str, Any]
39
+ source: str
40
+ status: str
41
+ task_id: str | None
42
+ version: int
43
+
44
+
45
+ type AnnotationSource = Literal["human", "model"]
46
+
47
+
48
+ class AnnotationStats(TypedDict):
49
+ by_source: dict[str, int]
50
+ latest_by_status: dict[str, int]
51
+ versions: int
52
+
53
+
54
+ type AnnotationStatus = Literal["draft", "submitted", "approved", "rejected"]
55
+
56
+
57
+ class AnnotatorQuality(TypedDict):
58
+ """
59
+ One annotator's accuracy against gold references (QA-4).
60
+ """
61
+
62
+ classification_accuracy: float | None
63
+ display_name: str
64
+ email: str
65
+ gold_items: int
66
+ mean_iou: float | None
67
+ score: float | None
68
+ shape_f1: float | None
69
+ span_f1: float | None
70
+ user_id: str
71
+
72
+
73
+ class AnnotatorQualityResponse(TypedDict):
74
+ """
75
+ `GET /projects/{id}/quality/annotators` response body (QA-4).
76
+ """
77
+
78
+ annotators: list[AnnotatorQuality]
79
+
80
+
81
+ class AnnotatorStats(TypedDict):
82
+ approved: NotRequired[int]
83
+ display_name: str
84
+ rejected: NotRequired[int]
85
+ submitted: NotRequired[int]
86
+ user_id: str
87
+
88
+
89
+ class ApiKeyCreate(TypedDict):
90
+ """
91
+ Payload to mint an API key (AUTH-4).
92
+
93
+ `scopes` is a subset of `read` / `write` / `admin`; `user_id` (superuser
94
+ only) issues the key for another user or a service account.
95
+ """
96
+
97
+ expires_at: NotRequired[str | None]
98
+ name: str
99
+ scopes: NotRequired[list[str]]
100
+ user_id: NotRequired[str | None]
101
+
102
+
103
+ class ApiKeyCreated(TypedDict):
104
+ """
105
+ The freshly minted key, carrying the bearer `token` exactly once.
106
+ """
107
+
108
+ created_at: str
109
+ created_by: str | None
110
+ expires_at: str | None
111
+ id: str
112
+ last_used_at: str | None
113
+ name: str
114
+ organization_id: str
115
+ revoked_at: str | None
116
+ scopes: list[str]
117
+ token: str
118
+ user_id: str
119
+
120
+
121
+ class ApiKeyRead(TypedDict):
122
+ """
123
+ API key metadata; the token itself is only returned at creation.
124
+ """
125
+
126
+ created_at: str
127
+ created_by: str | None
128
+ expires_at: str | None
129
+ id: str
130
+ last_used_at: str | None
131
+ name: str
132
+ organization_id: str
133
+ revoked_at: str | None
134
+ scopes: list[str]
135
+ user_id: str
136
+
137
+
138
+ type AttributeType = Literal["text", "number", "select", "multiselect", "boolean"]
139
+
140
+
141
+ class AuditEventRead(TypedDict):
142
+ """
143
+ One append-only audit row.
144
+ """
145
+
146
+ action: str
147
+ actor_id: str | None
148
+ after: dict[str, Any] | None
149
+ before: dict[str, Any] | None
150
+ created_at: str
151
+ id: str
152
+ ip: str | None
153
+ organization_id: str
154
+ target_id: str | None
155
+ target_type: str
156
+
157
+
158
+ BBoxShape = TypedDict(
159
+ "BBoxShape",
160
+ {
161
+ "attributes": NotRequired[dict[str, Any]],
162
+ "bbox": tuple[float, float, float, float],
163
+ "class": str,
164
+ "confidence": NotRequired[float | None],
165
+ "frame": NotRequired[int | None],
166
+ "id": str,
167
+ "keyframe": NotRequired[bool],
168
+ "outside": NotRequired[bool],
169
+ "page": NotRequired[int | None],
170
+ "text": NotRequired[str | None],
171
+ "track_id": NotRequired[str | None],
172
+ "type": NotRequired[Literal["bbox"]],
173
+ },
174
+ )
175
+
176
+
177
+ class BulkApprove(TypedDict):
178
+ """
179
+ Approve the latest `submitted` version of each item (WF-4 verdict
180
+ without a correction). Items not awaiting review are skipped.
181
+ """
182
+
183
+ action: Literal["approve"]
184
+ comment: NotRequired[str | None]
185
+ item_ids: list[str]
186
+
187
+
188
+ class BulkReject(TypedDict):
189
+ """
190
+ Reject the latest `submitted` version of each item (WF-4) with one
191
+ shared `comment`, which every item's thread gets — a rejection always
192
+ tells the annotator why. Items not awaiting review are skipped.
193
+ """
194
+
195
+ action: Literal["reject"]
196
+ comment: str
197
+ item_ids: list[str]
198
+
199
+
200
+ class BulkReturn(TypedDict):
201
+ """
202
+ Return the items' `in_progress` tasks to the open queue: the lock is
203
+ dropped and the assignee cleared, as if the holder had released it.
204
+ """
205
+
206
+ action: Literal["return"]
207
+ item_ids: list[str]
208
+
209
+
210
+ class BulkSkipped(TypedDict):
211
+ """
212
+ One item the action did not apply to, and why.
213
+ """
214
+
215
+ item_id: str
216
+ reason: str
217
+
218
+
219
+ class BulkTag(TypedDict):
220
+ """
221
+ Add and / or remove free-form tags on the items (`item.meta.tags`).
222
+ """
223
+
224
+ action: Literal["tag"]
225
+ add: NotRequired[list[str]]
226
+ item_ids: list[str]
227
+ remove: NotRequired[list[str]]
228
+
229
+
230
+ class CacheRebuildRequest(TypedDict):
231
+ """
232
+ Body of `POST /projects/{id}/cache/rebuild` (SRC-6).
233
+ """
234
+
235
+ purge: NotRequired[bool]
236
+
237
+
238
+ class ClassCount(TypedDict):
239
+ count: int
240
+ label: str
241
+
242
+
243
+ class ClassificationAgreement(TypedDict):
244
+ """
245
+ Agreement for one classification field, pooled over items with a value (QA-2).
246
+ """
247
+
248
+ field: str
249
+ fleiss_kappa: float | None
250
+ items: int
251
+ krippendorff_alpha: float | None
252
+
253
+
254
+ class CommentCreate(TypedDict):
255
+ """
256
+ Payload to add a comment to an item's thread.
257
+ """
258
+
259
+ anchor: NotRequired[dict[str, Any] | None]
260
+ annotation_id: NotRequired[str | None]
261
+ body: str
262
+ parent_id: NotRequired[str | None]
263
+
264
+
265
+ class CommentRead(TypedDict):
266
+ """
267
+ Comment as returned by the API.
268
+ """
269
+
270
+ anchor: dict[str, Any] | None
271
+ annotation_id: str | None
272
+ author_id: str
273
+ body: str
274
+ created_at: str
275
+ id: str
276
+ item_id: str | None
277
+ parent_id: str | None
278
+ project_id: str
279
+ resolved_at: str | None
280
+ updated_at: str
281
+
282
+
283
+ class CommentResolve(TypedDict):
284
+ """
285
+ Payload to resolve or reopen a comment.
286
+ """
287
+
288
+ resolved: bool
289
+
290
+
291
+ class ConnectorCheckResult(TypedDict):
292
+ """
293
+ Result of testing a connector's connectivity (SRC-7).
294
+ """
295
+
296
+ messages: list[str]
297
+ ok: bool
298
+
299
+
300
+ type ConnectorIdentity = Literal[
301
+ "managed_identity",
302
+ "service_principal",
303
+ "account_key",
304
+ "sas_token",
305
+ "iam_role",
306
+ "access_key",
307
+ "none",
308
+ ]
309
+
310
+
311
+ type ConnectorType = Literal[
312
+ "azure_blob", "s3", "gcs", "local", "http", "sharepoint", "databricks_volume"
313
+ ]
314
+
315
+
316
+ class ConnectorUpdate(TypedDict):
317
+ """
318
+ Partial update payload for a connector; all fields optional.
319
+ """
320
+
321
+ config: NotRequired[dict[str, Any] | None]
322
+ identity_type: NotRequired[ConnectorIdentity | None]
323
+ name: NotRequired[str | None]
324
+ secret_ref: NotRequired[str | None]
325
+ type: NotRequired[ConnectorType | None]
326
+
327
+
328
+ class ConsensusAnnotationRead(TypedDict):
329
+ """
330
+ The annotation version `resolve` stores, mirroring `annotations.py`'s `AnnotationRead`.
331
+ """
332
+
333
+ author_model_version_id: str | None
334
+ author_user_id: str | None
335
+ blob_path: NotRequired[str | None]
336
+ duration_ms: int | None
337
+ id: str
338
+ item_id: str
339
+ label_schema_version_id: str
340
+ result: dict[str, Any]
341
+ source: str
342
+ status: str
343
+ task_id: str | None
344
+ version: int
345
+
346
+
347
+ class ConsensusAnnotatorRead(TypedDict):
348
+ """
349
+ One consensus annotator's latest submitted version on an item.
350
+ """
351
+
352
+ annotation_id: str
353
+ created_at: str
354
+ display_name: str
355
+ email: str
356
+ status: str
357
+ user_id: str
358
+ version: int
359
+
360
+
361
+ class CorrectionClassMetrics(TypedDict):
362
+ """
363
+ The same counts for one class, with its precision / recall.
364
+ """
365
+
366
+ added: int
367
+ adjusted: int
368
+ deleted: int
369
+ kept: int
370
+ mean_iou_adjusted: float | None
371
+ model: int
372
+ name: str
373
+ precision: float | None
374
+ recall: float | None
375
+ relabeled: int
376
+
377
+
378
+ class CorrectionShapeCounts(TypedDict):
379
+ """
380
+ Fate of a model version's shapes once a human finished the item.
381
+ """
382
+
383
+ added: int
384
+ adjusted: int
385
+ deleted: int
386
+ kept: int
387
+ model: int
388
+ relabeled: int
389
+
390
+
391
+ class DependencyStatus(TypedDict):
392
+ detail: NotRequired[str | None]
393
+ ok: bool
394
+
395
+
396
+ class EraseRequest(TypedDict):
397
+ """
398
+ `confirm_email` must repeat the user's current e-mail, as a guard.
399
+ """
400
+
401
+ confirm_email: str
402
+ redact_comments: NotRequired[bool]
403
+
404
+
405
+ class EventDeliveryResult(TypedDict):
406
+ """
407
+ What one storage-event delivery queued (SRC-3).
408
+ """
409
+
410
+ ignored: int
411
+ job_ids: list[str]
412
+ matched: int
413
+ received: int
414
+
415
+
416
+ class EventTokenRead(TypedDict):
417
+ """
418
+ A freshly minted storage-event token (SRC-3), shown once.
419
+ """
420
+
421
+ path: str
422
+ token: str
423
+
424
+
425
+ class ExportDownload(TypedDict):
426
+ """
427
+ A short-lived signed URL for a succeeded export's archive (EXP-5).
428
+ """
429
+
430
+ expires_in: int
431
+ url: str
432
+
433
+
434
+ class ExtendRequest(TypedDict):
435
+ """
436
+ Optional JSON body for `POST /tasks/{task_id}/extend`.
437
+ """
438
+
439
+ lock_ttl_seconds: NotRequired[int | None]
440
+
441
+
442
+ class ExtractTextRequest(TypedDict):
443
+ """
444
+ Body of `POST /projects/{id}/extract-text` (CONTRACTS.md *PDF text mode*).
445
+ """
446
+
447
+ force: NotRequired[bool]
448
+ item_ids: NotRequired[list[str] | None]
449
+
450
+
451
+ class FuseResolve(TypedDict):
452
+ """
453
+ Resolve by fusing every submitted consensus version (QA-3).
454
+ """
455
+
456
+ comment: NotRequired[str | None]
457
+ iou_threshold: NotRequired[float]
458
+ method: NotRequired[Literal["fuse"]]
459
+ min_votes: NotRequired[int | None]
460
+
461
+
462
+ class GoldSetRequest(TypedDict):
463
+ """
464
+ `PUT /items/{id}/gold` payload: an approved primary version of this item.
465
+ """
466
+
467
+ annotation_id: str
468
+
469
+
470
+ class GoldTasksRequest(TypedDict):
471
+ """
472
+ `POST /projects/{id}/gold/tasks` payload.
473
+
474
+ Defaults (both omitted) to every member with role `annotator` times every
475
+ item with a gold reference.
476
+ """
477
+
478
+ item_ids: NotRequired[list[str] | None]
479
+ priority: NotRequired[int]
480
+ user_ids: NotRequired[list[str] | None]
481
+
482
+
483
+ class GoldTasksResult(TypedDict):
484
+ """
485
+ How many (item, user) gold tasks a `gold/tasks` request opened or skipped.
486
+ """
487
+
488
+ opened: int
489
+ skipped: int
490
+
491
+
492
+ class HealthResponse(TypedDict):
493
+ status: Literal["ok"]
494
+
495
+
496
+ type ImportStatus = Literal["submitted", "draft"]
497
+
498
+
499
+ class InteractivePoint(TypedDict):
500
+ """
501
+ A click, in original-image pixels.
502
+ """
503
+
504
+ x: float
505
+ y: float
506
+
507
+
508
+ class InteractiveRequest(TypedDict):
509
+ """
510
+ `POST /items/{id}/interactive`: one prompt for a `segment` model.
511
+
512
+ Exactly one of `point` / `box` — the model turns it into a polygon. The
513
+ text prompt the reference service also understands is deliberately not
514
+ exposed yet: nothing in the annotator asks for it.
515
+ """
516
+
517
+ box: NotRequired[tuple[float, float, float, float] | None]
518
+ model_id: str
519
+ point: NotRequired[InteractivePoint | None]
520
+
521
+
522
+ class InteractiveResult(TypedDict):
523
+ """
524
+ The polygon the model proposed; the browser adds it as a normal shape.
525
+ """
526
+
527
+ confidence: float
528
+ points: list[tuple[float, float]]
529
+ type: NotRequired[Literal["polygon"]]
530
+
531
+
532
+ class ItemStats(TypedDict):
533
+ by_status: dict[str, int]
534
+ total: int
535
+
536
+
537
+ type ItemStatusOutput = Literal[
538
+ "new",
539
+ "prelabeled",
540
+ "annotating",
541
+ "submitted",
542
+ "in_review",
543
+ "approved",
544
+ "rejected",
545
+ "skipped",
546
+ ]
547
+
548
+
549
+ type JobStatusInput = Literal["queued", "running", "succeeded", "failed", "cancelled"]
550
+
551
+
552
+ type JobStatusOutput = Literal["queued", "running", "succeeded", "failed", "cancelled"]
553
+
554
+
555
+ type JobTypeInput = Literal[
556
+ "scan_source",
557
+ "tile_image",
558
+ "prelabel",
559
+ "export",
560
+ "snapshot",
561
+ "import",
562
+ "thumbnail",
563
+ "rebuild_cache",
564
+ "extract_text",
565
+ ]
566
+
567
+
568
+ type JobTypeOutput = Literal[
569
+ "scan_source",
570
+ "tile_image",
571
+ "prelabel",
572
+ "export",
573
+ "snapshot",
574
+ "import",
575
+ "thumbnail",
576
+ "rebuild_cache",
577
+ "extract_text",
578
+ ]
579
+
580
+
581
+ KeypointsShape = TypedDict(
582
+ "KeypointsShape",
583
+ {
584
+ "attributes": NotRequired[dict[str, Any]],
585
+ "class": str,
586
+ "confidence": NotRequired[float | None],
587
+ "frame": NotRequired[int | None],
588
+ "id": str,
589
+ "keyframe": NotRequired[bool],
590
+ "outside": NotRequired[bool],
591
+ "page": NotRequired[int | None],
592
+ "points": list[tuple[float, float, int]],
593
+ "track_id": NotRequired[str | None],
594
+ "type": NotRequired[Literal["keypoints"]],
595
+ },
596
+ )
597
+
598
+
599
+ class LabelSchemaVersionRead(TypedDict):
600
+ """
601
+ One immutable version of a project's label schema (TOOL-4).
602
+ """
603
+
604
+ created_at: str
605
+ definition: dict[str, Any]
606
+ id: str
607
+ label_schema_id: str
608
+ version: int
609
+
610
+
611
+ class LicenseInfo(TypedDict):
612
+ """
613
+ Licence status as seen by an administrator.
614
+
615
+ ``tier`` is the edition (LIC-32): without a key in force (or with an
616
+ invalid one) it is ``"community"`` and the key's fields are ``None``.
617
+ ``seat_limit`` includes the overage and is ``None`` when the build
618
+ enforces no limit (LIC-23, LIC-24).
619
+ """
620
+
621
+ active_users: int
622
+ business_features: list[str]
623
+ expires_at: str | None
624
+ features: list[str]
625
+ grace_ends_at: str | None
626
+ host_mismatch: bool
627
+ hosts: list[str]
628
+ license_id: str | None
629
+ licensee: str | None
630
+ owner_only: bool
631
+ restricted: bool
632
+ revoked_at: str | None
633
+ seat_limit: int | None
634
+ seats: int | None
635
+ source: str | None
636
+ status: str
637
+ tier: str
638
+ trial_used: bool
639
+
640
+
641
+ class LicenseKeyUpdate(TypedDict):
642
+ """
643
+ `PUT /license` body: a key to keep in the database (LIC-26).
644
+ """
645
+
646
+ key: str
647
+
648
+
649
+ class LicenseRefreshStatus(TypedDict):
650
+ """
651
+ `GET` / `POST /license/refresh` (LIC-27): what is sent, and how the last try went.
652
+ """
653
+
654
+ attempted_at: str | None
655
+ enabled: bool
656
+ error: str | None
657
+ last_payload: dict[str, Any] | None
658
+ payload: dict[str, Any] | None
659
+ server_configured: bool
660
+ succeeded_at: str | None
661
+
662
+
663
+ class LoginRequest(TypedDict):
664
+ """
665
+ Local login credentials (AUTH-2).
666
+ """
667
+
668
+ email: str
669
+ otp: NotRequired[str | None]
670
+ password: str
671
+
672
+
673
+ class MaskRLE(TypedDict):
674
+ """
675
+ Uncompressed run-length encoding of a binary mask (COCO-style: alternating
676
+
677
+ background/foreground run lengths, starting with background).
678
+ """
679
+
680
+ counts: list[int]
681
+ size: tuple[int, int]
682
+
683
+
684
+ MaskShape = TypedDict(
685
+ "MaskShape",
686
+ {
687
+ "attributes": NotRequired[dict[str, Any]],
688
+ "class": str,
689
+ "confidence": NotRequired[float | None],
690
+ "frame": NotRequired[int | None],
691
+ "id": str,
692
+ "keyframe": NotRequired[bool],
693
+ "outside": NotRequired[bool],
694
+ "page": NotRequired[int | None],
695
+ "rle": MaskRLE,
696
+ "track_id": NotRequired[str | None],
697
+ "type": NotRequired[Literal["mask"]],
698
+ },
699
+ )
700
+
701
+
702
+ type MediaType = Literal["image", "video", "audio", "text", "pdf", "llm", "timeseries"]
703
+
704
+
705
+ class MfaCode(TypedDict):
706
+ """
707
+ A six-digit code from the authenticator app, or a recovery code where allowed.
708
+ """
709
+
710
+ code: str
711
+
712
+
713
+ class MfaRecoveryCodes(TypedDict):
714
+ """
715
+ Single-use recovery codes, shown once.
716
+ """
717
+
718
+ recovery_codes: list[str]
719
+
720
+
721
+ class MfaSetup(TypedDict):
722
+ """
723
+ `POST /auth/mfa/setup`: the seed to add to an authenticator app.
724
+ """
725
+
726
+ otpauth_uri: str
727
+ secret: str
728
+
729
+
730
+ class MfaStatus(TypedDict):
731
+ """
732
+ `GET /auth/mfa`: the caller's MFA state (AUTH-2).
733
+ """
734
+
735
+ available: bool
736
+ enabled: bool
737
+ pending: bool
738
+ recovery_codes_left: int
739
+
740
+
741
+ type MlIdentity = Literal[
742
+ "none", "bearer", "basic", "service_principal", "managed_identity"
743
+ ]
744
+
745
+
746
+ class MlPlatformCheckResult(TypedDict):
747
+ """
748
+ `POST /ml-platforms/{id}/check`: failures are `ok: false`, never an error status.
749
+ """
750
+
751
+ info: NotRequired[dict[str, Any] | None]
752
+ messages: list[str]
753
+ ok: bool
754
+
755
+
756
+ type MlPlatformKind = Literal["mlflow", "databricks", "azureml"]
757
+
758
+
759
+ class MlPlatformRead(TypedDict):
760
+ """
761
+ A platform as the API returns it: `secret_ref` never, only `has_secret`.
762
+ """
763
+
764
+ config: dict[str, Any]
765
+ created_at: str
766
+ has_secret: bool
767
+ id: str
768
+ identity_type: MlIdentity
769
+ kind: MlPlatformKind
770
+ name: str
771
+ organization_id: str
772
+ tracking_uri: str
773
+ updated_at: str
774
+
775
+
776
+ class MlPlatformUpdate(TypedDict):
777
+ """
778
+ Partial update; the merged row is validated as a whole.
779
+ """
780
+
781
+ config: NotRequired[dict[str, Any] | None]
782
+ identity_type: NotRequired[MlIdentity | None]
783
+ name: NotRequired[str | None]
784
+ secret_ref: NotRequired[str | None]
785
+ tracking_uri: NotRequired[str | None]
786
+
787
+
788
+ class MlRun(TypedDict):
789
+ """
790
+ A run the platform started on an ML platform (retrain on Databricks).
791
+ """
792
+
793
+ ml_platform_id: str
794
+ run_id: str
795
+ run_url: str | None
796
+
797
+
798
+ class ModelCheckResult(TypedDict):
799
+ """
800
+ Result of testing a model endpoint's connectivity (BYOM-3).
801
+ """
802
+
803
+ info: NotRequired[dict[str, Any] | None]
804
+ messages: list[str]
805
+ ok: bool
806
+
807
+
808
+ type ModelDerivation = Literal["trained", "distilled", "quantized"]
809
+
810
+
811
+ type ModelIdentity = Literal[
812
+ "none", "api_key", "bearer", "service_principal", "managed_identity"
813
+ ]
814
+
815
+
816
+ class ModelIdentityConfig(TypedDict):
817
+ """
818
+ The non-secret half of an Entra identity (BYOM-3).
819
+
820
+ `scope` is the token audience, e.g. `https://ml.azure.com/.default` for an
821
+ Azure ML online endpoint or `https://cognitiveservices.azure.com/.default`
822
+ for Azure OpenAI / AI Foundry. `tenant_id` and `client_id` name a service
823
+ principal; for a managed identity, `client_id` picks a user-assigned one
824
+ (omitted: the system-assigned or workload identity).
825
+ """
826
+
827
+ client_id: NotRequired[str | None]
828
+ scope: NotRequired[str | None]
829
+ tenant_id: NotRequired[str | None]
830
+
831
+
832
+ type ModelTask = Literal["detect", "segment", "classify", "ner", "llm", "ocr"]
833
+
834
+
835
+ class ModelUpdate(TypedDict):
836
+ """
837
+ Partial update payload for a model; all fields optional.
838
+ """
839
+
840
+ endpoint_url: NotRequired[str | None]
841
+ identity_config: NotRequired[ModelIdentityConfig | None]
842
+ identity_type: NotRequired[ModelIdentity | None]
843
+ name: NotRequired[str | None]
844
+ secret_ref: NotRequired[str | None]
845
+ task: NotRequired[ModelTask | None]
846
+
847
+
848
+ class ModelVersionCreate(TypedDict):
849
+ """
850
+ Payload to add a version to a model.
851
+
852
+ `version` defaults to the next integer after the model's current
853
+ highest version (starting at 1) when omitted.
854
+ """
855
+
856
+ class_mapping: NotRequired[dict[str, str | None]]
857
+ derivation: NotRequired[ModelDerivation | None]
858
+ metrics: NotRequired[dict[str, Any]]
859
+ parent_version_id: NotRequired[str | None]
860
+ snapshot_digest: NotRequired[str | None]
861
+ snapshot_id: NotRequired[str | None]
862
+ training_run: NotRequired[dict[str, Any] | None]
863
+ version: NotRequired[int | None]
864
+
865
+
866
+ class ModelVersionImport(TypedDict):
867
+ """
868
+ `POST /models/{id}/versions/import`: a version from an MLflow run.
869
+
870
+ Name the run directly, or a registered model version whose run is read.
871
+ """
872
+
873
+ class_mapping: NotRequired[dict[str, str | None]]
874
+ ml_platform_id: str
875
+ model_version: NotRequired[str | None]
876
+ registered_model: NotRequired[str | None]
877
+ run_id: NotRequired[str | None]
878
+ version: NotRequired[int | None]
879
+
880
+
881
+ class ModelVersionRead(TypedDict):
882
+ """
883
+ A model version as returned by the API.
884
+ """
885
+
886
+ class_mapping: dict[str, str | None]
887
+ created_at: str
888
+ derivation: NotRequired[ModelDerivation | None]
889
+ id: str
890
+ metrics: dict[str, Any]
891
+ model_id: str
892
+ parent_version_id: NotRequired[str | None]
893
+ snapshot_digest: NotRequired[str | None]
894
+ snapshot_id: NotRequired[str | None]
895
+ training_run: NotRequired[dict[str, Any] | None]
896
+ version: int
897
+
898
+
899
+ type NotificationType = Literal["mention", "reply", "review"]
900
+
901
+
902
+ class OcrRequest(TypedDict):
903
+ """
904
+ `POST /items/{id}/ocr`: the words of one page of a scanned PDF.
905
+ """
906
+
907
+ model_id: str
908
+ page: int
909
+
910
+
911
+ class OcrWord(TypedDict):
912
+ """
913
+ One word; `bbox` `[x_min, y_min, x_max, y_max]` in the page's points.
914
+ """
915
+
916
+ bbox: tuple[float, float, float, float]
917
+ text: str
918
+
919
+
920
+ class OidcProviderInfo(TypedDict):
921
+ """
922
+ The configured single sign-on provider, as the login page sees it (AUTH-1).
923
+ """
924
+
925
+ display_name: str
926
+ login_path: NotRequired[str]
927
+
928
+
929
+ class OrganizationalUseNotice(TypedDict):
930
+ """
931
+ Whether this Community install looks like it is being used by an organisation.
932
+ """
933
+
934
+ looks_organizational: bool
935
+ message: str | None
936
+ reasons: list[str]
937
+
938
+
939
+ class PageAuditEventRead(TypedDict):
940
+ items: list[AuditEventRead]
941
+ next_cursor: NotRequired[str | None]
942
+
943
+
944
+ class PageMlPlatformRead(TypedDict):
945
+ items: list[MlPlatformRead]
946
+ next_cursor: NotRequired[str | None]
947
+
948
+
949
+ class PageModelVersionRead(TypedDict):
950
+ items: list[ModelVersionRead]
951
+ next_cursor: NotRequired[str | None]
952
+
953
+
954
+ class PairAgreement(TypedDict):
955
+ """
956
+ Agreement between one pair of annotators.
957
+
958
+ `items` is `None` on `ItemAgreement` (one item; the count would always be
959
+ 1) and the number of shared items on `ProjectAgreement`.
960
+ """
961
+
962
+ a: str
963
+ b: str
964
+ cohen_kappa: float | None
965
+ items: NotRequired[int | None]
966
+ mean_iou: float | None
967
+ shape_f1: float | None
968
+ span_f1_exact: float | None
969
+ span_f1_overlap: float | None
970
+
971
+
972
+ class PersonalAnnotation(TypedDict):
973
+ """
974
+ Metadata only: the result is project content, not personal data.
975
+ """
976
+
977
+ created_at: str
978
+ duration_ms: int | None
979
+ id: str
980
+ item_id: str
981
+ kind: str
982
+ status: str
983
+ version: int
984
+
985
+
986
+ class PersonalApiKey(TypedDict):
987
+ created_at: str
988
+ expires_at: str | None
989
+ id: str
990
+ last_used_at: str | None
991
+ name: str
992
+ revoked_at: str | None
993
+ scopes: list[str]
994
+
995
+
996
+ class PersonalAuditEvent(TypedDict):
997
+ action: str
998
+ created_at: str
999
+ id: str
1000
+ ip: str | None
1001
+ target_id: str | None
1002
+ target_type: str
1003
+
1004
+
1005
+ class PersonalComment(TypedDict):
1006
+ annotation_id: str | None
1007
+ body: str
1008
+ created_at: str
1009
+ id: str
1010
+ item_id: str | None
1011
+ project_id: str
1012
+ resolved_at: str | None
1013
+
1014
+
1015
+ class PersonalMembership(TypedDict):
1016
+ created_at: str
1017
+ project_id: str
1018
+ project_name: str
1019
+ role: str
1020
+
1021
+
1022
+ class PersonalNotification(TypedDict):
1023
+ created_at: str
1024
+ id: str
1025
+ payload: dict[str, Any]
1026
+ read_at: str | None
1027
+ type: str
1028
+
1029
+
1030
+ class PersonalProfile(TypedDict):
1031
+ """
1032
+ The user row without credentials: flags stand in for secrets.
1033
+ """
1034
+
1035
+ created_at: str
1036
+ display_name: str
1037
+ email: str
1038
+ erased_at: str | None
1039
+ id: str
1040
+ idp_linked: bool
1041
+ is_active: bool
1042
+ is_service: bool
1043
+ is_superuser: bool
1044
+ last_seen_at: str | None
1045
+ mfa_enabled: bool
1046
+ organization_id: str
1047
+ updated_at: str
1048
+
1049
+
1050
+ class PersonalTask(TypedDict):
1051
+ id: str
1052
+ item_id: str
1053
+ project_id: str
1054
+ status: str
1055
+ type: str
1056
+
1057
+
1058
+ class PickResolve(TypedDict):
1059
+ """
1060
+ Resolve by copying one annotator's submitted consensus version verbatim.
1061
+ """
1062
+
1063
+ annotation_id: str
1064
+ method: NotRequired[Literal["pick"]]
1065
+
1066
+
1067
+ PointShape = TypedDict(
1068
+ "PointShape",
1069
+ {
1070
+ "attributes": NotRequired[dict[str, Any]],
1071
+ "class": str,
1072
+ "confidence": NotRequired[float | None],
1073
+ "frame": NotRequired[int | None],
1074
+ "id": str,
1075
+ "keyframe": NotRequired[bool],
1076
+ "outside": NotRequired[bool],
1077
+ "page": NotRequired[int | None],
1078
+ "point": tuple[float, float],
1079
+ "track_id": NotRequired[str | None],
1080
+ "type": NotRequired[Literal["point"]],
1081
+ },
1082
+ )
1083
+
1084
+
1085
+ PolygonShape = TypedDict(
1086
+ "PolygonShape",
1087
+ {
1088
+ "attributes": NotRequired[dict[str, Any]],
1089
+ "class": str,
1090
+ "confidence": NotRequired[float | None],
1091
+ "frame": NotRequired[int | None],
1092
+ "id": str,
1093
+ "keyframe": NotRequired[bool],
1094
+ "outside": NotRequired[bool],
1095
+ "page": NotRequired[int | None],
1096
+ "points": list[tuple[float, float]],
1097
+ "track_id": NotRequired[str | None],
1098
+ "type": NotRequired[Literal["polygon"]],
1099
+ },
1100
+ )
1101
+
1102
+
1103
+ PolylineShape = TypedDict(
1104
+ "PolylineShape",
1105
+ {
1106
+ "attributes": NotRequired[dict[str, Any]],
1107
+ "class": str,
1108
+ "confidence": NotRequired[float | None],
1109
+ "frame": NotRequired[int | None],
1110
+ "id": str,
1111
+ "keyframe": NotRequired[bool],
1112
+ "outside": NotRequired[bool],
1113
+ "page": NotRequired[int | None],
1114
+ "points": list[tuple[float, float]],
1115
+ "track_id": NotRequired[str | None],
1116
+ "type": NotRequired[Literal["polyline"]],
1117
+ },
1118
+ )
1119
+
1120
+
1121
+ type ProjectRole = Literal["owner", "annotator", "reviewer", "viewer"]
1122
+
1123
+
1124
+ RBoxShape = TypedDict(
1125
+ "RBoxShape",
1126
+ {
1127
+ "angle": float,
1128
+ "attributes": NotRequired[dict[str, Any]],
1129
+ "center": tuple[float, float],
1130
+ "class": str,
1131
+ "confidence": NotRequired[float | None],
1132
+ "frame": NotRequired[int | None],
1133
+ "id": str,
1134
+ "keyframe": NotRequired[bool],
1135
+ "outside": NotRequired[bool],
1136
+ "page": NotRequired[int | None],
1137
+ "size": tuple[float, float],
1138
+ "track_id": NotRequired[str | None],
1139
+ "type": NotRequired[Literal["rbox"]],
1140
+ },
1141
+ )
1142
+
1143
+
1144
+ RankingShape = TypedDict(
1145
+ "RankingShape",
1146
+ {
1147
+ "attributes": NotRequired[dict[str, Any]],
1148
+ "class": str,
1149
+ "confidence": NotRequired[float | None],
1150
+ "frame": NotRequired[int | None],
1151
+ "id": str,
1152
+ "keyframe": NotRequired[bool],
1153
+ "order": list[str],
1154
+ "outside": NotRequired[bool],
1155
+ "page": NotRequired[int | None],
1156
+ "track_id": NotRequired[str | None],
1157
+ "type": NotRequired[Literal["ranking"]],
1158
+ },
1159
+ )
1160
+
1161
+
1162
+ RatingShape = TypedDict(
1163
+ "RatingShape",
1164
+ {
1165
+ "attributes": NotRequired[dict[str, Any]],
1166
+ "class": str,
1167
+ "confidence": NotRequired[float | None],
1168
+ "frame": NotRequired[int | None],
1169
+ "id": str,
1170
+ "keyframe": NotRequired[bool],
1171
+ "outside": NotRequired[bool],
1172
+ "page": NotRequired[int | None],
1173
+ "target": str,
1174
+ "track_id": NotRequired[str | None],
1175
+ "type": NotRequired[Literal["rating"]],
1176
+ "value": int,
1177
+ },
1178
+ )
1179
+
1180
+
1181
+ class ReadyResponse(TypedDict):
1182
+ checks: dict[str, DependencyStatus]
1183
+ status: Literal["ready", "degraded"]
1184
+
1185
+
1186
+ type RejectionTarget = Literal["same_annotator", "queue"]
1187
+
1188
+
1189
+ RelationShape = TypedDict(
1190
+ "RelationShape",
1191
+ {
1192
+ "attributes": NotRequired[dict[str, Any]],
1193
+ "class": str,
1194
+ "confidence": NotRequired[float | None],
1195
+ "frame": NotRequired[int | None],
1196
+ "from": str,
1197
+ "id": str,
1198
+ "keyframe": NotRequired[bool],
1199
+ "outside": NotRequired[bool],
1200
+ "page": NotRequired[int | None],
1201
+ "to": str,
1202
+ "track_id": NotRequired[str | None],
1203
+ "type": NotRequired[Literal["relation"]],
1204
+ },
1205
+ )
1206
+
1207
+
1208
+ class RetrainRequest(TypedDict):
1209
+ """
1210
+ `POST /projects/{id}/retrain` (ML-9): ask subscribers to train.
1211
+
1212
+ Everything is optional context for the training pipeline; the platform
1213
+ does not train anything itself.
1214
+ """
1215
+
1216
+ ml_platform_id: NotRequired[str | None]
1217
+ model_id: NotRequired[str | None]
1218
+ note: NotRequired[str | None]
1219
+ snapshot_id: NotRequired[str | None]
1220
+
1221
+
1222
+ class RetrainResult(TypedDict):
1223
+ """
1224
+ How many webhook deliveries the request queued, and the job run it started.
1225
+ """
1226
+
1227
+ deliveries: int
1228
+ event: str
1229
+ ml_run: NotRequired[MlRun | None]
1230
+
1231
+
1232
+ type ReviewMode = Literal["required", "none", "sampled"]
1233
+
1234
+
1235
+ class ReviewStats(TypedDict):
1236
+ approved: int
1237
+ rejected: int
1238
+ rejection_rate: float
1239
+
1240
+
1241
+ class ScaleDef(TypedDict):
1242
+ """
1243
+ The integer scale of a `rating` class, e.g. 1-5 with named ends (§5 LLM-data).
1244
+ """
1245
+
1246
+ labels: NotRequired[dict[str, str]]
1247
+ max: int
1248
+ min: int
1249
+
1250
+
1251
+ class ScanRequest(TypedDict):
1252
+ """
1253
+ Body for queuing a source-scan job (SRC-2).
1254
+
1255
+ Both fields are optional overrides of the project's own `source_prefix`
1256
+ / `source_glob`; an empty body scans with the project's defaults.
1257
+ """
1258
+
1259
+ glob: NotRequired[str | None]
1260
+ prefix: NotRequired[str | None]
1261
+
1262
+
1263
+ class ScimTokenRead(TypedDict):
1264
+ """
1265
+ A freshly minted SCIM token, shown once, and the SCIM base path.
1266
+ """
1267
+
1268
+ path: str
1269
+ token: str
1270
+
1271
+
1272
+ class ScimTokenState(TypedDict):
1273
+ enabled: bool
1274
+
1275
+
1276
+ class SeatReportPeriod(TypedDict):
1277
+ """
1278
+ Seat use in one calendar month, clipped to the report range (LIC-30).
1279
+ """
1280
+
1281
+ active_users: int
1282
+ end: str
1283
+ overage: int | None
1284
+ peak_active_users: int
1285
+ peak_at: str | None
1286
+ start: str
1287
+
1288
+
1289
+ SegmentShape = TypedDict(
1290
+ "SegmentShape",
1291
+ {
1292
+ "attributes": NotRequired[dict[str, Any]],
1293
+ "channels": NotRequired[list[str] | None],
1294
+ "class": str,
1295
+ "confidence": NotRequired[float | None],
1296
+ "end": float,
1297
+ "frame": NotRequired[int | None],
1298
+ "id": str,
1299
+ "keyframe": NotRequired[bool],
1300
+ "outside": NotRequired[bool],
1301
+ "page": NotRequired[int | None],
1302
+ "speaker": NotRequired[str | None],
1303
+ "start": float,
1304
+ "text": NotRequired[str | None],
1305
+ "track_id": NotRequired[str | None],
1306
+ "type": NotRequired[Literal["segment"]],
1307
+ },
1308
+ )
1309
+
1310
+
1311
+ class ServiceAccountCreate(TypedDict):
1312
+ """
1313
+ Payload to create a service account (AUTH-4); the e-mail is synthetic.
1314
+ """
1315
+
1316
+ display_name: str
1317
+
1318
+
1319
+ class ShapeAgreement(TypedDict):
1320
+ """
1321
+ Pooled shape agreement: mean IoU of matched pairs and shape-F1 (QA-2).
1322
+ """
1323
+
1324
+ envelope_iou: NotRequired[bool]
1325
+ f1: float | None
1326
+ iou_threshold: float
1327
+ mean_iou: float | None
1328
+
1329
+
1330
+ class SkeletonDef(TypedDict):
1331
+ """
1332
+ Named keypoints of a `keypoints` class and the bones between them (TOOL).
1333
+
1334
+ The order of `points` is the order a `keypoints` shape stores them in.
1335
+ `edges` are 0-based index pairs into `points`.
1336
+ """
1337
+
1338
+ edges: NotRequired[list[tuple[int, int]]]
1339
+ points: list[str]
1340
+
1341
+
1342
+ class SkipRequest(TypedDict):
1343
+ """
1344
+ Payload for `POST /items/{item_id}/skip`; a reason is mandatory (TOOL-6).
1345
+ """
1346
+
1347
+ reason: str
1348
+
1349
+
1350
+ class SnapshotCreate(TypedDict):
1351
+ """
1352
+ Body for `POST /projects/{id}/snapshots`. Queues a snapshot job.
1353
+
1354
+ `filter` is a dataset filter (`services/datasets.py::DatasetFilter`,
1355
+ documented in CONTRACTS.md → snapshot); empty freezes every annotated
1356
+ item at its latest version.
1357
+ """
1358
+
1359
+ filter: NotRequired[dict[str, Any]]
1360
+ label_schema_version_id: NotRequired[str | None]
1361
+ name: str
1362
+ split: NotRequired[dict[str, Any] | None]
1363
+
1364
+
1365
+ class SnapshotDiffChanged(TypedDict):
1366
+ """
1367
+ An item frozen at different annotation versions on the two sides.
1368
+ """
1369
+
1370
+ from_version: int
1371
+ item_id: str
1372
+ path: str
1373
+ shapes: dict[str, int]
1374
+ to_version: int
1375
+
1376
+
1377
+ class SnapshotDiffClass(TypedDict):
1378
+ """
1379
+ Shape count per class on each side; `delta` is target minus base.
1380
+ """
1381
+
1382
+ base: int
1383
+ delta: int
1384
+ name: str
1385
+ target: int
1386
+
1387
+
1388
+ class SnapshotDiffEntry(TypedDict):
1389
+ """
1390
+ An item present on only one side.
1391
+ """
1392
+
1393
+ item_id: str
1394
+ path: str
1395
+ split: NotRequired[str | None]
1396
+ version: int
1397
+
1398
+
1399
+ class SnapshotDiffItems(TypedDict):
1400
+ """
1401
+ Item-level totals; complete even when the lists below are truncated.
1402
+ """
1403
+
1404
+ added: int
1405
+ changed: int
1406
+ removed: int
1407
+ split_moved: int
1408
+ unchanged: int
1409
+
1410
+
1411
+ class SnapshotDiffSide(TypedDict):
1412
+ """
1413
+ One of the two snapshots being compared.
1414
+ """
1415
+
1416
+ created_at: str
1417
+ digest: str
1418
+ id: str
1419
+ item_count: int
1420
+ name: str
1421
+ split_counts: NotRequired[dict[str, int] | None]
1422
+
1423
+
1424
+ class SnapshotLineageSnapshot(TypedDict):
1425
+ """
1426
+ The snapshot side of a lineage answer.
1427
+ """
1428
+
1429
+ created_at: str
1430
+ digest: str
1431
+ id: str
1432
+ item_count: int
1433
+ name: str
1434
+
1435
+
1436
+ class SnapshotLineageVersion(TypedDict):
1437
+ """
1438
+ A model version trained on the snapshot, with its downstream footprint.
1439
+ """
1440
+
1441
+ created_at: str
1442
+ id: str
1443
+ items_predicted: int
1444
+ model_id: str
1445
+ model_name: str
1446
+ snapshot_digest: str | None
1447
+ training_run: dict[str, Any] | None
1448
+ version: int
1449
+
1450
+
1451
+ class SnapshotPublishRequest(TypedDict):
1452
+ """
1453
+ `POST /projects/{id}/snapshots/{sid}/mlflow`.
1454
+ """
1455
+
1456
+ experiment: NotRequired[str | None]
1457
+ ml_platform_id: str
1458
+
1459
+
1460
+ class SnapshotPublishResult(TypedDict):
1461
+ """
1462
+ The MLflow run that stands for the snapshot.
1463
+ """
1464
+
1465
+ created: bool
1466
+ experiment_id: str
1467
+ experiment_name: str
1468
+ ml_platform_id: str
1469
+ run_id: str
1470
+ run_url: str | None
1471
+
1472
+
1473
+ class SnapshotRead(TypedDict):
1474
+ """
1475
+ A frozen, immutable dataset (EXP-1) as returned by the API.
1476
+ """
1477
+
1478
+ blob_path: str
1479
+ created_at: str
1480
+ created_by_id: str
1481
+ digest: str
1482
+ filter: dict[str, Any]
1483
+ id: str
1484
+ item_count: int
1485
+ label_schema_version_id: str
1486
+ name: str
1487
+ project_id: str
1488
+ split: NotRequired[dict[str, Any] | None]
1489
+
1490
+
1491
+ class SpanAgreement(TypedDict):
1492
+ """
1493
+ Pooled span agreement: exact and overlap F1 (QA-2).
1494
+ """
1495
+
1496
+ f1_exact: float | None
1497
+ f1_overlap: float | None
1498
+
1499
+
1500
+ type Box = tuple[float, float, float, float]
1501
+
1502
+
1503
+ SpanShape = TypedDict(
1504
+ "SpanShape",
1505
+ {
1506
+ "attributes": NotRequired[dict[str, Any]],
1507
+ "boxes": NotRequired[list[Box] | None],
1508
+ "class": str,
1509
+ "confidence": NotRequired[float | None],
1510
+ "end": NotRequired[int | None],
1511
+ "frame": NotRequired[int | None],
1512
+ "id": str,
1513
+ "keyframe": NotRequired[bool],
1514
+ "outside": NotRequired[bool],
1515
+ "page": NotRequired[int | None],
1516
+ "start": NotRequired[int | None],
1517
+ "text": NotRequired[str | None],
1518
+ "track_id": NotRequired[str | None],
1519
+ "type": NotRequired[Literal["span"]],
1520
+ },
1521
+ )
1522
+
1523
+
1524
+ class SplitGrid(TypedDict):
1525
+ """
1526
+ Split an image into `rows` x `cols` equal cells, 1-16 each.
1527
+
1528
+ Cells extend by `overlap_px` on their *inner* edges only (an edge cell's
1529
+ outer border stays at the image edge), then are clipped to the image.
1530
+ """
1531
+
1532
+ cols: int
1533
+ overlap_px: NotRequired[float]
1534
+ rows: int
1535
+
1536
+
1537
+ type Region = tuple[float, float, float, float]
1538
+
1539
+
1540
+ class SplitRequest(TypedDict):
1541
+ """
1542
+ Body of `POST /items/{id}/split`: exactly one of `grid` or `regions`.
1543
+ """
1544
+
1545
+ grid: NotRequired[SplitGrid | None]
1546
+ regions: NotRequired[list[Region] | None]
1547
+
1548
+
1549
+ type TaskStatus = Literal["open", "in_progress", "done", "cancelled"]
1550
+
1551
+
1552
+ type TaskType = Literal["annotate", "review"]
1553
+
1554
+
1555
+ class TaskTypeStats(TypedDict):
1556
+ cancelled: NotRequired[int]
1557
+ done: NotRequired[int]
1558
+ in_progress: NotRequired[int]
1559
+ open: NotRequired[int]
1560
+
1561
+
1562
+ class TaskUpdate(TypedDict):
1563
+ """
1564
+ Partial update for a live task (WF-6): only the fields present in the body change.
1565
+
1566
+ `deadline: null` / `assignee_id: null` clear the field; leaving a key out
1567
+ leaves it alone (see `model_fields_set`). Status and lock fields are not
1568
+ settable here — they move through claim / release / complete only.
1569
+ """
1570
+
1571
+ assignee_id: NotRequired[str | None]
1572
+ deadline: NotRequired[str | None]
1573
+ priority: NotRequired[int | None]
1574
+
1575
+
1576
+ class TelemetryPreview(TypedDict):
1577
+ """
1578
+ Exactly what the heartbeat would send, plus what was withheld and what was sent.
1579
+ """
1580
+
1581
+ active_users: int
1582
+ attempted_at: NotRequired[str | None]
1583
+ enabled: bool
1584
+ error: NotRequired[str | None]
1585
+ fingerprint: dict[str, Any]
1586
+ install_id: str | None
1587
+ last_payload: NotRequired[dict[str, Any] | None]
1588
+ licence_type: str
1589
+ notice: NotRequired[str | None]
1590
+ sent_at: NotRequired[str | None]
1591
+ server_configured: NotRequired[bool]
1592
+ version: str
1593
+ withheld: NotRequired[list[str]]
1594
+
1595
+
1596
+ class ThroughputDay(TypedDict):
1597
+ approved: NotRequired[int]
1598
+ day: str
1599
+ rejected: NotRequired[int]
1600
+ submitted: NotRequired[int]
1601
+
1602
+
1603
+ class ThumbnailRequest(TypedDict):
1604
+ """
1605
+ Body for `POST /projects/{id}/thumbnails` (IMG-8).
1606
+ """
1607
+
1608
+ force: NotRequired[bool]
1609
+ item_ids: NotRequired[list[str] | None]
1610
+
1611
+
1612
+ class TileJobRequest(TypedDict):
1613
+ """
1614
+ Body for `POST /projects/{id}/tiles` (IMG-1).
1615
+ """
1616
+
1617
+ force: NotRequired[bool]
1618
+ item_ids: NotRequired[list[str] | None]
1619
+
1620
+
1621
+ type Tile = tuple[int, int, int]
1622
+
1623
+
1624
+ class TileSignRequest(TypedDict):
1625
+ """
1626
+ Body for `POST /items/{id}/tiles/sign`: `[level, col, row]` triples.
1627
+ """
1628
+
1629
+ tiles: list[Tile]
1630
+
1631
+
1632
+ class TileSignResponse(TypedDict):
1633
+ """
1634
+ Signed URLs for the requested tiles, in the same order as the request.
1635
+ """
1636
+
1637
+ expires_in: int
1638
+ urls: list[str]
1639
+
1640
+
1641
+ class TokenResponse(TypedDict):
1642
+ """
1643
+ Access token issued on successful login.
1644
+ """
1645
+
1646
+ access_token: str
1647
+ expires_in: int
1648
+ mfa_setup_required: NotRequired[bool]
1649
+ token_type: NotRequired[str]
1650
+
1651
+
1652
+ type ToolType = Literal[
1653
+ "bbox",
1654
+ "rbox",
1655
+ "polygon",
1656
+ "polyline",
1657
+ "point",
1658
+ "mask",
1659
+ "keypoints",
1660
+ "span",
1661
+ "relation",
1662
+ "classification",
1663
+ "ranking",
1664
+ "rating",
1665
+ "segment",
1666
+ ]
1667
+
1668
+
1669
+ class UnreadCount(TypedDict):
1670
+ """
1671
+ `GET /notifications/unread-count`.
1672
+ """
1673
+
1674
+ count: int
1675
+
1676
+
1677
+ class UploadFileSpec(TypedDict):
1678
+ """
1679
+ One file the browser wants to upload. `path` is relative to the project's source prefix.
1680
+ """
1681
+
1682
+ content_type: NotRequired[str | None]
1683
+ path: str
1684
+ size_bytes: NotRequired[int | None]
1685
+
1686
+
1687
+ class UploadTarget(TypedDict):
1688
+ """
1689
+ Where and how to PUT one file. `path` is the object path the item will be registered at.
1690
+ """
1691
+
1692
+ headers: NotRequired[dict[str, str]]
1693
+ method: NotRequired[str]
1694
+ path: str
1695
+ url: str
1696
+
1697
+
1698
+ class UploadUrlsRequest(TypedDict):
1699
+ """
1700
+ Body for `POST /projects/{id}/uploads`.
1701
+ """
1702
+
1703
+ files: list[UploadFileSpec]
1704
+
1705
+
1706
+ class UploadUrlsResponse(TypedDict):
1707
+ """
1708
+ One write-scoped signed URL per requested file.
1709
+ """
1710
+
1711
+ prefix: str
1712
+ uploads: list[UploadTarget]
1713
+
1714
+
1715
+ class UsageNoticeOut(TypedDict):
1716
+ """
1717
+ One sign of seat sharing (LIC-31). A notice for the admin, never a block.
1718
+ """
1719
+
1720
+ count: int
1721
+ detail: str
1722
+ display_name: str
1723
+ email: str
1724
+ kind: str
1725
+ user_id: str
1726
+
1727
+
1728
+ class UsageNotices(TypedDict):
1729
+ """
1730
+ `GET /license/usage-notices`.
1731
+ """
1732
+
1733
+ notices: list[UsageNoticeOut]
1734
+ window_days: int
1735
+
1736
+
1737
+ class UserPreferencesUpdate(TypedDict):
1738
+ """
1739
+ `PATCH /auth/me`: the caller's own preferences; only keys present change.
1740
+ """
1741
+
1742
+ email_notifications: NotRequired[bool | None]
1743
+
1744
+
1745
+ class UserRead(TypedDict):
1746
+ """
1747
+ User as returned by the API. `password_hash` is never exposed.
1748
+ """
1749
+
1750
+ created_at: str
1751
+ display_name: str
1752
+ email: str
1753
+ email_notifications: NotRequired[bool]
1754
+ erased_at: NotRequired[str | None]
1755
+ id: str
1756
+ idp_subject: str | None
1757
+ is_active: bool
1758
+ is_service: NotRequired[bool]
1759
+ is_superuser: bool
1760
+ last_seen_at: str | None
1761
+ mfa_enabled: NotRequired[bool]
1762
+ organization_id: str
1763
+ updated_at: str
1764
+
1765
+
1766
+ class ValidationError(TypedDict):
1767
+ ctx: NotRequired[dict[str, Any]]
1768
+ input: NotRequired[Any]
1769
+ loc: list[str | int]
1770
+ msg: str
1771
+ type: str
1772
+
1773
+
1774
+ type WebhookDeliveryStatus = Literal["pending", "succeeded", "failed"]
1775
+
1776
+
1777
+ type WebhookFormat = Literal["json", "slack", "teams"]
1778
+
1779
+
1780
+ class WebhookRead(TypedDict):
1781
+ """
1782
+ A webhook as returned by the API; the secret is never included.
1783
+ """
1784
+
1785
+ created_at: str
1786
+ created_by_id: str | None
1787
+ description: str | None
1788
+ events: list[str]
1789
+ format: NotRequired[WebhookFormat]
1790
+ id: str
1791
+ is_active: bool
1792
+ last_delivery_at: str | None
1793
+ last_response_status: int | None
1794
+ organization_id: str
1795
+ project_id: str | None
1796
+ updated_at: str
1797
+ url: str
1798
+
1799
+
1800
+ class WebhookUpdate(TypedDict):
1801
+ """
1802
+ `PATCH /webhooks/{id}`: only keys present change. `rotate_secret: true`
1803
+ replaces the signing secret and returns the new one once.
1804
+ """
1805
+
1806
+ description: NotRequired[str | None]
1807
+ events: NotRequired[list[str] | None]
1808
+ format: NotRequired[WebhookFormat | None]
1809
+ is_active: NotRequired[bool | None]
1810
+ rotate_secret: NotRequired[bool]
1811
+ url: NotRequired[str | None]
1812
+
1813
+
1814
+ class WebhookUpdated(TypedDict):
1815
+ """
1816
+ `PATCH` response: `secret` is set only when it was rotated in this call.
1817
+ """
1818
+
1819
+ created_at: str
1820
+ created_by_id: str | None
1821
+ description: str | None
1822
+ events: list[str]
1823
+ format: NotRequired[WebhookFormat]
1824
+ id: str
1825
+ is_active: bool
1826
+ last_delivery_at: str | None
1827
+ last_response_status: int | None
1828
+ organization_id: str
1829
+ project_id: str | None
1830
+ secret: NotRequired[str | None]
1831
+ updated_at: str
1832
+ url: str
1833
+
1834
+
1835
+ class WorkflowConfig(TypedDict):
1836
+ """
1837
+ `project.workflow`, see CONTRACTS.md *Project workflow JSON* (WF-1).
1838
+
1839
+ Every field defaults to the standard annotate → review → approve flow, so
1840
+ `{}` and pre-existing rows behave as before. Unknown keys are refused so a
1841
+ typo cannot silently leave the default in force.
1842
+ """
1843
+
1844
+ allow_self_review: NotRequired[bool]
1845
+ allow_skip: NotRequired[bool]
1846
+ consensus_annotators: NotRequired[int]
1847
+ gold_every: NotRequired[int | None]
1848
+ rejection_returns_to: NotRequired[RejectionTarget]
1849
+ review: NotRequired[ReviewMode]
1850
+ review_sample_rate: NotRequired[float]
1851
+
1852
+
1853
+ type AppModelsItemItemStatus = Literal[
1854
+ "new",
1855
+ "prelabeled",
1856
+ "annotating",
1857
+ "submitted",
1858
+ "in_review",
1859
+ "approved",
1860
+ "rejected",
1861
+ "skipped",
1862
+ ]
1863
+
1864
+
1865
+ type AppSchemasItemItemStatus = Literal[
1866
+ "new",
1867
+ "prelabeled",
1868
+ "annotating",
1869
+ "submitted",
1870
+ "in_review",
1871
+ "approved",
1872
+ "rejected",
1873
+ "skipped",
1874
+ ]
1875
+
1876
+
1877
+ type Shapes = (
1878
+ BBoxShape
1879
+ | RBoxShape
1880
+ | PolygonShape
1881
+ | PolylineShape
1882
+ | PointShape
1883
+ | MaskShape
1884
+ | KeypointsShape
1885
+ | SpanShape
1886
+ | RelationShape
1887
+ | RankingShape
1888
+ | RatingShape
1889
+ | SegmentShape
1890
+ )
1891
+
1892
+
1893
+ class AnnotationResult(TypedDict):
1894
+ """
1895
+ Top-level annotation result stored in `annotation.result` (DATA-8).
1896
+ """
1897
+
1898
+ classification: NotRequired[dict[str, Any]]
1899
+ media_type: MediaType
1900
+ schema_version: int
1901
+ shapes: NotRequired[list[Shapes]]
1902
+
1903
+
1904
+ class AttributeDef(TypedDict):
1905
+ """
1906
+ One attribute definition, attached to a class or to top-level classification.
1907
+ """
1908
+
1909
+ default: NotRequired[Any]
1910
+ name: str
1911
+ options: NotRequired[list[str] | None]
1912
+ required: NotRequired[bool]
1913
+ type: AttributeType
1914
+
1915
+
1916
+ class AuthProviders(TypedDict):
1917
+ """
1918
+ Which sign-in methods this installation offers.
1919
+ """
1920
+
1921
+ local: NotRequired[bool]
1922
+ oidc: NotRequired[OidcProviderInfo | None]
1923
+
1924
+
1925
+ class BodyUploadImportJobApiV1ProjectsProjectIdImportsUploadPost(TypedDict):
1926
+ attribute_mapping: NotRequired[str | None]
1927
+ class_mapping: NotRequired[str | None]
1928
+ dry_run: NotRequired[bool]
1929
+ file: str
1930
+ format: str
1931
+ label_schema_version_id: NotRequired[str | None]
1932
+ status: NotRequired[ImportStatus]
1933
+
1934
+
1935
+ class BulkAssign(TypedDict):
1936
+ """
1937
+ Point the items' live `type` tasks at `assignee_id` (or nobody), and /
1938
+ or set their priority and deadline. An item without a live task of that
1939
+ type gets one opened when its status allows annotation (`annotate`) or
1940
+ review (`review`); items being worked on right now (`in_progress`) are
1941
+ skipped rather than pulled from under the annotator.
1942
+ """
1943
+
1944
+ action: Literal["assign"]
1945
+ assignee_id: NotRequired[str | None]
1946
+ deadline: NotRequired[str | None]
1947
+ item_ids: list[str]
1948
+ priority: NotRequired[int | None]
1949
+ type: NotRequired[TaskType]
1950
+
1951
+
1952
+ class BulkResult(TypedDict):
1953
+ """
1954
+ Outcome of a bulk request: how many items changed, and which did not.
1955
+ """
1956
+
1957
+ applied: int
1958
+ skipped: list[BulkSkipped]
1959
+
1960
+
1961
+ class ClaimRequest(TypedDict):
1962
+ """
1963
+ Optional JSON body for `POST /tasks/next`, alternative to the query parameter.
1964
+ """
1965
+
1966
+ project_id: NotRequired[str | None]
1967
+ type: NotRequired[TaskType | None]
1968
+
1969
+
1970
+ class ClassDef(TypedDict):
1971
+ """
1972
+ One annotation class: its display, tools and attributes.
1973
+ """
1974
+
1975
+ attributes: NotRequired[list[AttributeDef]]
1976
+ color: str
1977
+ display_name: str
1978
+ hotkey: NotRequired[str | None]
1979
+ name: str
1980
+ scale: NotRequired[ScaleDef | None]
1981
+ skeleton: NotRequired[SkeletonDef | None]
1982
+ tools: list[ToolType]
1983
+
1984
+
1985
+ class ConnectorCreate(TypedDict):
1986
+ """
1987
+ Payload to register a new storage connector.
1988
+
1989
+ `secret_ref` is a Key Vault / secret-store reference, never a raw secret
1990
+ (SEC/AUTH-7).
1991
+ """
1992
+
1993
+ config: NotRequired[dict[str, Any]]
1994
+ identity_type: ConnectorIdentity
1995
+ name: str
1996
+ secret_ref: NotRequired[str | None]
1997
+ type: ConnectorType
1998
+
1999
+
2000
+ class ConnectorRead(TypedDict):
2001
+ """
2002
+ Connector as returned by the API; `secret_ref` is never exposed, only its presence.
2003
+ """
2004
+
2005
+ config: dict[str, Any]
2006
+ created_at: str
2007
+ events_enabled: NotRequired[bool]
2008
+ has_secret: bool
2009
+ id: str
2010
+ identity_type: ConnectorIdentity
2011
+ name: str
2012
+ organization_id: str
2013
+ type: ConnectorType
2014
+ updated_at: str
2015
+
2016
+
2017
+ class CorrectionMetrics(TypedDict):
2018
+ """
2019
+ `GET /models/{id}/versions/{vid}/metrics` (ML-5).
2020
+ """
2021
+
2022
+ classes: list[CorrectionClassMetrics]
2023
+ items_accepted_unchanged: int
2024
+ items_corrected: int
2025
+ items_pending: int
2026
+ items_predicted: int
2027
+ mean_iou_adjusted: float | None
2028
+ model_version_id: str
2029
+ precision: float | None
2030
+ project_id: str | None
2031
+ recall: float | None
2032
+ shapes: CorrectionShapeCounts
2033
+
2034
+
2035
+ class DatasetFilter(TypedDict):
2036
+ """
2037
+ Which items a snapshot or export covers (EXP-2). Empty means every annotated item.
2038
+
2039
+ Every field is a further restriction on the *latest* annotation version
2040
+ of each item; the field list is documented in CONTRACTS.md → snapshot.
2041
+ """
2042
+
2043
+ annotated_after: NotRequired[str | None]
2044
+ annotated_before: NotRequired[str | None]
2045
+ annotation_status: NotRequired[list[AnnotationStatus] | None]
2046
+ annotator_ids: NotRequired[list[str] | None]
2047
+ classes: NotRequired[list[str] | None]
2048
+ item_status: NotRequired[list[AppModelsItemItemStatus] | None]
2049
+ path_prefix: NotRequired[str | None]
2050
+ source: NotRequired[list[AnnotationSource] | None]
2051
+
2052
+
2053
+ class ExportRequest(TypedDict):
2054
+ """
2055
+ Body for queuing an export job (EXP-5).
2056
+
2057
+ Either `snapshot_id` (export exactly that frozen set) or `filter` (export
2058
+ the latest annotation of every matching item right now). `split` picks
2059
+ one partition of a split snapshot (EXP-3); it needs `snapshot_id`.
2060
+ """
2061
+
2062
+ filter: NotRequired[DatasetFilter]
2063
+ format: str
2064
+ label_schema_version_id: NotRequired[str | None]
2065
+ snapshot_id: NotRequired[str | None]
2066
+ split: NotRequired[Literal["train", "val", "test"] | None]
2067
+
2068
+
2069
+ class HTTPValidationError(TypedDict):
2070
+ detail: NotRequired[list[ValidationError]]
2071
+
2072
+
2073
+ class ImportRequest(TypedDict):
2074
+ """
2075
+ Body for queuing an import job (EXP-6).
2076
+
2077
+ `path` names the file, `.zip` archive or `/`-terminated prefix on
2078
+ `connector_id` (default: the project's source connector). `dry_run`
2079
+ parses and matches without writing anything — the preview to run first.
2080
+ """
2081
+
2082
+ attribute_mapping: NotRequired[dict[str, dict[str, str | None]]]
2083
+ class_mapping: NotRequired[dict[str, str]]
2084
+ connector_id: NotRequired[str | None]
2085
+ dry_run: NotRequired[bool]
2086
+ format: str
2087
+ label_schema_version_id: NotRequired[str | None]
2088
+ path: str
2089
+ status: NotRequired[ImportStatus]
2090
+
2091
+
2092
+ class ItemAgreement(TypedDict):
2093
+ """
2094
+ Agreement over one item's consensus versions (embedded in `GET /items/{id}/consensus`).
2095
+ """
2096
+
2097
+ classification: NotRequired[list[ClassificationAgreement]]
2098
+ pairs: NotRequired[list[PairAgreement]]
2099
+ shapes: ShapeAgreement
2100
+ spans: SpanAgreement
2101
+
2102
+
2103
+ class ItemCreate(TypedDict):
2104
+ """
2105
+ Payload to register a new item under a project (project id comes from the route).
2106
+ """
2107
+
2108
+ connector_id: str
2109
+ etag: NotRequired[str | None]
2110
+ height: NotRequired[int | None]
2111
+ media_type: MediaType
2112
+ meta: NotRequired[dict[str, Any]]
2113
+ path: str
2114
+ size_bytes: int
2115
+ width: NotRequired[int | None]
2116
+
2117
+
2118
+ class ItemRead(TypedDict):
2119
+ """
2120
+ Item as returned by the API, with an optional short-lived signed media URL.
2121
+ """
2122
+
2123
+ connector_id: str
2124
+ created_at: str
2125
+ etag: str | None
2126
+ height: int | None
2127
+ id: str
2128
+ media_type: MediaType
2129
+ media_url: NotRequired[str | None]
2130
+ meta: dict[str, Any]
2131
+ path: str
2132
+ project_id: str
2133
+ size_bytes: int
2134
+ status: ItemStatusOutput
2135
+ thumbnail_url: NotRequired[str | None]
2136
+ updated_at: str
2137
+ width: int | None
2138
+
2139
+
2140
+ class ItemView(TypedDict):
2141
+ """
2142
+ `GET /items/{id}/views`: one companion view, signed (§5 multimodal).
2143
+ """
2144
+
2145
+ label: NotRequired[str | None]
2146
+ media_type: NotRequired[MediaType | None]
2147
+ path: str
2148
+ url: NotRequired[str | None]
2149
+
2150
+
2151
+ class JobRead(TypedDict):
2152
+ """
2153
+ Job as returned by the API, e.g. `GET /jobs/{id}` for status and progress.
2154
+ """
2155
+
2156
+ attempts: int
2157
+ created_at: str
2158
+ error: str | None
2159
+ finished_at: str | None
2160
+ id: str
2161
+ payload: dict[str, Any]
2162
+ progress: int
2163
+ project_id: str | None
2164
+ result: dict[str, Any] | None
2165
+ started_at: str | None
2166
+ status: JobStatusOutput
2167
+ type: JobTypeOutput
2168
+ updated_at: str
2169
+
2170
+
2171
+ class LabelSchemaDefinition(TypedDict):
2172
+ """
2173
+ The full label schema stored in `label_schema_version.definition`.
2174
+ """
2175
+
2176
+ classes: list[ClassDef]
2177
+ classification: NotRequired[list[AttributeDef]]
2178
+ version: int
2179
+
2180
+
2181
+ class MemberCreate(TypedDict):
2182
+ """
2183
+ Payload to add a member to a project — owner only.
2184
+
2185
+ Exactly one of `user_id` / `email` identifies the user to add; the other
2186
+ must be omitted.
2187
+ """
2188
+
2189
+ email: NotRequired[str | None]
2190
+ path_prefixes: NotRequired[list[str] | None]
2191
+ role: ProjectRole
2192
+ user_id: NotRequired[str | None]
2193
+
2194
+
2195
+ class MemberRead(TypedDict):
2196
+ """
2197
+ A project member, joined with the `user` row for display fields.
2198
+ """
2199
+
2200
+ created_at: str
2201
+ display_name: str
2202
+ email: str
2203
+ path_prefixes: NotRequired[list[str] | None]
2204
+ role: ProjectRole
2205
+ source: NotRequired[Literal["manual", "idp"]]
2206
+ user_id: str
2207
+
2208
+
2209
+ class MemberUpdate(TypedDict):
2210
+ """
2211
+ Payload to change a member's role and / or folders — owner only; keys present change.
2212
+ """
2213
+
2214
+ path_prefixes: NotRequired[list[str] | None]
2215
+ role: NotRequired[ProjectRole | None]
2216
+
2217
+
2218
+ class MlPlatformCreate(TypedDict):
2219
+ """
2220
+ Register a platform. `secret_ref` is a secret-store reference (AUTH-7).
2221
+ """
2222
+
2223
+ config: NotRequired[dict[str, Any]]
2224
+ identity_type: MlIdentity
2225
+ kind: MlPlatformKind
2226
+ name: str
2227
+ secret_ref: NotRequired[str | None]
2228
+ tracking_uri: str
2229
+
2230
+
2231
+ class ModelCreate(TypedDict):
2232
+ """
2233
+ Payload to register a new model endpoint.
2234
+
2235
+ `secret_ref` is a secret-store reference, never a raw credential
2236
+ (SEC/AUTH-7): the key or token for `api_key` / `bearer`, the client
2237
+ secret for `service_principal`, and absent for `none` and
2238
+ `managed_identity`. Entra identities also need `identity_config`.
2239
+ """
2240
+
2241
+ endpoint_url: NotRequired[str | None]
2242
+ identity_config: NotRequired[ModelIdentityConfig]
2243
+ identity_type: NotRequired[ModelIdentity]
2244
+ name: str
2245
+ secret_ref: NotRequired[str | None]
2246
+ task: ModelTask
2247
+
2248
+
2249
+ class ModelFamilyVersion(TypedDict):
2250
+ """
2251
+ A version in a derivation graph, with the model it belongs to (EXP-8).
2252
+ """
2253
+
2254
+ class_mapping: dict[str, str | None]
2255
+ created_at: str
2256
+ derivation: NotRequired[ModelDerivation | None]
2257
+ id: str
2258
+ metrics: dict[str, Any]
2259
+ model_id: str
2260
+ model_name: str
2261
+ model_task: ModelTask
2262
+ parent_version_id: NotRequired[str | None]
2263
+ snapshot_digest: NotRequired[str | None]
2264
+ snapshot_id: NotRequired[str | None]
2265
+ training_run: NotRequired[dict[str, Any] | None]
2266
+ version: int
2267
+
2268
+
2269
+ class ModelRead(TypedDict):
2270
+ """
2271
+ Model as returned by the API; `secret_ref` is never exposed, only its presence.
2272
+ """
2273
+
2274
+ created_at: str
2275
+ endpoint_url: str | None
2276
+ has_secret: bool
2277
+ id: str
2278
+ identity_config: ModelIdentityConfig
2279
+ identity_type: ModelIdentity
2280
+ name: str
2281
+ organization_id: str
2282
+ task: ModelTask
2283
+
2284
+
2285
+ class NotificationRead(TypedDict):
2286
+ """
2287
+ One notification as returned by the API.
2288
+ """
2289
+
2290
+ created_at: str
2291
+ id: str
2292
+ payload: dict[str, Any]
2293
+ read_at: str | None
2294
+ type: NotificationType
2295
+ user_id: str
2296
+
2297
+
2298
+ class OcrResult(TypedDict):
2299
+ """
2300
+ The words an `ocr` model read on a page. Nothing is stored.
2301
+ """
2302
+
2303
+ engine: str
2304
+ height: float
2305
+ page: int
2306
+ width: float
2307
+ words: list[OcrWord]
2308
+
2309
+
2310
+ class PageConnectorRead(TypedDict):
2311
+ items: list[ConnectorRead]
2312
+ next_cursor: NotRequired[str | None]
2313
+
2314
+
2315
+ class PageItemRead(TypedDict):
2316
+ items: list[ItemRead]
2317
+ next_cursor: NotRequired[str | None]
2318
+
2319
+
2320
+ class PageJobRead(TypedDict):
2321
+ items: list[JobRead]
2322
+ next_cursor: NotRequired[str | None]
2323
+
2324
+
2325
+ class PageModelRead(TypedDict):
2326
+ items: list[ModelRead]
2327
+ next_cursor: NotRequired[str | None]
2328
+
2329
+
2330
+ class PageNotificationRead(TypedDict):
2331
+ items: list[NotificationRead]
2332
+ next_cursor: NotRequired[str | None]
2333
+
2334
+
2335
+ class PageSnapshotRead(TypedDict):
2336
+ items: list[SnapshotRead]
2337
+ next_cursor: NotRequired[str | None]
2338
+
2339
+
2340
+ class PageWebhookRead(TypedDict):
2341
+ items: list[WebhookRead]
2342
+ next_cursor: NotRequired[str | None]
2343
+
2344
+
2345
+ class PersonalDataExport(TypedDict):
2346
+ """
2347
+ Everything the platform holds about one person (SEC-6 access).
2348
+ """
2349
+
2350
+ annotations: NotRequired[list[PersonalAnnotation]]
2351
+ api_keys: NotRequired[list[PersonalApiKey]]
2352
+ audit_events: NotRequired[list[PersonalAuditEvent]]
2353
+ comments: NotRequired[list[PersonalComment]]
2354
+ generated_at: str
2355
+ memberships: NotRequired[list[PersonalMembership]]
2356
+ notifications: NotRequired[list[PersonalNotification]]
2357
+ tasks: NotRequired[list[PersonalTask]]
2358
+ user: PersonalProfile
2359
+
2360
+
2361
+ class PrelabelCreate(TypedDict):
2362
+ """
2363
+ An external producer's pre-label (API-8): a model-authored draft.
2364
+ """
2365
+
2366
+ label_schema_version_id: NotRequired[str | None]
2367
+ model_version_id: str
2368
+ result: AnnotationResult
2369
+
2370
+
2371
+ class PrelabelFilter(TypedDict):
2372
+ """
2373
+ Which items a pre-labelling job covers (ML-2).
2374
+
2375
+ Defaults to the items a customer would normally want touched: unstarted
2376
+ and previously pre-labelled ones. Items with a human annotation version
2377
+ are never selected, whichever statuses are listed here (ML-10).
2378
+ """
2379
+
2380
+ item_status: NotRequired[list[AppSchemasItemItemStatus]]
2381
+ path_prefix: NotRequired[str | None]
2382
+
2383
+
2384
+ class PrelabelRequest(TypedDict):
2385
+ """
2386
+ Body for queuing a pre-labelling job (ML-2).
2387
+
2388
+ `limit` caps how many items are sent to the model in this run — a dry
2389
+ run over a handful of items before committing to the whole project
2390
+ (BYOM-7).
2391
+ """
2392
+
2393
+ confidence_threshold: NotRequired[float]
2394
+ filter: NotRequired[PrelabelFilter]
2395
+ label_schema_version_id: NotRequired[str | None]
2396
+ limit: NotRequired[int | None]
2397
+ model_version_id: str
2398
+ prioritize_uncertain: NotRequired[bool]
2399
+
2400
+
2401
+ class ProjectAgreement(TypedDict):
2402
+ """
2403
+ Project-wide inter-annotator agreement (`GET /projects/{id}/agreement`, QA-2).
2404
+ """
2405
+
2406
+ annotators: NotRequired[list[AgreementAnnotator]]
2407
+ classification: NotRequired[list[ClassificationAgreement]]
2408
+ items: int
2409
+ pairs: NotRequired[list[PairAgreement]]
2410
+ shapes: ShapeAgreement
2411
+ spans: SpanAgreement
2412
+
2413
+
2414
+ class ProjectCreate(TypedDict):
2415
+ """
2416
+ Payload to create a new project (organization id comes from the auth context).
2417
+ """
2418
+
2419
+ cache_connector_id: NotRequired[str | None]
2420
+ description: NotRequired[str | None]
2421
+ label_schema_id: NotRequired[str | None]
2422
+ name: str
2423
+ result_connector_id: NotRequired[str | None]
2424
+ settings: NotRequired[dict[str, Any]]
2425
+ source_connector_id: NotRequired[str | None]
2426
+ source_glob: NotRequired[str | None]
2427
+ source_prefix: NotRequired[str | None]
2428
+ workflow: NotRequired[WorkflowConfig]
2429
+
2430
+
2431
+ class ProjectRead(TypedDict):
2432
+ """
2433
+ Project as returned by the API.
2434
+ """
2435
+
2436
+ cache_connector_id: str | None
2437
+ created_at: str
2438
+ description: str | None
2439
+ id: str
2440
+ label_schema_id: str | None
2441
+ name: str
2442
+ organization_id: str
2443
+ result_connector_id: str | None
2444
+ settings: dict[str, Any]
2445
+ source_connector_id: str | None
2446
+ source_glob: str | None
2447
+ source_prefix: str | None
2448
+ updated_at: str
2449
+ workflow: WorkflowConfig
2450
+
2451
+
2452
+ class ProjectUpdate(TypedDict):
2453
+ """
2454
+ Partial update payload for a project; all fields optional.
2455
+ """
2456
+
2457
+ cache_connector_id: NotRequired[str | None]
2458
+ description: NotRequired[str | None]
2459
+ label_schema_id: NotRequired[str | None]
2460
+ name: NotRequired[str | None]
2461
+ result_connector_id: NotRequired[str | None]
2462
+ settings: NotRequired[dict[str, Any] | None]
2463
+ source_connector_id: NotRequired[str | None]
2464
+ source_glob: NotRequired[str | None]
2465
+ source_prefix: NotRequired[str | None]
2466
+ workflow: NotRequired[WorkflowConfig | None]
2467
+
2468
+
2469
+ class ReviewRequest(TypedDict):
2470
+ """
2471
+ A reviewer's verdict on a submitted annotation (WF-4).
2472
+ """
2473
+
2474
+ approve: bool
2475
+ comment: NotRequired[str | None]
2476
+ corrected_result: NotRequired[AnnotationResult | None]
2477
+
2478
+
2479
+ class SeatReport(TypedDict):
2480
+ """
2481
+ `GET /license/seat-report`: distinct active users per month for true-up (LIC-30).
2482
+
2483
+ Overage is measured against the licence in force now. Not signed; the
2484
+ licence terms back it.
2485
+ """
2486
+
2487
+ end: str
2488
+ generated_at: str
2489
+ install_id: str | None
2490
+ license_id: str | None
2491
+ licensee: str | None
2492
+ peak_active_users: int
2493
+ peak_overage: int | None
2494
+ periods: list[SeatReportPeriod]
2495
+ seat_limit: int | None
2496
+ seats: int | None
2497
+ start: str
2498
+ tier: str
2499
+
2500
+
2501
+ class SnapshotDiff(TypedDict):
2502
+ """
2503
+ `GET /projects/{id}/snapshots/{base}/diff/{target}` (EXP-4).
2504
+ """
2505
+
2506
+ added: list[SnapshotDiffEntry]
2507
+ base: SnapshotDiffSide
2508
+ changed: list[SnapshotDiffChanged]
2509
+ classes: list[SnapshotDiffClass]
2510
+ items: SnapshotDiffItems
2511
+ removed: list[SnapshotDiffEntry]
2512
+ target: SnapshotDiffSide
2513
+ truncated: bool
2514
+
2515
+
2516
+ class SnapshotLineage(TypedDict):
2517
+ """
2518
+ `GET /projects/{id}/snapshots/{sid}/lineage` (EXP-8).
2519
+ """
2520
+
2521
+ snapshot: SnapshotLineageSnapshot
2522
+ versions: list[SnapshotLineageVersion]
2523
+
2524
+
2525
+ class TaskCreate(TypedDict):
2526
+ """
2527
+ Payload to create/assign a task for an item (project id comes from the route).
2528
+ """
2529
+
2530
+ assignee_id: NotRequired[str | None]
2531
+ deadline: NotRequired[str | None]
2532
+ item_id: str
2533
+ priority: NotRequired[int]
2534
+ slot: NotRequired[int | None]
2535
+ type: TaskType
2536
+
2537
+
2538
+ class TaskRead(TypedDict):
2539
+ """
2540
+ Task as returned by the API.
2541
+ """
2542
+
2543
+ assignee_id: str | None
2544
+ created_at: str
2545
+ deadline: str | None
2546
+ gold: NotRequired[bool]
2547
+ id: str
2548
+ item_id: str
2549
+ locked_by_id: str | None
2550
+ locked_until: str | None
2551
+ priority: int
2552
+ project_id: str
2553
+ region: NotRequired[tuple[float, float, float, float] | None]
2554
+ slot: NotRequired[int | None]
2555
+ status: TaskStatus
2556
+ type: TaskType
2557
+ updated_at: str
2558
+
2559
+
2560
+ class TaskStats(TypedDict):
2561
+ annotate: TaskTypeStats
2562
+ review: TaskTypeStats
2563
+
2564
+
2565
+ class WebhookCreate(TypedDict):
2566
+ """
2567
+ `POST /webhooks`: subscribe a URL to events.
2568
+
2569
+ `project_id` null subscribes to every project in the organisation
2570
+ (superuser only); set, the caller must own that project. `events` names
2571
+ the events to receive, or `["*"]` for all of them.
2572
+ """
2573
+
2574
+ description: NotRequired[str | None]
2575
+ events: list[str]
2576
+ format: NotRequired[WebhookFormat]
2577
+ is_active: NotRequired[bool]
2578
+ project_id: NotRequired[str | None]
2579
+ url: str
2580
+
2581
+
2582
+ class WebhookCreated(TypedDict):
2583
+ """
2584
+ The freshly created (or rotated) webhook, carrying `secret` exactly once.
2585
+ """
2586
+
2587
+ created_at: str
2588
+ created_by_id: str | None
2589
+ description: str | None
2590
+ events: list[str]
2591
+ format: NotRequired[WebhookFormat]
2592
+ id: str
2593
+ is_active: bool
2594
+ last_delivery_at: str | None
2595
+ last_response_status: int | None
2596
+ organization_id: str
2597
+ project_id: str | None
2598
+ secret: str
2599
+ updated_at: str
2600
+ url: str
2601
+
2602
+
2603
+ class WebhookDeliveryRead(TypedDict):
2604
+ """
2605
+ One delivery, for the per-hook delivery log.
2606
+ """
2607
+
2608
+ attempts: int
2609
+ created_at: str
2610
+ delivered_at: str | None
2611
+ error: str | None
2612
+ event: str
2613
+ id: str
2614
+ next_attempt_at: str
2615
+ payload: dict[str, Any]
2616
+ response_status: int | None
2617
+ status: WebhookDeliveryStatus
2618
+ webhook_id: str
2619
+
2620
+
2621
+ class AnnotationCreate(TypedDict):
2622
+ """
2623
+ A new annotation version.
2624
+ """
2625
+
2626
+ duration_ms: NotRequired[int | None]
2627
+ label_schema_version_id: str
2628
+ result: AnnotationResult
2629
+ submit: NotRequired[bool]
2630
+ task_id: NotRequired[str | None]
2631
+
2632
+
2633
+ class ConsensusRead(TypedDict):
2634
+ """
2635
+ `GET /items/{id}/consensus` response body (QA-1, QA-2, QA-3).
2636
+ """
2637
+
2638
+ agreement: ItemAgreement
2639
+ annotators: list[ConsensusAnnotatorRead]
2640
+ conflicts: list[str]
2641
+ expected: int
2642
+ preview: AnnotationResult
2643
+
2644
+
2645
+ class ModelFamily(TypedDict):
2646
+ """
2647
+ Every version connected to a model's versions through parent links.
2648
+ """
2649
+
2650
+ versions: list[ModelFamilyVersion]
2651
+
2652
+
2653
+ class PageProjectRead(TypedDict):
2654
+ items: list[ProjectRead]
2655
+ next_cursor: NotRequired[str | None]
2656
+
2657
+
2658
+ class PageTaskRead(TypedDict):
2659
+ items: list[TaskRead]
2660
+ next_cursor: NotRequired[str | None]
2661
+
2662
+
2663
+ class PageWebhookDeliveryRead(TypedDict):
2664
+ items: list[WebhookDeliveryRead]
2665
+ next_cursor: NotRequired[str | None]
2666
+
2667
+
2668
+ class ProjectStats(TypedDict):
2669
+ annotations: AnnotationStats
2670
+ annotators: list[AnnotatorStats]
2671
+ classes: list[ClassCount]
2672
+ items: ItemStats
2673
+ review: ReviewStats
2674
+ tasks: TaskStats
2675
+ throughput: list[ThroughputDay]
2676
+
2677
+
2678
+ class SplitResponse(TypedDict):
2679
+ """
2680
+ One region task per region opened by the split.
2681
+ """
2682
+
2683
+ tasks: list[TaskRead]