001/*
002 *  Copyright (c) 2023-2026, Agents-Flex (fuhai999@gmail.com).
003 *  <p>
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *  <p>
008 *  http://www.apache.org/licenses/LICENSE-2.0
009 *  <p>
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package com.agentsflex.core.model.chat;
017
018import com.agentsflex.core.model.client.ChatRequestSpec;
019import com.agentsflex.core.prompt.Prompt;
020
021/**
022 * 聊天上下文管理器,用于在当前线程中保存聊天相关的上下文信息。
023 * <p>
024 * 供日志、监控、拦截器等模块使用。
025 * <p>
026 * 支持同步和流式调用,通过 {@link ChatContextScope} 实现自动清理。
027 */
028public final class ChatContextHolder {
029
030    private static final ThreadLocal<ChatContext> CONTEXT_HOLDER = new ThreadLocal<>();
031
032    private ChatContextHolder() {
033        // 工具类,禁止实例化
034    }
035
036
037    /**
038     * 开始一次聊天上下文,并设置传输层请求信息。
039     * 适用于远程 LLM 模型(如 HTTP/gRPC/WebSocket)。
040     *
041     * @param config  聊天配置
042     * @param options 聊天选项
043     * @param prompt  用户提示
044     * @param request 请求信息构建起
045     * @return 可用于 try-with-resources 的作用域对象
046     */
047    public static ChatContextScope beginChat(
048        Prompt prompt,
049        ChatOptions options,
050        ChatRequestSpec request,
051        ChatConfig config) {
052
053        ChatContext ctx = new ChatContext();
054        ctx.prompt = prompt;
055        ctx.options = options;
056        ctx.requestSpec = request;
057        ctx.config = config;
058
059        CONTEXT_HOLDER.set(ctx);
060
061        return new ChatContextScope(ctx);
062    }
063
064    /**
065     * 获取当前线程的聊天上下文(可能为 null)。
066     *
067     * @return 聊天上下文,若未设置则返回 null
068     */
069    public static ChatContext currentContext() {
070        return CONTEXT_HOLDER.get();
071    }
072
073    /**
074     * 手动清除当前线程的上下文。
075     * <p>
076     * 通常由 {@link ChatContextScope} 自动调用,无需手动调用。
077     */
078    public static void clear() {
079        CONTEXT_HOLDER.remove();
080    }
081
082
083    /**
084     * 用于 try-with-resources 的作用域对象,确保上下文自动清理。
085     */
086    public static class ChatContextScope implements AutoCloseable {
087
088        ChatContext context;
089
090        public ChatContextScope(ChatContext context) {
091            this.context = context;
092        }
093
094        @Override
095        public void close() {
096            clear();
097        }
098    }
099}