feat(agent): thread runtime model/provider into per-turn context injection

This commit is contained in:
倪程伟 2026-06-05 00:07:10 +08:00 committed by matevip
parent bd1ceace74
commit 2e1ef6b4b1
4 changed files with 27 additions and 14 deletions

View File

@ -509,6 +509,8 @@ public class ReasoningNode implements NodeAction {
String workspaceBasePath = state.value(vip.mate.agent.graph.state.MateClawStateKeys.WORKSPACE_BASE_PATH, "");
String agentIdStr = state.value(MateClawStateKeys.AGENT_ID, "");
String userMsg = state.value(MateClawStateKeys.USER_MESSAGE, "");
String runtimeModelName = state.value(MateClawStateKeys.RUNTIME_MODEL_NAME, "");
String runtimeProviderId = state.value(MateClawStateKeys.RUNTIME_PROVIDER_ID, "");
// Build the non-history prefix ONCE. The PTL retry branch below
// reuses this list verbatim so the retried prompt has exactly the
@ -517,7 +519,7 @@ public class ReasoningNode implements NodeAction {
// segment which led to "answer regressed after compaction"
// complaints on long sessions.
List<Message> nonHistoryPrefix = buildNonHistoryPrefix(systemPrompt, workspaceBasePath, agentIdStr, userMsg,
accessor.chatOrigin());
accessor.chatOrigin(), runtimeModelName, runtimeProviderId);
// Append the runtime-rendered skill catalog as a SEPARATE SystemMessage
// right after the skeleton system prompt. Keeping it out of the baked
@ -967,10 +969,13 @@ public class ReasoningNode implements NodeAction {
String workspaceBasePath,
String agentIdStr,
String userMsg,
vip.mate.agent.context.ChatOrigin chatOrigin) {
vip.mate.agent.context.ChatOrigin chatOrigin,
String runtimeModelName,
String runtimeProviderId) {
List<Message> prefix = new ArrayList<>();
prefix.add(new SystemMessage(systemPrompt));
prefix.add(new UserMessage(RuntimeContextInjector.buildContextMessage(workspaceBasePath, null, chatOrigin)));
prefix.add(new UserMessage(RuntimeContextInjector.buildContextMessage(
workspaceBasePath, null, chatOrigin, runtimeModelName, runtimeProviderId)));
// When this turn already recalled the user's own current project from
// structured memory, skip auto-injecting knowledge-base reference context.
// Otherwise the KB pages (reference material, possibly about unrelated

View File

@ -169,8 +169,11 @@ public class PlanGenerationNode implements NodeAction {
vip.mate.agent.context.ChatOrigin chatOrigin =
state.<vip.mate.agent.context.ChatOrigin>value(MateClawStateKeys.CHAT_ORIGIN)
.orElse(vip.mate.agent.context.ChatOrigin.EMPTY);
String runtimeModelName = state.value(MateClawStateKeys.RUNTIME_MODEL_NAME, "");
String runtimeProviderId = state.value(MateClawStateKeys.RUNTIME_PROVIDER_ID, "");
promptMessages.add(new UserMessage(
RuntimeContextInjector.buildContextMessage(workspaceBasePath, null, chatOrigin)));
RuntimeContextInjector.buildContextMessage(
workspaceBasePath, null, chatOrigin, runtimeModelName, runtimeProviderId)));
// Advertise available tools so the LLM can recognize when an action is possible,
// but do NOT force "any tool usage implies multi-step" single-hop tool use

View File

@ -166,6 +166,8 @@ public class StepExecutionNode implements NodeAction {
vip.mate.agent.context.ChatOrigin chatOrigin =
state.<vip.mate.agent.context.ChatOrigin>value(MateClawStateKeys.CHAT_ORIGIN)
.orElse(vip.mate.agent.context.ChatOrigin.EMPTY);
String runtimeModelName = state.value(MateClawStateKeys.RUNTIME_MODEL_NAME, "");
String runtimeProviderId = state.value(MateClawStateKeys.RUNTIME_PROVIDER_ID, "");
if (stepIndex >= steps.size()) {
log.warn("[StepExecution] stepIndex {} >= steps.size() {}, skipping", stepIndex, steps.size());
@ -195,7 +197,8 @@ public class StepExecutionNode implements NodeAction {
planningService.updateSubPlanStatus(planId, stepIndex, "running");
// 构建消息列表
List<Message> messages = buildStepMessages(accessor, step, systemPrompt, workspaceBasePath);
List<Message> messages = buildStepMessages(accessor, step, systemPrompt, workspaceBasePath,
runtimeModelName, runtimeProviderId);
// 显式工具执行循环
String finalResult = null;
@ -509,7 +512,8 @@ public class StepExecutionNode implements NodeAction {
return sb.toString();
}
private List<Message> buildStepMessages(PlanStateAccessor accessor, String step, String systemPrompt, String workspaceBasePath) {
private List<Message> buildStepMessages(PlanStateAccessor accessor, String step, String systemPrompt,
String workspaceBasePath, String runtimeModelName, String runtimeProviderId) {
List<Message> messages = new ArrayList<>();
// Layer 1: System prompt增强指令
@ -537,9 +541,10 @@ public class StepExecutionNode implements NodeAction {
messages.add(new SystemMessage(skillCatalog));
}
}
// 注入运行时上下文当前时间 + 工作目录 + 发起者上下文
// 注入运行时上下文当前时间 + 工作目录 + 发起者上下文 + 模型身份
messages.add(new UserMessage(
RuntimeContextInjector.buildContextMessage(workspaceBasePath, null, accessor.chatOrigin())));
RuntimeContextInjector.buildContextMessage(
workspaceBasePath, null, accessor.chatOrigin(), runtimeModelName, runtimeProviderId)));
// Layer 2: Working context对话历史 + 步骤结果的受控长度摘要
String workingContext = accessor.workingContext();

View File

@ -48,7 +48,7 @@ class ReasoningNodePtlPromptTest {
"/workspace/active",
"42",
"investigate the bug in module X",
vip.mate.agent.context.ChatOrigin.EMPTY);
vip.mate.agent.context.ChatOrigin.EMPTY, "", "");
// Three layers: System, runtime-context UserMessage, wiki UserMessage.
assertThat(prefix).hasSize(3);
@ -74,10 +74,10 @@ class ReasoningNodePtlPromptTest {
List<Message> a = node.buildNonHistoryPrefix(
"sys", "/workspace", "42", "goal",
vip.mate.agent.context.ChatOrigin.EMPTY);
vip.mate.agent.context.ChatOrigin.EMPTY, "", "");
List<Message> b = node.buildNonHistoryPrefix(
"sys", "/workspace", "42", "goal",
vip.mate.agent.context.ChatOrigin.EMPTY);
vip.mate.agent.context.ChatOrigin.EMPTY, "", "");
assertThat(a).hasSameSizeAs(b);
for (int i = 0; i < a.size(); i++) {
@ -98,7 +98,7 @@ class ReasoningNodePtlPromptTest {
"/workspace/active",
"42",
"investigate the bug in module X",
vip.mate.agent.context.ChatOrigin.EMPTY);
vip.mate.agent.context.ChatOrigin.EMPTY, "", "");
assertThat(prefix).hasSize(2);
assertThat(prefix.get(0)).isInstanceOf(SystemMessage.class);
@ -112,7 +112,7 @@ class ReasoningNodePtlPromptTest {
List<Message> prefix = node.buildNonHistoryPrefix(
"sys", "/workspace", "not-a-number", "goal",
vip.mate.agent.context.ChatOrigin.EMPTY);
vip.mate.agent.context.ChatOrigin.EMPTY, "", "");
// Non-numeric agentId is the contract carried over from the
// pre-refactor codebase skip wiki injection rather than throwing.
@ -132,7 +132,7 @@ class ReasoningNodePtlPromptTest {
List<Message> prefix = node.buildNonHistoryPrefix(
"sys", "/workspace", "42", "goal",
vip.mate.agent.context.ChatOrigin.EMPTY);
vip.mate.agent.context.ChatOrigin.EMPTY, "", "");
assertThat(prefix).hasSize(2);
}