From 87a109c7ef3dfec98c13779a620ced96898bf89f Mon Sep 17 00:00:00 2001 From: vegu-ai-tools <152010387+vegu-ai-tools@users.noreply.github.com> Date: Tue, 31 Mar 2026 18:34:18 +0300 Subject: [PATCH] expand arc polish --- src/talemate/agents/director/__init__.py | 3 + src/talemate/agents/director/chat/mixin.py | 23 - .../agents/director/chat/websocket_handler.py | 16 +- .../director/modules/create-outline.json | 1063 +++++++++++------ .../director/modules/critique-outline.json | 2 +- .../director-action-direct-story-arc.json | 87 +- .../agents/director/modules/manage-plan.json | 174 +-- src/talemate/agents/director/plan/__init__.py | 3 +- src/talemate/agents/director/plan/expand.py | 211 +--- src/talemate/agents/director/plan/mixin.py | 293 +++++ src/talemate/agents/director/plan/nodes.py | 14 +- .../director/scene-plan-create-outline.jinja2 | 2 +- .../scene-plan-critique-outline.jinja2 | 2 +- .../src/components/SceneToolsDirector.vue | 30 +- ...ermine_character_dialogue_instructions.txt | 5 +- .../prompts/baselines/director/arc_expand.txt | 104 ++ .../arc_expand__with_preceding_text.txt | 104 ++ .../director/arc_expand_critique.txt | 33 + .../baselines/editor/revision_unslop.txt | 69 +- ...ermine_character_dialogue_instructions.txt | 5 +- .../editor/revision_unslop.txt | 69 +- ...ermine_character_dialogue_instructions.txt | 5 +- .../editor/revision_unslop.txt | 69 +- ...ermine_character_dialogue_instructions.txt | 5 +- .../editor/revision_unslop.txt | 69 +- ...ermine_character_dialogue_instructions.txt | 5 +- .../editor/revision_unslop.txt | 69 +- ...ermine_character_dialogue_instructions.txt | 5 +- .../baselines_xml/editor/revision_unslop.txt | 69 +- .../baselines/test_director_baselines.py | 167 ++- tests/test_plan_expand.py | 259 ++++ 31 files changed, 2054 insertions(+), 980 deletions(-) create mode 100644 src/talemate/agents/director/plan/mixin.py create mode 100644 tests/data/prompts/baselines/director/arc_expand.txt create mode 100644 tests/data/prompts/baselines/director/arc_expand__with_preceding_text.txt create mode 100644 tests/data/prompts/baselines/director/arc_expand_critique.txt create mode 100644 tests/test_plan_expand.py diff --git a/src/talemate/agents/director/__init__.py b/src/talemate/agents/director/__init__.py index a57d250a..39a6e91f 100644 --- a/src/talemate/agents/director/__init__.py +++ b/src/talemate/agents/director/__init__.py @@ -26,6 +26,7 @@ from .websocket_handler import DirectorWebsocketHandler from .chat.mixin import DirectorChatMixin from .character_management import CharacterManagementMixin from .scene_direction.mixin import SceneDirectionMixin +from .plan.mixin import PlanMixin import talemate.agents.director.nodes # noqa: F401 if TYPE_CHECKING: @@ -38,6 +39,7 @@ log = structlog.get_logger("talemate.agent.director") class DirectorAgent( DirectorChatMixin, SceneDirectionMixin, + PlanMixin, GuideSceneMixin, MemoryRAGMixin, GenerateChoicesMixin, @@ -95,6 +97,7 @@ class DirectorAgent( CharacterManagementMixin.add_actions(actions) DirectorChatMixin.add_actions(actions) SceneDirectionMixin.add_scene_direction_actions(actions) + PlanMixin.add_plan_actions(actions) return actions @classmethod diff --git a/src/talemate/agents/director/chat/mixin.py b/src/talemate/agents/director/chat/mixin.py index 6f537dee..165cc639 100644 --- a/src/talemate/agents/director/chat/mixin.py +++ b/src/talemate/agents/director/chat/mixin.py @@ -118,25 +118,6 @@ class DirectorChatMixin: step=10, min=20, max=500, - title="Arc Generation", - ), - "generate_arc_dialogue_ratio": AgentActionConfig( - type="number", - label="Dialogue beat ratio", - description="Target fraction of beats that should be dialogue during arc generation. 0.4 = 40% dialogue beats.", - value=0.4, - step=0.1, - min=0.0, - max=1.0, - ), - "generate_arc_expand_chunk_size": AgentActionConfig( - type="number", - label="Expand chunk size", - description="Number of beats per expansion chunk in expand mode. Larger chunks produce more cohesive prose but use more context.", - value=5, - step=1, - min=3, - max=12, ), }, ) @@ -163,10 +144,6 @@ class DirectorChatMixin: def chat_scene_context_ratio(self) -> float: return self.actions["chat"].config["scene_context_ratio"].value - @property - def chat_dialogue_ratio(self) -> float: - return self.actions["chat"].config["generate_arc_dialogue_ratio"].value - @property def chat_enable_analysis(self) -> bool: return self.actions["chat"].config["enable_analysis"].value diff --git a/src/talemate/agents/director/chat/websocket_handler.py b/src/talemate/agents/director/chat/websocket_handler.py index 27a0096d..a167a550 100644 --- a/src/talemate/agents/director/chat/websocket_handler.py +++ b/src/talemate/agents/director/chat/websocket_handler.py @@ -44,6 +44,8 @@ class ChatCreateGenerateArcPayload(pydantic.BaseModel): beat_count: int = 8 dialogue_ratio: float | None = None mode: Literal["generate_arc", "generate_arc_expand"] = "generate_arc" + outline_critique: bool | None = None + expand_critique: bool | None = None class ChatRegeneratePayload(pydantic.BaseModel): @@ -451,10 +453,20 @@ class DirectorChatWebsocketMixin: payload = ChatCreateGenerateArcPayload(**data) if payload.dialogue_ratio is not None: - self.director.actions["chat"].config[ - "generate_arc_dialogue_ratio" + self.director.actions["plan"].config[ + "dialogue_ratio" ].value = payload.dialogue_ratio + if payload.outline_critique is not None: + self.director.actions["plan"].config[ + "outline_critique" + ].value = payload.outline_critique + + if payload.expand_critique is not None: + self.director.actions["plan"].config[ + "expand_critique" + ].value = payload.expand_critique + chat = self.director.chat_create_generate_arc( payload.instructions, payload.beat_count, diff --git a/src/talemate/agents/director/modules/create-outline.json b/src/talemate/agents/director/modules/create-outline.json index 4754b13d..77822dfc 100644 --- a/src/talemate/agents/director/modules/create-outline.json +++ b/src/talemate/agents/director/modules/create-outline.json @@ -16,8 +16,8 @@ "properties": { "number_type": "int" }, - "x": 298, - "y": 524, + "x": 296, + "y": 258, "width": 210, "height": 58, "collapsed": false, @@ -32,8 +32,8 @@ "name": "beat_count", "scope": "local" }, - "x": 578, - "y": 524, + "x": 576, + "y": 258, "width": 210, "height": 122, "collapsed": false, @@ -48,8 +48,8 @@ "name": "instructions", "scope": "local" }, - "x": 568, - "y": 304, + "x": 566, + "y": 38, "width": 210, "height": 122, "collapsed": false, @@ -67,8 +67,8 @@ "input_group": "", "num": 0 }, - "x": 28, - "y": 74, + "x": 26, + "y": -192, "width": 210, "height": 154, "collapsed": false, @@ -84,8 +84,8 @@ "output_name": "beat_count", "num": 2 }, - "x": 1218, - "y": 554, + "x": 1216, + "y": 288, "width": 210, "height": 106, "collapsed": false, @@ -101,8 +101,8 @@ "output_name": "instructions", "num": 1 }, - "x": 1218, - "y": 304, + "x": 1216, + "y": 38, "width": 210, "height": 106, "collapsed": false, @@ -110,21 +110,6 @@ "registry": "core/Output", "base_type": "core/Node" }, - "2051509a-fc52-41ea-b674-faf9ca7a2faf": { - "title": "Stage 0", - "id": "2051509a-fc52-41ea-b674-faf9ca7a2faf", - "properties": { - "stage": 0 - }, - "x": 898, - "y": 404, - "width": 210, - "height": 118, - "collapsed": false, - "inherited": false, - "registry": "core/Stage", - "base_type": "core/Node" - }, "1e9d954a-1e56-4880-9f80-00c235bed988": { "title": "OUT state", "id": "1e9d954a-1e56-4880-9f80-00c235bed988", @@ -133,8 +118,8 @@ "output_name": "state", "num": 0 }, - "x": 1208, - "y": 84, + "x": 1206, + "y": -182, "width": 210, "height": 106, "collapsed": false, @@ -148,8 +133,8 @@ "properties": { "value": true }, - "x": 1044, - "y": 788, + "x": 1041, + "y": 802, "width": 210, "height": 58, "collapsed": false, @@ -165,8 +150,8 @@ "template_file": "scene-plan-create-outline", "template_text": "" }, - "x": 1059, - "y": 1022, + "x": 1056, + "y": 1036, "width": 210, "height": 146, "collapsed": false, @@ -180,8 +165,8 @@ "properties": { "value": true }, - "x": 98, - "y": 1171, + "x": 95, + "y": 1185, "width": 210, "height": 58, "collapsed": true, @@ -193,8 +178,8 @@ "title": "template_vars", "id": "517d4bb8-38aa-4b11-8ba9-f569a6a45338", "properties": {}, - "x": 849, - "y": 1056, + "x": 846, + "y": 1070, "width": 140, "height": 26, "collapsed": false, @@ -208,8 +193,8 @@ "properties": { "character_status": "active" }, - "x": 229, - "y": 916, + "x": 226, + "y": 930, "width": 228, "height": 58, "collapsed": false, @@ -224,8 +209,8 @@ "name": "beat_count", "scope": "local" }, - "x": 29, - "y": 1236, + "x": 26, + "y": 1250, "width": 210, "height": 122, "collapsed": true, @@ -239,8 +224,8 @@ "properties": { "beat_count": 8 }, - "x": 259, - "y": 1176, + "x": 256, + "y": 1190, "width": 304, "height": 118, "collapsed": false, @@ -248,74 +233,6 @@ "registry": "agents/director/plan/EstimateWords", "base_type": "core/Node" }, - "0bf06241-b92b-4f0f-bc67-0789fe061c18": { - "title": "Meta", - "id": "0bf06241-b92b-4f0f-bc67-0789fe061c18", - "properties": {}, - "x": 2009, - "y": 1466, - "width": 140, - "height": 81, - "collapsed": false, - "inherited": false, - "registry": "data/DictCollector", - "dynamic_inputs": [ - { - "name": "item0", - "type": "*" - } - ], - "base_type": "core/DynamicSocketNodeBase" - }, - "fcc70ad0-b17c-4f1a-9752-9f1377c3aa39": { - "title": "SET local.plan_id", - "id": "fcc70ad0-b17c-4f1a-9752-9f1377c3aa39", - "properties": { - "name": "plan_id", - "scope": "local" - }, - "x": 2955, - "y": 1084, - "width": 210, - "height": 122, - "collapsed": false, - "inherited": false, - "registry": "state/SetState", - "base_type": "core/Node" - }, - "789e16f5-239e-4bec-9906-4690a692a01b": { - "title": "SET local.summary", - "id": "789e16f5-239e-4bec-9906-4690a692a01b", - "properties": { - "name": "summary", - "scope": "local" - }, - "x": 2955, - "y": 1254, - "width": 210, - "height": 122, - "collapsed": false, - "inherited": false, - "registry": "state/SetState", - "base_type": "core/Node" - }, - "d70c7ca4-ef49-4964-9c3c-c9ec0df7fa04": { - "title": "OUT beat_count", - "id": "d70c7ca4-ef49-4964-9c3c-c9ec0df7fa04", - "properties": { - "output_type": "str", - "output_name": "plan_id", - "num": 3 - }, - "x": 1864, - "y": 94, - "width": 210, - "height": 106, - "collapsed": false, - "inherited": false, - "registry": "core/Output", - "base_type": "core/Node" - }, "efa8c129-8445-4860-83cd-8c180e9053aa": { "title": "GET local.plan_id", "id": "efa8c129-8445-4860-83cd-8c180e9053aa", @@ -324,7 +241,7 @@ "scope": "local" }, "x": 1484, - "y": 74, + "y": 334, "width": 210, "height": 122, "collapsed": false, @@ -332,31 +249,14 @@ "registry": "state/GetState", "base_type": "core/Node" }, - "8641d43d-c5d7-471e-870b-27fcaf4b4564": { - "title": "OUT summary", - "id": "8641d43d-c5d7-471e-870b-27fcaf4b4564", - "properties": { - "output_type": "str", - "output_name": "summary", - "num": 4 - }, - "x": 1864, - "y": 304, - "width": 210, - "height": 106, - "collapsed": false, - "inherited": false, - "registry": "core/Output", - "base_type": "core/Node" - }, "75689617-050f-4092-a0d0-36d9ca63262c": { "title": "Get Agent", "id": "75689617-050f-4092-a0d0-36d9ca63262c", "properties": { "agent_name": "director" }, - "x": 721, - "y": 890, + "x": 718, + "y": 904, "width": 210, "height": 58, "collapsed": false, @@ -368,8 +268,8 @@ "title": "Template Variables", "id": "34f29d9b-828c-4450-86ce-7163a9ffd2e0", "properties": {}, - "x": 891, - "y": 1220, + "x": 888, + "y": 1234, "width": 170, "height": 46, "collapsed": false, @@ -385,7 +285,7 @@ "scope": "local" }, "x": 1484, - "y": 284, + "y": 544, "width": 210, "height": 122, "collapsed": false, @@ -393,53 +293,8 @@ "registry": "state/GetState", "base_type": "core/Node" }, - "944cd2b9-8d55-4353-a7a9-e3cd98882768": { - "title": "GET obj.perspective", - "id": "944cd2b9-8d55-4353-a7a9-e3cd98882768", - "properties": { - "attribute": "perspective" - }, - "x": 1759, - "y": 1316, - "width": 210, - "height": 98, - "collapsed": false, - "inherited": false, - "registry": "data/Get", - "base_type": "core/Node" - }, - "78cbb918-22da-4e99-87b4-e7a0a3c9da67": { - "title": "GET obj.response", - "id": "78cbb918-22da-4e99-87b4-e7a0a3c9da67", - "properties": { - "attribute": "response" - }, - "x": 1761, - "y": 1170, - "width": 210, - "height": 98, - "collapsed": false, - "inherited": false, - "registry": "data/Get", - "base_type": "core/Node" - }, - "a6b6acdb-c0ad-4c79-a9fc-0cb4a7c5878a": { - "title": "Stage 1", - "id": "a6b6acdb-c0ad-4c79-a9fc-0cb4a7c5878a", - "properties": { - "stage": 1 - }, - "x": 3260, - "y": 1170, - "width": 210, - "height": 118, - "collapsed": false, - "inherited": false, - "registry": "core/Stage", - "base_type": "core/Node" - }, "18339c3e-031b-471d-a317-efcd2c14a4e0": { - "title": "Generate Response", + "title": "Generate Story Outline", "id": "18339c3e-031b-471d-a317-efcd2c14a4e0", "properties": { "data_output": false, @@ -448,8 +303,8 @@ "action_type": "scene_direction", "attempts": 2 }, - "x": 1399, - "y": 986, + "x": 1396, + "y": 1000, "width": 270, "height": 334, "collapsed": false, @@ -457,134 +312,12 @@ "registry": "prompt/GenerateResponse", "base_type": "core/Node" }, - "cb985916-16c3-4a51-bbf8-d961cabbf07a": { - "title": "GET local.instructions", - "id": "cb985916-16c3-4a51-bbf8-d961cabbf07a", - "properties": { - "name": "instructions", - "scope": "local" - }, - "x": 1770, - "y": 1100, - "width": 210, - "height": 122, - "collapsed": true, - "inherited": false, - "registry": "state/GetState", - "base_type": "core/Node" - }, - "97d95ce0-dccb-41ed-b41a-aca140af56eb": { - "title": "Create Plan", - "id": "97d95ce0-dccb-41ed-b41a-aca140af56eb", - "properties": { - "instructions": "", - "status": "ready" - }, - "x": 2620, - "y": 1170, - "width": 210, - "height": 162, - "collapsed": false, - "inherited": false, - "registry": "agents/director/plan/CreatePlan", - "base_type": "core/Node" - }, - "9c312643-3e88-43f7-a473-ade757d8c550": { - "title": "Critique Outline", - "id": "9c312643-3e88-43f7-a473-ade757d8c550", - "properties": {}, - "x": 2070, - "y": 1050, - "width": 346, - "height": 146, - "collapsed": false, - "inherited": false, - "registry": "agents/director/plan/critiqueOutline", - "base_type": "core/Graph" - }, - "c6488e1b-62c6-4bde-a967-f06996fbb14c": { - "title": "changes", - "id": "c6488e1b-62c6-4bde-a967-f06996fbb14c", - "properties": {}, - "x": 2280, - "y": 1290, - "width": 140, - "height": 26, - "collapsed": true, - "inherited": false, - "registry": "core/Watch", - "base_type": "core/Node" - }, - "66e5a663-7ac7-4b8f-8ab8-16c6f1623b0f": { - "title": "orig_outline", - "id": "66e5a663-7ac7-4b8f-8ab8-16c6f1623b0f", - "properties": {}, - "x": 2280, - "y": 1250, - "width": 140, - "height": 26, - "collapsed": true, - "inherited": false, - "registry": "core/Watch", - "base_type": "core/Node" - }, - "91972225-9a2c-4cb4-ae5f-a61d0de227c6": { - "title": "outline", - "id": "91972225-9a2c-4cb4-ae5f-a61d0de227c6", - "properties": {}, - "x": 2440, - "y": 1210, - "width": 140, - "height": 26, - "collapsed": false, - "inherited": false, - "registry": "core/Watch", - "base_type": "core/Node" - }, - "c9775f83-e7bc-4dc5-959c-bc2182a0d10b": { - "title": "IN instructions", - "id": "c9775f83-e7bc-4dc5-959c-bc2182a0d10b", - "properties": { - "input_type": "str", - "input_name": "instructions", - "input_optional": false, - "input_group": "", - "num": 1 - }, - "x": 28, - "y": 294, - "width": 210, - "height": 154, - "collapsed": false, - "inherited": false, - "registry": "core/Input", - "base_type": "core/Node" - }, - "7d565eb9-f156-4a92-9723-e27964dfe759": { - "title": "IN beat_count", - "id": "7d565eb9-f156-4a92-9723-e27964dfe759", - "properties": { - "input_type": "int", - "input_name": "beat_count", - "input_optional": false, - "input_group": "", - "num": 1 - }, - "x": 28, - "y": 524, - "width": 210, - "height": 154, - "collapsed": false, - "inherited": false, - "registry": "core/Input", - "base_type": "core/Node" - }, "6bb81c40-cff1-42e6-a471-001985e57e5c": { "title": "Dict Collector", "id": "6bb81c40-cff1-42e6-a471-001985e57e5c", "properties": {}, - "x": 640, - "y": 1150, + "x": 637, + "y": 1164, "width": 140, "height": 141, "collapsed": false, @@ -617,14 +350,540 @@ "name": "instructions", "scope": "local" }, - "x": 360, - "y": 1360, + "x": 357, + "y": 1374, "width": 210, "height": 122, "collapsed": false, "inherited": false, "registry": "state/GetState", "base_type": "core/Node" + }, + "cd6a7f30-cc94-4fcc-8d2a-a99dd985a526": { + "title": "As Bool", + "id": "cd6a7f30-cc94-4fcc-8d2a-a99dd985a526", + "properties": { + "default": false + }, + "x": 317, + "y": 519, + "width": 210, + "height": 58, + "collapsed": false, + "inherited": false, + "registry": "core/AsBool", + "base_type": "core/Node" + }, + "857a9a27-0b46-4ab7-99b3-c00d773c4902": { + "title": "SET local.critique", + "id": "857a9a27-0b46-4ab7-99b3-c00d773c4902", + "properties": { + "name": "critique", + "scope": "local" + }, + "x": 590, + "y": 520, + "width": 210, + "height": 122, + "collapsed": false, + "inherited": false, + "registry": "state/SetState", + "base_type": "core/Node" + }, + "d70c7ca4-ef49-4964-9c3c-c9ec0df7fa04": { + "title": "OUT beat_count", + "id": "d70c7ca4-ef49-4964-9c3c-c9ec0df7fa04", + "properties": { + "output_type": "str", + "output_name": "plan_id", + "num": 4 + }, + "x": 1864, + "y": 354, + "width": 210, + "height": 106, + "collapsed": false, + "inherited": false, + "registry": "core/Output", + "base_type": "core/Node" + }, + "8641d43d-c5d7-471e-870b-27fcaf4b4564": { + "title": "OUT summary", + "id": "8641d43d-c5d7-471e-870b-27fcaf4b4564", + "properties": { + "output_type": "str", + "output_name": "summary", + "num": 5 + }, + "x": 1864, + "y": 564, + "width": 210, + "height": 106, + "collapsed": false, + "inherited": false, + "registry": "core/Output", + "base_type": "core/Node" + }, + "2051509a-fc52-41ea-b674-faf9ca7a2faf": { + "title": "Stage 0", + "id": "2051509a-fc52-41ea-b674-faf9ca7a2faf", + "properties": { + "stage": 0 + }, + "x": 896, + "y": 138, + "width": 210, + "height": 118, + "collapsed": false, + "inherited": false, + "registry": "core/Stage", + "base_type": "core/Node" + }, + "7ef30f81-082b-4294-b0a9-bc5cb57fd6ed": { + "title": "OUT critique", + "id": "7ef30f81-082b-4294-b0a9-bc5cb57fd6ed", + "properties": { + "output_type": "bool", + "output_name": "critique", + "num": 3 + }, + "x": 1220, + "y": 540, + "width": 210, + "height": 106, + "collapsed": false, + "inherited": false, + "registry": "core/Output", + "base_type": "core/Node" + }, + "0bf06241-b92b-4f0f-bc67-0789fe061c18": { + "title": "Meta", + "id": "0bf06241-b92b-4f0f-bc67-0789fe061c18", + "properties": {}, + "x": 2006, + "y": 1480, + "width": 140, + "height": 81, + "collapsed": false, + "inherited": false, + "registry": "data/DictCollector", + "dynamic_inputs": [ + { + "name": "item0", + "type": "*" + } + ], + "base_type": "core/DynamicSocketNodeBase" + }, + "78cbb918-22da-4e99-87b4-e7a0a3c9da67": { + "title": "GET obj.response", + "id": "78cbb918-22da-4e99-87b4-e7a0a3c9da67", + "properties": { + "attribute": "response" + }, + "x": 1767, + "y": 1104, + "width": 210, + "height": 98, + "collapsed": false, + "inherited": false, + "registry": "data/Get", + "base_type": "core/Node" + }, + "944cd2b9-8d55-4353-a7a9-e3cd98882768": { + "title": "GET obj.perspective", + "id": "944cd2b9-8d55-4353-a7a9-e3cd98882768", + "properties": { + "attribute": "perspective" + }, + "x": 1767, + "y": 1304, + "width": 210, + "height": 98, + "collapsed": false, + "inherited": false, + "registry": "data/Get", + "base_type": "core/Node" + }, + "a0a70d5d-6fdc-4875-8f97-e74ad6a6480e": { + "title": "SET local.outline", + "id": "a0a70d5d-6fdc-4875-8f97-e74ad6a6480e", + "properties": { + "name": "outline", + "scope": "local" + }, + "x": 2200, + "y": 1010, + "width": 210, + "height": 122, + "collapsed": false, + "inherited": false, + "registry": "state/SetState", + "base_type": "core/Node" + }, + "2e6b8777-ffab-48c7-b396-fd4c38e8936f": { + "title": "SET local.plan_meta", + "id": "2e6b8777-ffab-48c7-b396-fd4c38e8936f", + "properties": { + "name": "plan_meta", + "scope": "local" + }, + "x": 2220, + "y": 1440, + "width": 210, + "height": 122, + "collapsed": false, + "inherited": false, + "registry": "state/SetState", + "base_type": "core/Node" + }, + "c78ff25c-e271-4da7-95e7-ea55026eb0ae": { + "title": "SET local.perspective", + "id": "c78ff25c-e271-4da7-95e7-ea55026eb0ae", + "properties": { + "name": "perspective", + "scope": "local" + }, + "x": 2210, + "y": 1240, + "width": 210, + "height": 122, + "collapsed": false, + "inherited": false, + "registry": "state/SetState", + "base_type": "core/Node" + }, + "a6b6acdb-c0ad-4c79-a9fc-0cb4a7c5878a": { + "title": "Stage 1", + "id": "a6b6acdb-c0ad-4c79-a9fc-0cb4a7c5878a", + "properties": { + "stage": 1 + }, + "x": 2530, + "y": 1240, + "width": 210, + "height": 118, + "collapsed": false, + "inherited": false, + "registry": "core/Stage", + "base_type": "core/Node" + }, + "297241d7-cf15-4f7a-98b7-077e9238258b": { + "title": "GET local.plan_meta", + "id": "297241d7-cf15-4f7a-98b7-077e9238258b", + "properties": { + "name": "plan_meta", + "scope": "local" + }, + "x": 538, + "y": 2807, + "width": 210, + "height": 122, + "collapsed": false, + "inherited": false, + "registry": "state/GetState", + "base_type": "core/Node" + }, + "50a12485-7ff7-4688-b73e-ee665f19ad20": { + "title": "SET local.summary", + "id": "50a12485-7ff7-4688-b73e-ee665f19ad20", + "properties": { + "name": "summary", + "scope": "local" + }, + "x": 1178, + "y": 2687, + "width": 210, + "height": 122, + "collapsed": false, + "inherited": false, + "registry": "state/SetState", + "base_type": "core/Node" + }, + "9e59f7a6-1e3c-4e39-a6b3-31fdd20473d7": { + "title": "SET local.plan_id", + "id": "9e59f7a6-1e3c-4e39-a6b3-31fdd20473d7", + "properties": { + "name": "plan_id", + "scope": "local" + }, + "x": 1178, + "y": 2487, + "width": 210, + "height": 122, + "collapsed": false, + "inherited": false, + "registry": "state/SetState", + "base_type": "core/Node" + }, + "fac41364-9daf-42d4-a6cb-ed52b5247830": { + "title": "GET local.outline", + "id": "fac41364-9daf-42d4-a6cb-ed52b5247830", + "properties": { + "name": "outline", + "scope": "local" + }, + "x": 25, + "y": 2061, + "width": 210, + "height": 122, + "collapsed": false, + "inherited": false, + "registry": "state/GetState", + "base_type": "core/Node" + }, + "1ffc7551-5a84-4445-8dd6-d4bf8fbe4c11": { + "title": "GET local.perspective", + "id": "1ffc7551-5a84-4445-8dd6-d4bf8fbe4c11", + "properties": { + "name": "perspective", + "scope": "local" + }, + "x": 25, + "y": 2261, + "width": 210, + "height": 122, + "collapsed": false, + "inherited": false, + "registry": "state/GetState", + "base_type": "core/Node" + }, + "f542f3d3-8b0c-4dd7-bc64-c77dd99ca10d": { + "title": "GET local.instructions", + "id": "f542f3d3-8b0c-4dd7-bc64-c77dd99ca10d", + "properties": { + "name": "instructions", + "scope": "local" + }, + "x": 25, + "y": 1861, + "width": 210, + "height": 122, + "collapsed": false, + "inherited": false, + "registry": "state/GetState", + "base_type": "core/Node" + }, + "9f99ab9d-9e25-487d-8007-2b57eedbccf0": { + "title": "GET local.critique", + "id": "9f99ab9d-9e25-487d-8007-2b57eedbccf0", + "properties": { + "name": "critique", + "scope": "local" + }, + "x": 25, + "y": 1671, + "width": 210, + "height": 122, + "collapsed": false, + "inherited": false, + "registry": "state/GetState", + "base_type": "core/Node" + }, + "5c3c0736-5504-4c7d-aff3-55efc38c4dfb": { + "title": "IS", + "id": "5c3c0736-5504-4c7d-aff3-55efc38c4dfb", + "properties": { + "pass_through": true + }, + "x": 295, + "y": 1731, + "width": 210, + "height": 78, + "collapsed": true, + "inherited": false, + "registry": "core/Switch", + "base_type": "core/Node" + }, + "1b840b34-d28e-428f-8a55-2b2062b1a9c1": { + "title": "Critique Outline", + "id": "1b840b34-d28e-428f-8a55-2b2062b1a9c1", + "properties": {}, + "x": 420, + "y": 1891, + "width": 346, + "height": 146, + "collapsed": false, + "inherited": false, + "registry": "agents/director/plan/critiqueOutline", + "base_type": "core/Graph" + }, + "e0f2a097-0a50-4a14-957e-31f607d09eaa": { + "title": "changes", + "id": "e0f2a097-0a50-4a14-957e-31f607d09eaa", + "properties": {}, + "x": 935, + "y": 2171, + "width": 140, + "height": 26, + "collapsed": true, + "inherited": false, + "registry": "core/Watch", + "base_type": "core/Node" + }, + "1521d05d-6894-4ea0-be22-4158b6ae502d": { + "title": "orig_outline", + "id": "1521d05d-6894-4ea0-be22-4158b6ae502d", + "properties": {}, + "x": 945, + "y": 1851, + "width": 140, + "height": 26, + "collapsed": true, + "inherited": false, + "registry": "core/Watch", + "base_type": "core/Node" + }, + "d7875776-8ae3-40dc-9b4b-3ce3aebee755": { + "title": "Stage 2", + "id": "d7875776-8ae3-40dc-9b4b-3ce3aebee755", + "properties": { + "stage": 2 + }, + "x": 1175, + "y": 1961, + "width": 210, + "height": 118, + "collapsed": false, + "inherited": false, + "registry": "core/Stage", + "base_type": "core/Node" + }, + "881ce23b-d561-4163-baa1-3d4b02d55c15": { + "title": "Create Plan", + "id": "881ce23b-d561-4163-baa1-3d4b02d55c15", + "properties": { + "instructions": "", + "status": "ready" + }, + "x": 848, + "y": 2597, + "width": 210, + "height": 162, + "collapsed": false, + "inherited": false, + "registry": "agents/director/plan/CreatePlan", + "base_type": "core/Node" + }, + "0cab9899-8d23-4f31-b878-582f493e9374": { + "title": "GET local.instructions", + "id": "0cab9899-8d23-4f31-b878-582f493e9374", + "properties": { + "name": "instructions", + "scope": "local" + }, + "x": 24, + "y": 2546, + "width": 210, + "height": 122, + "collapsed": false, + "inherited": false, + "registry": "state/GetState", + "base_type": "core/Node" + }, + "ba9fb7b5-9945-4286-8a02-b5d97780986a": { + "title": "GET local.outline", + "id": "ba9fb7b5-9945-4286-8a02-b5d97780986a", + "properties": { + "name": "outline", + "scope": "local" + }, + "x": 24, + "y": 2736, + "width": 210, + "height": 122, + "collapsed": false, + "inherited": false, + "registry": "state/GetState", + "base_type": "core/Node" + }, + "d119ebc0-f6d2-43d3-a38d-32f19cd27b2d": { + "title": "SET local.outline", + "id": "d119ebc0-f6d2-43d3-a38d-32f19cd27b2d", + "properties": { + "name": "outline", + "scope": "local" + }, + "x": 895, + "y": 1951, + "width": 210, + "height": 122, + "collapsed": false, + "inherited": false, + "registry": "state/SetState", + "base_type": "core/Node" + }, + "34897457-4117-4ea8-9671-97670cc3fe0d": { + "title": "Stage 2", + "id": "34897457-4117-4ea8-9671-97670cc3fe0d", + "properties": { + "stage": 3 + }, + "x": 1494, + "y": 2596, + "width": 210, + "height": 118, + "collapsed": false, + "inherited": false, + "registry": "core/Stage", + "base_type": "core/Node" + }, + "62afee08-6a03-40db-b2b4-220fb104b617": { + "title": "IN critique", + "id": "62afee08-6a03-40db-b2b4-220fb104b617", + "properties": { + "input_type": "bool", + "input_name": "critique", + "input_optional": true, + "input_group": "", + "num": 3 + }, + "x": 30, + "y": 500, + "width": 210, + "height": 154, + "collapsed": false, + "inherited": false, + "registry": "core/Input", + "base_type": "core/Node" + }, + "7d565eb9-f156-4a92-9723-e27964dfe759": { + "title": "IN beat_count", + "id": "7d565eb9-f156-4a92-9723-e27964dfe759", + "properties": { + "input_type": "int", + "input_name": "beat_count", + "input_optional": false, + "input_group": "", + "num": 2 + }, + "x": 26, + "y": 258, + "width": 210, + "height": 154, + "collapsed": false, + "inherited": false, + "registry": "core/Input", + "base_type": "core/Node" + }, + "c9775f83-e7bc-4dc5-959c-bc2182a0d10b": { + "title": "IN instructions", + "id": "c9775f83-e7bc-4dc5-959c-bc2182a0d10b", + "properties": { + "input_type": "str", + "input_name": "instructions", + "input_optional": false, + "input_group": "", + "num": 1 + }, + "x": 26, + "y": 28, + "width": 210, + "height": 154, + "collapsed": false, + "inherited": false, + "registry": "core/Input", + "base_type": "core/Node" } }, "edges": { @@ -640,12 +899,6 @@ "e9b150a0-0aab-4b92-b7ec-9f52f4e716fe.value": [ "1e9d954a-1e56-4880-9f80-00c235bed988.value" ], - "2051509a-fc52-41ea-b674-faf9ca7a2faf.state": [ - "501a32e7-e22a-4ffc-b7d9-6faef9e44b17.value" - ], - "2051509a-fc52-41ea-b674-faf9ca7a2faf.state_b": [ - "fb04842e-74d7-493e-aded-8e12a05263ce.value" - ], "d864bf7b-83ce-440b-8a9b-ac00f5ad496a.value": [ "18339c3e-031b-471d-a317-efcd2c14a4e0.state" ], @@ -667,15 +920,6 @@ "903af300-88b8-4a88-9200-1fc8a11f4100.estimated_words": [ "6bb81c40-cff1-42e6-a471-001985e57e5c.item2" ], - "0bf06241-b92b-4f0f-bc67-0789fe061c18.dict": [ - "97d95ce0-dccb-41ed-b41a-aca140af56eb.meta" - ], - "fcc70ad0-b17c-4f1a-9752-9f1377c3aa39.value": [ - "a6b6acdb-c0ad-4c79-a9fc-0cb4a7c5878a.state" - ], - "789e16f5-239e-4bec-9906-4690a692a01b.value": [ - "a6b6acdb-c0ad-4c79-a9fc-0cb4a7c5878a.state_b" - ], "efa8c129-8445-4860-83cd-8c180e9053aa.value": [ "d70c7ca4-ef49-4964-9c3c-c9ec0df7fa04.value" ], @@ -689,53 +933,10 @@ "f50e95f8-21ac-4018-a5cd-a351d646bebd.value": [ "8641d43d-c5d7-471e-870b-27fcaf4b4564.value" ], - "944cd2b9-8d55-4353-a7a9-e3cd98882768.value": [ - "0bf06241-b92b-4f0f-bc67-0789fe061c18.item0", - "9c312643-3e88-43f7-a473-ade757d8c550.perspective" - ], - "78cbb918-22da-4e99-87b4-e7a0a3c9da67.value": [ - "9c312643-3e88-43f7-a473-ade757d8c550.outline" - ], - "18339c3e-031b-471d-a317-efcd2c14a4e0.state": [ - "9c312643-3e88-43f7-a473-ade757d8c550.state" - ], "18339c3e-031b-471d-a317-efcd2c14a4e0.extracted": [ "944cd2b9-8d55-4353-a7a9-e3cd98882768.object", "78cbb918-22da-4e99-87b4-e7a0a3c9da67.object" ], - "cb985916-16c3-4a51-bbf8-d961cabbf07a.value": [ - "9c312643-3e88-43f7-a473-ade757d8c550.outline_instructions" - ], - "97d95ce0-dccb-41ed-b41a-aca140af56eb.plan_id": [ - "fcc70ad0-b17c-4f1a-9752-9f1377c3aa39.value" - ], - "97d95ce0-dccb-41ed-b41a-aca140af56eb.result": [ - "789e16f5-239e-4bec-9906-4690a692a01b.value" - ], - "9c312643-3e88-43f7-a473-ade757d8c550.state": [ - "97d95ce0-dccb-41ed-b41a-aca140af56eb.state" - ], - "9c312643-3e88-43f7-a473-ade757d8c550.outline_instructions": [ - "97d95ce0-dccb-41ed-b41a-aca140af56eb.instructions" - ], - "9c312643-3e88-43f7-a473-ade757d8c550.orig_outline": [ - "66e5a663-7ac7-4b8f-8ab8-16c6f1623b0f.value" - ], - "9c312643-3e88-43f7-a473-ade757d8c550.outline": [ - "91972225-9a2c-4cb4-ae5f-a61d0de227c6.value" - ], - "9c312643-3e88-43f7-a473-ade757d8c550.changes": [ - "c6488e1b-62c6-4bde-a967-f06996fbb14c.value" - ], - "91972225-9a2c-4cb4-ae5f-a61d0de227c6.value": [ - "97d95ce0-dccb-41ed-b41a-aca140af56eb.tasks" - ], - "c9775f83-e7bc-4dc5-959c-bc2182a0d10b.value": [ - "88f6f84d-c3ef-4efa-ad22-e079cc3f10e5.value" - ], - "7d565eb9-f156-4a92-9723-e27964dfe759.value": [ - "f06086ba-6253-4da2-ad37-d12b4f64443c.value" - ], "6bb81c40-cff1-42e6-a471-001985e57e5c.dict": [ "517d4bb8-38aa-4b11-8ba9-f569a6a45338.value", "0bf06241-b92b-4f0f-bc67-0789fe061c18.dict", @@ -743,25 +944,117 @@ ], "1a5053b8-6cb9-449e-a52c-acb44b79ab14.value": [ "6bb81c40-cff1-42e6-a471-001985e57e5c.item3" + ], + "cd6a7f30-cc94-4fcc-8d2a-a99dd985a526.value": [ + "857a9a27-0b46-4ab7-99b3-c00d773c4902.value" + ], + "857a9a27-0b46-4ab7-99b3-c00d773c4902.value": [ + "2051509a-fc52-41ea-b674-faf9ca7a2faf.state_c" + ], + "2051509a-fc52-41ea-b674-faf9ca7a2faf.state": [ + "501a32e7-e22a-4ffc-b7d9-6faef9e44b17.value" + ], + "2051509a-fc52-41ea-b674-faf9ca7a2faf.state_b": [ + "fb04842e-74d7-493e-aded-8e12a05263ce.value" + ], + "2051509a-fc52-41ea-b674-faf9ca7a2faf.state_c": [ + "7ef30f81-082b-4294-b0a9-bc5cb57fd6ed.value" + ], + "0bf06241-b92b-4f0f-bc67-0789fe061c18.dict": [ + "2e6b8777-ffab-48c7-b396-fd4c38e8936f.value" + ], + "78cbb918-22da-4e99-87b4-e7a0a3c9da67.value": [ + "a0a70d5d-6fdc-4875-8f97-e74ad6a6480e.value" + ], + "944cd2b9-8d55-4353-a7a9-e3cd98882768.value": [ + "0bf06241-b92b-4f0f-bc67-0789fe061c18.item0", + "c78ff25c-e271-4da7-95e7-ea55026eb0ae.value" + ], + "a0a70d5d-6fdc-4875-8f97-e74ad6a6480e.value": [ + "a6b6acdb-c0ad-4c79-a9fc-0cb4a7c5878a.state" + ], + "2e6b8777-ffab-48c7-b396-fd4c38e8936f.value": [ + "a6b6acdb-c0ad-4c79-a9fc-0cb4a7c5878a.state_c" + ], + "c78ff25c-e271-4da7-95e7-ea55026eb0ae.value": [ + "a6b6acdb-c0ad-4c79-a9fc-0cb4a7c5878a.state_b" + ], + "297241d7-cf15-4f7a-98b7-077e9238258b.value": [ + "881ce23b-d561-4163-baa1-3d4b02d55c15.meta" + ], + "50a12485-7ff7-4688-b73e-ee665f19ad20.value": [ + "34897457-4117-4ea8-9671-97670cc3fe0d.state_b" + ], + "9e59f7a6-1e3c-4e39-a6b3-31fdd20473d7.value": [ + "34897457-4117-4ea8-9671-97670cc3fe0d.state" + ], + "fac41364-9daf-42d4-a6cb-ed52b5247830.value": [ + "1b840b34-d28e-428f-8a55-2b2062b1a9c1.outline" + ], + "1ffc7551-5a84-4445-8dd6-d4bf8fbe4c11.value": [ + "1b840b34-d28e-428f-8a55-2b2062b1a9c1.perspective" + ], + "f542f3d3-8b0c-4dd7-bc64-c77dd99ca10d.value": [ + "1b840b34-d28e-428f-8a55-2b2062b1a9c1.outline_instructions" + ], + "9f99ab9d-9e25-487d-8007-2b57eedbccf0.value": [ + "5c3c0736-5504-4c7d-aff3-55efc38c4dfb.value" + ], + "5c3c0736-5504-4c7d-aff3-55efc38c4dfb.yes": [ + "1b840b34-d28e-428f-8a55-2b2062b1a9c1.state" + ], + "1b840b34-d28e-428f-8a55-2b2062b1a9c1.orig_outline": [ + "1521d05d-6894-4ea0-be22-4158b6ae502d.value" + ], + "1b840b34-d28e-428f-8a55-2b2062b1a9c1.outline": [ + "d119ebc0-f6d2-43d3-a38d-32f19cd27b2d.value" + ], + "1b840b34-d28e-428f-8a55-2b2062b1a9c1.changes": [ + "e0f2a097-0a50-4a14-957e-31f607d09eaa.value" + ], + "881ce23b-d561-4163-baa1-3d4b02d55c15.plan_id": [ + "9e59f7a6-1e3c-4e39-a6b3-31fdd20473d7.value" + ], + "881ce23b-d561-4163-baa1-3d4b02d55c15.result": [ + "50a12485-7ff7-4688-b73e-ee665f19ad20.value" + ], + "0cab9899-8d23-4f31-b878-582f493e9374.value": [ + "881ce23b-d561-4163-baa1-3d4b02d55c15.instructions" + ], + "ba9fb7b5-9945-4286-8a02-b5d97780986a.value": [ + "881ce23b-d561-4163-baa1-3d4b02d55c15.tasks", + "881ce23b-d561-4163-baa1-3d4b02d55c15.state" + ], + "d119ebc0-f6d2-43d3-a38d-32f19cd27b2d.value": [ + "d7875776-8ae3-40dc-9b4b-3ce3aebee755.state" + ], + "62afee08-6a03-40db-b2b4-220fb104b617.value": [ + "cd6a7f30-cc94-4fcc-8d2a-a99dd985a526.value" + ], + "7d565eb9-f156-4a92-9723-e27964dfe759.value": [ + "f06086ba-6253-4da2-ad37-d12b4f64443c.value" + ], + "c9775f83-e7bc-4dc5-959c-bc2182a0d10b.value": [ + "88f6f84d-c3ef-4efa-ad22-e079cc3f10e5.value" ] }, "groups": [ { "title": "Input", - "x": 3, - "y": -1, - "width": 1450, - "height": 704, + "x": 1, + "y": -267, + "width": 1451, + "height": 966, "color": "#88A", "font_size": 24, "inherited": false }, { "title": "Process", - "x": 3, - "y": 713, - "width": 3586, - "height": 897, + "x": 1, + "y": 704, + "width": 2761, + "height": 882, "color": "#3f789e", "font_size": 24, "inherited": false @@ -769,12 +1062,32 @@ { "title": "Output", "x": 1459, - "y": -1, + "y": 259, "width": 640, "height": 436, "color": "#8A8", "font_size": 24, "inherited": false + }, + { + "title": "Process", + "x": 0, + "y": 1591, + "width": 1410, + "height": 817, + "color": "#3f789e", + "font_size": 24, + "inherited": false + }, + { + "title": "Process", + "x": -1, + "y": 2412, + "width": 1730, + "height": 542, + "color": "#3f789e", + "font_size": 24, + "inherited": false } ], "comments": [], diff --git a/src/talemate/agents/director/modules/critique-outline.json b/src/talemate/agents/director/modules/critique-outline.json index ec89b5db..5d9cffac 100644 --- a/src/talemate/agents/director/modules/critique-outline.json +++ b/src/talemate/agents/director/modules/critique-outline.json @@ -161,7 +161,7 @@ "base_type": "core/DynamicSocketNodeBase" }, "6afa0a64-551b-4724-85f4-53a5bdebbac9": { - "title": "Generate Response", + "title": "Critique Outline", "id": "6afa0a64-551b-4724-85f4-53a5bdebbac9", "properties": { "data_output": false, diff --git a/src/talemate/agents/director/modules/director-action-direct-story-arc.json b/src/talemate/agents/director/modules/director-action-direct-story-arc.json index 4a4987cd..ba29d1ba 100644 --- a/src/talemate/agents/director/modules/director-action-direct-story-arc.json +++ b/src/talemate/agents/director/modules/director-action-direct-story-arc.json @@ -169,28 +169,15 @@ }, "x": 570, "y": 320, - "width": 212, - "height": 158, + "width": 220, + "height": 178, "collapsed": false, "inherited": false, "registry": "agents/director/plan/ExpandStoryArc", "base_type": "core/Node" }, - "dc9bff13-a1bb-46a7-9159-090287494766": { - "title": "Director Settings", - "id": "dc9bff13-a1bb-46a7-9159-090287494766", - "properties": {}, - "x": 10, - "y": 760, - "width": 363, - "height": 926, - "collapsed": true, - "inherited": false, - "registry": "agents/director/Settings", - "base_type": "core/Node" - }, "fe4b0231-b5ec-4dd2-9ff5-8e3b2bfad061": { - "title": "chat_generate_arc_expand_chunk_size", + "title": "plan_expand_chunk_size", "id": "fe4b0231-b5ec-4dd2-9ff5-8e3b2bfad061", "properties": {}, "x": 200, @@ -216,6 +203,47 @@ "inherited": false, "registry": "data/number/AsNumber", "base_type": "core/Node" + }, + "08c18906-862b-4450-a1b1-71937b095717": { + "title": "plan_expand_critique", + "id": "08c18906-862b-4450-a1b1-71937b095717", + "properties": {}, + "x": 230, + "y": 850, + "width": 168, + "height": 26, + "collapsed": false, + "inherited": false, + "registry": "core/Watch", + "base_type": "core/Node" + }, + "673c3bef-fe28-409e-8f3a-1be74aa33780": { + "title": "As Bool", + "id": "673c3bef-fe28-409e-8f3a-1be74aa33780", + "properties": { + "default": false + }, + "x": 450, + "y": 870, + "width": 210, + "height": 58, + "collapsed": true, + "inherited": false, + "registry": "core/AsBool", + "base_type": "core/Node" + }, + "dc9bff13-a1bb-46a7-9159-090287494766": { + "title": "Director Settings", + "id": "dc9bff13-a1bb-46a7-9159-090287494766", + "properties": {}, + "x": 10, + "y": 770, + "width": 363, + "height": 986, + "collapsed": true, + "inherited": false, + "registry": "agents/director/Settings", + "base_type": "core/Node" } }, "edges": { @@ -252,14 +280,23 @@ "a30b01b3-84da-46c0-8783-785660b85ccb.result": [ "b12ebc94-8767-4ce4-9d97-1f8adfa8ae66.value" ], - "dc9bff13-a1bb-46a7-9159-090287494766.chat_generate_arc_expand_chunk_size": [ - "fe4b0231-b5ec-4dd2-9ff5-8e3b2bfad061.value" - ], "fe4b0231-b5ec-4dd2-9ff5-8e3b2bfad061.value": [ "9b188432-1182-4fe0-82d4-28ad012a7a9a.value" ], "9b188432-1182-4fe0-82d4-28ad012a7a9a.value": [ "a30b01b3-84da-46c0-8783-785660b85ccb.chunk_size" + ], + "08c18906-862b-4450-a1b1-71937b095717.value": [ + "673c3bef-fe28-409e-8f3a-1be74aa33780.value" + ], + "673c3bef-fe28-409e-8f3a-1be74aa33780.value": [ + "a30b01b3-84da-46c0-8783-785660b85ccb.expand_critique" + ], + "dc9bff13-a1bb-46a7-9159-090287494766.plan_expand_chunk_size": [ + "fe4b0231-b5ec-4dd2-9ff5-8e3b2bfad061.value" + ], + "dc9bff13-a1bb-46a7-9159-090287494766.plan_expand_critique": [ + "08c18906-862b-4450-a1b1-71937b095717.value" ] }, "groups": [ @@ -277,8 +314,8 @@ "title": "Process", "x": -2, "y": 226, - "width": 1051, - "height": 574, + "width": 1050, + "height": 675, "color": "#3f789e", "font_size": 24, "inherited": false @@ -290,28 +327,28 @@ "inputs": [], "outputs": [ { - "id": "3d11a687-076d-4645-9bfc-43e63daf0739", + "id": "37499312-00a2-4f6f-862e-63372a020be1", "name": "fn", "optional": false, "group": null, "socket_type": "function" }, { - "id": "0901e75e-4235-484a-a5ed-3bdf1bd83e52", + "id": "deea07dc-3fde-475f-b6f1-db7a4e723862", "name": "name", "optional": false, "group": null, "socket_type": "str" }, { - "id": "728a9946-813f-4125-bffb-153eeaa3e2fb", + "id": "235121d0-ddca-48e0-828c-e4f8c0fe1602", "name": "allow_multiple_calls", "optional": false, "group": null, "socket_type": "bool" }, { - "id": "26402d15-3605-4ae7-aa5a-c909b2e13825", + "id": "bcbb8f4e-0ad8-48ae-b874-3d7615c4d3a1", "name": "ai_callback", "optional": false, "group": null, diff --git a/src/talemate/agents/director/modules/manage-plan.json b/src/talemate/agents/director/modules/manage-plan.json index 4a332596..e9000879 100644 --- a/src/talemate/agents/director/modules/manage-plan.json +++ b/src/talemate/agents/director/modules/manage-plan.json @@ -149,8 +149,8 @@ "typ": "int", "instructions": "The exact number of beats to generate. Each beat represents one narrator or conversation generation turn." }, - "x": -1367, - "y": 747, + "x": -1722, + "y": 642, "width": 210, "height": 106, "collapsed": false, @@ -166,8 +166,8 @@ "typ": "str", "instructions": "What the scene outline should cover. Include the setting, characters involved, tone, themes, and any specific events or arcs." }, - "x": -1367, - "y": 587, + "x": -1722, + "y": 482, "width": 210, "height": 106, "collapsed": false, @@ -191,8 +191,8 @@ } ] }, - "x": -560, - "y": 650, + "x": -546, + "y": 542, "width": 244, "height": 82, "collapsed": false, @@ -308,21 +308,6 @@ "registry": "agents/director/chat/DirectorChatSubAction", "base_type": "core/Node" }, - "506d845f-e842-4e95-9285-2ad407a2146e": { - "title": "DEF create_outline", - "id": "506d845f-e842-4e95-9285-2ad407a2146e", - "properties": { - "name": "create_outline" - }, - "x": -270, - "y": 650, - "width": 210, - "height": 78, - "collapsed": false, - "inherited": false, - "registry": "core/functions/DefineFunction", - "base_type": "core/Node" - }, "32c778ed-68e4-4039-9b95-03726c146323": { "title": "DEF create_plan", "id": "32c778ed-68e4-4039-9b95-03726c146323", @@ -861,46 +846,12 @@ "registry": "focal/Argument", "base_type": "core/Node" }, - "651a5f02-fd36-4da3-8e6a-80d18c415f22": { - "title": "Create Outline", - "id": "651a5f02-fd36-4da3-8e6a-80d18c415f22", - "properties": {}, - "x": -1053, - "y": 646, - "width": 212, - "height": 106, - "collapsed": false, - "inherited": false, - "registry": "agents/director/plan/CreateOutline", - "base_type": "core/Graph" - }, - "b52af225-f7f7-4466-b27e-3a96b591eb26": { - "title": "Jinja2 Format", - "id": "b52af225-f7f7-4466-b27e-3a96b591eb26", - "properties": { - "template": "Plan ID: {{ plan_id }}" - }, - "x": -970, - "y": 800, - "width": 210, - "height": 153, - "collapsed": true, - "inherited": false, - "registry": "prompt/Jinja2Format", - "dynamic_inputs": [ - { - "name": "item0", - "type": "*" - } - ], - "base_type": "core/DynamicSocketNodeBase" - }, "ce9a5ea3-57cf-4323-8c61-b32a47c310f6": { "title": "Return", "id": "ce9a5ea3-57cf-4323-8c61-b32a47c310f6", "properties": {}, - "x": -780, - "y": 680, + "x": -766, + "y": 542, "width": 140, "height": 26, "collapsed": false, @@ -944,6 +895,81 @@ } ], "base_type": "core/DynamicSocketNodeBase" + }, + "506d845f-e842-4e95-9285-2ad407a2146e": { + "title": "DEF create_outline", + "id": "506d845f-e842-4e95-9285-2ad407a2146e", + "properties": { + "name": "create_outline" + }, + "x": -256, + "y": 542, + "width": 210, + "height": 78, + "collapsed": false, + "inherited": false, + "registry": "core/functions/DefineFunction", + "base_type": "core/Node" + }, + "651a5f02-fd36-4da3-8e6a-80d18c415f22": { + "title": "Create Outline", + "id": "651a5f02-fd36-4da3-8e6a-80d18c415f22", + "properties": {}, + "x": -1206, + "y": 542, + "width": 212, + "height": 126, + "collapsed": false, + "inherited": false, + "registry": "agents/director/plan/CreateOutline", + "base_type": "core/Graph" + }, + "50a06e8b-0b1f-4794-ac11-5b76b6d0a341": { + "title": "plan_outline_critique", + "id": "50a06e8b-0b1f-4794-ac11-5b76b6d0a341", + "properties": {}, + "x": -1446, + "y": 722, + "width": 176, + "height": 26, + "collapsed": false, + "inherited": false, + "registry": "core/Watch", + "base_type": "core/Node" + }, + "0680094e-85a3-4704-a2c5-2a6b9c60085d": { + "title": "Director Settings", + "id": "0680094e-85a3-4704-a2c5-2a6b9c60085d", + "properties": {}, + "x": -1722, + "y": 832, + "width": 363, + "height": 986, + "collapsed": true, + "inherited": false, + "registry": "agents/director/Settings", + "base_type": "core/Node" + }, + "b52af225-f7f7-4466-b27e-3a96b591eb26": { + "title": "Jinja2 Format", + "id": "b52af225-f7f7-4466-b27e-3a96b591eb26", + "properties": { + "template": "Plan ID: {{ plan_id }}" + }, + "x": -933, + "y": 542, + "width": 210, + "height": 153, + "collapsed": true, + "inherited": false, + "registry": "prompt/Jinja2Format", + "dynamic_inputs": [ + { + "name": "item0", + "type": "*" + } + ], + "base_type": "core/DynamicSocketNodeBase" } }, "edges": { @@ -1094,12 +1120,6 @@ "c9309352-4080-401f-8e7a-8f82d4cb0cd1.state", "c9309352-4080-401f-8e7a-8f82d4cb0cd1.task_id" ], - "651a5f02-fd36-4da3-8e6a-80d18c415f22.plan_id": [ - "b52af225-f7f7-4466-b27e-3a96b591eb26.item0" - ], - "b52af225-f7f7-4466-b27e-3a96b591eb26.result": [ - "ce9a5ea3-57cf-4323-8c61-b32a47c310f6.value" - ], "ce9a5ea3-57cf-4323-8c61-b32a47c310f6.value": [ "1f391a2f-a696-44fd-8dbb-951f6612d627.state" ], @@ -1111,15 +1131,27 @@ ], "acfef6ab-44e3-4a82-8fef-ff6428374181.result": [ "bb0aaccf-8d2e-4b7a-9536-ac729b8e02dc.value" + ], + "651a5f02-fd36-4da3-8e6a-80d18c415f22.plan_id": [ + "b52af225-f7f7-4466-b27e-3a96b591eb26.item0" + ], + "50a06e8b-0b1f-4794-ac11-5b76b6d0a341.value": [ + "651a5f02-fd36-4da3-8e6a-80d18c415f22.critique" + ], + "0680094e-85a3-4704-a2c5-2a6b9c60085d.plan_outline_critique": [ + "50a06e8b-0b1f-4794-ac11-5b76b6d0a341.value" + ], + "b52af225-f7f7-4466-b27e-3a96b591eb26.result": [ + "ce9a5ea3-57cf-4323-8c61-b32a47c310f6.value" ] }, "groups": [ { "title": "Function", - "x": -1388, - "y": 521, - "width": 1366, - "height": 365, + "x": -1747, + "y": 402, + "width": 1726, + "height": 484, "color": "#b06634", "font_size": 24, "inherited": false @@ -1191,28 +1223,28 @@ "inputs": [], "outputs": [ { - "id": "e6602099-1ace-47f3-9f17-bbc3c7dea5f6", + "id": "161139d1-8eb6-4a7d-89d4-00cefc247065", "name": "fn", "optional": false, "group": null, "socket_type": "function" }, { - "id": "353a9c7c-4b64-4273-ba85-0461105f7d56", + "id": "03903a3d-5342-4b07-859f-70cb10384b7d", "name": "name", "optional": false, "group": null, "socket_type": "str" }, { - "id": "c5e18533-c2a3-4d0e-a927-0c7f11db3d99", + "id": "1c5b36f4-cd45-4b3b-9fdc-0602f0a76330", "name": "allow_multiple_calls", "optional": false, "group": null, "socket_type": "bool" }, { - "id": "8f932bf2-9c66-4ec9-8d91-a0ec166364f9", + "id": "b632a9f9-c4ae-4157-ae24-d0a8490de4b9", "name": "ai_callback", "optional": false, "group": null, diff --git a/src/talemate/agents/director/plan/__init__.py b/src/talemate/agents/director/plan/__init__.py index 847c39a2..8ee8e386 100644 --- a/src/talemate/agents/director/plan/__init__.py +++ b/src/talemate/agents/director/plan/__init__.py @@ -6,4 +6,5 @@ The director creates plans with tasks, then uses existing actions to execute the from .schema import Task, Beat, Plan, PlanStatus # noqa: F401 from .util import get_plan, save_plan, delete_plan, complete_task, parse_beats # noqa: F401 -from .expand import expand_beats # noqa: F401 +from .expand import compute_chunks, compute_arc_info # noqa: F401 +from .mixin import PlanMixin # noqa: F401 diff --git a/src/talemate/agents/director/plan/expand.py b/src/talemate/agents/director/plan/expand.py index ff567655..87f33f84 100644 --- a/src/talemate/agents/director/plan/expand.py +++ b/src/talemate/agents/director/plan/expand.py @@ -1,26 +1,24 @@ """ -Arc expansion — expands plan beats into prose and pushes to scene history. +Arc expansion — pure functions for chunking and arc metadata computation. + +The expand pipeline methods live on PlanMixin (mixin.py). """ import re -import structlog import pydantic -from talemate.emit import emit -import talemate.emit.async_signals -from talemate.agents.narrator import NarratorAgentEmission -from talemate.prompts import Prompt -from talemate.scene_message import NarratorMessage, CharacterMessage from .schema import Beat -from .util import complete_task, emit_plan_updated, get_plan - -log = structlog.get_logger("talemate.agents.director.plan.expand") # Matches any opening block tag leaked into content -# TODO: this can't hardcode the tag style or names -- the template defines it _LEAKED_TAG_RE = re.compile(r"?(?:NARRATOR|CHARACTER)\b", re.IGNORECASE) + +def has_leaked_tags(blocks: list[dict]) -> bool: + """Check if any extracted block contains raw block tags in its content.""" + return any(_LEAKED_TAG_RE.search(b.get("content", "")) for b in blocks) + + # Minimum beats per chunk when splitting at tension valleys MIN_CHUNK_BEATS = 3 @@ -120,194 +118,3 @@ def compute_arc_info( ) return infos - - -async def revise_narrator_content(narrator, content: str) -> str: - """Send narrator generated signal so automatic revision can process the content.""" - emission = NarratorAgentEmission(agent=narrator, response=content) - await talemate.emit.async_signals.get("agent.narrator.generated").send(emission) - return emission.response - - -async def critique_expanded_blocks( - blocks: list[dict], narrator -) -> list[dict]: - """ - Run a post-expansion critique pass on all blocks to fix cross-beat - redundancy, intensity monotony, and repeated vocabulary. - """ - log.info("expand.critique", block_count=len(blocks)) - - response, extracted = await Prompt.request( - "narrator.arc-expand-critique", - narrator.client, - "narrate_4096", - vars={ - "blocks": blocks, - "max_tokens": narrator.client.max_token_length, - "response_length": 4096, - }, - ) - - revised = extracted.get("response", []) - if not revised: - log.warning("expand.critique.no_blocks_returned, using originals") - return blocks - - log.info("expand.critique.done", original=len(blocks), revised=len(revised)) - return revised - - -async def push_and_emit_block(scene, block: dict, narrator) -> int: - """ - Push a single extracted block to scene history and emit to frontend. - - Runs automatic revision on narrator blocks. Returns word count of the block, - or 0 if the block was empty/skipped. - """ - content = block.get("content", "").strip() - if not content: - return 0 - - if block["type"] == "narrator": - content = await revise_narrator_content(narrator, content) - msg = NarratorMessage(content) - await scene.push_history(msg) - emit("narrator", msg) - elif block["type"] == "character": - char_name = block.get("name", "Unknown") - msg = CharacterMessage(f"{char_name}: {content}") - await scene.push_history(msg) - character = scene.get_character(char_name) - emit("character", message=msg, character=character) - else: - return 0 - - return len(content.split()) - - -async def expand_beats( - scene, - narrator, - beats: list[Beat], - plan_id: str, - perspective: str, - director_notes: str = "", - chunk_size: int = 3, - chat_id: str | None = None, -) -> tuple[int, int]: - """ - Expand beats into prose in chunks and push to scene history. - - Chunks are split at tension valleys when possible (deliberate chunking), - falling back to max chunk_size. Each chunk receives arc-position metadata - to guide pacing. - - Returns (total_blocks, total_words). - """ - total_words = 0 - total_blocks = 0 - preceding_text = "" - all_blocks: list[dict] = [] - - # Compute chunks and arc metadata - chunks = compute_chunks(beats, chunk_size) - arc_infos = compute_arc_info(chunks, beats) - - # Build a flat index to find following beats across chunk boundaries - beat_offset = 0 - - for chunk_num, (chunk_beats, arc_info) in enumerate( - zip(chunks, arc_infos), start=1 - ): - # Following beats: first 2 beats from the next chunk - following_beats = [] - next_offset = beat_offset + len(chunk_beats) - if next_offset < len(beats): - following_beats = beats[next_offset : next_offset + 2] - - log.info( - "expand.chunk", - chunk=chunk_num, - beats=f"{beat_offset + 1}-{beat_offset + len(chunk_beats)}", - total=len(beats), - position=arc_info.position, - tension=f"{arc_info.tension_range[0]:.1f}-{arc_info.tension_range[1]:.1f}", - ) - - # Call the expansion template with retry on malformed output - max_attempts = 3 - blocks = [] - prompt_vars = { - "scene": scene, - "max_tokens": narrator.client.max_token_length, - "beats": chunk_beats, - "following_beats": following_beats, - "preceding_text": preceding_text[-2000:] if preceding_text else "", - "perspective": perspective, - "director_notes": director_notes, - "extra_instructions": narrator.extra_instructions, - "response_length": 4096, - "arc_info": arc_info, - } - - for attempt in range(1, max_attempts + 1): - response, extracted = await Prompt.request( - "narrator.arc-expand", - narrator.client, - "narrate_4096", - vars=prompt_vars, - ) - - blocks = extracted.get("response", []) - if not blocks: - log.warning("expand.no_blocks", chunk=chunk_num, attempt=attempt) - continue - - # Validate: check for leaked block tags in content - has_leaked_tags = any( - _LEAKED_TAG_RE.search(b.get("content", "")) for b in blocks - ) - if not has_leaked_tags: - break - - log.warning("expand.leaked_tags", chunk=chunk_num, attempt=attempt) - blocks = [] - - if not blocks: - raise RuntimeError( - f"Expansion failed for chunk {chunk_num} after {max_attempts} attempts. " - f"The model produced malformed output with leaked block tags. " - f"This may indicate the model is too weak for structured generation — " - f"consider using a more capable model." - ) - - all_blocks.extend(blocks) - - # Accumulate preceding text for next chunk - chunk_text = "\n\n".join(b.get("content", "") for b in blocks) - preceding_text += "\n\n" + chunk_text - - beat_offset += len(chunk_beats) - - # Post-expansion critique pass - if len(chunks) > 1 and all_blocks: - all_blocks = await critique_expanded_blocks(all_blocks, narrator) - - # Push all blocks to scene history and emit to frontend - for block in all_blocks: - words = await push_and_emit_block(scene, block, narrator) - if words: - total_blocks += 1 - total_words += words - - # Mark all beats as completed - for beat in beats: - complete_task(scene, beat.id, plan_id=plan_id) - - # Emit plan update - plan = get_plan(scene, plan_id) - if plan: - emit_plan_updated(plan, chat_id=chat_id) - - return total_blocks, total_words diff --git a/src/talemate/agents/director/plan/mixin.py b/src/talemate/agents/director/plan/mixin.py new file mode 100644 index 00000000..d8a252d0 --- /dev/null +++ b/src/talemate/agents/director/plan/mixin.py @@ -0,0 +1,293 @@ +""" +Plan mixin — provides arc generation configuration and expand pipeline methods +to the director agent. +""" + +import structlog + +from talemate.agents.base import AgentAction, AgentActionConfig +from talemate.emit import emit +import talemate.emit.async_signals +from talemate.agents.narrator import NarratorAgentEmission +from talemate.prompts import Prompt +from talemate.scene_message import NarratorMessage, CharacterMessage + +from .expand import ( + compute_chunks, + compute_arc_info, + has_leaked_tags, +) +from .schema import Beat +from .util import complete_task, emit_plan_updated, get_plan + +log = structlog.get_logger("talemate.agents.director.plan.mixin") + + +class PlanMixin: + """ + Agent mixin for arc generation planning and expansion. + + Provides: + - Configuration for expand chunk size, dialogue ratio, critique toggles + - The expand pipeline: chunked expansion with arc metadata + - Post-expansion critique pass + """ + + @classmethod + def add_plan_actions(cls, actions: dict[str, AgentAction]): + actions["plan"] = AgentAction( + enabled=True, + container=True, + can_be_disabled=False, + label="Arc Generation", + icon="mdi-movie-open", + description="Settings for the arc generation pipeline.", + config={ + "dialogue_ratio": AgentActionConfig( + type="number", + label="Dialogue beat ratio", + description="Target fraction of beats that should be dialogue during arc generation. 0.4 = 40% dialogue beats.", + value=0.4, + step=0.1, + min=0.0, + max=1.0, + ), + "expand_chunk_size": AgentActionConfig( + type="number", + label="Expand chunk size", + description="Maximum number of beats per expansion chunk in expand mode. Larger chunks produce more cohesive prose but use more context.", + value=5, + step=1, + min=3, + max=12, + ), + "outline_critique": AgentActionConfig( + type="bool", + label="Outline critique", + description="Run a critique pass on the generated outline to improve beat quality before expansion.", + value=True, + ), + "expand_critique": AgentActionConfig( + type="bool", + label="Expansion critique", + description="Run a post-expansion critique pass to fix cross-beat redundancy and intensity monotony. Adds ~10s per generation.", + value=True, + ), + }, + ) + + # === Config property helpers === + + @property + def plan_dialogue_ratio(self) -> float: + return float(self.actions["plan"].config["dialogue_ratio"].value) + + @property + def plan_expand_chunk_size(self) -> int: + return int(self.actions["plan"].config["expand_chunk_size"].value) + + @property + def plan_outline_critique(self) -> bool: + return bool(self.actions["plan"].config["outline_critique"].value) + + @property + def plan_expand_critique(self) -> bool: + return bool(self.actions["plan"].config["expand_critique"].value) + + # === Expand pipeline methods === + + async def _plan_revise_narrator_content(self, narrator, content: str) -> str: + """Send narrator generated signal so automatic revision can process the content.""" + emission = NarratorAgentEmission(agent=narrator, response=content) + await talemate.emit.async_signals.get("agent.narrator.generated").send( + emission + ) + return emission.response + + async def _plan_push_and_emit_block(self, scene, block: dict, narrator) -> int: + """ + Push a single extracted block to scene history and emit to frontend. + + Runs automatic revision on narrator blocks. Returns word count of the block, + or 0 if the block was empty/skipped. + """ + content = block.get("content", "").strip() + if not content: + return 0 + + if block["type"] == "narrator": + content = await self._plan_revise_narrator_content(narrator, content) + msg = NarratorMessage(content) + await scene.push_history(msg) + emit("narrator", msg) + elif block["type"] == "character": + char_name = block.get("name", "Unknown") + msg = CharacterMessage(f"{char_name}: {content}") + await scene.push_history(msg) + character = scene.get_character(char_name) + emit("character", message=msg, character=character) + else: + return 0 + + return len(content.split()) + + async def _plan_critique_expanded_blocks( + self, blocks: list[dict], narrator + ) -> list[dict]: + """ + Run a post-expansion critique pass on all blocks to fix cross-beat + redundancy, intensity monotony, and repeated vocabulary. + """ + log.info("expand.critique", block_count=len(blocks)) + + response, extracted = await Prompt.request( + "narrator.arc-expand-critique", + narrator.client, + "narrate_4096", + vars={ + "blocks": blocks, + "max_tokens": narrator.client.max_token_length, + "response_length": 4096, + }, + ) + + revised = extracted.get("response", []) + if not revised: + log.warning("expand.critique.no_blocks_returned", fallback="using originals") + return blocks + + log.info("expand.critique.done", original=len(blocks), revised=len(revised)) + return revised + + async def plan_expand_beats( + self, + scene, + narrator, + beats: list[Beat], + plan_id: str, + perspective: str, + director_notes: str = "", + chunk_size: int | None = None, + chat_id: str | None = None, + critique: bool | None = None, + ) -> tuple[int, int]: + """ + Expand beats into prose in chunks and push to scene history. + + Chunks are split at tension valleys when possible (deliberate chunking), + falling back to max chunk_size. Each chunk receives arc-position metadata + to guide pacing. + + Returns (total_blocks, total_words). + """ + if chunk_size is None: + chunk_size = self.plan_expand_chunk_size + + total_words = 0 + total_blocks = 0 + preceding_text = "" + all_blocks: list[dict] = [] + + # Compute chunks and arc metadata + chunks = compute_chunks(beats, chunk_size) + arc_infos = compute_arc_info(chunks, beats) + + # Build a flat index to find following beats across chunk boundaries + beat_offset = 0 + + for chunk_num, (chunk_beats, arc_info) in enumerate( + zip(chunks, arc_infos), start=1 + ): + # Following beats: first 2 beats from the next chunk + following_beats = [] + next_offset = beat_offset + len(chunk_beats) + if next_offset < len(beats): + following_beats = beats[next_offset : next_offset + 2] + + log.info( + "expand.chunk", + chunk=chunk_num, + beats=f"{beat_offset + 1}-{beat_offset + len(chunk_beats)}", + total=len(beats), + position=arc_info.position, + tension=f"{arc_info.tension_range[0]:.1f}-{arc_info.tension_range[1]:.1f}", + ) + + # Call the expansion template with retry on malformed output + max_attempts = 3 + blocks = [] + prompt_vars = { + "scene": scene, + "max_tokens": narrator.client.max_token_length, + "beats": chunk_beats, + "following_beats": following_beats, + "preceding_text": preceding_text[-2000:] if preceding_text else "", + "perspective": perspective, + "director_notes": director_notes, + "extra_instructions": narrator.extra_instructions, + "response_length": 4096, + "arc_info": arc_info, + } + + for attempt in range(1, max_attempts + 1): + response, extracted = await Prompt.request( + "narrator.arc-expand", + narrator.client, + "narrate_4096", + vars=prompt_vars, + ) + + blocks = extracted.get("response", []) + if not blocks: + log.warning( + "expand.no_blocks", chunk=chunk_num, attempt=attempt + ) + continue + + # Validate: check for leaked block tags in content + if not has_leaked_tags(blocks): + break + + log.warning( + "expand.leaked_tags", chunk=chunk_num, attempt=attempt + ) + blocks = [] + + if not blocks: + raise RuntimeError( + f"Expansion failed for chunk {chunk_num} after {max_attempts} attempts. " + f"The model produced malformed output with leaked block tags. " + f"This may indicate the model is too weak for structured generation — " + f"consider using a more capable model." + ) + + all_blocks.extend(blocks) + + # Accumulate preceding text for next chunk + chunk_text = "\n\n".join(b.get("content", "") for b in blocks) + preceding_text += "\n\n" + chunk_text + + beat_offset += len(chunk_beats) + + # Post-expansion critique pass + do_critique = critique if critique is not None else self.plan_expand_critique + if do_critique and len(chunks) > 1 and all_blocks: + all_blocks = await self._plan_critique_expanded_blocks(all_blocks, narrator) + + # Push all blocks to scene history and emit to frontend + for block in all_blocks: + words = await self._plan_push_and_emit_block(scene, block, narrator) + if words: + total_blocks += 1 + total_words += words + + # Mark all beats as completed + for beat in beats: + complete_task(scene, beat.id, plan_id=plan_id) + + # Emit plan update + plan = get_plan(scene, plan_id) + if plan: + emit_plan_updated(plan, chat_id=chat_id) + + return total_blocks, total_words diff --git a/src/talemate/agents/director/plan/nodes.py b/src/talemate/agents/director/plan/nodes.py index 5dfc2cae..07502273 100644 --- a/src/talemate/agents/director/plan/nodes.py +++ b/src/talemate/agents/director/plan/nodes.py @@ -33,7 +33,6 @@ from .schema import ( NARRATION_BEAT_RATIO, ) from .util import save_plan, complete_task, emit_plan_updated, get_plan -from .expand import expand_beats log = structlog.get_logger("talemate.agents.director.plan.nodes") @@ -327,8 +326,8 @@ class ExpandStoryArc(AgentNode): """ Expands a plan's beats into full prose and pushes them to scene history. - Delegates to expand_beats() which handles chunking, template calls, - revision, emission, and task completion. + Delegates to the director's PlanMixin.expand_beats() which handles + chunking, template calls, revision, emission, and task completion. """ _agent_name: ClassVar[str] = "narrator" @@ -353,6 +352,7 @@ class ExpandStoryArc(AgentNode): self.add_input("perspective", socket_type="str") self.add_input("director_notes", socket_type="str", optional=True) self.add_input("chunk_size", socket_type="int", optional=True) + self.add_input("expand_critique", socket_type="bool", optional=True) self.set_property("chunk_size", 5) @@ -369,9 +369,10 @@ class ExpandStoryArc(AgentNode): chunk_size = self.normalized_input_value("chunk_size") or int( self.get_property("chunk_size") ) + expand_critique = self.normalized_input_value("expand_critique") scene = active_scene.get() - narrator = get_agent("narrator") + director = get_agent("director") if not beats: self.set_output_values( @@ -386,15 +387,16 @@ class ExpandStoryArc(AgentNode): chat_ctx = director_chat_context.get() chat_id = chat_ctx.chat_id if chat_ctx else None - total_blocks, total_words = await expand_beats( + total_blocks, total_words = await director.plan_expand_beats( scene=scene, - narrator=narrator, + narrator=get_agent("narrator"), beats=beats, plan_id=plan_id, perspective=perspective, director_notes=director_notes, chunk_size=chunk_size, chat_id=chat_id, + critique=expand_critique, ) result = f"Generated {total_blocks} blocks, {total_words} words from {len(beats)} beats" diff --git a/src/talemate/prompts/templates/director/scene-plan-create-outline.jinja2 b/src/talemate/prompts/templates/director/scene-plan-create-outline.jinja2 index 62b2148e..6b1bdd7a 100644 --- a/src/talemate/prompts/templates/director/scene-plan-create-outline.jinja2 +++ b/src/talemate/prompts/templates/director/scene-plan-create-outline.jinja2 @@ -41,7 +41,7 @@ Guidelines: - The `tension` value must reflect genuine escalation. Early beats must have LOW tension (0.1-0.3). Save high tension (0.7+) for the latter portion. Do not start at high intensity. **Beat construction:** -{% set dialogue_pct = (agent_config("director.chat.generate_arc_dialogue_ratio") * 100) | int -%} +{% set dialogue_pct = (agent_config("director.plan.dialogue_ratio") * 100) | int -%} - Approximately {{ dialogue_pct }}% of beats should be `dialogue` type — characters need to speak, not just act and observe - Vary beat types for engaging pacing (don't stack 5 dialogue beats in a row) - Use `transition` beats for time/location changes diff --git a/src/talemate/prompts/templates/director/scene-plan-critique-outline.jinja2 b/src/talemate/prompts/templates/director/scene-plan-critique-outline.jinja2 index aba80840..c90d44f3 100644 --- a/src/talemate/prompts/templates/director/scene-plan-critique-outline.jinja2 +++ b/src/talemate/prompts/templates/director/scene-plan-critique-outline.jinja2 @@ -52,7 +52,7 @@ Every beat description must specify a concrete EVENT or ACTION — something tha **Structural completeness:** The final beat MUST involve a character making a choice, taking an action, or facing a consequence — not just witnessing a revelation or spectacle. If the last beat is purely "they see something terrifying/beautiful," rewrite it so the character DOES something in response that closes or pivots the arc. The arc needs somewhere to land, and that landing must involve character agency. -{% set dialogue_pct = (agent_config("director.chat.generate_arc_dialogue_ratio") * 100) | int -%} +{% set dialogue_pct = (agent_config("director.plan.dialogue_ratio") * 100) | int -%} **Dialogue ratio:** Approximately {{ dialogue_pct }}% of beats should be `dialogue` type. Characters need to speak, argue, and reveal information through conversation — not just act and observe. If the outline is heavily skewed toward narration, convert some beats to dialogue. **Perspective consistency:** All beat descriptions must be compatible with the stated perspective ({{ perspective }}). If the perspective is limited to one character, beats must not describe another character's internal thoughts. diff --git a/talemate_frontend/src/components/SceneToolsDirector.vue b/talemate_frontend/src/components/SceneToolsDirector.vue index 7d711c2d..18bafcce 100644 --- a/talemate_frontend/src/components/SceneToolsDirector.vue +++ b/talemate_frontend/src/components/SceneToolsDirector.vue @@ -130,6 +130,28 @@