// 段与优先级模型。
//
// 优先级为什么这样分(README 要解释):
// * `Pinned`  —— system 提示、工具定义:一旦丢失语义就崩,永不被裁。
// * `Newest`  —— 最近若干轮:对下一步生成影响最大,优先保留。
// * `Middle`  —— 中间历史:第一批牺牲品之一。
// * `Oldest`  —— 最早的历史:最先被丢。

///|
/// 段的丢弃权重,从「不可丢」到「最先牺牲」。
///
/// 典型用法:system 提示与工具定义用 `Pinned`,最近几轮用 `Newest`,
/// 中间历史用 `Middle`,最早的历史用 `Oldest`。
/// 权重相同时先丢原始下标更小的段(更早的历史),因此结果与输入顺序无关可复现。
pub(all) enum Priority {
  Pinned
  Newest
  Middle
  Oldest
} derive(Eq, Debug)

///|
/// 优先级权重;越大越不可丢。
pub fn Priority::weight(self : Priority) -> Int {
  match self {
    Pinned => 3
    Newest => 2
    Middle => 1
    Oldest => 0
  }
}

///|
/// 规范名称(用于可冻结的报告文本,不用 Debug 输出)。
pub fn Priority::name(self : Priority) -> String {
  match self {
    Pinned => "pinned"
    Newest => "newest"
    Middle => "middle"
    Oldest => "oldest"
  }
}

///|
/// 上下文里的一段。`role` 是自由标签(如 `system` / `user`),
/// `bytes` 是该段要送进窗口的内容。
///
/// 两个可选维度都只影响**取舍**,不影响编码:
/// * `pool` —— 配额池名(如 `tools` / `retrieval` / `history`)。同名段共享一份配额,
///   池用不完的配额可按声明顺序借给超额的池,借用规则会写进报告。
///   空串表示默认池,不参与配额。
/// * `score` —— 同优先级内的取舍分数,**越大越优先保留**(检索片段的相关性、
///   工具定义的重要性都可以放这里)。分数只在同一 `Priority` 内比较,
///   不会越过优先级。
pub(all) struct Segment {
  role : String
  priority : Priority
  pool : String
  score : Int64
  bytes : Bytes
}

///|
pub fn Segment::new(role : String, priority : Priority, bytes : Bytes) -> Segment {
  { role, priority, pool: "", score: 0L, bytes }
}

///|
pub fn Segment::text(role : String, priority : Priority, text : String) -> Segment {
  { role, priority, pool: "", score: 0L, bytes: @utf8.encode(text) }
}

///|
/// 归入某个配额池(`name` 不得含空格或换行:它会直接进报告)。
pub fn Segment::with_pool(self : Segment, name : String) -> Segment {
  { ..self, pool: name }
}

///|
/// 设置同优先级内的取舍分数(越大越优先保留)。
pub fn Segment::with_score(self : Segment, score : Int64) -> Segment {
  { ..self, score }
}