fix: cross-session assistant trigger guard — heartbeat liveness detection
- Replace fixed-timeout stale detection with localStorage heartbeat mechanism
- Heartbeat writes {sid, ts} every 10s; isOwnerAlive checks sid matches AND freshness
- Stop heartbeat when triggered stream completes (useEffect on !isStreaming)
- removeHeartbeatIfOwned: only delete key if it still belongs to this session
(prevents new owner's heartbeat from being wiped by old session's cleanup)
- Export clearOnboardingHeartbeat with optional sessionId parameter
- hook-triggered route sets/clears hookTriggeredAt alongside hookTriggeredSessionId
- MiniMax model auto-correction: reset model when not in current provider's list
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
8cce9889eb
commit
2a0451329b
4 files changed
+130
-6
No files matched your search
@@ -38,8 +38,8 @@ export async function POST(request: NextRequest) {
|
||||
let activeLockId: string | undefined;
|
||||
|
||||
try {
|
||||
const body: SendMessageRequest & { files?: FileAttachment[]; toolTimeout?: number; provider_id?: string; systemPromptAppend?: string; autoTrigger?: boolean; thinking?: unknown; effort?: string; enableFileCheckpointing?: boolean; displayOverride?: string } = await request.json();
|
||||
const { session_id, content, model, mode, files, toolTimeout, provider_id, systemPromptAppend, autoTrigger, thinking, effort, enableFileCheckpointing, displayOverride } = body;
|
||||
const body: SendMessageRequest & { files?: FileAttachment[]; toolTimeout?: number; provider_id?: string; systemPromptAppend?: string; autoTrigger?: boolean; thinking?: unknown; effort?: string; enableFileCheckpointing?: boolean; displayOverride?: string; context_1m?: boolean } = await request.json();
|
||||
const { session_id, content, model, mode, files, toolTimeout, provider_id, systemPromptAppend, autoTrigger, thinking, effort, enableFileCheckpointing, displayOverride, context_1m } = body;
|
||||
|
||||
console.log('[chat API] content length:', content.length, 'first 200 chars:', content.slice(0, 200));
|
||||
console.log('[chat API] systemPromptAppend:', systemPromptAppend ? `${systemPromptAppend.length} chars` : 'none');
|
||||
@@ -357,6 +357,7 @@ Start by greeting the user and asking the first question.
|
||||
bypassPermissions: session.permission_profile === 'full_access',
|
||||
thinking: thinking as ClaudeStreamOptions['thinking'],
|
||||
effort: effort as ClaudeStreamOptions['effort'],
|
||||
context1m: context_1m,
|
||||
enableFileCheckpointing: enableFileCheckpointing ?? (effectiveMode === 'code'),
|
||||
autoTrigger: !!autoTrigger,
|
||||
onRuntimeStatusChange: (status: string) => {
|
||||
@@ -648,6 +649,7 @@ async function processCompletionServerSide(
|
||||
if (wsPath) {
|
||||
const state = loadState(wsPath);
|
||||
state.hookTriggeredSessionId = undefined;
|
||||
state.hookTriggeredAt = undefined;
|
||||
saveState(wsPath, state);
|
||||
}
|
||||
} catch {
|
||||
|
||||
@@ -11,7 +11,13 @@ export async function POST(request: NextRequest) {
|
||||
const { sessionId } = await request.json();
|
||||
const state = loadState(workspacePath);
|
||||
// '__clear__' sentinel clears the field (used after onboarding/checkin completes)
|
||||
state.hookTriggeredSessionId = sessionId === '__clear__' ? undefined : sessionId;
|
||||
if (sessionId === '__clear__') {
|
||||
state.hookTriggeredSessionId = undefined;
|
||||
state.hookTriggeredAt = undefined;
|
||||
} else {
|
||||
state.hookTriggeredSessionId = sessionId;
|
||||
state.hookTriggeredAt = new Date().toISOString();
|
||||
}
|
||||
saveState(workspacePath, state);
|
||||
return NextResponse.json({ success: true });
|
||||
} catch (e) {
|
||||
|
||||
Reference in new issue
Block a user