feat(h5): inject direct-chat history on agent escalation and defer ambiguous routing.

Phase B appends snapshot context when leaving h5direct sessions so Goose no longer starts blind. Phase C lets the 0.72 fallback return null on gated chat text so the existing LLM router can run, flags default off.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
john
2026-08-28 20:45:34 +08:00
parent 6f48cad4c2
commit 5f3980e0df
9 changed files with 654 additions and 3 deletions
+54 -2
View File
@@ -45,6 +45,10 @@ import {
import { applyCursorFirstAgentExecution } from './cursor-page-routing.mjs';
import { cursorDeepseekFallbackEnabled } from './cursor-agent-launch.mjs';
import { buildCursorBillingTokenState } from './cursor-agent-usage.mjs';
import {
isDirectEscalationContextEnabledForUser,
resolveDirectEscalationContextPolicy,
} from './chat-task-intent-config.mjs';
const DEFAULT_RUN_RETRY_DELAYS_MS = [1500, 5000, 15000];
const TERMINAL_STATUSES = new Set(['succeeded', 'failed']);
@@ -260,6 +264,26 @@ function appendFreshSessionContext(
return { ...message, content };
}
function maybeInjectDirectEscalationContext({
userMessage,
conversation,
userId,
policy,
} = {}) {
if (!isDirectEscalationContextEnabledForUser(userId, policy)) {
return { userMessage, injected: false, messageCount: 0 };
}
const context = buildFreshSessionContext(conversation);
if (!context) {
return { userMessage, injected: false, messageCount: 0 };
}
return {
userMessage: appendFreshSessionContext(userMessage, conversation),
injected: true,
messageCount: Array.isArray(conversation) ? conversation.length : 0,
};
}
const FRESH_SESSION_RECOVERY_CODES = new Set([
'SESSION_TOOL_HISTORY_FRESH_SESSION_REQUIRED',
'SESSION_REASONING_CONTENT_POISONED',
@@ -871,9 +895,12 @@ export function createAgentRunGateway({
),
goalRunService = null,
workerIdentity = null,
directEscalationContextPolicy = null,
}) {
const worker = normalizeAgentRunWorkerIdentity(workerIdentity ?? {});
const sessionStore = resolveSessionAccess({ userAuth, sessionAccess });
const escalationContextPolicy = directEscalationContextPolicy
?? resolveDirectEscalationContextPolicy();
const inFlight = new Set();
const queuedDispatches = [];
const queuedDispatchSet = new Set();
@@ -2044,6 +2071,7 @@ export function createAgentRunGateway({
forceDeepReasoning: runOptions.forceDeepReasoning,
});
let escalatedDirectSessionId = null;
let escalationContextMessages = null;
if (isDirectChatSessionId(sessionId)) {
escalatedDirectSessionId = sessionId;
await appendEvent(runId, 'direct_session_escalated_to_deep_reasoning', {
@@ -2069,7 +2097,7 @@ export function createAgentRunGateway({
});
await appendRunSnapshot(runId);
if (escalatedDirectSessionId) {
const priorMessages = await loadSnapshotMessages(
escalationContextMessages = await loadSnapshotMessages(
sessionSnapshotService,
escalatedDirectSessionId,
);
@@ -2077,7 +2105,7 @@ export function createAgentRunGateway({
conversationMemoryService,
sessionId,
userId: row.user_id,
messages: priorMessages,
messages: escalationContextMessages,
});
if (persisted.saved > 0) {
await appendEvent(runId, 'direct_session_transcript_persisted', {
@@ -2102,6 +2130,30 @@ export function createAgentRunGateway({
sessionId,
saved: transcriptPersisted.saved,
});
if (!escalationContextMessages?.length) {
escalationContextMessages = await loadSnapshotMessages(
sessionSnapshotService,
escalatedDirectSessionId ?? sessionId,
);
}
}
if (escalationContextMessages?.length) {
const escalationContext = maybeInjectDirectEscalationContext({
userMessage,
conversation: escalationContextMessages,
userId: row.user_id,
policy: escalationContextPolicy,
});
if (escalationContext.injected) {
userMessage = escalationContext.userMessage;
await appendEvent(runId, 'direct_escalation_context_injected', {
sessionId,
previousSessionId: escalatedDirectSessionId ?? null,
messageCount: escalationContext.messageCount,
retainedContextMessages: 16,
retainedContextChars: 12_000,
});
}
}
if (typeof tkmindProxy.compactSessionConversationForUser === 'function') {
try {