comfygit-studio 0.7.0__tar.gz → 0.7.1__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.
- {comfygit_studio-0.7.0 → comfygit_studio-0.7.1}/PKG-INFO +2 -2
- {comfygit_studio-0.7.0 → comfygit_studio-0.7.1}/comfygit_studio/api_schema.py +26 -2
- {comfygit_studio-0.7.0 → comfygit_studio-0.7.1}/comfygit_studio/openapi/studio-contract-api.v1.json +213 -0
- {comfygit_studio-0.7.0 → comfygit_studio-0.7.1}/comfygit_studio/runtime.py +89 -15
- {comfygit_studio-0.7.0 → comfygit_studio-0.7.1}/pyproject.toml +2 -2
- {comfygit_studio-0.7.0 → comfygit_studio-0.7.1}/.gitignore +0 -0
- {comfygit_studio-0.7.0 → comfygit_studio-0.7.1}/README.md +0 -0
- {comfygit_studio-0.7.0 → comfygit_studio-0.7.1}/comfygit_studio/__init__.py +0 -0
- {comfygit_studio-0.7.0 → comfygit_studio-0.7.1}/comfygit_studio/embedded.py +0 -0
- {comfygit_studio-0.7.0 → comfygit_studio-0.7.1}/comfygit_studio/executor.py +0 -0
- {comfygit_studio-0.7.0 → comfygit_studio-0.7.1}/comfygit_studio/state.py +0 -0
- {comfygit_studio-0.7.0 → comfygit_studio-0.7.1}/comfygit_studio/static/assets/geist-cyrillic-wght-normal-CHSlOQsW.woff2 +0 -0
- {comfygit_studio-0.7.0 → comfygit_studio-0.7.1}/comfygit_studio/static/assets/geist-latin-ext-wght-normal-DMtmJ5ZE.woff2 +0 -0
- {comfygit_studio-0.7.0 → comfygit_studio-0.7.1}/comfygit_studio/static/assets/geist-latin-wght-normal-Dm3htQBi.woff2 +0 -0
- {comfygit_studio-0.7.0 → comfygit_studio-0.7.1}/comfygit_studio/static/assets/index-BDmIh9tA.css +0 -0
- {comfygit_studio-0.7.0 → comfygit_studio-0.7.1}/comfygit_studio/static/assets/index-ry5Db1EL.js +0 -0
- {comfygit_studio-0.7.0 → comfygit_studio-0.7.1}/comfygit_studio/static/index.html +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: comfygit-studio
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.1
|
|
4
4
|
Summary: ComfyGit Studio runtime - contract API and Studio serving adapters
|
|
5
5
|
Project-URL: Documentation, https://docs.comfygit.org/
|
|
6
6
|
Project-URL: Repository, https://github.com/comfygit-ai/comfygit
|
|
7
7
|
Project-URL: Issues, https://github.com/comfygit-ai/comfygit/issues
|
|
8
8
|
Requires-Python: >=3.10
|
|
9
9
|
Requires-Dist: aiohttp>=3.14.3
|
|
10
|
-
Requires-Dist: comfygit-core==0.7.
|
|
10
|
+
Requires-Dist: comfygit-core==0.7.1
|
|
11
11
|
Description-Content-Type: text/markdown
|
|
12
12
|
|
|
13
13
|
# ComfyGit Studio Runtime
|
|
@@ -82,7 +82,7 @@ def _paths() -> dict[str, Any]:
|
|
|
82
82
|
"get": {
|
|
83
83
|
"summary": "List available workflow contracts",
|
|
84
84
|
"operationId": "listContracts",
|
|
85
|
-
"responses": _json_response("Contracts response", "ContractsResponse"),
|
|
85
|
+
"responses": {**_json_response("Contracts response", "ContractsResponse"), "503": _busy_response()},
|
|
86
86
|
}
|
|
87
87
|
},
|
|
88
88
|
"/contracts/{workflow}/{contract}": {
|
|
@@ -93,7 +93,7 @@ def _paths() -> dict[str, Any]:
|
|
|
93
93
|
{"$ref": "#/components/parameters/workflow"},
|
|
94
94
|
{"$ref": "#/components/parameters/contract"},
|
|
95
95
|
],
|
|
96
|
-
"responses": _json_response("Contract response", "ContractSummary"),
|
|
96
|
+
"responses": {**_json_response("Contract response", "ContractSummary"), "503": _busy_response()},
|
|
97
97
|
}
|
|
98
98
|
},
|
|
99
99
|
"/uploads/prepare": {
|
|
@@ -152,6 +152,7 @@ def _paths() -> dict[str, Any]:
|
|
|
152
152
|
"400": _json_content("Invalid request", "RunResponse"),
|
|
153
153
|
"413": _json_content("Request too large", "ErrorResponse"),
|
|
154
154
|
"502": _json_content("Executor unavailable", "RunResponse"),
|
|
155
|
+
"503": _busy_response(),
|
|
155
156
|
"504": _json_content("Run timed out", "RunResponse"),
|
|
156
157
|
},
|
|
157
158
|
}
|
|
@@ -289,6 +290,7 @@ def _schemas() -> dict[str, Any]:
|
|
|
289
290
|
"type": "object",
|
|
290
291
|
"required": ["workflow", "contract", "inputs", "outputs"],
|
|
291
292
|
"properties": {
|
|
293
|
+
"manifest_revision": {"type": "string"},
|
|
292
294
|
"workflow": {"type": "string"},
|
|
293
295
|
"contract": {"type": "string"},
|
|
294
296
|
"display_name": {"type": "string"},
|
|
@@ -303,6 +305,7 @@ def _schemas() -> dict[str, Any]:
|
|
|
303
305
|
"required": ["environment", "contracts"],
|
|
304
306
|
"properties": {
|
|
305
307
|
"environment": {"type": "string"},
|
|
308
|
+
"manifest_revision": {"type": "string"},
|
|
306
309
|
"contracts": {"type": "array", "items": {"$ref": "#/components/schemas/ContractSummary"}},
|
|
307
310
|
},
|
|
308
311
|
},
|
|
@@ -464,6 +467,9 @@ def _schemas() -> dict[str, Any]:
|
|
|
464
467
|
"status": {"type": "string"},
|
|
465
468
|
"run_id": {"type": "string"},
|
|
466
469
|
"prompt_id": {"type": "string"},
|
|
470
|
+
"manifest_revision": {"type": "string"},
|
|
471
|
+
"prompt_digest": {"type": "string"},
|
|
472
|
+
"request_id": {"type": ["string", "null"]},
|
|
467
473
|
"issues": {"type": "array", "items": {"$ref": "#/components/schemas/RunIssue"}},
|
|
468
474
|
"outputs": {"type": "array", "items": {"$ref": "#/components/schemas/RunOutput"}},
|
|
469
475
|
"output_slots": {"type": "array", "items": {"$ref": "#/components/schemas/RunOutputSlot"}},
|
|
@@ -538,6 +544,24 @@ def _parameters() -> dict[str, Any]:
|
|
|
538
544
|
}
|
|
539
545
|
|
|
540
546
|
|
|
547
|
+
def _busy_response() -> dict[str, Any]:
|
|
548
|
+
return {
|
|
549
|
+
"description": "Environment mutation in progress; no run submitted. Retry GET after Retry-After. Do not replay uncertain POSTs.",
|
|
550
|
+
"headers": {"Retry-After": {"schema": {"type": "string"}}, "X-Request-ID": {"schema": {"type": "string"}}},
|
|
551
|
+
"content": {"application/json": {"schema": {
|
|
552
|
+
"type": "object", "required": ["error", "retryable", "request_id", "owner"],
|
|
553
|
+
"properties": {
|
|
554
|
+
"error": {"const": "environment_busy"}, "retryable": {"const": True},
|
|
555
|
+
"request_id": {"type": "string"}, "message": {"type": "string"},
|
|
556
|
+
"owner": {"type": "object", "properties": {
|
|
557
|
+
"pid": {"type": ["integer", "null"]}, "operation": {"type": ["string", "null"]},
|
|
558
|
+
"acquired_at": {"type": ["string", "null"]},
|
|
559
|
+
}},
|
|
560
|
+
},
|
|
561
|
+
}}},
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
|
|
541
565
|
def _json_response(description: str, schema_name: str) -> dict[str, Any]:
|
|
542
566
|
return {"200": _json_content(description, schema_name)}
|
|
543
567
|
|
{comfygit_studio-0.7.0 → comfygit_studio-0.7.1}/comfygit_studio/openapi/studio-contract-api.v1.json
RENAMED
|
@@ -242,6 +242,9 @@
|
|
|
242
242
|
},
|
|
243
243
|
"type": "array"
|
|
244
244
|
},
|
|
245
|
+
"manifest_revision": {
|
|
246
|
+
"type": "string"
|
|
247
|
+
},
|
|
245
248
|
"outputs": {
|
|
246
249
|
"items": {
|
|
247
250
|
"$ref": "#/components/schemas/ContractOutput"
|
|
@@ -270,6 +273,9 @@
|
|
|
270
273
|
},
|
|
271
274
|
"environment": {
|
|
272
275
|
"type": "string"
|
|
276
|
+
},
|
|
277
|
+
"manifest_revision": {
|
|
278
|
+
"type": "string"
|
|
273
279
|
}
|
|
274
280
|
},
|
|
275
281
|
"required": [
|
|
@@ -708,6 +714,9 @@
|
|
|
708
714
|
},
|
|
709
715
|
"type": "array"
|
|
710
716
|
},
|
|
717
|
+
"manifest_revision": {
|
|
718
|
+
"type": "string"
|
|
719
|
+
},
|
|
711
720
|
"message": {
|
|
712
721
|
"type": "string"
|
|
713
722
|
},
|
|
@@ -723,9 +732,18 @@
|
|
|
723
732
|
},
|
|
724
733
|
"type": "array"
|
|
725
734
|
},
|
|
735
|
+
"prompt_digest": {
|
|
736
|
+
"type": "string"
|
|
737
|
+
},
|
|
726
738
|
"prompt_id": {
|
|
727
739
|
"type": "string"
|
|
728
740
|
},
|
|
741
|
+
"request_id": {
|
|
742
|
+
"type": [
|
|
743
|
+
"string",
|
|
744
|
+
"null"
|
|
745
|
+
]
|
|
746
|
+
},
|
|
729
747
|
"run_id": {
|
|
730
748
|
"type": "string"
|
|
731
749
|
},
|
|
@@ -860,6 +878,71 @@
|
|
|
860
878
|
}
|
|
861
879
|
},
|
|
862
880
|
"description": "Contracts response"
|
|
881
|
+
},
|
|
882
|
+
"503": {
|
|
883
|
+
"content": {
|
|
884
|
+
"application/json": {
|
|
885
|
+
"schema": {
|
|
886
|
+
"properties": {
|
|
887
|
+
"error": {
|
|
888
|
+
"const": "environment_busy"
|
|
889
|
+
},
|
|
890
|
+
"message": {
|
|
891
|
+
"type": "string"
|
|
892
|
+
},
|
|
893
|
+
"owner": {
|
|
894
|
+
"properties": {
|
|
895
|
+
"acquired_at": {
|
|
896
|
+
"type": [
|
|
897
|
+
"string",
|
|
898
|
+
"null"
|
|
899
|
+
]
|
|
900
|
+
},
|
|
901
|
+
"operation": {
|
|
902
|
+
"type": [
|
|
903
|
+
"string",
|
|
904
|
+
"null"
|
|
905
|
+
]
|
|
906
|
+
},
|
|
907
|
+
"pid": {
|
|
908
|
+
"type": [
|
|
909
|
+
"integer",
|
|
910
|
+
"null"
|
|
911
|
+
]
|
|
912
|
+
}
|
|
913
|
+
},
|
|
914
|
+
"type": "object"
|
|
915
|
+
},
|
|
916
|
+
"request_id": {
|
|
917
|
+
"type": "string"
|
|
918
|
+
},
|
|
919
|
+
"retryable": {
|
|
920
|
+
"const": true
|
|
921
|
+
}
|
|
922
|
+
},
|
|
923
|
+
"required": [
|
|
924
|
+
"error",
|
|
925
|
+
"retryable",
|
|
926
|
+
"request_id",
|
|
927
|
+
"owner"
|
|
928
|
+
],
|
|
929
|
+
"type": "object"
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
},
|
|
933
|
+
"description": "Environment mutation in progress; no run submitted. Retry GET after Retry-After. Do not replay uncertain POSTs.",
|
|
934
|
+
"headers": {
|
|
935
|
+
"Retry-After": {
|
|
936
|
+
"schema": {
|
|
937
|
+
"type": "string"
|
|
938
|
+
}
|
|
939
|
+
},
|
|
940
|
+
"X-Request-ID": {
|
|
941
|
+
"schema": {
|
|
942
|
+
"type": "string"
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
}
|
|
863
946
|
}
|
|
864
947
|
},
|
|
865
948
|
"summary": "List available workflow contracts"
|
|
@@ -886,6 +969,71 @@
|
|
|
886
969
|
}
|
|
887
970
|
},
|
|
888
971
|
"description": "Contract response"
|
|
972
|
+
},
|
|
973
|
+
"503": {
|
|
974
|
+
"content": {
|
|
975
|
+
"application/json": {
|
|
976
|
+
"schema": {
|
|
977
|
+
"properties": {
|
|
978
|
+
"error": {
|
|
979
|
+
"const": "environment_busy"
|
|
980
|
+
},
|
|
981
|
+
"message": {
|
|
982
|
+
"type": "string"
|
|
983
|
+
},
|
|
984
|
+
"owner": {
|
|
985
|
+
"properties": {
|
|
986
|
+
"acquired_at": {
|
|
987
|
+
"type": [
|
|
988
|
+
"string",
|
|
989
|
+
"null"
|
|
990
|
+
]
|
|
991
|
+
},
|
|
992
|
+
"operation": {
|
|
993
|
+
"type": [
|
|
994
|
+
"string",
|
|
995
|
+
"null"
|
|
996
|
+
]
|
|
997
|
+
},
|
|
998
|
+
"pid": {
|
|
999
|
+
"type": [
|
|
1000
|
+
"integer",
|
|
1001
|
+
"null"
|
|
1002
|
+
]
|
|
1003
|
+
}
|
|
1004
|
+
},
|
|
1005
|
+
"type": "object"
|
|
1006
|
+
},
|
|
1007
|
+
"request_id": {
|
|
1008
|
+
"type": "string"
|
|
1009
|
+
},
|
|
1010
|
+
"retryable": {
|
|
1011
|
+
"const": true
|
|
1012
|
+
}
|
|
1013
|
+
},
|
|
1014
|
+
"required": [
|
|
1015
|
+
"error",
|
|
1016
|
+
"retryable",
|
|
1017
|
+
"request_id",
|
|
1018
|
+
"owner"
|
|
1019
|
+
],
|
|
1020
|
+
"type": "object"
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
},
|
|
1024
|
+
"description": "Environment mutation in progress; no run submitted. Retry GET after Retry-After. Do not replay uncertain POSTs.",
|
|
1025
|
+
"headers": {
|
|
1026
|
+
"Retry-After": {
|
|
1027
|
+
"schema": {
|
|
1028
|
+
"type": "string"
|
|
1029
|
+
}
|
|
1030
|
+
},
|
|
1031
|
+
"X-Request-ID": {
|
|
1032
|
+
"schema": {
|
|
1033
|
+
"type": "string"
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
889
1037
|
}
|
|
890
1038
|
},
|
|
891
1039
|
"summary": "Return one workflow contract"
|
|
@@ -953,6 +1101,71 @@
|
|
|
953
1101
|
},
|
|
954
1102
|
"description": "Executor unavailable"
|
|
955
1103
|
},
|
|
1104
|
+
"503": {
|
|
1105
|
+
"content": {
|
|
1106
|
+
"application/json": {
|
|
1107
|
+
"schema": {
|
|
1108
|
+
"properties": {
|
|
1109
|
+
"error": {
|
|
1110
|
+
"const": "environment_busy"
|
|
1111
|
+
},
|
|
1112
|
+
"message": {
|
|
1113
|
+
"type": "string"
|
|
1114
|
+
},
|
|
1115
|
+
"owner": {
|
|
1116
|
+
"properties": {
|
|
1117
|
+
"acquired_at": {
|
|
1118
|
+
"type": [
|
|
1119
|
+
"string",
|
|
1120
|
+
"null"
|
|
1121
|
+
]
|
|
1122
|
+
},
|
|
1123
|
+
"operation": {
|
|
1124
|
+
"type": [
|
|
1125
|
+
"string",
|
|
1126
|
+
"null"
|
|
1127
|
+
]
|
|
1128
|
+
},
|
|
1129
|
+
"pid": {
|
|
1130
|
+
"type": [
|
|
1131
|
+
"integer",
|
|
1132
|
+
"null"
|
|
1133
|
+
]
|
|
1134
|
+
}
|
|
1135
|
+
},
|
|
1136
|
+
"type": "object"
|
|
1137
|
+
},
|
|
1138
|
+
"request_id": {
|
|
1139
|
+
"type": "string"
|
|
1140
|
+
},
|
|
1141
|
+
"retryable": {
|
|
1142
|
+
"const": true
|
|
1143
|
+
}
|
|
1144
|
+
},
|
|
1145
|
+
"required": [
|
|
1146
|
+
"error",
|
|
1147
|
+
"retryable",
|
|
1148
|
+
"request_id",
|
|
1149
|
+
"owner"
|
|
1150
|
+
],
|
|
1151
|
+
"type": "object"
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
},
|
|
1155
|
+
"description": "Environment mutation in progress; no run submitted. Retry GET after Retry-After. Do not replay uncertain POSTs.",
|
|
1156
|
+
"headers": {
|
|
1157
|
+
"Retry-After": {
|
|
1158
|
+
"schema": {
|
|
1159
|
+
"type": "string"
|
|
1160
|
+
}
|
|
1161
|
+
},
|
|
1162
|
+
"X-Request-ID": {
|
|
1163
|
+
"schema": {
|
|
1164
|
+
"type": "string"
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
},
|
|
956
1169
|
"504": {
|
|
957
1170
|
"content": {
|
|
958
1171
|
"application/json": {
|
|
@@ -5,11 +5,13 @@ from __future__ import annotations
|
|
|
5
5
|
import asyncio
|
|
6
6
|
import hashlib
|
|
7
7
|
import json
|
|
8
|
+
import logging
|
|
8
9
|
import secrets
|
|
9
10
|
import subprocess
|
|
10
11
|
import uuid
|
|
11
|
-
from collections.abc import Callable, Mapping
|
|
12
|
+
from collections.abc import Awaitable, Callable, Mapping
|
|
12
13
|
from dataclasses import asdict, dataclass
|
|
14
|
+
from functools import wraps
|
|
13
15
|
from importlib import resources
|
|
14
16
|
from pathlib import Path
|
|
15
17
|
from typing import Any, cast
|
|
@@ -18,7 +20,11 @@ from urllib.parse import quote
|
|
|
18
20
|
import aiohttp
|
|
19
21
|
from aiohttp import web
|
|
20
22
|
from comfygit_core import Environment
|
|
21
|
-
from comfygit_core.models import
|
|
23
|
+
from comfygit_core.models import (
|
|
24
|
+
CDEnvironmentBusyError,
|
|
25
|
+
EnvironmentManifestSnapshot,
|
|
26
|
+
NamedWorkflowContract,
|
|
27
|
+
)
|
|
22
28
|
from comfygit_core.workflow import build_manifest_contract_prompt
|
|
23
29
|
|
|
24
30
|
from .api_schema import studio_contract_api_openapi
|
|
@@ -92,6 +98,43 @@ UPLOAD_MIME_TYPE_ALIASES = {
|
|
|
92
98
|
}
|
|
93
99
|
|
|
94
100
|
|
|
101
|
+
logger = logging.getLogger(__name__)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class _ContractPreparationBusy(CDEnvironmentBusyError):
|
|
105
|
+
"""Known contention before any executor call; safe to report as unsubmitted."""
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _contract_request(
|
|
109
|
+
handler: Callable[[web.Request], Awaitable[web.Response]],
|
|
110
|
+
) -> Callable[[web.Request], Awaitable[web.Response]]:
|
|
111
|
+
"""Correlate contract requests and expose pre-submission lock contention."""
|
|
112
|
+
@wraps(handler)
|
|
113
|
+
async def wrapped(request: web.Request) -> web.Response:
|
|
114
|
+
request_id = uuid.uuid4().hex
|
|
115
|
+
request["contract_request_id"] = request_id
|
|
116
|
+
try:
|
|
117
|
+
response = await handler(request)
|
|
118
|
+
except CDEnvironmentBusyError as exc:
|
|
119
|
+
owner = asdict(exc.owner)
|
|
120
|
+
logger.warning("Environment busy request_id=%s method=%s route=%s owner=%s",
|
|
121
|
+
request_id, request.method, request.path, owner)
|
|
122
|
+
response = web.json_response({
|
|
123
|
+
"error": "environment_busy", "retryable": True,
|
|
124
|
+
"message": "Environment is being updated; retry after the operation completes.",
|
|
125
|
+
"request_id": request_id, "owner": owner,
|
|
126
|
+
}, status=503, headers={"Retry-After": "1"})
|
|
127
|
+
except web.HTTPException:
|
|
128
|
+
raise
|
|
129
|
+
except Exception:
|
|
130
|
+
logger.exception("Contract request failed request_id=%s route=%s", request_id, request.path)
|
|
131
|
+
response = web.json_response({"error": "internal_error", "request_id": request_id,
|
|
132
|
+
"message": "Contract request failed; inspect the server log."}, status=500)
|
|
133
|
+
response.headers["X-Request-ID"] = request_id
|
|
134
|
+
return response
|
|
135
|
+
return wrapped
|
|
136
|
+
|
|
137
|
+
|
|
95
138
|
@dataclass(frozen=True)
|
|
96
139
|
class ServeConfig:
|
|
97
140
|
"""Configuration for the local ComfyGit serve adapter."""
|
|
@@ -959,10 +1002,12 @@ async def proxy_artifact_handler(request: web.Request) -> web.StreamResponse:
|
|
|
959
1002
|
return web.Response(body=output_response.body, status=output_response.status, headers=headers)
|
|
960
1003
|
|
|
961
1004
|
|
|
1005
|
+
@_contract_request
|
|
962
1006
|
async def contracts_handler(request: web.Request) -> web.Response:
|
|
963
1007
|
return web.json_response(_contracts_payload(_state(request)))
|
|
964
1008
|
|
|
965
1009
|
|
|
1010
|
+
@_contract_request
|
|
966
1011
|
async def single_contract_handler(request: web.Request) -> web.Response:
|
|
967
1012
|
try:
|
|
968
1013
|
payload = _single_contract_payload(
|
|
@@ -1491,6 +1536,7 @@ def _localize_worker_callback_outputs(
|
|
|
1491
1536
|
return output_payloads
|
|
1492
1537
|
|
|
1493
1538
|
|
|
1539
|
+
@_contract_request
|
|
1494
1540
|
async def run_contract_handler(request: web.Request) -> web.Response:
|
|
1495
1541
|
body: dict[str, Any] = {}
|
|
1496
1542
|
session = _serve_session(request)
|
|
@@ -1502,9 +1548,12 @@ async def run_contract_handler(request: web.Request) -> web.Response:
|
|
|
1502
1548
|
request.match_info["workflow"],
|
|
1503
1549
|
request.match_info["contract"],
|
|
1504
1550
|
body,
|
|
1551
|
+
request_id=request["contract_request_id"],
|
|
1505
1552
|
)
|
|
1506
1553
|
status = 400 if payload.get("status") == "invalid_request" else 200
|
|
1507
1554
|
return _json_response_for_session(payload, session, status=status, request=request)
|
|
1555
|
+
except _ContractPreparationBusy:
|
|
1556
|
+
raise # Preparation did not submit a run; the outer handler returns 503.
|
|
1508
1557
|
except web.HTTPRequestEntityTooLarge:
|
|
1509
1558
|
state = _state(request)
|
|
1510
1559
|
max_mib = _max_request_bytes(state) // (1024 * 1024)
|
|
@@ -1552,7 +1601,9 @@ async def run_contract_handler(request: web.Request) -> web.Response:
|
|
|
1552
1601
|
payload.update(_record_failed_run(_state(request), session, request.match_info["workflow"], request.match_info["contract"], body, payload))
|
|
1553
1602
|
return _json_response_for_session(payload, session, status=400)
|
|
1554
1603
|
except Exception as exc:
|
|
1555
|
-
|
|
1604
|
+
request_id = request["contract_request_id"]
|
|
1605
|
+
logger.exception("Contract request failed request_id=%s route=%s", request_id, request.path)
|
|
1606
|
+
payload = {"error": "internal_error", "message": str(exc), "request_id": request_id}
|
|
1556
1607
|
payload.update(_record_failed_run(_state(request), session, request.match_info["workflow"], request.match_info["contract"], body, payload))
|
|
1557
1608
|
return _json_response_for_session(payload, session, status=500)
|
|
1558
1609
|
|
|
@@ -2241,6 +2292,7 @@ def _contracts_payload(state: ServeState) -> dict[str, Any]:
|
|
|
2241
2292
|
contracts.append(_contract_payload(workflow_name, contract_name, contract))
|
|
2242
2293
|
return {
|
|
2243
2294
|
"environment": state.env.name,
|
|
2295
|
+
"manifest_revision": manifest.revision,
|
|
2244
2296
|
"contracts": contracts,
|
|
2245
2297
|
}
|
|
2246
2298
|
|
|
@@ -2257,7 +2309,7 @@ def _single_contract_payload(
|
|
|
2257
2309
|
contract = workflow.execution_contract.contracts.get(contract_name)
|
|
2258
2310
|
if contract is None:
|
|
2259
2311
|
raise ValueError(f"Workflow '{workflow_name}' does not declare contract '{contract_name}'.")
|
|
2260
|
-
return _contract_payload(workflow_name, contract_name, contract)
|
|
2312
|
+
return {**_contract_payload(workflow_name, contract_name, contract), "manifest_revision": manifest.revision}
|
|
2261
2313
|
|
|
2262
2314
|
|
|
2263
2315
|
def _contract_payload(
|
|
@@ -2281,6 +2333,8 @@ async def _run_contract(
|
|
|
2281
2333
|
workflow_name: str,
|
|
2282
2334
|
contract_name: str,
|
|
2283
2335
|
body: dict[str, Any],
|
|
2336
|
+
*,
|
|
2337
|
+
request_id: str | None = None,
|
|
2284
2338
|
) -> dict[str, Any]:
|
|
2285
2339
|
if "inputs" in body:
|
|
2286
2340
|
inputs = body["inputs"]
|
|
@@ -2293,16 +2347,19 @@ async def _run_contract(
|
|
|
2293
2347
|
timeout_seconds = float(body.get("timeout_seconds", state.config.run_timeout_seconds))
|
|
2294
2348
|
poll_interval_seconds = float(body.get("poll_interval_seconds", 1))
|
|
2295
2349
|
|
|
2296
|
-
manifest
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2350
|
+
# One synchronous shared read protects both manifest and captured prompt.
|
|
2351
|
+
# No environment lock is held across any network call or GPU execution.
|
|
2352
|
+
try:
|
|
2353
|
+
with state.env.read_manifest_snapshot() as manifest:
|
|
2354
|
+
prepared_contract = _resolve_contract_run_inputs(state, manifest, workflow_name, contract_name, inputs)
|
|
2355
|
+
inputs = prepared_contract.inputs
|
|
2356
|
+
build_result = build_manifest_contract_prompt(
|
|
2357
|
+
manifest, state.env.cec_path, workflow_name, inputs, contract_name=contract_name,
|
|
2358
|
+
)
|
|
2359
|
+
manifest_revision = manifest.revision
|
|
2360
|
+
prompt_digest = hashlib.sha256(json.dumps(build_result.prompt, sort_keys=True).encode()).hexdigest()
|
|
2361
|
+
except CDEnvironmentBusyError as exc:
|
|
2362
|
+
raise _ContractPreparationBusy(exc.lock_path, exc.owner) from exc
|
|
2306
2363
|
if build_result.has_errors:
|
|
2307
2364
|
payload: dict[str, Any] = {
|
|
2308
2365
|
"status": "invalid_request",
|
|
@@ -2318,8 +2375,13 @@ async def _run_contract(
|
|
|
2318
2375
|
callback_token = _callback_auth_token(state) if callback_url else None
|
|
2319
2376
|
|
|
2320
2377
|
async def record_submitted(prompt_id: str) -> None:
|
|
2378
|
+
logger.info("Contract submitted request_id=%s run_id=%s prompt_id=%s manifest_revision=%s prompt_digest=%s",
|
|
2379
|
+
request_id, run_id, prompt_id, manifest_revision, prompt_digest)
|
|
2321
2380
|
response = {
|
|
2322
2381
|
"status": "submitted",
|
|
2382
|
+
"manifest_revision": manifest_revision,
|
|
2383
|
+
"prompt_digest": prompt_digest,
|
|
2384
|
+
"request_id": request_id,
|
|
2323
2385
|
"run_id": run_id,
|
|
2324
2386
|
"prompt_id": prompt_id,
|
|
2325
2387
|
"issues": [asdict(issue) for issue in build_result.issues],
|
|
@@ -2356,6 +2418,9 @@ async def _run_contract(
|
|
|
2356
2418
|
|
|
2357
2419
|
response: dict[str, Any] = {
|
|
2358
2420
|
"status": execution.status,
|
|
2421
|
+
"manifest_revision": manifest_revision,
|
|
2422
|
+
"prompt_digest": prompt_digest,
|
|
2423
|
+
"request_id": request_id,
|
|
2359
2424
|
"run_id": run_id,
|
|
2360
2425
|
"prompt_id": execution.prompt_id,
|
|
2361
2426
|
"issues": [asdict(issue) for issue in build_result.issues],
|
|
@@ -3139,7 +3204,16 @@ async def _prepare_contract_run_inputs(
|
|
|
3139
3204
|
) -> PreparedContractInputs:
|
|
3140
3205
|
"""Resolve uploaded media refs before building the ComfyUI prompt."""
|
|
3141
3206
|
|
|
3142
|
-
|
|
3207
|
+
return _resolve_contract_run_inputs(state, state.manifest_snapshot(), workflow_name, contract_name, inputs)
|
|
3208
|
+
|
|
3209
|
+
|
|
3210
|
+
def _resolve_contract_run_inputs(
|
|
3211
|
+
state: ServeState,
|
|
3212
|
+
manifest: EnvironmentManifestSnapshot,
|
|
3213
|
+
workflow_name: str,
|
|
3214
|
+
contract_name: str,
|
|
3215
|
+
inputs: dict[str, Any],
|
|
3216
|
+
) -> PreparedContractInputs:
|
|
3143
3217
|
workflow = manifest.workflows.get(workflow_name)
|
|
3144
3218
|
execution_contract = getattr(workflow, "execution_contract", None) if workflow else None
|
|
3145
3219
|
contract = execution_contract.contracts.get(contract_name) if execution_contract else None
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "comfygit-studio"
|
|
3
|
-
version = "0.7.
|
|
3
|
+
version = "0.7.1"
|
|
4
4
|
description = "ComfyGit Studio runtime - contract API and Studio serving adapters"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.10"
|
|
7
7
|
dependencies = [
|
|
8
8
|
"aiohttp>=3.14.3",
|
|
9
|
-
"comfygit-core==0.7.
|
|
9
|
+
"comfygit-core==0.7.1",
|
|
10
10
|
]
|
|
11
11
|
|
|
12
12
|
[project.urls]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{comfygit_studio-0.7.0 → comfygit_studio-0.7.1}/comfygit_studio/static/assets/index-BDmIh9tA.css
RENAMED
|
File without changes
|
{comfygit_studio-0.7.0 → comfygit_studio-0.7.1}/comfygit_studio/static/assets/index-ry5Db1EL.js
RENAMED
|
File without changes
|
|
File without changes
|