feat: refine codex live chat context flows

This commit is contained in:
2026-05-08 21:15:51 +09:00
parent 82c0d8a197
commit 442879313f
92 changed files with 14815 additions and 7314 deletions

View File

@@ -1,6 +1,14 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import { mergeDefaultChatTypes, resolveAppConfigByOrigin } from './app-config-service.js';
import {
mergeDefaultChatTypes,
migrateLegacyChatTypeContexts,
stripBuiltInChatTypes,
resolveAppConfigByOrigin,
resolveCanonicalChatTypesFromConfig,
resolveCanonicalChatContextSettingsFromConfig,
stripChatContextSettingsFromScopedAppConfigs,
} from './app-config-service.js';
test('mergeDefaultChatTypes preserves saved edits for built-in chat types', () => {
const merged = mergeDefaultChatTypes([
@@ -64,9 +72,74 @@ test('mergeDefaultChatTypes still appends missing built-in chat types', () => {
assert.ok(merged.some((item) => item.id === 'layout-editor-execution'));
assert.ok(merged.some((item) => item.id === 'api-request-template'));
assert.ok(merged.some((item) => item.id === 'general-inquiry'));
assert.ok(!merged.some((item) => item.id === 'plan-checklist-execution'));
assert.ok(!merged.some((item) => item.id === 'layout-editor-guided-execution'));
});
test('stripBuiltInChatTypes removes built-in chat type ids from saved list', () => {
const stripped = stripBuiltInChatTypes([
{
id: 'general-request',
name: '일반 요청',
description: 'builtin',
permissions: ['token-user'],
enabled: true,
updatedAt: '2026-05-08T00:00:00.000Z',
},
{
id: 'plan-checklist-execution',
name: 'Plan 체크리스트 실행',
description: 'custom-seeded',
permissions: ['token-user'],
enabled: true,
updatedAt: '2026-05-08T00:00:00.000Z',
},
{
id: 'custom-support-flow',
name: '운영 문의 전용',
description: 'custom',
permissions: ['token-user'],
enabled: true,
updatedAt: '2026-05-08T00:00:00.000Z',
},
]);
assert.deepEqual(stripped.map((item) => item.id), ['custom-support-flow', 'plan-checklist-execution']);
});
test('migrateLegacyChatTypeContexts moves legacy plan checklist chat type into default context settings', () => {
const migrated = migrateLegacyChatTypeContexts(
{
defaultContexts: [],
chatTypeDefaults: [
{
chatTypeId: 'plan-checklist-execution',
defaultContextIds: ['legacy-linked-context'],
updatedAt: '2026-05-08T00:00:00.000Z',
},
],
roomContexts: [],
},
[
{
id: 'plan-checklist-execution',
name: 'Plan 체크리스트 실행',
description: 'legacy plan context',
permissions: ['token-user'],
enabled: true,
updatedAt: '2026-05-08T00:00:00.000Z',
},
],
);
assert.equal(migrated.defaultContexts.some((item) => item.id === 'chat-default-plan-checklist-execution'), true);
assert.equal(
migrated.defaultContexts.find((item) => item.id === 'chat-default-plan-checklist-execution')?.content,
'legacy plan context',
);
assert.equal(migrated.chatTypeDefaults.some((item) => item.chatTypeId === 'plan-checklist-execution'), false);
});
test('resolveAppConfigByOrigin prefers scoped app config over legacy global config', () => {
const resolved = resolveAppConfigByOrigin(
{
@@ -112,3 +185,149 @@ test('resolveAppConfigByOrigin falls back to legacy global config when scoped co
assert.equal(resolved.chat?.receiveRoomNotifications, true);
});
test('resolveCanonicalChatContextSettingsFromConfig prefers global chat context settings over stale scoped entries', () => {
const resolved = resolveCanonicalChatContextSettingsFromConfig(
{
chatContextSettings: {
defaultContexts: [
{
id: 'global-a',
title: '전역 A',
content: 'global',
enabled: true,
updatedAt: '2026-05-08T00:00:00.000Z',
},
{
id: 'global-b',
title: '전역 B',
content: 'global',
enabled: true,
updatedAt: '2026-05-08T00:00:00.000Z',
},
],
},
scopedAppConfigs: {
'https://test.sm-home.cloud': {
config: {
chatContextSettings: {
defaultContexts: [
{
id: 'scoped-a',
title: '스코프 A',
content: 'scoped',
enabled: true,
updatedAt: '2026-05-01T00:00:00.000Z',
},
],
},
},
},
},
},
'https://test.sm-home.cloud',
);
assert.deepEqual(
resolved.defaultContexts.map((item) => item.id),
['global-a', 'global-b'],
);
});
test('resolveCanonicalChatContextSettingsFromConfig falls back to scoped settings only when global settings are empty', () => {
const resolved = resolveCanonicalChatContextSettingsFromConfig(
{
scopedAppConfigs: {
'https://test.sm-home.cloud': {
config: {
chatContextSettings: {
defaultContexts: [
{
id: 'scoped-a',
title: '스코프 A',
content: 'scoped',
enabled: true,
updatedAt: '2026-05-01T00:00:00.000Z',
},
],
},
},
},
},
},
'https://test.sm-home.cloud',
);
assert.deepEqual(
resolved.defaultContexts.map((item) => item.id),
['scoped-a'],
);
});
test('resolveCanonicalChatTypesFromConfig merges global chat types with stale scoped entries', () => {
const resolved = resolveCanonicalChatTypesFromConfig(
{
chatTypes: [
{
id: 'verification-test-generation',
name: '검증 밑 테스트 생성',
description: 'global',
permissions: ['token-user'],
enabled: true,
updatedAt: '2026-05-08T08:15:18.440Z',
},
],
scopedAppConfigs: {
'https://test.sm-home.cloud': {
config: {
chatTypes: [
{
id: 'general-request',
name: '일반 요청',
description: 'scoped',
permissions: ['token-user'],
enabled: true,
updatedAt: '2026-05-01T00:00:00.000Z',
},
],
},
},
},
},
'https://test.sm-home.cloud',
);
assert.ok(resolved);
assert.equal(resolved.some((item) => item.id === 'verification-test-generation'), true);
assert.equal(resolved.some((item) => item.id === 'general-request'), true);
});
test('stripChatContextSettingsFromScopedAppConfigs removes stale scoped chat context settings only', () => {
const stripped = stripChatContextSettingsFromScopedAppConfigs({
scopedAppConfigs: {
'https://test.sm-home.cloud': {
config: {
chatContextSettings: {
defaultContexts: [{ id: 'legacy', title: 'legacy', content: 'legacy', enabled: true }],
},
chat: {
receiveRoomNotifications: false,
},
},
updatedAt: '2026-05-08T00:00:00.000Z',
},
},
});
assert.equal(stripped.changed, true);
assert.deepEqual(stripped.scopedConfigs, {
'https://test.sm-home.cloud': {
config: {
chat: {
receiveRoomNotifications: false,
},
},
updatedAt: '2026-05-08T00:00:00.000Z',
},
});
});