docforge-sdk 0.21.2__tar.gz → 0.22.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 (79) hide show
  1. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/PKG-INFO +1 -1
  2. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/__init__.py +9 -1
  3. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/_version.py +1 -1
  4. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/models/__init__.py +10 -1
  5. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/models/documents.py +47 -1
  6. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/resources/documents.py +43 -1
  7. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/tests/openapi_snapshot.json +117 -0
  8. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/tests/parity_map.py +9 -1
  9. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/tests/route_map.py +1 -0
  10. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/.gitignore +0 -0
  11. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/.python-version +0 -0
  12. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/LICENSE +0 -0
  13. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/README.md +0 -0
  14. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/_exceptions.py +0 -0
  15. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/_requestspec.py +0 -0
  16. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/_transport_async.py +0 -0
  17. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/_transport_base.py +0 -0
  18. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/_transport_sync.py +0 -0
  19. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/client.py +0 -0
  20. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/models/_shared.py +0 -0
  21. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/models/audit.py +0 -0
  22. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/models/auth.py +0 -0
  23. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/models/blobs.py +0 -0
  24. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/models/capabilities.py +0 -0
  25. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/models/collections.py +0 -0
  26. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/models/corpus.py +0 -0
  27. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/models/estimate.py +0 -0
  28. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/models/explorer.py +0 -0
  29. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/models/health.py +0 -0
  30. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/models/ir.py +0 -0
  31. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/models/jobs.py +0 -0
  32. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/models/pipelines.py +0 -0
  33. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/models/preview.py +0 -0
  34. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/models/reingest.py +0 -0
  35. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/models/search.py +0 -0
  36. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/models/snippets.py +0 -0
  37. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/models/storage.py +0 -0
  38. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/models/trace.py +0 -0
  39. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/models/transfers.py +0 -0
  40. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/py.typed +0 -0
  41. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/resources/__init__.py +0 -0
  42. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/resources/_base.py +0 -0
  43. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/resources/audit.py +0 -0
  44. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/resources/auth.py +0 -0
  45. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/resources/blobs.py +0 -0
  46. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/resources/capabilities.py +0 -0
  47. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/resources/collections.py +0 -0
  48. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/resources/corpus.py +0 -0
  49. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/resources/explorer.py +0 -0
  50. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/resources/health.py +0 -0
  51. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/resources/jobs.py +0 -0
  52. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/resources/pipelines.py +0 -0
  53. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/resources/search.py +0 -0
  54. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/resources/snippets.py +0 -0
  55. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/docforge_sdk/resources/transfers.py +0 -0
  56. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/pyproject.toml +0 -0
  57. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/tests/__init__.py +0 -0
  58. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/tests/check_schema_drift.py +0 -0
  59. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/tests/live/__init__.py +0 -0
  60. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/tests/live/test_openapi_parity_live.py +0 -0
  61. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/tests/unit/__init__.py +0 -0
  62. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/tests/unit/test_audit.py +0 -0
  63. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/tests/unit/test_auth.py +0 -0
  64. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/tests/unit/test_blobs.py +0 -0
  65. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/tests/unit/test_collections.py +0 -0
  66. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/tests/unit/test_corpus.py +0 -0
  67. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/tests/unit/test_documents.py +0 -0
  68. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/tests/unit/test_explorer.py +0 -0
  69. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/tests/unit/test_health.py +0 -0
  70. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/tests/unit/test_jobs.py +0 -0
  71. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/tests/unit/test_models_offline_parity.py +0 -0
  72. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/tests/unit/test_pipelines.py +0 -0
  73. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/tests/unit/test_resource_parity.py +0 -0
  74. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/tests/unit/test_route_coverage.py +0 -0
  75. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/tests/unit/test_search.py +0 -0
  76. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/tests/unit/test_snippets.py +0 -0
  77. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/tests/unit/test_transfers.py +0 -0
  78. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/tests/unit/test_transport.py +0 -0
  79. {docforge_sdk-0.21.2 → docforge_sdk-0.22.0}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: docforge-sdk
3
- Version: 0.21.2
3
+ Version: 0.22.0
4
4
  Summary: Typed async + sync Python client for the DocForge REST API (standalone, zero server deps).
5
5
  Project-URL: Homepage, https://github.com/Florian-BARRE/docforge
6
6
  Project-URL: Repository, https://github.com/Florian-BARRE/docforge
@@ -51,7 +51,13 @@ from .models.collections import (
51
51
  )
