Files
memind/chat-agent-run-gate.test.mjs
john 48c61a3279
Memind CI / Test, build, and release guards (push) Successful in 1m28s
fix: harden long conversation continuity
2026-07-27 21:39:34 +08:00

168 lines
4.9 KiB
JavaScript

import assert from 'node:assert/strict';
import test from 'node:test';
import {
reconcileSessionEventRequestContext,
resolvePostAgentRunChatState,
shouldIgnoreZeroActivityFinish,
shouldKeepStreamingAfterRunError,
shouldPromoteSessionIdToStreaming,
shouldScheduleMissingActiveRequestGrace,
} from './chat-agent-run-gate.mjs';
test('resolvePostAgentRunChatState keeps idle when Finish beat agent-run gate', () => {
assert.equal(
resolvePostAgentRunChatState({ chatState: 'idle', finishedViaPortalDirectChat: false }),
'idle',
);
});
test('resolvePostAgentRunChatState returns streaming while still waiting for session Finish', () => {
assert.equal(resolvePostAgentRunChatState({ chatState: 'waiting' }), 'streaming');
assert.equal(resolvePostAgentRunChatState({ chatState: 'streaming' }), 'streaming');
});
test('resolvePostAgentRunChatState prefers portal direct chat completion', () => {
assert.equal(
resolvePostAgentRunChatState({ chatState: 'streaming', finishedViaPortalDirectChat: true }),
'idle',
);
});
test('resolvePostAgentRunChatState idles after worker-side agent run success', () => {
assert.equal(
resolvePostAgentRunChatState({ chatState: 'waiting', agentRunSucceeded: true }),
'idle',
);
assert.equal(
resolvePostAgentRunChatState({ chatState: 'streaming', agentRunSucceeded: true }),
'idle',
);
});
test('completed run wins when the direct-chat snapshot is not ready', () => {
assert.equal(
resolvePostAgentRunChatState({
chatState: 'streaming',
finishedViaPortalDirectChat: false,
agentRunSucceeded: true,
}),
'idle',
);
});
test('only ambiguous transport failures keep the chat streaming', () => {
assert.equal(shouldKeepStreamingAfterRunError(0), true);
assert.equal(shouldKeepStreamingAfterRunError(409), false);
assert.equal(shouldKeepStreamingAfterRunError(503), true);
assert.equal(shouldKeepStreamingAfterRunError(400), false);
assert.equal(shouldKeepStreamingAfterRunError(undefined), false);
assert.equal(
shouldKeepStreamingAfterRunError(
409,
'Session already has an active request. Cancel it first.',
),
true,
);
assert.equal(
shouldKeepStreamingAfterRunError(
undefined,
'Session already has an active request. Cancel it first.',
),
true,
);
assert.equal(
shouldKeepStreamingAfterRunError(
undefined,
'Session already has an active request. Cancel it first.',
'AGENT_RUN_FAILED',
),
false,
);
assert.equal(shouldKeepStreamingAfterRunError(undefined, '后台任务失败'), false);
});
test('shouldPromoteSessionIdToStreaming skips re-streaming after Finish', () => {
assert.equal(shouldPromoteSessionIdToStreaming('idle'), false);
assert.equal(shouldPromoteSessionIdToStreaming('waiting'), true);
assert.equal(shouldPromoteSessionIdToStreaming('streaming'), true);
});
test('zero-token Finish cannot unlock a composer with an active request', () => {
assert.equal(
shouldIgnoreZeroActivityFinish({
eventType: 'Finish',
hasActiveRequest: true,
tokenState: {
inputTokens: 0,
outputTokens: 0,
totalTokens: 0,
accumulatedInputTokens: 0,
accumulatedOutputTokens: 0,
accumulatedTotalTokens: 0,
},
}),
true,
);
assert.equal(
shouldIgnoreZeroActivityFinish({
eventType: 'Finish',
hasActiveRequest: true,
tokenState: { inputTokens: 8, outputTokens: 2, totalTokens: 10 },
}),
false,
);
assert.equal(
shouldIgnoreZeroActivityFinish({
eventType: 'Finish',
hasActiveRequest: false,
tokenState: { inputTokens: 0, outputTokens: 0, totalTokens: 0 },
}),
false,
);
});
test('missing ActiveRequests cannot unlock while the Portal agent-run is pending', () => {
assert.equal(
shouldScheduleMissingActiveRequestGrace({
allowMissingGrace: true,
agentRunPending: true,
}),
false,
);
assert.equal(
shouldScheduleMissingActiveRequestGrace({
allowMissingGrace: true,
agentRunPending: false,
}),
true,
);
assert.equal(
shouldScheduleMissingActiveRequestGrace({
allowMissingGrace: false,
agentRunPending: false,
}),
false,
);
});
test('reconcileSessionEventRequestContext adopts Goose request id while agent-run gate waits', () => {
assert.deepEqual(
reconcileSessionEventRequestContext({
activeRequestId: 'portal-req',
chatState: 'waiting',
eventType: 'ActiveRequests',
activeRequestIds: ['goose-req'],
}),
{ activeRequestId: 'goose-req', promoteStreaming: true, allowMissingGrace: false },
);
assert.deepEqual(
reconcileSessionEventRequestContext({
activeRequestId: 'portal-req',
chatState: 'waiting',
eventType: 'Message',
eventRequestId: 'goose-req',
}),
{ activeRequestId: 'goose-req', promoteStreaming: true, allowMissingGrace: false },
);
});