fix(wechat): stop relay bootstrap from hijacking LLM provider selection.
Memind CI / Test, build, and release guards (push) Failing after 2s

Schedule LLM now binds an explicit provider key and fails closed on network errors so dead relay endpoints cannot block ordinary chat; relay bootstrap is opt-in only.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
john
2026-08-01 21:44:08 +08:00
parent 122a25649b
commit dac06753ce
7 changed files with 121 additions and 39 deletions
+57 -28
View File
@@ -60,40 +60,50 @@ function normalizeLlmScheduleIntent(payload) {
return { action: 'none' };
}
async function parseScheduleIntentWithLlm({ text, llmProviderService, logger = console }) {
async function parseScheduleIntentWithLlm({ text, llmProviderService, modelProviderKeyId = null, model = null, logger = console }) {
if (!llmProviderService || typeof llmProviderService.createChatCompletion !== 'function') {
return { action: 'none' };
}
const result = await llmProviderService.createChatCompletion({
temperature: 0,
messages: [
{
role: 'system',
content: [
'你是公众号提醒助手,只做意图识别。',
'请严格输出 JSON,不要输出解释。',
'允许 action: create_todo, create_daily_todo_digest, create_balance_alert, query_schedule, schedule_agent, none。',
'create_todo 需要 title。',
'create_daily_todo_digest 需要 hour(0-23) 和 minute(0-59)。',
'create_balance_alert 需要 thresholdYuan 数字。',
'如果用户在说具体时间提醒、一次性闹钟、某天某时提醒,返回 schedule_agent。',
'不确定时返回 none。',
].join('\n'),
},
{
role: 'user',
content: text,
},
],
});
try {
const result = await llmProviderService.createChatCompletion({
...(modelProviderKeyId ? { providerKeyId: modelProviderKeyId } : {}),
...(model ? { model } : {}),
temperature: 0,
messages: [
{
role: 'system',
content: [
'你是公众号提醒助手,只做意图识别。',
'请严格输出 JSON,不要输出解释。',
'允许 action: create_todo, create_daily_todo_digest, create_balance_alert, query_schedule, schedule_agent, none。',
'create_todo 需要 title。',
'create_daily_todo_digest 需要 hour(0-23) 和 minute(0-59)。',
'create_balance_alert 需要 thresholdYuan 数字。',
'如果用户在说具体时间提醒、一次性闹钟、某天某时提醒,返回 schedule_agent。',
'不确定时返回 none。',
].join('\n'),
},
{
role: 'user',
content: text,
},
],
});
if (!result?.ok) {
logger?.warn?.('[wechat-schedule-llm] parse skipped:', result?.message ?? 'unknown');
if (!result?.ok) {
logger?.warn?.('[wechat-schedule-llm] parse skipped:', result?.message ?? 'unknown');
return { action: 'none' };
}
return normalizeLlmScheduleIntent(parseJsonReply(result.reply));
} catch (err) {
logger?.warn?.(
'[wechat-schedule-llm] parse skipped:',
err instanceof Error ? err.message : err,
);
return { action: 'none' };
}
return normalizeLlmScheduleIntent(parseJsonReply(result.reply));
}
async function resolveScheduleIntent({
@@ -118,7 +128,26 @@ async function resolveScheduleIntent({
}
if (!enabled) return ruleIntent;
return parseScheduleIntentWithLlm({ text, llmProviderService, logger });
let modelProviderKeyId = null;
let model = null;
try {
const config = await wechatScheduleLlmConfigService.getConfig();
modelProviderKeyId = config.modelProviderKeyId ?? null;
model = config.model ?? null;
} catch (err) {
logger?.warn?.(
'[wechat-schedule-llm] provider config load failed:',
err instanceof Error ? err.message : err,
);
}
return parseScheduleIntentWithLlm({
text,
llmProviderService,
modelProviderKeyId,
model,
logger,
});
}
export async function handleWechatScheduleIntent({