diff --git a/README.md b/README.md index 0542272..d8ffd58 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,24 @@ Phase 1 初始支持包括: - LoRA loader 的文件名和强度会单独进入 setting;但 LoRA trigger words 如果通过文本节点进入 prompt,就会保留在 positive / negative 中。 - 不做内容审查,不做提示词优化,不删 token。 +## LLM / ShowText 缓存说明 + +对于 Gemini / OpenAI / ChatGPT / Claude / LLM 反推工作流,插件只能恢复已经写入 metadata、并且位于最终 selected sampler/generator `positive` / `negative` 链路上的运行结果。 + +可以恢复: + +- 最终链路上的 `ShowText|pysssss` cache,例如 prompt JSON 的 `inputs.text_0` 或同 node_id workflow JSON 的 `widgets_values[0]`。 +- 最终链路上的 `SmartMetadataReader` positive / negative output 递归结果。 +- 最终链路上的 `StringFunction`、文本拼接、`ConditioningCombine` / `ConditioningConcat` 多分支组合结果。 + +无法恢复: + +- 只存在于 LLM runtime node 内部、但没有写入 `ShowText` cache 的运行结果。 +- workflow 其他未连接分支里的 `ShowText` 缓存,即使它看起来像 prompt。 +- Gemini / OpenAI 节点的 `prompt`、`system_instruction`、`system_prompt`、`messages`、模板或 API 参数。 + +这种情况下节点会返回 `PARTIAL` / unresolved。这是为了避免误读旧分支、备用分支、UI 展示分支或 LLM 指令模板。 + ## 已验证场景 Phase 1 实机和回归测试已覆盖: diff --git a/README_EN.md b/README_EN.md index 10e2135..511b706 100644 --- a/README_EN.md +++ b/README_EN.md @@ -115,6 +115,24 @@ Initial Phase 1 support includes: - LoRA loader file names and strengths are extracted separately for settings; LoRA trigger words remain in the prompt if they entered the text chain. - The parser does not perform content moderation, prompt optimization, or token deletion. +## LLM / ShowText Cache Notes + +For Gemini / OpenAI / ChatGPT / Claude / LLM prompt-generation workflows, the plugin can only recover runtime results that were written into metadata and are on the final selected sampler/generator `positive` / `negative` chain. + +Recoverable: + +- `ShowText|pysssss` cache on the final chain, such as `inputs.text_0` in prompt JSON or `widgets_values[0]` on the same node id in workflow JSON. +- Recursive `SmartMetadataReader` positive / negative output results on the final chain. +- `StringFunction`, text concatenation, `ConditioningCombine`, and `ConditioningConcat` branch results on the final chain. + +Not recoverable: + +- Runtime LLM output that exists only inside an LLM runtime node and was not embedded into `ShowText` cache. +- `ShowText` caches from other workflow branches that are not connected to the final selected generator, even if they look like prompts. +- Gemini / OpenAI node `prompt`, `system_instruction`, `system_prompt`, `messages`, templates, or API parameters. + +In these cases the node returns `PARTIAL` / unresolved. This avoids reading stale branches, fallback branches, UI-only display branches, or LLM instruction templates as final prompts. + ## Verified Scenarios Phase 1 real-world validation and regression tests cover: diff --git a/smart_metadata_reader/adapters/pysssss.py b/smart_metadata_reader/adapters/pysssss.py index 6ab7ad4..ef54fac 100644 --- a/smart_metadata_reader/adapters/pysssss.py +++ b/smart_metadata_reader/adapters/pysssss.py @@ -4,6 +4,13 @@ from .base import TextResolutionContext from ..models import NodeRecord, PromptSegment +MISSING_LLM_SHOWTEXT_CACHE_REASON = ( + "ShowText cache missing on final chain; upstream LLM runtime output was not " + "embedded in metadata. Other ShowText caches outside the final chain are " + "ignored to avoid prompt pollution." +) + + class StringFunctionAdapter: def matches(self, node: NodeRecord) -> bool: return node.class_type == "StringFunction|pysssss" @@ -86,7 +93,7 @@ class ShowTextAdapter: node=node, field="text", role=role, - reason="ShowText cache missing and upstream is LLM runtime output not embedded", + reason=MISSING_LLM_SHOWTEXT_CACHE_REASON, ) return [] diff --git a/tests/test_metadata_reader.py b/tests/test_metadata_reader.py index 49fbcc4..8e9d30f 100644 --- a/tests/test_metadata_reader.py +++ b/tests/test_metadata_reader.py @@ -718,6 +718,20 @@ def test_showtext_cache_from_llm_chain_is_used_without_reading_llm_template(): assert "wrong unused prompt" not in result.positive +def test_showtext_prompt_text_0_on_final_chain_beats_llm_template(): + from smart_metadata_reader.metadata_reader import parse_metadata_bundle + + prompt = _llm_showtext_upscale_prompt() + prompt["37"]["inputs"]["text_0"] = "cached final chain prompt" + + result = parse_metadata_bundle(_bundle_for_prompt(prompt)) + + assert result.positive == "cached final chain prompt" + assert "Gemini prompt template" not in result.positive + assert "system instruction" not in result.positive + assert result.status_message != "FAILED" + + def test_showtext_cache_compatible_class_from_llm_chain_is_used(): from smart_metadata_reader.metadata_reader import parse_metadata_bundle @@ -797,8 +811,9 @@ def test_showtext_missing_cache_with_llm_upstream_returns_partial_unresolved(): assert result.status_message == "PARTIAL" assert result.confidence <= 0.6 assert result.partial_result["unresolved"][0]["class_type"] == "ShowText|pysssss" - assert ( - result.partial_result["unresolved"][0]["reason"] - == "ShowText cache missing and upstream is LLM runtime output not embedded" - ) + reason = result.partial_result["unresolved"][0]["reason"] + assert "ShowText cache missing on final chain" in reason + assert "upstream LLM runtime output was not embedded in metadata" in reason + assert "Other ShowText caches outside the final chain are ignored" in reason + assert "wrong unused prompt" not in result.positive assert "Unresolved:" in result.setting