52
52
 
53
53
  # ------------------- Documents models ------------------- #
54
- from .models.documents import DocumentEnabledResponse, EnabledPatch, UploadAccepted
54
+ from .models.documents import (
55
+ DocumentEnabledResponse,
56
+ EnabledPatch,
57
+ MetadataUpdateResponse,
58
+ MetadataValuesPatch,
59
+ UploadAccepted,
60
+ )
55
61
 
56
62
  # ------------------- Estimate models ------------------- #
57
63
  from .models.estimate import (
@@ -188,6 +194,8 @@ __all__ = [
188
194
  "UploadAccepted",
189
195
  "EnabledPatch",
190
196
  "DocumentEnabledResponse",
197
+ "MetadataValuesPatch",
198
+ "MetadataUpdateResponse",
191
199
  # Estimate
192
200
  "CollectionEstimateRequest",
193
201
  "EstimateAssumptions",
@@ -2,4 +2,4 @@
2
2
  # Single source of truth for the package version. Hatchling reads ``__version__`` from this file to
3
3
  # populate the distribution metadata (see ``[tool.hatch.version]`` in pyproject.toml).
4
4
 
5
- __version__ = "0.21.2"
5
+ __version__ = "0.22.0"
@@ -55,7 +55,14 @@ from .corpus import (
55
55
  )
56
56
 
57
57
  # ------------------- Documents models ------------------- #
58
- from .documents import DocumentEnabledResponse, DocumentView, EnabledPatch, UploadAccepted
58
+ from .documents import (
59
+ DocumentEnabledResponse,
60
+ DocumentView,
61
+ EnabledPatch,
62
+ MetadataUpdateResponse,
63
+ MetadataValuesPatch,
64
+ UploadAccepted,
65
+ )
59
66
 
60
67
  # ------------------- Estimate models ------------------- #
61
68
  from .estimate import (
@@ -228,6 +235,8 @@ __all__ = [
228
235
  "UploadAccepted",
229
236
  "EnabledPatch",
230
237
  "DocumentEnabledResponse",
238
+ "MetadataValuesPatch",
239
+ "MetadataUpdateResponse",
231
240
  "DocumentView",
232
241
  # Snippets
233
242
  "SNIPPET_FILE_EXTENSION",
@@ -5,6 +5,9 @@
5
5
  # endpoints stream a raw text body with a Content-Type header rather than a JSON body, mirroring the
6
6
  # blobs resource's BlobContent wrapper.
7
7
 
8
+ # ====== Standard Library Imports ======
9
+ from typing import Any
10
+
8
11
  # ====== Third-Party Library Imports ======
9
12
  from pydantic import BaseModel, Field
10
13
 
@@ -49,6 +52,42 @@ class DocumentEnabledResponse(BaseModel):
49
52
  enabled: bool = Field(description="The new searchability state.")
50
53
 
51
54
 
55
+ class MetadataValuesPatch(BaseModel):
56
+ """
57
+ The metadata VALUES to write on a document (field_name -> new value), the cheap value-edit.
58
+
59
+ Attributes:
60
+ values (dict[str, Any]): Map of metadata field name -> new value. DOCUMENT-scope USER or
61
+ GENERATED fields only; a chunk-scope or unknown field is rejected (422). A value's shape
62
+ must match its field type (scalar, or a list for the *_list types).
63
+ """
64
+
65
+ values: dict[str, Any] = Field(
66
+ min_length=1,
67
+ description="Map of metadata field name -> new value (document-scope fields only).",
68
+ )
69
+
70
+
71
+ class MetadataUpdateResponse(BaseModel):
72
+ """
73
+ The result of a document metadata value edit.
74
+
75
+ Attributes:
76
+ updated_fields (list[str]): The field names whose values were written.
77
+ reembedding (bool): True when a changed field feeds a named vector (semantic/lexical) and a
78
+ re-embed job was enqueued.
79
+ reembed_fields (list[str]): The changed fields that need their metadata vectors re-embedded.
80
+ job_id (str | None): The enqueued re-embed job's id, or null when nothing needed re-embedding.
81
+ """
82
+
83
+ updated_fields: list[str] = Field(description="Field names whose values were written.")
84
+ reembedding: bool = Field(
85
+ description="A semantic/lexical field changed - a re-embed was queued."
86
+ )
87
+ reembed_fields: list[str] = Field(description="Changed fields needing a metadata re-embed.")
88
+ job_id: str | None = Field(default=None, description="The re-embed job's UUID, or null.")
89
+
90
+
52
91
  class DocumentView(BaseModel):
53
92
  """
54
93
  A rendered document view's raw text plus its server-declared media type.
@@ -62,4 +101,11 @@ class DocumentView(BaseModel):
62
101
  mime_type: str = Field(description="The media type the server declared for the view.")
63
102
 
64
103
 
65
- __all__ = ["UploadAccepted", "EnabledPatch", "DocumentEnabledResponse", "DocumentView"]
104
+ __all__ = [
105
+ "UploadAccepted",
106
+ "EnabledPatch",
107
+ "DocumentEnabledResponse",
108
+ "MetadataValuesPatch",
109
+ "MetadataUpdateResponse",
110
+ "DocumentView",
111
+ ]
@@ -10,7 +10,14 @@ from typing import Any
10
10
 
11
11
  # ====== Local Project Imports ======
12
12
  from .._requestspec import RequestSpec
13
- from ..models.documents import DocumentEnabledResponse, DocumentView, EnabledPatch, UploadAccepted
13
+ from ..models.documents import (
14
+ DocumentEnabledResponse,
15
+ DocumentView,
16
+ EnabledPatch,
17
+ MetadataUpdateResponse,
18
+ MetadataValuesPatch,
19
+ UploadAccepted,
20
+ )
14
21
  from ..models.trace import TracePurgeResult
15
22
  from ._base import AsyncResource, SyncResource, _ResourceMixin
16
23
 
@@ -68,6 +75,14 @@ class _DocumentsSpecs(_ResourceMixin):
68
75
  json=EnabledPatch(enabled=enabled).model_dump(mode="json"),
69
76
  )
70
77
 
78
+ def _update_metadata_spec(self, document_id: str, values: dict[str, Any]) -> RequestSpec:
79
+ """A PATCH writing metadata VALUES (document-scope fields) onto one document in place."""
80
+ return RequestSpec(
81
+ "PATCH",
82
+ f"{self._DOCUMENTS_PATH}/{document_id}/metadata",
83
+ json=MetadataValuesPatch(values=values).model_dump(mode="json"),
84
+ )
85
+
71
86
  def _reingest_spec(self, document_id: str, force: bool) -> RequestSpec:
72
87
  """A POST re-running the full ingestion of one document (``force`` bypasses the doc cache)."""
73
88
  return RequestSpec(
@@ -143,6 +158,27 @@ class AsyncDocuments(AsyncResource, _DocumentsSpecs):
143
158
  self._set_enabled_spec(document_id, enabled), DocumentEnabledResponse
144
159
  )
145
160
 
161
+ async def update_metadata(
162
+ self, document_id: str, values: dict[str, Any]
163
+ ) -> MetadataUpdateResponse:
164
+ """
165
+ Update a document's metadata VALUES in place (document-scope fields only).
166
+
167
+ Filterable changes apply instantly; semantic/lexical changes enqueue a background re-embed
168
+ whose ``job_id`` can be polled. Unknown/chunk-scope fields or bad values raise a
169
+ ValidationError (422); an unknown document raises NotFound (404).
170
+
171
+ Args:
172
+ document_id (str): The document to edit.
173
+ values (dict[str, Any]): Map of metadata field name -> new value (at least one entry).
174
+
175
+ Returns:
176
+ MetadataUpdateResponse: Written fields, whether a re-embed was queued, and its job id.
177
+ """
178
+ return await self._transport.request(
179
+ self._update_metadata_spec(document_id, values), MetadataUpdateResponse
180
+ )
181
+
146
182
  async def reingest(self, document_id: str, force: bool = False) -> UploadAccepted:
147
183
  """
148
184
  Re-run the full ingestion of a single document.
@@ -251,6 +287,12 @@ class SyncDocuments(SyncResource, _DocumentsSpecs):
251
287
  self._set_enabled_spec(document_id, enabled), DocumentEnabledResponse
252
288
  )
253
289
 
290
+ def update_metadata(self, document_id: str, values: dict[str, Any]) -> MetadataUpdateResponse:
291
+ """Update a document's metadata VALUES in place (a semantic/lexical change queues a re-embed)."""
292
+ return self._transport.request(
293
+ self._update_metadata_spec(document_id, values), MetadataUpdateResponse
294
+ )
295
+
254
296
  def reingest(self, document_id: str, force: bool = False) -> UploadAccepted:
255
297
  """Re-run the full ingestion of a single document (``force`` bypasses the doc cache)."""
256
298
  return self._transport.request(self._reingest_spec(document_id, force), UploadAccepted)
@@ -1271,6 +1271,60 @@
1271
1271
  }
1272
1272
  }
1273
1273
  },
