This commit is contained in:
Richard Yu 2025-07-18 17:14:46 -07:00
parent b64df1196f
commit 94684db953
2 changed files with 37 additions and 37 deletions

View File

@ -1121,7 +1121,7 @@ class PromptQueue:
Retrieves execution history in chronological order with pagination support. Retrieves execution history in chronological order with pagination support.
Returns a lightweight list of history objects. Returns a lightweight list of history objects.
Used by the /history_v2. Used by the /history_v2.
API Output Structure: API Output Structure:
{ {
"history": [ "history": [
@ -1135,7 +1135,7 @@ class PromptQueue:
"extra_data": dict # Additional metadata (workflow removed from extra_pnginfo) "extra_data": dict # Additional metadata (workflow removed from extra_pnginfo)
} | None, # None if no prompt data available } | None, # None if no prompt data available
"status": { "status": {
"status_str": str, # "success" | "error" "status_str": str, # "success" | "error"
"messages": [ # Filtered execution event messages "messages": [ # Filtered execution event messages
(event_name: str, event_data: dict) (event_name: str, event_data: dict)
] ]
@ -1144,7 +1144,7 @@ class PromptQueue:
# ... more history items # ... more history items
] ]
} }
Parameters: Parameters:
- max_items: Maximum number of items to return (None = all) - max_items: Maximum number of items to return (None = all)
- offset: Starting index (0-based, negative values calculated from end) - offset: Starting index (0-based, negative values calculated from end)
@ -1161,36 +1161,36 @@ class PromptQueue:
history_items = [] history_items = []
for key in selected_keys: for key in selected_keys:
history_entry = self.history[key] history_entry = self.history[key]
filtered_prompt = None filtered_prompt = None
if "prompt" in history_entry: if "prompt" in history_entry:
priority, prompt_id, _, extra_data, _ = history_entry["prompt"] priority, prompt_id, _, extra_data, _ = history_entry["prompt"]
filtered_extra_data = {} filtered_extra_data = {}
for k, v in extra_data.items(): for k, v in extra_data.items():
if k == "extra_pnginfo": if k == "extra_pnginfo":
filtered_extra_data[k] = { filtered_extra_data[k] = {
pk: pv for pk, pv in v.items() pk: pv for pk, pv in v.items()
if pk != "workflow" if pk != "workflow"
} }
else: else:
filtered_extra_data[k] = v filtered_extra_data[k] = v
filtered_prompt = { filtered_prompt = {
"priority": priority, "priority": priority,
"prompt_id": prompt_id, "prompt_id": prompt_id,
"extra_data": filtered_extra_data "extra_data": filtered_extra_data
} }
status = None status = None
if history_entry.get("status"): if history_entry.get("status"):
status = { status = {
"status_str": history_entry["status"]["status_str"], "status_str": history_entry["status"]["status_str"],
"messages": [(e, {k: v for k, v in d.items() if k != "nodes"}) "messages": [(e, {k: v for k, v in d.items() if k != "nodes"})
if e == "execution_cached" else (e, d) if e == "execution_cached" else (e, d)
for e, d in history_entry["status"]["messages"]] for e, d in history_entry["status"]["messages"]]
} }
item = { item = {
"prompt_id": key, "prompt_id": key,
"outputs": history_entry.get("outputs", {}), "outputs": history_entry.get("outputs", {}),
@ -1198,7 +1198,7 @@ class PromptQueue:
"prompt": filtered_prompt, "prompt": filtered_prompt,
"status": status "status": status
} }
history_items.append(item) history_items.append(item)
return {"history": history_items} return {"history": history_items}
@ -1207,7 +1207,7 @@ class PromptQueue:
""" """
Retrieves execution history for a specific prompt ID. Retrieves execution history for a specific prompt ID.
Used by /history_v2/:prompt_id Used by /history_v2/:prompt_id
API Output Structure: API Output Structure:
{ {
"<prompt_id>": { "<prompt_id>": {
@ -1227,15 +1227,15 @@ class PromptQueue:
} | None # None if no status recorded } | None # None if no status recorded
} }
} }
Returns empty dict {} if prompt_id not found. Returns empty dict {} if prompt_id not found.
""" """
with self.mutex: with self.mutex:
if prompt_id in self.history: if prompt_id in self.history:
history_entry = self.history[prompt_id] history_entry = self.history[prompt_id]
new_entry = {} new_entry = {}
if "prompt" in history_entry: if "prompt" in history_entry:
priority, prompt_id_inner, prompt_data, extra_data, outputs_to_execute = history_entry["prompt"] priority, prompt_id_inner, prompt_data, extra_data, outputs_to_execute = history_entry["prompt"]
new_entry["prompt"] = { new_entry["prompt"] = {
@ -1245,11 +1245,11 @@ class PromptQueue:
"extra_data": extra_data, "extra_data": extra_data,
"outputs_to_execute": outputs_to_execute "outputs_to_execute": outputs_to_execute
} }
for key, value in history_entry.items(): for key, value in history_entry.items():
if key != "prompt": if key != "prompt":
new_entry[key] = value new_entry[key] = value
return {prompt_id: new_entry} return {prompt_id: new_entry}
else: else:
return {} return {}

