This commit is contained in:
Mikan
2026-06-19 16:31:45 +03:00
parent d0d1f003ae
commit 5a78def096
21 changed files with 1250 additions and 548 deletions

View File

@@ -91,13 +91,29 @@ RAG_ADD_SCHEMA = build_tool_schema(
SCHEDULE_TRIGGER_SCHEMA = build_tool_schema(
name="schedule_trigger",
description="Schedule a deferred event tied to world time. When world time reaches fire_at, the system will fire it.",
description=(
"Schedule a deferred event tied to in-world time. When the world's "
"internal clock reaches fire_at, the engine fires the event (calls the "
"LLM with the description to produce a narrative beat and optional "
"state patch). fire_at must use the same format as world.current_time "
"('day_N_hour_H' or 'day_N_hour_H_min_M'). The world's calendar "
"(hours_per_day, minutes_per_hour) is honored when comparing times."
),
params={
"type": "object",
"properties": {
"fire_at": {"type": "string", "description": "World time string in same format as world.current_time, e.g. 'day_3_hour_14'"},
"description": {"type": "string", "description": "What should happen"},
"payload": {"type": "object", "description": "Arbitrary structured payload for the trigger runner"},
"fire_at": {
"type": "string",
"description": "In-world time when the trigger fires, e.g. 'day_3_hour_14' or 'day_3_hour_14_min_30'.",
},
"description": {
"type": "string",
"description": "What should happen when the trigger fires. Be specific — this is fed to the LLM at fire time.",
},
"payload": {
"type": "object",
"description": "Optional structured payload (e.g. who, conditions, parameters).",
},
},
"required": ["fire_at", "description"],
},
@@ -106,14 +122,22 @@ SCHEDULE_TRIGGER_SCHEMA = build_tool_schema(
ADVANCE_TIME_SCHEMA = build_tool_schema(
name="advance_time",
description="Advance the world's internal clock by days/hours/minutes. Use this when the action takes time.",
description=(
"Advance the world's internal clock by days / hours / minutes. Use "
"this when the player's action takes measurable in-world time (travel, "
"sleep, crafting, long rest). The world's calendar (hours_per_day, "
"minutes_per_hour) is honored. After time advances, any scheduled "
"triggers whose fire_at is now <= the new time will fire "
"automatically — so this is also how you 'run out the clock' on a "
"scheduled event."
),
params={
"type": "object",
"properties": {
"days": {"type": "integer", "default": 0},
"hours": {"type": "integer", "default": 0},
"minutes": {"type": "integer", "default": 0},
"reason": {"type": "string", "description": "Why time advances"},
"reason": {"type": "string", "description": "Why time advances (logged for debugging)."},
},
},
)
@@ -133,6 +157,219 @@ RUN_SUBAGENT_SCHEMA = build_tool_schema(
)
# === Submission tools (how the LLM returns structured results) ===
# These replace the old "return JSON in your text response" pattern, which
# conflicted with tool use and caused the model to dump raw JSON into chat.
SUBMIT_PLAN_SCHEMA = build_tool_schema(
name="submit_plan",
description=(
"Submit the orchestrator's final plan for this iteration. This MUST be "
"the last tool you call. After you call it, the iteration ends and the "
"step-writer takes over to produce the cinematic scene."
),
params={
"type": "object",
"properties": {
"assessment": {
"type": "string",
"description": "Brief assessment of the player's action (1-2 sentences, English).",
},
"outcome": {
"type": "string",
"description": "What concretely happened (1-3 sentences, English). Fed to the step-writer as the raw outcome.",
},
"state_patch": {
"type": "object",
"description": "JSON-patch for world state. Keys: set, unset, append, increment, remove. Empty object if no change.",
"properties": {
"set": {"type": "object"},
"unset": {"type": "array", "items": {"type": "string"}},
"append": {"type": "object"},
"increment": {"type": "object"},
"remove": {"type": "object"},
},
},
"time_advance": {
"type": "object",
"description": "How much in-world time advances. null/omitted if no time passes.",
"properties": {
"days": {"type": "integer", "default": 0},
"hours": {"type": "integer", "default": 0},
"minutes": {"type": "integer", "default": 0},
},
},
"narrative_prompt": {
"type": "string",
"description": "Facts the step-writer should know to write the scene (English). Max ~100 words.",
},
"next_options": {
"type": "array",
"items": {"type": "string"},
"description": "3 suggested next actions for the player (short, 5-12 words each).",
},
"rails_update": {
"type": "object",
"description": "Optional update to plot rails. Omit if no change.",
"properties": {
"main_goal": {"type": "string"},
"new_subgoals": {"type": "array", "items": {"type": "string"}},
"completed_subgoals": {"type": "array", "items": {"type": "string"}},
},
},
"rag_facts": {
"type": "array",
"description": "New persistent facts to add to the glossary. Empty array if none.",
"items": {
"type": "object",
"properties": {
"kind": {"type": "string", "enum": ["npc", "location", "item", "lore", "event"]},
"name": {"type": "string"},
"description": {"type": "string"},
},
"required": ["kind", "name", "description"],
},
},
},
"required": ["assessment", "outcome", "narrative_prompt", "next_options"],
},
)
SUBMIT_SCENE_SCHEMA = build_tool_schema(
name="submit_scene",
description=(
"Submit the narrative scene for this step. This is the ONLY way to "
"return the scene — your text response is ignored. The narrative "
"should be 200-400 words, cinematic, second-person ('You...'), in the "
"world's player-facing language."
),
params={
"type": "object",
"properties": {
"narrative": {
"type": "string",
"description": "200-400 words of cinematic prose describing the scene. Second-person ('You...').",
},
"options": {
"type": "array",
"items": {"type": "string"},
"description": "Exactly 3 short (5-12 words) options for the player's next action.",
},
},
"required": ["narrative", "options"],
},
)
SUBMIT_WORLD_DEFINITION_SCHEMA = build_tool_schema(
name="submit_world_definition",
description=(
"Submit a proposed world definition. Call this when you have enough "
"information to build the world. Your text response will be shown to "
"the player as your conversational reply (use it to summarize the "
"proposed world in 2-4 sentences)."
),
params={
"type": "object",
"properties": {
"setting_description": {"type": "string", "description": "Expanded setting, 1-2 paragraphs."},
"rules": {
"type": "object",
"description": "Object with keys like stats, combat, magic, time, inventory, death (whichever apply).",
},
"world_schema": {
"type": "object",
"description": "JSON Schema describing the shape of the world state.",
},
"plot_rails": {
"type": "object",
"description": "{main_goal, subgoals, hooks}.",
"properties": {
"main_goal": {"type": "string"},
"subgoals": {"type": "array", "items": {"type": "string"}},
"hooks": {"type": "array", "items": {"type": "string"}},
},
},
"initial_state": {
"type": "object",
"description": "Initial world state matching world_schema.",
},
"initial_time": {
"type": "string",
"description": "World time string e.g. 'day_1_hour_8'.",
},
"calendar": {
"type": "object",
"description": "Optional. Custom calendar. Include only if non-standard.",
"properties": {
"hours_per_day": {"type": "integer"},
"minutes_per_hour": {"type": "integer"},
"days_per_week": {"type": "integer"},
},
},
"is_final": {
"type": "boolean",
"description": "True ONLY when the player has explicitly accepted the world.",
},
},
"required": ["setting_description", "rules", "world_schema", "initial_state", "initial_time"],
},
)
SUBMIT_SUMMARY_SCHEMA = build_tool_schema(
name="submit_summary",
description="Submit the compressed summary of older session messages.",
params={
"type": "object",
"properties": {
"summary": {"type": "string", "description": "3-6 sentences, max 150 words."},
"facts": {
"type": "array",
"items": {
"type": "object",
"properties": {
"kind": {"type": "string", "enum": ["npc", "location", "item", "lore", "event"]},
"name": {"type": "string"},
"description": {"type": "string"},
},
"required": ["kind", "name", "description"],
},
},
},
"required": ["summary", "facts"],
},
)
SUBMIT_TRIGGER_RESULT_SCHEMA = build_tool_schema(
name="submit_trigger_result",
description="Submit the result of firing a deferred trigger.",
params={
"type": "object",
"properties": {
"outcome": {"type": "string", "description": "1-2 sentences, English. For logs."},
"state_patch": {
"type": "object",
"description": "JSON-patch for world state. Empty object if no change.",
"properties": {
"set": {"type": "object"},
"unset": {"type": "array", "items": {"type": "string"}},
"append": {"type": "object"},
"increment": {"type": "object"},
"remove": {"type": "object"},
},
},
"narrative": {"type": "string", "description": "1-paragraph scene description for the player, in world.language. Empty string if offscreen."},
"should_notify_player": {"type": "boolean", "description": "True if the player should see the narrative."},
},
"required": ["outcome", "narrative", "should_notify_player"],
},
)
# Tools available to the orchestrator (game-loop tools + submit_plan)
ALL_TOOL_SCHEMAS = [
DICE_ROLL_SCHEMA,
UPDATE_STATE_SCHEMA,
@@ -141,8 +378,21 @@ ALL_TOOL_SCHEMAS = [
SCHEDULE_TRIGGER_SCHEMA,
ADVANCE_TIME_SCHEMA,
RUN_SUBAGENT_SCHEMA,
SUBMIT_PLAN_SCHEMA,
]
# Tools for the step writer (only submit_scene)
STEP_WRITER_TOOL_SCHEMAS = [SUBMIT_SCENE_SCHEMA]
# Tools for the world builder (only submit_world_definition)
WORLD_BUILDER_TOOL_SCHEMAS = [SUBMIT_WORLD_DEFINITION_SCHEMA]
# Tools for the summarizer
SUMMARIZER_TOOL_SCHEMAS = [SUBMIT_SUMMARY_SCHEMA]
# Tools for the trigger runner
TRIGGER_RUNNER_TOOL_SCHEMAS = [SUBMIT_TRIGGER_RESULT_SCHEMA]
# === Tool handlers ===