--- name: session-usage description: Session 对话单元的设计理念、上下文组装规则、memory / insight 槽位语义、单一 Session 模型与跨 Session 通信模型。 --- # Session 使用 ## 单一 Session 模型 `@stello-ai/session` 只对外暴露**一种** Session。对话起点是一个 `parentId === null` 的 root session(由 `agent.createSession()` 创建),其余通过 `agent.forkSession()` 挂在父节点下。Root 与 child 在运行时行为完全一致——差异仅在 `TopologyNode.parentId`。 一棵树可以有任意多 root,互相独立(森林)。 Session 始终是**单次 LLM 调用原语**:`send()` 单次调用 + 持久化,tool call 循环由 `@stello-ai/core` 的 `Engine` 驱动。 --- ## 上下文组装规则 这是固定规则,不暴露扩展点(设计决策 #7)。 ``` system prompt → session_identity(label) → insight(若有,消费后清除) → L3 历史 → 当前用户消息 ``` - **system prompt** 来自 `getSystemPrompt(sessionId)`,全局每 Session 一份。 - **session_identity** 由 `label` 自动生成的 `` 系统消息,告知 LLM 当前所在子会话身份。 - **insight** 来自 `getInsight(sessionId)`,**一次性**:被消费后 send() 内置触发 `clearInsight`。 - **L3 历史** 来自 `listRecords(sessionId)`,会先经 `removeIncompleteToolCallGroups` 净化掉因中断/崩溃残留的不完整 tool call 组。 - **memory 槽位不进入 send() 上下文**——它是对外暴露的描述,由 orchestrator-facing 视角消费,详见下文。 当估算 token 数超过 `maxContextTokens * 0.8` 时,会调用闭包注入的 `compressFn`,将历史压缩为一段 system 摘要,与近期消息拼接。Session 内部缓存压缩结果,避免每次 send() 都调用 compressFn。 --- ## 三个上下文槽位的语义 每个 Session 在 `SessionStorage` 中有三个独立内容槽位: | 槽位 | 写入者 | 消费者 | 生命周期 | |------|--------|--------|---------| | `systemPrompt` | fork 合成链固化 / 应用层 | Session.send() 组装上下文 | 持久(每次 send 读取) | | `insight` | Orchestrator(应用层通过 `putInsight`) | Session.send() 消费一次后清除 | 一次性 inbox | | `memory` | 应用层(通过 consolidate 输出 / 直接 `putMemory`) | Orchestrator-facing 反思层(`listSessionDigests`) | 持久(被外部读,不进 send) | **关键不变量**:`memory` 不进入 Session 自身的 LLM 上下文。它是面向外部视角的描述——上层可以批量收集所有 Session 的 memory 做反思、规划、调度,再通过 `putInsight` 把派生的洞察定向回写给目标 Session。Session 自身不感知这个回路。 --- ## 跨 Session 通信模型 子 Session 之间完全不感知。唯一的跨 Session 信息通道: ``` 所有 Session 的 memory ──┐ ├─→ 应用层反思层(任意 LLM)──→ putInsight(targetId, content) ┘ (StelloAgent.listSessionDigests 一次性取齐) ``` - **反思层由应用层实现**:应用层可以用任意频率、任意 LLM、任意策略对 `listSessionDigests` 的结果做综合,再把派生 insight 定向回写。 - **insight 是一次性的**:每次 reflection 写入新 insight;target session 下一次 send() 注入后自动 clear。重复 reflect 不会累积。 - **memory 是持久的**:`putMemory` 的语义是替换不是追加。 --- ## fork() 的语义 Session 层 `fork(options)` 完成上下文继承: - 创建一个新 Session 实例(id 由调用方传入,topology-first) - 按 `context: 'none' | 'inherit' | ForkContextFn` 决定是否拷贝父 session 的 L3 记录 - 不复制 memory / insight 槽位 - 一次性继承后两个 Session 互相独立 Engine 在编排层会先创建 TopologyNode(拿到 ID),再调用 `session.fork({ id })`。调用方通过 `agent.forkSession()` 一次完成两步,详见 skill `fork-design`。 --- ## LLM Adapter 包内置两个 adapter:OpenAI 兼容协议和 Anthropic 协议(均为 optional peerDependencies)。也可自行实现 `LLMAdapter` 接口,但 `stream()` 是必需能力,不支持 complete-only adapter。 Session 始终以 stream 作为底层传输:`stream()` 实时转发文本增量,`send()` 使用同一执行器静默消费并聚合完整结果。`complete()` 仅是 adapter 对直接调用方保留的流式聚合 facade,不得切回 provider 的非流式端点。 --- ## ConsolidateFn / CompressFn - **ConsolidateFn**:L3 → memory 的提炼函数,由应用层定义输出格式,框架对 memory 内容格式完全无感知。 - **CompressFn**:超 token 阈值时把对话历史压缩为一段摘要,注入到上下文里。 - 两者都不注入 LLM——应用层通过闭包自行选择 LLM tier(设计决策 #12)。