diff --git a/docs/branch-disposition.md b/docs/branch-disposition.md index 049aa2f..d892a48 100644 --- a/docs/branch-disposition.md +++ b/docs/branch-disposition.md @@ -3,6 +3,29 @@ 本文件记录已经完成迁移、但仍可能因为 Git 拓扑或遗留 worktree 被误判为“尚未进入 `main`”的分支。 它是分支复用、合并、cherry-pick 和清理前的必查清单。 +## `feature/wechat-intent-channel-separation` + +**状态:禁止再次引用。改动已提交并进入 `origin/main`,该分支保留仅用于只读追溯,不是待合并开发分支。** + +审计日期:2026-08-31 +分支 HEAD:`8f88eec2` +`origin/main` 对应提交:`8f88eec2` + +### 原始用途 + +微信服务号聊天、改页、定时任务分流:频道前缀强制路由、【改页】prompt 钉原文件、改页/URL 强制新会话,避免误进 Goose 聊天烧 token。 + +### 验证摘要 + +- `npm run verify:intent-transaction-layer`:63 passed +- 103 发布 `memind-portal-runtime-20260831-141716-8f88eec2.tar.gz`,8081 健康 +- 103 已为唐启用 WeChat LLM Intent Router shadow(`custom_deepseek` + `deepseek-v4-flash`,canary openid) + +### 最终处置 + +- 保留本地分支名用于审计追溯。 +- 不要从该分支继续开发、merge、cherry-pick 或构建 runtime/artifact。 + ## `feature/scheduled-task-wechat-delivery-fix` **状态:禁止再次引用。改动已提交并进入 `origin/main`,该分支保留仅用于只读追溯,不是待合并开发分支。** diff --git a/scripts/enable-tang-wechat-intent-router-shadow-103.mjs b/scripts/enable-tang-wechat-intent-router-shadow-103.mjs new file mode 100644 index 0000000..2374666 --- /dev/null +++ b/scripts/enable-tang-wechat-intent-router-shadow-103.mjs @@ -0,0 +1,100 @@ +#!/usr/bin/env node +/** + * Enable WeChat LLM intent router in shadow mode for Tang (103). + * Dry-run by default; pass --apply to persist admin config. + */ +import process from 'node:process'; +import mysql from 'mysql2/promise'; +import { loadH5Environment } from './load-env.mjs'; + +loadH5Environment(import.meta.dirname); + +const TANG_USER_ID = 'a70ff537-8908-486e-9b6c-042e07cc25db'; +const CONFIG_KEY = 'intent_router'; +const CONFIG_TABLE = 'h5_wechat_admin_config'; +const PREFERRED_PROVIDER = 'custom_deepseek'; +const PREFERRED_MODEL = 'deepseek-v4-flash'; + +async function ensureTable(pool) { + await pool.query(` + CREATE TABLE IF NOT EXISTS ${CONFIG_TABLE} ( + config_key VARCHAR(64) PRIMARY KEY, + config_json JSON NOT NULL, + updated_by CHAR(36) NULL, + updated_at BIGINT NOT NULL + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci + `); +} + +async function main() { + const apply = process.argv.includes('--apply'); + if (!process.env.DATABASE_URL) { + console.error('DATABASE_URL missing'); + process.exit(1); + } + + const pool = mysql.createPool({ uri: process.env.DATABASE_URL, connectionLimit: 2 }); + await ensureTable(pool); + + const [identRows] = await pool.query( + 'SELECT openid FROM h5_user_wechat_identities WHERE user_id = ? LIMIT 1', + [TANG_USER_ID], + ); + const openid = identRows[0]?.openid; + if (!openid) { + console.error('Tang wechat openid not found'); + process.exit(1); + } + + const [providerRows] = await pool.query( + `SELECT id, provider_id, default_model FROM h5_llm_provider_keys + WHERE status = 'active' AND provider_id = ? + LIMIT 1`, + [PREFERRED_PROVIDER], + ); + const provider = providerRows[0]; + if (!provider) { + console.error(`Provider ${PREFERRED_PROVIDER} not found`); + process.exit(1); + } + + const config = { + enabled: true, + shadowMode: true, + modelProviderKeyId: provider.id, + model: PREFERRED_MODEL, + minConfidence: 0.65, + timeoutMs: 4000, + canaryOpenids: [openid], + }; + + const payload = { + apply, + tangUserId: TANG_USER_ID, + openid, + provider: { id: provider.id, providerId: provider.provider_id, model: PREFERRED_MODEL }, + config, + }; + + if (apply) { + const now = Date.now(); + await pool.query( + `INSERT INTO ${CONFIG_TABLE} (config_key, config_json, updated_by, updated_at) + VALUES (?, ?, ?, ?) + ON DUPLICATE KEY UPDATE + config_json = VALUES(config_json), + updated_by = VALUES(updated_by), + updated_at = VALUES(updated_at)`, + [CONFIG_KEY, JSON.stringify(config), TANG_USER_ID, now], + ); + payload.updatedAt = now; + } + + console.log(JSON.stringify(payload, null, 2)); + await pool.end(); +} + +main().catch((err) => { + console.error(err); + process.exit(1); +});