Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ The current Web UI already supports:
- persona review pages with key-field completion, evidence-gap checks, and secondary-field tuning
- creating, editing, selecting, and reusing scene cards, self cards, and opening presets
- automatic next-scene recommendation during chat, with in-session scene switching
- automatic next-beat surfacing when a scene matures, including a transition line, follow-up chain, and auto-opening cue
- session restore, recent-session resume, group chat continuation, and direct workbench entry into a scene
- dialogue context compression that trims persona / relation context around active participants and injects session memory summaries
- viewing transcripts, continuing group chat, and deleting recent sessions in the same interface
Expand Down Expand Up @@ -207,6 +208,7 @@ You can now layer these helpers before or during a session:
- self cards: prepare your identity, tone, motive, and in-scene role for `insert`
- opening presets: bundle mode, participants, scene card, and self card into a reusable starting setup
- automatic scene recommendation: while a session is running, the system can suggest a more suitable next scene card
- transition assist flow: besides recommending the next scene, it can also provide a transition line, a follow-up scene chain, and an auto-opening cue for the next beat

## Usage 🛠️

Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ python scripts/run_webui.py --reload
- 人物校对页,支持关键字段补全、证据不足检查与二级字段微调
- 场景卡、角色卡、开局模板的创建、编辑、选择与复用
- 聊天过程中自动推荐下一幕场景卡,并支持会话内切换场景
- 拍点成熟时自动浮出下一幕建议,附带转场起句、后续戏路和自动起拍提示
- 会话恢复、最近会话续聊、群聊继续与工作台直接入场
- 对话上下文自动压缩,按活跃角色裁剪人物/关系上下文,并注入会话记忆摘要
- 在同一页面查看 transcript、继续群聊、删除历史会话
Expand Down Expand Up @@ -217,6 +218,7 @@ python scripts/run_webui.py --reload
- 角色卡:为 `insert` 模式准备你的身份、语气、动机与在场定位
- 开局模板:把入场方式、参与角色、场景卡、角色卡打包成一套可复用开局
- 自动场景推荐:会话进行中,系统会结合当前局势推荐更适合的下一幕
- 转场辅助链路:除了推荐哪一幕,还会给出转场起句、后续戏路,以及切幕后可直接继续开聊的自动起拍提示

## 使用方式 🛠️

Expand Down
110 changes: 110 additions & 0 deletions docs/session-state-v1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# Session State V1

## Goal

This branch treats dialogue session state as a first-class runtime model instead of a loose bag of side effects.

We intentionally optimize for a clean canonical schema rather than backward compatibility.

## Canonical State

Each dialogue session owns one canonical `state` object:

```json
{
"version": 1,
"scene": {
"location": "",
"time_hint": "",
"atmosphere_summary": "",
"progression_note": "",
"updated_at": ""
},
"presence": {
"present_participants": [],
"offstage_participants": [],
"updated_at": ""
},
"progression": {
"should_offer_scene_shift": false,
"scene_shift_reason": "",
"turns_in_current_scene": 0,
"beat_maturity": 0,
"world_tension_summary": "",
"updated_at": ""
},
"relations": {
"matrix": {},
"delta": {}
},
"characters": {
"snapshots": {}
},
"signals": {
"recent": [],
"by_type": {},
"updated_at": ""
},
"memory": {
"summary": {}
}
}
```

## Rules

1. `state` is the only source of truth for session runtime evolution.
2. API payloads may still project convenience views like `scene_progress` or `relation_delta`, but those are derived views, not primary storage.
3. Session payloads may expose derived helpers like `runtime_state_overview` for UI rendering, but these are read-only projections from canonical `state`.
4. `runtime_state_overview` should stay presentation-friendly: short labels, trimmed text, and stable ordering for characters / relations / events.
5. Scene flow is split into three concerns:
- `scene`: where/when/what tone the current beat has
- `presence`: who is currently onstage or offstage
- `progression`: whether the beat is mature enough to shift scenes
6. Relationship updates are split into:
- `relations.matrix`: baseline merged relation graph for session participants
- `relations.delta`: session-local drift caused by this conversation
7. Character-local runtime drift belongs in `characters.snapshots`.
8. Small event cues, transitions, exits, and atmosphere shifts belong in `signals`.
9. Compression summaries belong in `memory.summary`.

