mirror of
https://github.com/calesthio/OpenMontage.git
synced 2026-08-05 15:20:40 +08:00
fix: complete Kling idempotency inputs
Include every request field that can alter Kling video, image, avatar, or lip-sync media in the public idempotency contract. Add a shared regression matrix that detects future cache-key collisions while excluding transport-only controls.
This commit is contained in:
@@ -401,6 +401,116 @@ def test_provider_agent_skills_reference_kling_official():
|
||||
assert "kling-official" in KlingLipSync().agent_skills
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("tool", "output_variants"),
|
||||
[
|
||||
(
|
||||
KlingOfficialVideo(),
|
||||
{
|
||||
"prompt": "changed prompt",
|
||||
"operation": "image_to_video",
|
||||
"api_family": "omni",
|
||||
"model_name": "kling-v2-6",
|
||||
"model_variant": "kling-v2-5-turbo",
|
||||
"duration": "10",
|
||||
"aspect_ratio": "9:16",
|
||||
"resolution": "1080p",
|
||||
"mode": "pro",
|
||||
"sound": "on",
|
||||
"negative_prompt": "blur",
|
||||
"cfg_scale": 0.7,
|
||||
"reference_image_url": "https://example.com/first.png",
|
||||
"reference_image_path": "/tmp/first.png",
|
||||
"reference_tail_image_url": "https://example.com/tail.png",
|
||||
"reference_tail_image_path": "/tmp/tail.png",
|
||||
"reference_image_urls": ["https://example.com/ref.png"],
|
||||
"reference_image_paths": ["/tmp/ref.png"],
|
||||
"reference_video_url": "https://example.com/ref.mp4",
|
||||
"video_urls": ["https://example.com/ref-2.mp4"],
|
||||
"image_list": [{"image_url": "https://example.com/list.png"}],
|
||||
"video_list": [{"video_url": "https://example.com/list.mp4"}],
|
||||
"element_list": [{"element_id": 123}],
|
||||
"multi_shot": True,
|
||||
"shot_type": "intelligence",
|
||||
"multi_prompt": [{"prompt": "second shot", "duration": "3"}],
|
||||
"camera_control": {"type": "simple", "config": {"horizontal": 1}},
|
||||
"watermark": True,
|
||||
},
|
||||
),
|
||||
(
|
||||
KlingOfficialImage(),
|
||||
{
|
||||
"prompt": "changed prompt",
|
||||
"negative_prompt": "blur",
|
||||
"operation": "omni",
|
||||
"api_family": "omni",
|
||||
"model_name": "kling-image-o1",
|
||||
"image_url": "https://example.com/source.png",
|
||||
"image_path": "/tmp/source.png",
|
||||
"image_urls": ["https://example.com/ref.png"],
|
||||
"image_paths": ["/tmp/ref.png"],
|
||||
"image_list": [{"image_url": "https://example.com/list.png"}],
|
||||
"image_reference": "subject",
|
||||
"image_fidelity": 0.7,
|
||||
"human_fidelity": 0.8,
|
||||
"resolution": "2k",
|
||||
"aspect_ratio": "1:1",
|
||||
"n": 2,
|
||||
"result_type": "series",
|
||||
"series_amount": "3",
|
||||
"element_list": [{"element_id": 123}],
|
||||
"watermark": True,
|
||||
},
|
||||
),
|
||||
(
|
||||
KlingAvatar(),
|
||||
{
|
||||
"image_url": "https://example.com/avatar.png",
|
||||
"image_path": "/tmp/avatar.png",
|
||||
"audio_id": "audio-a",
|
||||
"sound_file": "inline-audio",
|
||||
"sound_file_url": "https://example.com/audio.mp3",
|
||||
"sound_file_path": "/tmp/audio.mp3",
|
||||
"audio_path": "/tmp/audio-alias.mp3",
|
||||
"prompt": "natural presenter motion",
|
||||
"mode": "pro",
|
||||
},
|
||||
),
|
||||
(
|
||||
KlingLipSync(),
|
||||
{
|
||||
"operation": "full_lip_sync",
|
||||
"video_id": "video-a",
|
||||
"video_url": "https://example.com/video.mp4",
|
||||
"session_id": "session-a",
|
||||
"face_id": "face-a",
|
||||
"face_choose": [{"face_id": "face-a", "audio_id": "audio-a"}],
|
||||
"auto_select_face": True,
|
||||
"audio_id": "audio-a",
|
||||
"sound_file": "inline-audio",
|
||||
"sound_file_url": "https://example.com/audio.mp3",
|
||||
"sound_file_path": "/tmp/audio.mp3",
|
||||
"audio_path": "/tmp/audio-alias.mp3",
|
||||
"sound_start_time": 100,
|
||||
"sound_end_time": 4100,
|
||||
"sound_insert_time": 500,
|
||||
"sound_volume": 1.2,
|
||||
"original_audio_volume": 0.4,
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_kling_output_inputs_change_idempotency_keys(tool, output_variants):
|
||||
baseline = tool.idempotency_key({})
|
||||
collisions = [
|
||||
field
|
||||
for field, value in output_variants.items()
|
||||
if tool.idempotency_key({field: value}) == baseline
|
||||
]
|
||||
|
||||
assert collisions == [], f"{tool.name} idempotency key ignores: {collisions}"
|
||||
|
||||
|
||||
def test_phase3_does_not_register_audio_or_video_effect_tools(isolated_tool_registry):
|
||||
isolated_tool_registry.discover("tools")
|
||||
assert isolated_tool_registry.get("kling_audio") is None
|
||||
|
||||
@@ -124,7 +124,17 @@ class KlingAvatar(BaseTool):
|
||||
backoff_seconds=2.0,
|
||||
retryable_errors=["1302", "1303", "5000", "5001", "5002"],
|
||||
)
|
||||
idempotency_key_fields = ["image_url", "image_path", "audio_id", "sound_file", "sound_file_path", "mode"]
|
||||
idempotency_key_fields = [
|
||||
"image_url",
|
||||
"image_path",
|
||||
"audio_id",
|
||||
"sound_file",
|
||||
"sound_file_url",
|
||||
"sound_file_path",
|
||||
"audio_path",
|
||||
"prompt",
|
||||
"mode",
|
||||
]
|
||||
side_effects = ["paid remote generation via official Kling API", "writes avatar video to output_path"]
|
||||
user_visible_verification = ["Watch generated avatar video for identity preservation and mouth motion"]
|
||||
quality_score = 0.82
|
||||
|
||||
@@ -139,15 +139,23 @@ class KlingLipSync(BaseTool):
|
||||
retryable_errors=["1302", "1303", "5000", "5001", "5002"],
|
||||
)
|
||||
idempotency_key_fields = [
|
||||
"operation",
|
||||
"video_id",
|
||||
"video_url",
|
||||
"session_id",
|
||||
"face_id",
|
||||
"face_choose",
|
||||
"auto_select_face",
|
||||
"audio_id",
|
||||
"sound_file",
|
||||
"sound_file_url",
|
||||
"sound_file_path",
|
||||
"audio_path",
|
||||
"sound_start_time",
|
||||
"sound_end_time",
|
||||
"sound_insert_time",
|
||||
"sound_volume",
|
||||
"original_audio_volume",
|
||||
]
|
||||
side_effects = [
|
||||
"paid remote generation via official Kling API",
|
||||
|
||||
@@ -122,13 +122,25 @@ class KlingOfficialImage(BaseTool):
|
||||
)
|
||||
idempotency_key_fields = [
|
||||
"prompt",
|
||||
"negative_prompt",
|
||||
"operation",
|
||||
"api_family",
|
||||
"model_name",
|
||||
"image_url",
|
||||
"image_path",
|
||||
"image_urls",
|
||||
"image_paths",
|
||||
"image_list",
|
||||
"image_reference",
|
||||
"image_fidelity",
|
||||
"human_fidelity",
|
||||
"aspect_ratio",
|
||||
"resolution",
|
||||
"n",
|
||||
"result_type",
|
||||
"series_amount",
|
||||
"element_list",
|
||||
"watermark",
|
||||
]
|
||||
side_effects = [
|
||||
"paid remote generation via official Kling API",
|
||||
|
||||
@@ -142,13 +142,33 @@ class KlingOfficialVideo(BaseTool):
|
||||
)
|
||||
idempotency_key_fields = [
|
||||
"prompt",
|
||||
"negative_prompt",
|
||||
"operation",
|
||||
"api_family",
|
||||
"model_name",
|
||||
"reference_image_url",
|
||||
"reference_image_path",
|
||||
"model_variant",
|
||||
"duration",
|
||||
"aspect_ratio",
|
||||
"resolution",
|
||||
"mode",
|
||||
"sound",
|
||||
"cfg_scale",
|
||||
"camera_control",
|
||||
"reference_image_url",
|
||||
"reference_image_path",
|
||||
"reference_tail_image_url",
|
||||
"reference_tail_image_path",
|
||||
"reference_image_urls",
|
||||
"reference_image_paths",
|
||||
"reference_video_url",
|
||||
"video_urls",
|
||||
"image_list",
|
||||
"video_list",
|
||||
"element_list",
|
||||
"multi_shot",
|
||||
"shot_type",
|
||||
"multi_prompt",
|
||||
"watermark",
|
||||
]
|
||||
side_effects = [
|
||||
"paid remote generation via official Kling API",
|
||||
|
||||
Reference in New Issue
Block a user