feat(wechat): add Intent Transaction Layer with unified task schema

Introduce Draft → Confirm → Commit flow for WeChat schedule intents behind
feature flags, plus h5_tasks dual-write/read aggregation and rollout scripts
so reminders and automations get explicit user confirmation before persisting.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
john
2026-08-24 15:59:17 +08:00
parent b93c92a3e2
commit d58dc2a251
45 changed files with 4972 additions and 30 deletions
+59
View File
@@ -267,12 +267,20 @@ export async function migrateSchema(pool) {
['engine', "VARCHAR(32) NOT NULL DEFAULT 'openai' AFTER goosed_provider_id"],
['relay_provider', 'VARCHAR(64) NULL AFTER engine'],
['is_vision_selected', 'TINYINT(1) NOT NULL DEFAULT 0 AFTER is_selected'],
['vision_model', 'VARCHAR(128) NULL AFTER is_vision_selected'],
];
for (const [column, definition] of llmColumns) {
if (!(await columnExists(pool, 'h5_llm_provider_keys', column))) {
await pool.query(`ALTER TABLE h5_llm_provider_keys ADD COLUMN \`${column}\` ${definition}`);
}
}
if (await columnExists(pool, 'h5_llm_provider_keys', 'vision_model')) {
await pool.query(
`UPDATE h5_llm_provider_keys
SET vision_model = default_model
WHERE is_vision_selected = 1 AND (vision_model IS NULL OR vision_model = '')`,
);
}
await pool.query(`
CREATE TABLE IF NOT EXISTS h5_llm_executor_bindings (
@@ -831,6 +839,57 @@ export async function migrateSchema(pool) {
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
`);
await pool.query(`
CREATE TABLE IF NOT EXISTS h5_intent_drafts (
id CHAR(36) PRIMARY KEY,
user_id CHAR(36) NOT NULL,
layer ENUM('L0', 'L1', 'L2', 'L3', 'ambiguous') NOT NULL,
draft_type VARCHAR(64) NOT NULL,
action_level TINYINT UNSIGNED NOT NULL DEFAULT 1,
title VARCHAR(255) NOT NULL,
payload_json JSON NOT NULL,
card_text TEXT NOT NULL,
status ENUM('draft', 'confirmed', 'committed', 'cancelled', 'expired') NOT NULL DEFAULT 'draft',
source_channel VARCHAR(32) NOT NULL DEFAULT 'wechat',
source_message_id VARCHAR(128) NULL,
source_text TEXT NULL,
committed_ref_json JSON NULL,
event_log_json JSON NULL,
expires_at BIGINT NULL,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
KEY idx_intent_draft_user_status (user_id, status, created_at),
KEY idx_intent_draft_expires (status, expires_at),
CONSTRAINT fk_intent_draft_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
`);
await pool.query(`
CREATE TABLE IF NOT EXISTS h5_tasks (
id CHAR(36) PRIMARY KEY,
user_id CHAR(36) NOT NULL,
type ENUM('reminder', 'todo', 'digest', 'automation', 'condition') NOT NULL,
title VARCHAR(255) NOT NULL,
spec_json JSON NOT NULL,
trigger_json JSON NOT NULL,
action_json JSON NOT NULL,
action_level TINYINT UNSIGNED NOT NULL DEFAULT 1,
notify_channel ENUM('wechat', 'web', 'both', 'none') NOT NULL DEFAULT 'both',
status ENUM('active', 'locked', 'paused', 'completed', 'failed', 'cancelled') NOT NULL DEFAULT 'active',
next_run_at BIGINT NULL,
last_run_at BIGINT NULL,
legacy_ref_json JSON NULL,
source_channel VARCHAR(32) NULL,
source_message_id VARCHAR(128) NULL,
source_text TEXT NULL,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
KEY idx_h5_tasks_user_status (user_id, status, next_run_at),
KEY idx_h5_tasks_due (status, next_run_at),
CONSTRAINT fk_h5_tasks_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
`);
await pool.query(`
CREATE TABLE IF NOT EXISTS h5_schedule_delivery_logs (
id CHAR(36) PRIMARY KEY,