Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Fix review findings in active context policy
- Cache getSystemPrompt() in local var to avoid triple invocation
- Accept dotted qualified names in looksLikeSymbol (e.g. AppService.validate)
- Narrow inferPlanSignals "steps" match to "next steps" / "steps to"
- Cap request focus priority boost at 12 to prevent tier inversions
- Remove dead null checks in renderRequestFocus (JsonNode.path never null)
- Extract sectionToNode() helper in ContextRpcHelper to deduplicate fields
- Replace inline FQN java.util.LinkedHashSet with proper import
- Remove unnecessary distinct() in inferPlanSignals
  • Loading branch information
Xinhua Gu committed Mar 16, 2026
commit 4c1891ee0ae1c8e7491a183daf33b1839bffcd2f
6 changes: 3 additions & 3 deletions aceclaw-cli/src/main/java/dev/aceclaw/cli/TerminalRepl.java
Original file line number Diff line number Diff line change
Expand Up @@ -2830,9 +2830,9 @@ private void renderRequestFocus(PrintWriter out, JsonNode focus) {
out.printf(" %sPlan:%s %s%n", MUTED, RESET, joinArrayValues(planSignals, 4));
}
if (querySummary.isBlank()
&& (focusFiles == null || focusFiles.isEmpty())
&& (symbols == null || symbols.isEmpty())
&& (planSignals == null || planSignals.isEmpty())) {
&& focusFiles.isEmpty()
&& symbols.isEmpty()
&& planSignals.isEmpty()) {
out.println(" " + MUTED + "No request-local focus signals detected." + RESET);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package dev.aceclaw.daemon;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;

import java.util.Objects;
import java.util.function.IntSupplier;

/**
* Shared helper for registering context-observability RPC handlers.
*/
Expand Down Expand Up @@ -85,53 +87,44 @@ public static void registerContextInspect(RequestRouter router, ObjectMapper map
var sections = mapper.createArrayNode();
SystemPromptLoader.ContextSection selected = null;
for (var section : inspection.sections()) {
var node = mapper.createObjectNode();
node.put("key", section.key());
node.put("sourceType", section.sourceType());
node.put("scopeType", section.scopeType());
node.put("inclusionReason", section.inclusionReason());
node.put("priority", section.priority());
node.put("protected", section.protectedSection());
node.put("originalChars", section.originalChars());
node.put("finalChars", section.finalChars());
node.put("estimatedTokens", section.estimatedTokens());
node.put("included", section.included());
node.put("truncated", section.truncated());
var evidence = mapper.createArrayNode();
for (var item : section.evidence()) {
evidence.add(item);
}
node.set("evidence", evidence);
sections.add(node);
sections.add(sectionToNode(mapper, section, false));
if (!detailKey.isBlank() && detailKey.equals(section.key())) {
selected = section;
}
}
result.set("sections", sections);

if (selected != null) {
var detail = mapper.createObjectNode();
detail.put("key", selected.key());
detail.put("priority", selected.priority());
detail.put("protected", selected.protectedSection());
detail.put("originalChars", selected.originalChars());
detail.put("finalChars", selected.finalChars());
detail.put("sourceType", selected.sourceType());
detail.put("scopeType", selected.scopeType());
detail.put("inclusionReason", selected.inclusionReason());
detail.put("estimatedTokens", selected.estimatedTokens());
detail.put("included", selected.included());
detail.put("truncated", selected.truncated());
detail.put("content", selected.content());
var evidence = mapper.createArrayNode();
for (var item : selected.evidence()) {
evidence.add(item);
}
detail.set("evidence", evidence);
result.set("detail", detail);
result.set("detail", sectionToNode(mapper, selected, true));
}

return result;
});
}