View File

@ -660,15 +660,15 @@ class TestExecution:
# Test history_v2 endpoint for specific prompt # Test history_v2 endpoint for specific prompt
specific_history = client.get_history_v2_for_prompt(prompt_id) specific_history = client.get_history_v2_for_prompt(prompt_id)
assert prompt_id in specific_history, "History v2 should contain prompt ID" assert prompt_id in specific_history, "History v2 should contain prompt ID"
# Verify key fields match between legacy and v2 # Verify key fields match between legacy and v2
v2_data = specific_history[prompt_id] v2_data = specific_history[prompt_id]
legacy_data = legacy_history[prompt_id] legacy_data = legacy_history[prompt_id]
# Check that outputs and status match # Check that outputs and status match
assert v2_data["outputs"] == legacy_data["outputs"], "Outputs should match" assert v2_data["outputs"] == legacy_data["outputs"], "Outputs should match"
assert v2_data["status"] == legacy_data["status"], "Status should match" assert v2_data["status"] == legacy_data["status"], "Status should match"
# Verify prompt is converted to dict format in v2 # Verify prompt is converted to dict format in v2
assert isinstance(v2_data["prompt"], dict), "Prompt should be a dictionary in v2" assert isinstance(v2_data["prompt"], dict), "Prompt should be a dictionary in v2"
assert "prompt_id" in v2_data["prompt"], "Prompt dict should have prompt_id" assert "prompt_id" in v2_data["prompt"], "Prompt dict should have prompt_id"
@ -761,18 +761,18 @@ class TestExecution:
def test_ordered_history_prompt_field_filtering_unit(self): def test_ordered_history_prompt_field_filtering_unit(self):
"""Unit test for prompt field filtering logic in get_ordered_history.""" """Unit test for prompt field filtering logic in get_ordered_history."""
from execution import PromptQueue from execution import PromptQueue
# Mock server # Mock server
class MockServer: class MockServer:
def queue_updated(self): pass def queue_updated(self): pass
# Create queue and add mock history # Create queue and add mock history
queue = PromptQueue(MockServer()) queue = PromptQueue(MockServer())
# Mock history entry with full prompt structure # Mock history entry with full prompt structure
mock_prompt_tuple = ( mock_prompt_tuple = (
12345, # priority/timestamp 12345, # priority/timestamp
'test-prompt-123', # prompt_id 'test-prompt-123', # prompt_id
{'nodes': {'1': {'class_type': 'SaveImage'}}}, # workflow (should be filtered) {'nodes': {'1': {'class_type': 'SaveImage'}}}, # workflow (should be filtered)
{ # extra_data { # extra_data
'client_id': 'test-client', 'client_id': 'test-client',
@ -783,7 +783,7 @@ class TestExecution:
}, },
['1'] # execute_outputs (should be filtered) ['1'] # execute_outputs (should be filtered)
) )
queue.history['test-prompt-123'] = { queue.history['test-prompt-123'] = {
'prompt': mock_prompt_tuple, 'prompt': mock_prompt_tuple,
'outputs': {'1': {'images': []}}, 'outputs': {'1': {'images': []}},
@ -797,53 +797,53 @@ class TestExecution:
}, },
'meta': {'1': {'node_id': '1'}} 'meta': {'1': {'node_id': '1'}}
} }
# Test get_ordered_history with our filtering # Test get_ordered_history with our filtering
result = queue.get_ordered_history() result = queue.get_ordered_history()
# Verify structure # Verify structure
assert "history" in result, "Result should have history key" assert "history" in result, "Result should have history key"
assert len(result["history"]) == 1, "Should have one history item" assert len(result["history"]) == 1, "Should have one history item"
history_item = result["history"][0] history_item = result["history"][0]
# Verify prompt_id field is added # Verify prompt_id field is added
assert "prompt_id" in history_item, "History item should have prompt_id field" assert "prompt_id" in history_item, "History item should have prompt_id field"
assert history_item["prompt_id"] == 'test-prompt-123', "prompt_id should match" assert history_item["prompt_id"] == 'test-prompt-123', "prompt_id should match"
# Verify prompt field is filtered # Verify prompt field is filtered
filtered_prompt = history_item["prompt"] filtered_prompt = history_item["prompt"]
assert isinstance(filtered_prompt, dict), "Filtered prompt should be a dictionary" assert isinstance(filtered_prompt, dict), "Filtered prompt should be a dictionary"
assert "priority" in filtered_prompt, "Filtered prompt should have priority" assert "priority" in filtered_prompt, "Filtered prompt should have priority"
assert "prompt_id" in filtered_prompt, "Filtered prompt should have prompt_id" assert "prompt_id" in filtered_prompt, "Filtered prompt should have prompt_id"
assert "extra_data" in filtered_prompt, "Filtered prompt should have extra_data" assert "extra_data" in filtered_prompt, "Filtered prompt should have extra_data"
# Verify correct elements are preserved # Verify correct elements are preserved
assert filtered_prompt["priority"] == 12345, "Priority should be preserved" assert filtered_prompt["priority"] == 12345, "Priority should be preserved"
assert filtered_prompt["prompt_id"] == 'test-prompt-123', "Prompt ID should be preserved" assert filtered_prompt["prompt_id"] == 'test-prompt-123', "Prompt ID should be preserved"
# Verify extra_data filtering # Verify extra_data filtering
extra_data = filtered_prompt["extra_data"] extra_data = filtered_prompt["extra_data"]
assert extra_data['client_id'] == 'test-client', "Client ID should be preserved" assert extra_data['client_id'] == 'test-client', "Client ID should be preserved"
assert 'extra_pnginfo' in extra_data, "extra_pnginfo should be present" assert 'extra_pnginfo' in extra_data, "extra_pnginfo should be present"
assert 'workflow' not in extra_data['extra_pnginfo'], "Workflow should be filtered out" assert 'workflow' not in extra_data['extra_pnginfo'], "Workflow should be filtered out"
assert extra_data['extra_pnginfo']['version'] == '1.0', "Other extra_pnginfo data should be preserved" assert extra_data['extra_pnginfo']['version'] == '1.0', "Other extra_pnginfo data should be preserved"
# Verify other fields are unchanged # Verify other fields are unchanged
assert history_item["outputs"] == {'1': {'images': []}}, "Outputs should be unchanged" assert history_item["outputs"] == {'1': {'images': []}}, "Outputs should be unchanged"
assert history_item["meta"] == {'1': {'node_id': '1'}}, "Meta should be unchanged" assert history_item["meta"] == {'1': {'node_id': '1'}}, "Meta should be unchanged"
# Verify status field filtering # Verify status field filtering
status = history_item["status"] status = history_item["status"]
assert "status_str" in status, "Status should have status_str" assert "status_str" in status, "Status should have status_str"
assert status["status_str"] == 'success', "Status string should be preserved" assert status["status_str"] == 'success', "Status string should be preserved"
assert "completed" not in status, "Completed field should be filtered out" assert "completed" not in status, "Completed field should be filtered out"
assert "messages" in status, "Status should have messages" assert "messages" in status, "Status should have messages"
# Verify message filtering # Verify message filtering
messages = status["messages"] messages = status["messages"]
assert len(messages) == 2, "Should have 2 messages" assert len(messages) == 2, "Should have 2 messages"
# Check execution_cached message has nodes filtered out # Check execution_cached message has nodes filtered out
execution_cached_msg = messages[0] execution_cached_msg = messages[0]
assert execution_cached_msg[0] == 'execution_cached', "First message should be execution_cached" assert execution_cached_msg[0] == 'execution_cached', "First message should be execution_cached"
@ -851,7 +851,7 @@ class TestExecution:
assert "nodes" not in cached_data, "Nodes field should be filtered from execution_cached messages" assert "nodes" not in cached_data, "Nodes field should be filtered from execution_cached messages"
assert "timestamp" in cached_data, "Timestamp should be preserved in execution_cached messages" assert "timestamp" in cached_data, "Timestamp should be preserved in execution_cached messages"
assert cached_data["timestamp"] == 1234567890, "Timestamp value should be correct" assert cached_data["timestamp"] == 1234567890, "Timestamp value should be correct"
# Check execution_start message remains unchanged # Check execution_start message remains unchanged
execution_start_msg = messages[1] execution_start_msg = messages[1]
assert execution_start_msg[0] == 'execution_start', "Second message should be execution_start" assert execution_start_msg[0] == 'execution_start', "Second message should be execution_start"