mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-13 03:13:41 +08:00
feat(agent): render runtime model identity line in RuntimeContextInjector
Add 5-arg buildContextMessage overload that emits [system-context] Model: for every origin (web/cron/IM). Legacy 3/4-arg overloads delegate to the new one with null model args, keeping their output byte-identical. Also fix pre-existing FeishuMentionTest compile error caused by removed mentionMatchesAnyAlias/collectMentionIdentifiers methods.
This commit is contained in:
parent
453997eb9c
commit
bd1ceace74
@ -67,6 +67,24 @@ public final class RuntimeContextInjector {
|
||||
public static String buildContextMessage(String workspaceBasePath,
|
||||
vip.mate.i18n.I18nService i18n,
|
||||
ChatOrigin origin) {
|
||||
return buildContextMessage(workspaceBasePath, i18n, origin, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Full overload that also renders the agent's runtime model identity.
|
||||
* The model line is emitted for EVERY origin (web / cron / IM / null)
|
||||
* because it describes the agent, not the caller — only the sender
|
||||
* block stays IM-only. {@code modelName}/{@code providerId} come from
|
||||
* graph state ({@code RUNTIME_MODEL_NAME}/{@code RUNTIME_PROVIDER_ID}),
|
||||
* i.e. the model selected at run start (mid-run failover is not
|
||||
* reflected — accepted trade-off). Stays well under the 1024-char
|
||||
* spring-ai user-cache threshold.
|
||||
*/
|
||||
public static String buildContextMessage(String workspaceBasePath,
|
||||
vip.mate.i18n.I18nService i18n,
|
||||
ChatOrigin origin,
|
||||
String modelName,
|
||||
String providerId) {
|
||||
LocalDateTime now = LocalDateTime.now(ZONE);
|
||||
String dateStr = now.format(DATE_FMT);
|
||||
String timeStr = now.format(TIME_FMT);
|
||||
@ -91,6 +109,7 @@ public final class RuntimeContextInjector {
|
||||
}
|
||||
|
||||
appendSenderBlockIfPresent(sb, origin);
|
||||
appendModelLineIfPresent(sb, modelName, providerId, i18n);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@ -121,6 +140,33 @@ public final class RuntimeContextInjector {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Append the agent's runtime model identity. Emitted for all origins
|
||||
* (it's an agent fact, not a sender fact). Skipped when modelName is
|
||||
* blank. Provider parenthetical is omitted when providerId is blank.
|
||||
*/
|
||||
private static void appendModelLineIfPresent(StringBuilder sb, String modelName,
|
||||
String providerId,
|
||||
vip.mate.i18n.I18nService i18n) {
|
||||
if (modelName == null || modelName.isBlank()) return;
|
||||
String model = modelName.trim();
|
||||
sb.append("\n");
|
||||
if (i18n != null) {
|
||||
sb.append(i18n.msg("context.model_identity", model));
|
||||
} else {
|
||||
sb.append("[system-context] Model: ").append(model);
|
||||
}
|
||||
if (providerId != null && !providerId.isBlank()) {
|
||||
sb.append(" (provider: ").append(providerId.trim()).append(')');
|
||||
}
|
||||
sb.append("\n");
|
||||
if (i18n != null) {
|
||||
sb.append(i18n.msg("context.model_identity_hint"));
|
||||
} else {
|
||||
sb.append("If asked which model you are using, answer with this value for the current run.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a sender / channel / chat block when the origin carries
|
||||
* meaningful IM context. Format is intentionally one line per
|
||||
|
||||
@ -294,6 +294,8 @@ context.current_time=[system-context] \u5f53\u524d\u65f6\u95f4: {0} {1} (Asia/Sh
|
||||
context.working_dir=[system-context] \u5de5\u4f5c\u76ee\u5f55: {0}
|
||||
context.working_dir_hint=\u4f60\u53ea\u80fd\u5728\u6b64\u76ee\u5f55\u53ca\u5176\u5b50\u76ee\u5f55\u5185\u8bfb\u5199\u6587\u4ef6\u548c\u6267\u884c\u547d\u4ee4\u3002
|
||||
context.skill_dir_hint=\u5171\u4eab\u6280\u80fd\u4f4d\u4e8e {0}\uff0c\u4f60\u4e5f\u53ef\u4ee5\u8bfb\u53d6\u548c\u8fd0\u884c\u5176\u4e2d\u7684\u6587\u4ef6\uff08\u5373\u4f7f\u5728\u5de5\u4f5c\u76ee\u5f55\u4e4b\u5916\uff09\u3002
|
||||
context.model_identity=[system-context] \u6a21\u578b: {0}
|
||||
context.model_identity_hint=\u88ab\u95ee\u5230\u4f60\u7528\u7684\u4ec0\u4e48\u6a21\u578b\u65f6\uff0c\u6309\u672c\u8f6e\u8fd9\u4e2a\u5024\u56de\u7b54\u3002
|
||||
|
||||
# --- Wiki Research Fallback (RFC: prompt-cleanup) ---
|
||||
research.fallback.no_plan=\u65e0\u6cd5\u4e3a\u8be5\u4e3b\u9898\u751f\u6210\u7814\u7a76\u8ba1\u5212\u3002
|
||||
|
||||
@ -301,6 +301,8 @@ context.current_time=[system-context] Current time: {0} {1} (Asia/Shanghai)
|
||||
context.working_dir=[system-context] Working directory: {0}
|
||||
context.working_dir_hint=You can only read/write files and execute commands within this directory and its subdirectories.
|
||||
context.skill_dir_hint=Shared skills live under {0}; you may also read and run files there, even though it is outside the working directory.
|
||||
context.model_identity=[system-context] Model: {0}
|
||||
context.model_identity_hint=If asked which model you are using, answer with this value for the current run.
|
||||
|
||||
# --- Wiki Research Fallback (RFC: prompt-cleanup) ---
|
||||
research.fallback.no_plan=Unable to generate a research plan for this topic.
|
||||
|
||||
@ -0,0 +1,76 @@
|
||||
package vip.mate.agent.context;
|
||||
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* Pin the runtime model-identity line added by the 5-arg
|
||||
* {@link RuntimeContextInjector#buildContextMessage} overload.
|
||||
*
|
||||
* <p>Unlike the sender block, the model line is about the AGENT (which
|
||||
* model is driving this run), not the caller — so it must appear for
|
||||
* every origin, including web and cron. The legacy 3/4-arg overloads
|
||||
* must stay model-free so existing eval baselines don't shift.
|
||||
*/
|
||||
class RuntimeContextInjectorModelTest {
|
||||
|
||||
@Test
|
||||
@DisplayName("model + provider present → emits Model line with provider parenthetical + hint")
|
||||
void modelLineWithProvider() {
|
||||
String ctx = RuntimeContextInjector.buildContextMessage(
|
||||
"/data/ws/5", null, ChatOrigin.EMPTY, "gpt-4o", "openai");
|
||||
|
||||
assertTrue(ctx.contains("[system-context] Model: gpt-4o"), "model line missing: " + ctx);
|
||||
assertTrue(ctx.contains("(provider: openai)"), "provider missing: " + ctx);
|
||||
assertTrue(ctx.contains("answer with this value for the current run"),
|
||||
"model-identity hint missing: " + ctx);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("blank provider → Model line without provider parenthetical")
|
||||
void modelLineWithoutProvider() {
|
||||
String ctx = RuntimeContextInjector.buildContextMessage(
|
||||
"/data/ws/5", null, ChatOrigin.EMPTY, "claude-sonnet-4-6", " ");
|
||||
|
||||
assertTrue(ctx.contains("[system-context] Model: claude-sonnet-4-6"), "model line missing: " + ctx);
|
||||
assertFalse(ctx.contains("(provider:"), "blank provider must not emit parenthetical: " + ctx);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("web origin still gets the model line (agent fact, not sender fact)")
|
||||
void webOriginStillGetsModelLine() {
|
||||
ChatOrigin origin = ChatOrigin.web("conv_1", "user-1", 5L, "/data/ws/5");
|
||||
|
||||
String ctx = RuntimeContextInjector.buildContextMessage(
|
||||
"/data/ws/5", null, origin, "gpt-4o", "openai");
|
||||
|
||||
assertFalse(ctx.contains("Channel:"), "web origin must still suppress sender block: " + ctx);
|
||||
assertTrue(ctx.contains("Model: gpt-4o"), "web origin must still get model line: " + ctx);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("blank modelName → no model line at all")
|
||||
void blankModelNoLine() {
|
||||
String ctx = RuntimeContextInjector.buildContextMessage(
|
||||
"/data/ws/5", null, ChatOrigin.EMPTY, " ", "openai");
|
||||
|
||||
assertFalse(ctx.contains("Model:"), "blank model must not emit a model line: " + ctx);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("IM origin → both sender block AND model line present")
|
||||
void imOriginHasSenderAndModel() {
|
||||
ChatOrigin origin = new ChatOrigin(
|
||||
7L, "feishu:oc_abc", "ou_xyz", 5L, "/data/ws/5",
|
||||
9L, null, false, "Alice", "feishu", "oc_abc", null);
|
||||
|
||||
String ctx = RuntimeContextInjector.buildContextMessage(
|
||||
"/data/ws/5", null, origin, "gpt-4o", "openai");
|
||||
|
||||
assertTrue(ctx.contains("Channel: feishu"), "sender block missing: " + ctx);
|
||||
assertTrue(ctx.contains("Model: gpt-4o"), "model line missing: " + ctx);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user