private static ObjectNode sectionToNode(ObjectMapper mapper,
SystemPromptLoader.ContextSection section,
boolean includeContent) {
var node = mapper.createObjectNode();
node.put("key", section.key());
node.put("sourceType", section.sourceType());
node.put("scopeType", section.scopeType());
node.put("inclusionReason", section.inclusionReason());
node.put("priority", section.priority());
node.put("protected", section.protectedSection());
node.put("originalChars", section.originalChars());
node.put("finalChars", section.finalChars());
node.put("estimatedTokens", section.estimatedTokens());
node.put("included", section.included());
node.put("truncated", section.truncated());
var evidence = mapper.createArrayNode();
for (var item : section.evidence()) {
evidence.add(item);
}
node.set("evidence", evidence);
if (includeContent) {
node.put("content", section.content());
}
return node;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1740,15 +1740,16 @@ public SystemPromptLoader.ContextInspection inspectContext(String sessionId, Str
if (session.projectPath() == null) {
var activePaths = inferActiveFilePaths(effectiveQuery, session.messages(), null);
var requestFocus = SystemPromptLoader.analyzeRequestFocus(effectiveQuery, activePaths);
String prompt = getSystemPrompt(sessionId);
return new SystemPromptLoader.ContextInspection(
getSystemPrompt(sessionId),
prompt,
requestFocus,
List.of(),
requestFocus.activeFilePaths(),
List.of(),
List.of(),
getSystemPrompt(sessionId).length(),
ContextEstimator.estimateTokens(getSystemPrompt(sessionId)),
prompt.length(),
ContextEstimator.estimateTokens(prompt),
systemPromptBudget);
}
var activePaths = inferActiveFilePaths(effectiveQuery, session.messages(), session.projectPath());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
Expand Down Expand Up @@ -616,12 +617,15 @@ static RequestFocus analyzeRequestFocus(String queryHint, List<String> activeFil
inferPlanSignals(queryHint));
}

/** Maximum priority boost from request focus signals, preventing tier inversions. */
private static final int MAX_FOCUS_BOOST = 12;

private static int applyRequestFocusPriority(String key, int basePriority, String content, RequestFocus focus) {
if (focus == null) {
return basePriority;
}
int adjusted = basePriority + requestFocusBoost(key, content, focus);
return Math.max(0, Math.min(100, adjusted));
int boost = Math.min(MAX_FOCUS_BOOST, requestFocusBoost(key, content, focus));
return Math.max(0, Math.min(100, basePriority + boost));
}

private static int requestFocusBoost(String key, String content, RequestFocus focus) {
Expand Down Expand Up @@ -722,7 +726,7 @@ private static List<String> extractActiveSymbols(String queryHint) {
if (queryHint == null || queryHint.isBlank()) {
return List.of();
}
var symbols = new java.util.LinkedHashSet<String>();
var symbols = new LinkedHashSet<String>();
var backtickMatcher = BACKTICK_CODE.matcher(queryHint);
while (backtickMatcher.find() && symbols.size() < 8) {
String candidate = backtickMatcher.group(1).trim();
Expand All @@ -747,11 +751,24 @@ private static boolean looksLikeSymbol(String candidate) {
if (candidate.contains("/") || candidate.contains("\\")) {
return false;
}
if (candidate.contains(".")) {
return candidate.contains("::") || candidate.endsWith("()");
// Strip trailing () for method references like AppService.handle()
String clean = candidate.endsWith("()") ? candidate.substring(0, candidate.length() - 2) : candidate;
// Accept dotted qualified names where each segment is a valid identifier
// e.g. AppService.validate, dev.aceclaw.App
if (clean.contains(".")) {
String[] segments = clean.split("\\.");
if (segments.length < 2 || segments.length > 6) {
return false;
}
for (String seg : segments) {
if (!seg.matches("[A-Za-z_][A-Za-z0-9_]*")) {
return false;
}
}
return true;
}
return candidate.matches("[A-Z][A-Za-z0-9_]{2,}")
|| candidate.matches("[a-z]+[A-Z][A-Za-z0-9_]*");
return clean.matches("[A-Z][A-Za-z0-9_]{2,}")
|| clean.matches("[a-z]+[A-Z][A-Za-z0-9_]*");
}

private static List<String> inferPlanSignals(String queryHint) {
Expand All @@ -763,7 +780,7 @@ private static List<String> inferPlanSignals(String queryHint) {
if (lower.contains("continue") || lower.contains("resume") || lower.contains("next step")) {
signals.add("continue current execution");
}
if (lower.contains("plan") || lower.contains("steps")) {
if (lower.contains("plan") || lower.contains("next steps") || lower.contains("steps to")) {
signals.add("planning context");
}
if (lower.contains("fix") || lower.contains("implement") || lower.contains("edit")
Expand All @@ -773,7 +790,7 @@ private static List<String> inferPlanSignals(String queryHint) {
if (lower.contains("test") || lower.contains("verify") || lower.contains("review")) {
signals.add("verification requested");
}
return List.copyOf(signals.stream().distinct().toList());
return List.copyOf(signals);
}

private record RankedSection(
Expand Down
Loading