Merge branch 'codex/reminder-llm-toggle'

This commit is contained in:
john
2026-07-07 12:10:36 +08:00
6 changed files with 79 additions and 1 deletions
+22 -1
View File
@@ -97,6 +97,7 @@ export function createAdminApp(services) {
loadMindSpaceConfig, loadMindSpaceConfig,
updateMindSpaceConfig, updateMindSpaceConfig,
memoryV2ConfigService, memoryV2ConfigService,
wechatScheduleLlmConfigService,
adminSystemTestService, adminSystemTestService,
systemTestAccountService, systemTestAccountService,
wordFilterService, wordFilterService,
@@ -285,7 +286,27 @@ export function createAdminApp(services) {
adminApi.get('/wechat/summary', requireAdmin, async (_req, res) => { adminApi.get('/wechat/summary', requireAdmin, async (_req, res) => {
if (!wechatAdmin) return res.status(503).json({ message: '服务号管理未启用' }); if (!wechatAdmin) return res.status(503).json({ message: '服务号管理未启用' });
res.json(await wechatAdmin.getSummary()); const summary = await wechatAdmin.getSummary();
const scheduleLlmConfig = wechatScheduleLlmConfigService
? await wechatScheduleLlmConfigService.getConfig()
: { scheduleLlmEnabled: false };
res.json({
...summary,
config: {
...summary.config,
scheduleLlmEnabled: scheduleLlmConfig.scheduleLlmEnabled,
},
});
});
adminApi.patch('/wechat/schedule-llm-config', requireAdmin, async (req, res) => {
if (!wechatScheduleLlmConfigService) {
return res.status(503).json({ message: '服务号提醒 LLM 配置未启用' });
}
const result = await wechatScheduleLlmConfigService.updateConfig(req.body ?? {}, {
updatedBy: req.currentUser.id,
});
res.json(result);
}); });
adminApi.get('/mindspace/config', requireAdmin, async (_req, res) => { adminApi.get('/mindspace/config', requireAdmin, async (_req, res) => {
+5
View File
@@ -29,6 +29,7 @@ export async function bootstrapAdminServices() {
updateMindSpaceConfig, updateMindSpaceConfig,
} = await importMemind('mindspace-config.mjs'); } = await importMemind('mindspace-config.mjs');
const { createMemoryV2AdminConfigService } = await importMemind('memory-v2-admin-config.mjs'); const { createMemoryV2AdminConfigService } = await importMemind('memory-v2-admin-config.mjs');
const { createWechatScheduleLlmConfigService } = await importMemind('wechat-schedule-llm-config.mjs');
const { createAdminSystemTestService } = await importMemind('admin-system-tests.mjs'); const { createAdminSystemTestService } = await importMemind('admin-system-tests.mjs');
const { createOpsApi } = await importMemind('admin-routes.mjs'); const { createOpsApi } = await importMemind('admin-routes.mjs');
const { createWordFilterService, ensureWordFilterSchema } = await importMemind('word-filter.mjs'); const { createWordFilterService, ensureWordFilterSchema } = await importMemind('word-filter.mjs');
@@ -88,6 +89,9 @@ export async function bootstrapAdminServices() {
const memoryV2ConfigService = createMemoryV2AdminConfigService(pool, { const memoryV2ConfigService = createMemoryV2AdminConfigService(pool, {
env: process.env, env: process.env,
}); });
const wechatScheduleLlmConfigService = createWechatScheduleLlmConfigService(pool, {
env: process.env,
});
const adminSystemTestService = createAdminSystemTestService({ const adminSystemTestService = createAdminSystemTestService({
pool, pool,
userAuth, userAuth,
@@ -136,6 +140,7 @@ export async function bootstrapAdminServices() {
loadMindSpaceConfig, loadMindSpaceConfig,
updateMindSpaceConfig, updateMindSpaceConfig,
memoryV2ConfigService, memoryV2ConfigService,
wechatScheduleLlmConfigService,
adminSystemTestService, adminSystemTestService,
systemTestAccountService, systemTestAccountService,
wordFilterService, wordFilterService,
+2
View File
@@ -104,6 +104,7 @@ ready
loadMindSpaceConfig, loadMindSpaceConfig,
updateMindSpaceConfig, updateMindSpaceConfig,
memoryV2ConfigService, memoryV2ConfigService,
wechatScheduleLlmConfigService,
adminSystemTestService, adminSystemTestService,
systemTestAccountService, systemTestAccountService,
wordFilterService, wordFilterService,
@@ -125,6 +126,7 @@ ready
loadMindSpaceConfig, loadMindSpaceConfig,
updateMindSpaceConfig, updateMindSpaceConfig,
memoryV2ConfigService, memoryV2ConfigService,
wechatScheduleLlmConfigService,
adminSystemTestService, adminSystemTestService,
systemTestAccountService, systemTestAccountService,
wordFilterService, wordFilterService,
+32
View File
@@ -11,6 +11,7 @@ import {
listWechatMessages, listWechatMessages,
listWechatWebNotifications, listWechatWebNotifications,
resumeWechatDigest, resumeWechatDigest,
updateWechatScheduleLlmConfig,
} from '../../api/client'; } from '../../api/client';
import type { import type {
AdminUserRow, AdminUserRow,
@@ -38,6 +39,7 @@ function safeSummary(summary: WechatAdminSummary | null) {
bindPath: null, bindPath: null,
tokenEndpointConfigured: false, tokenEndpointConfigured: false,
customerServiceEndpointConfigured: false, customerServiceEndpointConfigured: false,
scheduleLlmEnabled: false,
}, },
counts: summary?.counts ?? { counts: summary?.counts ?? {
boundUsers: 0, boundUsers: 0,
@@ -88,6 +90,7 @@ export function WechatPage() {
const [notifyBody, setNotifyBody] = useState(''); const [notifyBody, setNotifyBody] = useState('');
const [notifyType, setNotifyType] = useState('manual'); const [notifyType, setNotifyType] = useState('manual');
const [notifyChannels, setNotifyChannels] = useState<Array<'web' | 'wechat'>>(['web']); const [notifyChannels, setNotifyChannels] = useState<Array<'web' | 'wechat'>>(['web']);
const [scheduleLlmEnabled, setScheduleLlmEnabled] = useState(false);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [busy, setBusy] = useState(false); const [busy, setBusy] = useState(false);
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
@@ -117,6 +120,7 @@ export function WechatPage() {
listAdminUsers({ page: 1, pageSize: 200, status: 'active' }), listAdminUsers({ page: 1, pageSize: 200, status: 'active' }),
]); ]);
setSummary(nextSummary); setSummary(nextSummary);
setScheduleLlmEnabled(nextSummary.config.scheduleLlmEnabled ?? false);
setBindings(nextBindings); setBindings(nextBindings);
setMessages(nextMessages); setMessages(nextMessages);
setDigests(nextDigests); setDigests(nextDigests);
@@ -224,6 +228,13 @@ export function WechatPage() {
} }
}; };
const handleSaveScheduleLlm = async () => {
await runAction(async () => {
await updateWechatScheduleLlmConfig({ scheduleLlmEnabled });
setNotice(`提醒待办 LLM 已${scheduleLlmEnabled ? '开启' : '关闭'}`);
});
};
return ( return (
<div className="admin-page"> <div className="admin-page">
<div className="admin-page-head"> <div className="admin-page-head">
@@ -280,7 +291,28 @@ export function WechatPage() {
<dt> worker</dt> <dt> worker</dt>
<dd>{summary.config.reminderWorkerEnabled ? '已启用' : '未启用'}</dd> <dd>{summary.config.reminderWorkerEnabled ? '已启用' : '未启用'}</dd>
</div> </div>
<div>
<dt> LLM</dt>
<dd>{summary.config.scheduleLlmEnabled ? '已开启' : '已关闭'}</dd>
</div>
</dl> </dl>
<div className="wechat-toolbar" style={{ marginTop: 16, justifyContent: 'space-between', alignItems: 'center' }}>
<label>
<input
type="checkbox"
checked={scheduleLlmEnabled}
onChange={(event) => setScheduleLlmEnabled(event.target.checked)}
disabled={busy}
/>{' '}
LLM
</label>
<button type="button" className="ghost-btn" onClick={() => void handleSaveScheduleLlm()} disabled={busy}>
{busy ? '保存中…' : '保存开关'}
</button>
</div>
<p className="muted" style={{ marginTop: 8 }}>
LLM
</p>
</section> </section>
)} )}
+11
View File
@@ -38,6 +38,7 @@ import type {
WechatBinding, WechatBinding,
WechatDeliveryLog, WechatDeliveryLog,
WechatDigestSubscription, WechatDigestSubscription,
WechatScheduleLlmConfig,
WechatMessage, WechatMessage,
WechatWebNotification, WechatWebNotification,
} from '../types'; } from '../types';
@@ -254,6 +255,7 @@ export async function getWechatAdminSummary(): Promise<WechatAdminSummary> {
bindPath: summary.config?.bindPath ?? null, bindPath: summary.config?.bindPath ?? null,
tokenEndpointConfigured: summary.config?.tokenEndpointConfigured ?? false, tokenEndpointConfigured: summary.config?.tokenEndpointConfigured ?? false,
customerServiceEndpointConfigured: summary.config?.customerServiceEndpointConfigured ?? false, customerServiceEndpointConfigured: summary.config?.customerServiceEndpointConfigured ?? false,
scheduleLlmEnabled: summary.config?.scheduleLlmEnabled ?? false,
}, },
counts: { counts: {
boundUsers: summary.counts?.boundUsers ?? 0, boundUsers: summary.counts?.boundUsers ?? 0,
@@ -268,6 +270,15 @@ export async function getWechatAdminSummary(): Promise<WechatAdminSummary> {
}; };
} }
export async function updateWechatScheduleLlmConfig(
payload: Pick<WechatScheduleLlmConfig, 'scheduleLlmEnabled'>,
): Promise<WechatScheduleLlmConfig> {
return portalFetch<WechatScheduleLlmConfig>('/admin-api/wechat/schedule-llm-config', {
method: 'PATCH',
body: JSON.stringify(payload),
});
}
export async function getMindSpaceAdminConfig(): Promise<MindSpaceAdminConfig> { export async function getMindSpaceAdminConfig(): Promise<MindSpaceAdminConfig> {
const result = await portalFetch<{ config: MindSpaceAdminConfig }>('/admin-api/mindspace/config'); const result = await portalFetch<{ config: MindSpaceAdminConfig }>('/admin-api/mindspace/config');
return result.config; return result.config;
+7
View File
@@ -241,6 +241,7 @@ export type WechatAdminSummary = {
bindPath: string | null; bindPath: string | null;
tokenEndpointConfigured: boolean; tokenEndpointConfigured: boolean;
customerServiceEndpointConfigured: boolean; customerServiceEndpointConfigured: boolean;
scheduleLlmEnabled: boolean;
}; };
counts: { counts: {
boundUsers: number; boundUsers: number;
@@ -251,6 +252,12 @@ export type WechatAdminSummary = {
}; };
}; };
export type WechatScheduleLlmConfig = {
scheduleLlmEnabled: boolean;
updatedAt: number | null;
updatedBy: string | null;
};
export type MindSpaceAdminConfig = { export type MindSpaceAdminConfig = {
publicPageLimit: number; publicPageLimit: number;
}; };