package com.gzzm.lobster.llm;

/**
 * StreamingSession —— 流式会话句柄 / Handle to an in-flight streaming LLM call.
 *
 * <p>对外契约：
 * <ul>
 *   <li>{@link #cancel(CancelReason)} 立即终止底层 HTTP 连接（{@code conn.disconnect()}），
 *       不等流自然结束</li>
 *   <li>{@link #cancelReason()} 返回触发取消的原因，{@code null} 表示未取消</li>
 *   <li>通过 {@link AutoCloseable#close()} 使用 try-with-resources，默认以 USER 取消</li>
 * </ul>
 *
 * <p>Claude Code 的 ESC 键语义就走这条路径：一旦 cancel，绝不允许继续输出 delta、
 * 绝不允许 LlmRuntime 切到 fallback 模型。cancel 原因通过
 * {@link RunCancelledException} 向上传递。
 *
 * @see CancelReason
 * @see LobsterLlmAdapter#startChatStream
 */
public interface StreamingSession extends AutoCloseable {

    /**
     * 主动取消会话 / Actively cancel.
     *
     * <p>幂等：重复调用仅首次生效。adapter 层必须在读取下一帧前检查
     * {@link #isCancelled()} 并主动断开连接。
     */
    void cancel(CancelReason reason);

    /** 是否已取消 / Whether cancel has been requested. */
    boolean isCancelled();

    /** 取消原因 / Cancel reason, {@code null} if not cancelled. */
    CancelReason cancelReason();

    /**
     * try-with-resources 语义下默认按用户主动取消处理 /
     * Default close interprets early termination as USER cancel.
     */
    @Override
    default void close() {
        if (!isCancelled()) {
            cancel(CancelReason.USER);
        }
    }
}