1274
+ "/api/v1/documents/{document_id}/metadata": {
1275
+ "patch": {
1276
+ "tags": [
1277
+ "documents"
1278
+ ],
1279
+ "summary": "Update Document Metadata",
1280
+ "description": "Edit a document's metadata VALUES in place \u2014 no re-ingest, chunk content untouched.\n\nThe cheap per-document value edit: the new values are validated against the collection's schema,\nwritten to Postgres, and the filterable Qdrant payloads are repainted synchronously (instant, no\nembed). When a CHANGED field feeds a named vector (semantic/lexical), a lightweight worker job is\nenqueued to re-embed ONLY the short metadata values onto the document's points \u2014 the index\nsignature is unchanged, so this never triggers a reindex. Accepts DOCUMENT-scope USER and\nGENERATED fields (a GENERATED override is overwritten again on the next reingest/metagen);\nchunk-scope and unknown fields are rejected with 422.\n\nReturns:\n MetadataUpdateResponse: The fields that actually changed, whether a re-embed was queued, and\n the reconciliation job id (set when a semantic/lexical field changed or a filterable\n repaint needs repair; null otherwise); 404 when the document is unknown.",
1281
+ "operationId": "update_document_metadata_api_v1_documents__document_id__metadata_patch",
1282
+ "parameters": [
1283
+ {
1284
+ "name": "document_id",
1285
+ "in": "path",
1286
+ "required": true,
1287
+ "schema": {
1288
+ "type": "string",
1289
+ "format": "uuid",
1290
+ "title": "Document Id"
1291
+ }
1292
+ }
1293
+ ],
1294
+ "requestBody": {
1295
+ "required": true,
1296
+ "content": {
1297
+ "application/json": {
1298
+ "schema": {
1299
+ "$ref": "#/components/schemas/MetadataValuesPatch"
1300
+ }
1301
+ }
1302
+ }
1303
+ },
1304
+ "responses": {
1305
+ "200": {
1306
+ "description": "Successful Response",
1307
+ "content": {
1308
+ "application/json": {
1309
+ "schema": {
1310
+ "$ref": "#/components/schemas/MetadataUpdateResponse"
1311
+ }
1312
+ }
1313
+ }
1314
+ },
1315
+ "422": {
1316
+ "description": "Validation Error",
1317
+ "content": {
1318
+ "application/json": {
1319
+ "schema": {
1320
+ "$ref": "#/components/schemas/HTTPValidationError"
1321
+ }
1322
+ }
1323
+ }
1324
+ }
1325
+ }
1326
+ }
1327
+ },
1274
1328
  "/api/v1/documents/{document_id}/trace-payloads/purge": {
1275
1329
  "post": {
1276
1330
  "tags": [
@@ -9062,6 +9116,51 @@
9062
9116
  "title": "MetadataFilter",
9063
9117
  "description": "One dynamic document-metadata predicate, addressed by field name.\n\nAttributes:\n field (str): The metadata field name (must exist in the collection schema + be filterable).\n op (str): The comparison \u2014 ``eq``/``contains`` (string/text), ``in`` (membership; matches\n any element for list-typed fields), ``gte``/``lte`` (int/float/datetime).\n value (Any): The comparison value, typed by the field (a list for ``in``)."
9064
9118
  },
9119
+ "MetadataUpdateResponse": {
9120
+ "properties": {
9121
+ "updated_fields": {
9122
+ "items": {
9123
+ "type": "string"
9124
+ },
9125
+ "type": "array",
9126
+ "title": "Updated Fields",
9127
+ "description": "Field names whose values were written."
9128
+ },
9129
+ "reembedding": {
9130
+ "type": "boolean",
9131
+ "title": "Reembedding",
9132
+ "description": "A semantic/lexical field changed \u2014 a re-embed was queued."
9133
+ },
9134
+ "reembed_fields": {
9135
+ "items": {
9136
+ "type": "string"
9137
+ },
9138
+ "type": "array",
9139
+ "title": "Reembed Fields",
9140
+ "description": "Changed fields needing a metadata re-embed."
9141
+ },
9142
+ "job_id": {
9143
+ "anyOf": [
9144
+ {
9145
+ "type": "string"
9146
+ },
9147
+ {
9148
+ "type": "null"
9149
+ }
9150
+ ],
9151
+ "title": "Job Id",
9152
+ "description": "The re-embed job's UUID, or null."
9153
+ }
9154
+ },
9155
+ "type": "object",
9156
+ "required": [
9157
+ "updated_fields",
9158
+ "reembedding",
9159
+ "reembed_fields"
9160
+ ],
9161
+ "title": "MetadataUpdateResponse",
9162
+ "description": "The result of a document metadata value edit.\n\nAttributes:\n updated_fields (list[str]): The field names whose values were written.\n reembedding (bool): True when a changed field feeds a named vector (semantic/lexical) and a\n re-embed job was enqueued.\n reembed_fields (list[str]): The changed fields that need their metadata vectors re-embedded.\n job_id (str | None): The enqueued re-embed job's id, or null when nothing needed re-embedding."
9163
+ },
9065
9164
  "MetadataValue": {
9066
9165
  "properties": {
9067
9166
  "field_name": {
@@ -9087,6 +9186,24 @@
9087
9186
  "title": "MetadataValue",
9088
9187
  "description": "One resolved metadata value \u2014 the field NAME (joined from the collection schema), the stored\nvalue, and the origin that actually filled THIS value (user upload / pipeline / metagen)."
9089
9188
  },
9189
+ "MetadataValuesPatch": {
9190
+ "properties": {
9191
+ "values": {
9192
+ "additionalProperties": true,
9193
+ "type": "object",
9194
+ "minProperties": 1,
9195
+ "title": "Values",
9196
+ "description": "Map of metadata field name \u2192 new value (document-scope fields only)."
9197
+ }
9198
+ },
9199
+ "additionalProperties": false,
9200
+ "type": "object",
9201
+ "required": [
9202
+ "values"
9203
+ ],
9204
+ "title": "MetadataValuesPatch",
9205
+ "description": "The metadata VALUES to write on a document (field_name \u2192 new value), the cheap value-edit.\n\nAttributes:\n values (dict[str, Any]): Map of metadata field name \u2192 new value. DOCUMENT-scope USER or\n GENERATED fields only; a chunk-scope or unknown field is rejected (422). A value's shape\n must match its field type (scalar, or a list for the *_list types)."
9206
+ },
9090
9207
  "ModelRateOverride": {
9091
9208
  "properties": {
9092
9209
  "input": {
@@ -44,7 +44,13 @@ from docforge_sdk.models.corpus import (
44
44
  Pagination,
45
45
  TextFilter,
46
46
  )
47
- from docforge_sdk.models.documents import DocumentEnabledResponse, EnabledPatch, UploadAccepted
47
+ from docforge_sdk.models.documents import (
48
+ DocumentEnabledResponse,
49
+ EnabledPatch,
50
+ MetadataUpdateResponse,
51
+ MetadataValuesPatch,
52
+ UploadAccepted,
53
+ )
48
54
  from docforge_sdk.models.estimate import (
49
55
  AssumptionOverrides,
50
56
  CollectionEstimateRequest,
@@ -197,6 +203,8 @@ MODELS: dict[str, type[BaseModel]] = {
197
203
  "UploadAccepted": UploadAccepted,
198
204
  "EnabledPatch": EnabledPatch,
199
205
  "DocumentEnabledResponse": DocumentEnabledResponse,
206
+ "MetadataValuesPatch": MetadataValuesPatch,
207
+ "MetadataUpdateResponse": MetadataUpdateResponse,
200
208
  # Corpus grid filters (also reused by CollectionEstimateRequest.filter below).
201
209
  "TextFilter": TextFilter,
202
210
  "NumberRange": NumberRange,
@@ -57,6 +57,7 @@ ROUTES: set[tuple[str, str]] = {
57
57
  # Documents (upload / toggle / reingest / rendered views) — resources/documents.py
58
58
  ("POST", "/api/v1/documents"),
59
59
  ("PATCH", "/api/v1/documents/{document_id}/enabled"),
60
+ ("PATCH", "/api/v1/documents/{document_id}/metadata"),
60
61
  ("POST", "/api/v1/documents/{document_id}/reingest"),
61
62
  ("POST", "/api/v1/documents/{document_id}/trace-payloads/purge"),
62
63
  ("GET", "/api/v1/documents/{document_id}/markdown"),
File without changes
File without changes
File without changes
File without changes