diff --git a/mateclaw-server/src/main/java/vip/mate/agent/context/RuntimeContextInjector.java b/mateclaw-server/src/main/java/vip/mate/agent/context/RuntimeContextInjector.java new file mode 100644 index 00000000..42c05f3f --- /dev/null +++ b/mateclaw-server/src/main/java/vip/mate/agent/context/RuntimeContextInjector.java @@ -0,0 +1,30 @@ +package vip.mate.agent.context; + +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; + +/** + * 运行时上下文注入器 — 在 LLM 消息列表中预注入当前时间等运行时信息。 + *

+ * 参考 Claude Code 的 prependUserContext 模式:将时间信息作为首条 meta UserMessage 注入, + * 而非修改 System Prompt,以保持 prompt cache 命中率。 + */ +public final class RuntimeContextInjector { + + private static final ZoneId ZONE = ZoneId.of("Asia/Shanghai"); + private static final DateTimeFormatter DATE_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + private static final DateTimeFormatter TIME_FMT = DateTimeFormatter.ofPattern("HH:mm"); + + private RuntimeContextInjector() { + } + + /** + * 构建运行时上下文消息,包含当前日期和时间。 + */ + public static String buildContextMessage() { + LocalDateTime now = LocalDateTime.now(ZONE); + return "[system-context] 当前时间: " + now.format(DATE_FMT) + + " " + now.format(TIME_FMT) + " (Asia/Shanghai)"; + } +} diff --git a/mateclaw-server/src/main/java/vip/mate/agent/graph/node/ReasoningNode.java b/mateclaw-server/src/main/java/vip/mate/agent/graph/node/ReasoningNode.java index b7a8beda..fd93f4bd 100644 --- a/mateclaw-server/src/main/java/vip/mate/agent/graph/node/ReasoningNode.java +++ b/mateclaw-server/src/main/java/vip/mate/agent/graph/node/ReasoningNode.java @@ -7,6 +7,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.ai.chat.messages.AssistantMessage; import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.messages.SystemMessage; +import org.springframework.ai.chat.messages.UserMessage; import org.springframework.ai.chat.model.ChatModel; import org.springframework.ai.chat.prompt.ChatOptions; import org.springframework.ai.chat.prompt.Prompt; @@ -18,6 +19,7 @@ import vip.mate.agent.AgentToolSet; import vip.mate.agent.GraphEventPublisher; import vip.mate.agent.graph.NodeStreamingChatHelper; import vip.mate.agent.context.ConversationWindowManager; +import vip.mate.agent.context.RuntimeContextInjector; import vip.mate.agent.graph.state.FinishReason; import vip.mate.agent.graph.state.MateClawStateAccessor; import vip.mate.agent.graph.state.MateClawStateKeys; @@ -155,6 +157,8 @@ public class ReasoningNode implements NodeAction { // 构建 Prompt,附带工具定义但禁用内部工具执行 List promptMessages = new ArrayList<>(); promptMessages.add(new SystemMessage(systemPrompt)); + // 注入运行时上下文(当前时间),让 LLM 在推理阶段即可感知真实日期 + promptMessages.add(new UserMessage(RuntimeContextInjector.buildContextMessage())); promptMessages.addAll(messages); ChatOptions options; diff --git a/mateclaw-server/src/main/java/vip/mate/agent/graph/plan/node/PlanGenerationNode.java b/mateclaw-server/src/main/java/vip/mate/agent/graph/plan/node/PlanGenerationNode.java index 4f7f9a6d..848ce088 100644 --- a/mateclaw-server/src/main/java/vip/mate/agent/graph/plan/node/PlanGenerationNode.java +++ b/mateclaw-server/src/main/java/vip/mate/agent/graph/plan/node/PlanGenerationNode.java @@ -16,6 +16,7 @@ import vip.mate.agent.graph.plan.state.PlanStateAccessor; import vip.mate.agent.graph.plan.state.PlanStateKeys; import vip.mate.agent.graph.state.MateClawStateKeys; import vip.mate.agent.context.ConversationWindowManager; +import vip.mate.agent.context.RuntimeContextInjector; import vip.mate.planning.service.PlanningService; import java.util.ArrayList; @@ -125,6 +126,8 @@ public class PlanGenerationNode implements NodeAction { // 构建 prompt 消息列表:system + 历史上下文 + 当前规划请求 List promptMessages = new ArrayList<>(); promptMessages.add(new SystemMessage(systemPrompt + "\n\n" + PLANNING_PROMPT)); + // 注入运行时上下文(当前时间) + promptMessages.add(new UserMessage(RuntimeContextInjector.buildContextMessage())); // 注入 working context(对话历史摘要),让规划能感知之前对话的约束和补充条件 String workingContext = accessor.workingContext(); diff --git a/mateclaw-server/src/main/java/vip/mate/agent/graph/plan/node/StepExecutionNode.java b/mateclaw-server/src/main/java/vip/mate/agent/graph/plan/node/StepExecutionNode.java index 17d7e2e9..b775d3f0 100644 --- a/mateclaw-server/src/main/java/vip/mate/agent/graph/plan/node/StepExecutionNode.java +++ b/mateclaw-server/src/main/java/vip/mate/agent/graph/plan/node/StepExecutionNode.java @@ -23,6 +23,7 @@ import vip.mate.agent.graph.plan.state.PlanStateAccessor; import vip.mate.agent.graph.plan.state.PlanStateKeys; import vip.mate.agent.graph.state.MateClawStateKeys; import vip.mate.agent.context.ConversationWindowManager; +import vip.mate.agent.context.RuntimeContextInjector; import vip.mate.agent.graph.executor.ToolExecutionExecutor; import vip.mate.channel.web.ChatStreamTracker; import vip.mate.planning.service.PlanningService; @@ -304,6 +305,8 @@ public class StepExecutionNode implements NodeAction { 8. 每一步最多做一个必要的检查和一个必要的执行,不要无意义循环。 """; messages.add(new SystemMessage(enhancedSystemPrompt)); + // 注入运行时上下文(当前时间) + messages.add(new UserMessage(RuntimeContextInjector.buildContextMessage())); // Layer 2: Working context(对话历史 + 步骤结果的受控长度摘要) String workingContext = accessor.workingContext(); diff --git a/mateclaw-ui/src/App.vue b/mateclaw-ui/src/App.vue index 1027a52c..e208928d 100644 --- a/mateclaw-ui/src/App.vue +++ b/mateclaw-ui/src/App.vue @@ -5,7 +5,8 @@ diff --git a/mateclaw-ui/src/i18n/locales/en-US.ts b/mateclaw-ui/src/i18n/locales/en-US.ts index 16be5a74..18c73356 100644 --- a/mateclaw-ui/src/i18n/locales/en-US.ts +++ b/mateclaw-ui/src/i18n/locales/en-US.ts @@ -1,4 +1,7 @@ export default { + app: { + title: 'MateClaw - AI Assistant', + }, common: { save: 'Save', cancel: 'Cancel', diff --git a/mateclaw-ui/src/i18n/locales/zh-CN.ts b/mateclaw-ui/src/i18n/locales/zh-CN.ts index 0127a51f..b89e477c 100644 --- a/mateclaw-ui/src/i18n/locales/zh-CN.ts +++ b/mateclaw-ui/src/i18n/locales/zh-CN.ts @@ -1,4 +1,7 @@ export default { + app: { + title: 'MateClaw - AI 助手', + }, common: { save: '保存', cancel: '取消', diff --git a/mateclaw-ui/src/views/ChatConsole.vue b/mateclaw-ui/src/views/ChatConsole.vue index ddd578ea..f9ac4a34 100644 --- a/mateclaw-ui/src/views/ChatConsole.vue +++ b/mateclaw-ui/src/views/ChatConsole.vue @@ -123,7 +123,7 @@ :loading="isGenerating" :assistant-icon="currentAgent?.icon || '🤖'" :user-icon="userInitial" - :title="showModelPrompt ? modelPromptTitle : 'MateClaw'" + :title="showModelPrompt ? modelPromptTitle : $t('app.title')" :subtitle="showModelPrompt ? modelPromptDesc : $t('chat.subtitle')" :suggestions="showModelPrompt ? [] : suggestions" @regenerate="handleRegenerate"