## Implementation Checklist

### Slice 1: Canonical State Foundation

- [x] Define the canonical session-state schema
- [x] Centralize session-state creation and normalization
- [x] Project derived `scene_progress` from canonical state
- [x] Project derived `relation_delta`, `character_snapshots`, and `event_signals`
- [x] Move session-store readers to canonical state paths

### Slice 2: Progression Engine

- [x] Split time, location, atmosphere, and onstage/offstage decisions into dedicated state updaters
- [x] Track scene maturity explicitly in `progression.beat_maturity`
- [x] Let narration, exits, and returns update canonical presence state directly

### Slice 3: Session Snapshots

- [x] Expand character snapshots into stable per-character runtime cards
- [x] Expand relation deltas into stable per-pair interaction drift
- [x] Add explicit session-level world tension / atmosphere summary

### Slice 4: Prompt Integration

- [x] Feed canonical state into turn payloads
- [x] Feed canonical state into suggestion payloads
- [x] Feed canonical state into scene-progress generation prompts
- [x] Trim prompt payloads using canonical active-state priority

### Slice 5: UI Integration

- [x] Surface canonical presence/time/progression hints in the chat UI
- [x] Surface natural next-scene hints from `progression`
- [x] Surface per-character session drift from `characters.snapshots`

## Non-Goals

- Preserving every old session-state shape on disk
- Layering more compatibility shims for low-value legacy paths
- Keeping duplicated state across multiple top-level session fields
8 changes: 4 additions & 4 deletions src/core/session_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,12 @@ def compress_context(
to_archive = history[:-recent_turns]
keep = history[-recent_turns:]
state = session.setdefault("state", {})
memory_summary = dict(state.get("memory_summary", {}) or {})
memory_summary = dict(dict(state.get("memory", {}) or {}).get("summary", {}) or {})
previous_summary = _normalize_text(memory_summary.get("summary", ""))
compressed = self._build_memory_summary(previous_summary, to_archive, summary_limit)
key_points = self._extract_key_points(to_archive, limit=8)

state["memory_summary"] = {
state.setdefault("memory", {})["summary"] = {
"summary": compressed,
"key_points": key_points,
"compressed_turns": len(to_archive),
Expand Down Expand Up @@ -199,8 +199,8 @@ def save_relation_snapshot(self, session: Dict[str, Any]) -> None:
"session_id": session_id,
"novel_id": session.get("novel_id"),
"updated_at": session.get("updated_at"),
"relation_matrix": session.get("state", {}).get("relation_matrix", {}),
"relation_delta": session.get("state", {}).get("relation_delta", {}),
"relation_matrix": dict(dict(session.get("state", {}).get("relations", {}) or {}).get("matrix", {}) or {}),
"relation_delta": dict(dict(session.get("state", {}).get("relations", {}) or {}).get("delta", {}) or {}),
}
save_markdown_data(
self._relation_snapshot_path(session_id),
Expand Down
15 changes: 15 additions & 0 deletions src/skill_support/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,18 @@

"""Shared helpers for prompt-first skill workflows."""

from .scene_recommendations import (
build_scene_opening_message,
build_scene_recommendation_bundle,
normalize_scene_recommendation_context,
recommend_dialogue_scene_cards,
recommend_scene_cards_base,
)

__all__ = [
"build_scene_opening_message",
"build_scene_recommendation_bundle",
"normalize_scene_recommendation_context",
"recommend_dialogue_scene_cards",
"recommend_scene_cards_base",
]
Loading
Loading