fix
This commit is contained in:
@@ -58,7 +58,10 @@ async def build_orchestrator_messages(
|
||||
|
||||
recent = visible_msgs[-recent_n:] if visible_msgs else []
|
||||
|
||||
# Build orchestrator system prompt with current state
|
||||
# Build orchestrator system prompt with current state.
|
||||
# NOTE: prompts are always English (system content convention). The LLM
|
||||
# produces player-facing text in world.language when relevant (the
|
||||
# step-writer prompt interpolates world_language explicitly).
|
||||
defn = world.definition or {}
|
||||
system_prompt_template = get_prompt("orchestrator", world.language)
|
||||
player_state = world.state.get("player", {}) if world.state else {}
|
||||
@@ -69,14 +72,14 @@ async def build_orchestrator_messages(
|
||||
current_time=world.current_time or "",
|
||||
player_state=json.dumps(player_state, ensure_ascii=False)[:600],
|
||||
plot_rails=json.dumps(defn.get("plot_rails", {}), ensure_ascii=False)[:400],
|
||||
summary=summary_text or "(нет сводки)",
|
||||
summary=summary_text or "(no summary yet)",
|
||||
)
|
||||
|
||||
messages: List[Dict[str, Any]] = [{"role": "system", "content": system_prompt}]
|
||||
|
||||
# Add summary as a system note if present
|
||||
if summary_text:
|
||||
messages.append({"role": "system", "content": f"Сводка прошлого:\n{summary_text}"})
|
||||
messages.append({"role": "system", "content": f"Past summary:\n{summary_text}"})
|
||||
|
||||
# Add recent visible messages
|
||||
for m in recent:
|
||||
@@ -86,7 +89,7 @@ async def build_orchestrator_messages(
|
||||
messages.append({"role": "assistant", "content": m.content})
|
||||
|
||||
# The current action
|
||||
messages.append({"role": "user", "content": f'Действие игрока: "{action_text}"'})
|
||||
messages.append({"role": "user", "content": f'Player action: "{action_text}"'})
|
||||
|
||||
return messages, settings_map
|
||||
|
||||
@@ -100,7 +103,11 @@ async def _maybe_compress(
|
||||
world: World,
|
||||
settings_map: Dict[str, Any],
|
||||
) -> None:
|
||||
"""If history exceeds threshold, summarize older messages into a single summary message."""
|
||||
"""If history exceeds threshold, summarize older messages into a single summary message.
|
||||
|
||||
Uses the `submit_summary` tool (tool-calling-first design) to get structured
|
||||
output from the summarizer LLM.
|
||||
"""
|
||||
visible = [m for m in all_msgs if not m.hidden]
|
||||
if len(visible) <= recent_n + summary_n:
|
||||
return
|
||||
@@ -110,45 +117,61 @@ async def _maybe_compress(
|
||||
if not to_summarize:
|
||||
return
|
||||
|
||||
# Build summarization input
|
||||
# Build summarization input (English labels — system content convention)
|
||||
summary_input_lines = []
|
||||
for m in to_summarize:
|
||||
prefix = {
|
||||
"player_action": "Игрок",
|
||||
"narrative_step": "Сцена",
|
||||
"summary": "Сводка",
|
||||
"player_action": "Player",
|
||||
"narrative_step": "Scene",
|
||||
"summary": "Summary",
|
||||
"orchestrator_plan": "GM",
|
||||
"technical_offscreen": "За кадром",
|
||||
"technical_offscreen": "Offscreen",
|
||||
}.get(m.kind, m.kind)
|
||||
summary_input_lines.append(f"{prefix}: {m.content[:300]}")
|
||||
summary_input = "\n\n".join(summary_input_lines)
|
||||
|
||||
llm = LlmClient(settings_map)
|
||||
system_prompt = get_prompt("summarizer", world.language)
|
||||
from app.engine.tools.tools import SUMMARIZER_TOOL_SCHEMAS
|
||||
response = await llm.chat(
|
||||
messages=[
|
||||
{"role": "system", "content": system_prompt},
|
||||
{"role": "user", "content": summary_input[:4000]},
|
||||
],
|
||||
tools=SUMMARIZER_TOOL_SCHEMAS,
|
||||
temperature=float(cast_setting("llm.summary_temperature", settings_map.get("llm.summary_temperature", 0.3))),
|
||||
max_tokens=300,
|
||||
max_tokens=400,
|
||||
purpose="summary",
|
||||
session_id=session_id,
|
||||
db=db,
|
||||
)
|
||||
|
||||
# Parse summary response
|
||||
summary_text = response.text
|
||||
# Extract from submit_summary tool call; fall back to text parse.
|
||||
summary_text = response.text or ""
|
||||
facts: List[Dict[str, Any]] = []
|
||||
import re as _re
|
||||
json_match = _re.search(r"\{[\s\S]*\}", response.text)
|
||||
if json_match:
|
||||
try:
|
||||
data = json.loads(json_match.group(0))
|
||||
summary_text = data.get("summary", response.text)
|
||||
facts = data.get("facts", [])
|
||||
except json.JSONDecodeError:
|
||||
pass
|
||||
extracted = False
|
||||
for tc in (response.tool_calls or []):
|
||||
if tc.get("function", {}).get("name") == "submit_summary":
|
||||
args_str = tc.get("function", {}).get("arguments", "{}")
|
||||
try:
|
||||
data = json.loads(args_str) if args_str else {}
|
||||
summary_text = data.get("summary", response.text or "")
|
||||
facts = data.get("facts", []) or []
|
||||
extracted = True
|
||||
except json.JSONDecodeError:
|
||||
pass
|
||||
break
|
||||
if not extracted:
|
||||
# Fallback: extract JSON from text response (older models).
|
||||
import re as _re
|
||||
json_match = _re.search(r"\{[\s\S]*\}", response.text or "")
|
||||
if json_match:
|
||||
try:
|
||||
data = json.loads(json_match.group(0))
|
||||
summary_text = data.get("summary", response.text or "")
|
||||
facts = data.get("facts", []) or []
|
||||
except json.JSONDecodeError:
|
||||
pass
|
||||
|
||||
# Create summary message
|
||||
next_seq = (max((m.seq for m in all_msgs), default=0)) + 1
|
||||
@@ -207,7 +230,11 @@ async def build_step_writer_messages(
|
||||
outcome: str,
|
||||
narrative_prompt: str,
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""Build messages for the step writer LLM call."""
|
||||
"""Build messages for the step writer LLM call.
|
||||
|
||||
The step-writer prompt is in English (system content convention) but
|
||||
instructs the LLM to produce the narrative in world.language.
|
||||
"""
|
||||
defn = world.definition or {}
|
||||
player_state = world.state.get("player", {}) if world.state else {}
|
||||
system_prompt = get_prompt("step_writer", world.language).format(
|
||||
@@ -216,6 +243,7 @@ async def build_step_writer_messages(
|
||||
player_state=json.dumps(player_state, ensure_ascii=False)[:400],
|
||||
outcome=outcome,
|
||||
narrative_prompt=narrative_prompt[:600],
|
||||
world_language=world.language or "en",
|
||||
)
|
||||
return [{"role": "system", "content": system_prompt}]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user