Skip to content

Commit c2a02e3

Browse files
committed
fix(ai): v0.17.0 审查即修——笔记级精修闭环/双入口 target_kind 分发/重生成沿用策略档位/流式订阅容错(P0x2 P1x1 P2x3)
1 parent 3b4936a commit c2a02e3

16 files changed

Lines changed: 313 additions & 60 deletions

‎app/src-tauri/src/commands_ai_enrich.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ pub async fn ai_enrich_start(
144144
created_at: crate::db_sessions_rows::unix_seconds(),
145145
finished_at: None,
146146
adopted: false,
147+
target_kind: Some("note".to_string()),
147148
}) {
148149
eprintln!("[AiTasks] enrich 任务 {} 落库失败(不阻断 AI 调用;重启后不可恢复): {}", task_id, e);
149150
}

‎app/src-tauri/src/commands_ai_note_refine.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ pub async fn ai_note_refine_start(
120120
created_at: crate::db_sessions_rows::unix_seconds(),
121121
finished_at: None,
122122
adopted: false,
123+
target_kind: Some("note".to_string()),
123124
}) {
124125
eprintln!("[AiTasks] note-refine 任务 {} 落库失败(不阻断 AI 调用;重启后不可恢复): {}", task_id, e);
125126
}

‎app/src-tauri/src/commands_ai_refine.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ pub async fn ai_refine_start(
224224
created_at: crate::db_sessions_rows::unix_seconds(),
225225
finished_at: None,
226226
adopted: false,
227+
target_kind: Some("session".to_string()),
227228
}) {
228229
eprintln!("[AiTasks] refine 任务 {} 落库失败(不阻断 AI 调用;重启后不可恢复): {}", task_id, e);
229230
}

‎app/src-tauri/src/db_ai_chat_tests.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ fn task_rec(task_id: u64, state: &str) -> AiTaskRecord {
2929
created_at: 1,
3030
finished_at: None,
3131
adopted: false,
32+
target_kind: None,
3233
}
3334
}
3435

‎app/src-tauri/src/db_ai_tasks.rs‎

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ pub struct AiTaskRecord {
2828
pub ref_id: i64,
2929
/// 状态(pending|running|succeeded|failed|partial_failed)
3030
pub state: String,
31+
/// 目标类别(v0.17.0 审查修复:session=会话级精修 | note=笔记级精修/补充;
32+
/// NULL=旧数据(展示层按 session 语义兜底——后端不猜,防双入口错跳)
33+
#[serde(default)]
34+
pub target_kind: Option<String>,
3135
/// 成功结果 JSON(AiRefineResult/AiEnrichResult;失败/进行中 NULL)
3236
pub result_json: Option<String>,
3337
/// 成本(元;采纳落库后回填)
@@ -61,6 +65,7 @@ impl Db {
6165
error TEXT,
6266
slices INTEGER,
6367
trajectory_json TEXT,
68+
target_kind TEXT,
6469
created_at INTEGER NOT NULL,
6570
finished_at INTEGER,
6671
adopted INTEGER NOT NULL DEFAULT 0
@@ -77,6 +82,14 @@ impl Db {
7782
"trajectory_json",
7883
"ALTER TABLE ai_tasks ADD COLUMN trajectory_json TEXT",
7984
)?;
85+
// v0.17.0 审查修复:目标类别列(session|note——双入口错跳修复)。
86+
// 幂等迁移;旧数据 NULL(展示层按 session 语义兜底——不猜)。
87+
crate::db_migrations::ensure_column(
88+
&conn,
89+
"ai_tasks",
90+
"target_kind",
91+
"ALTER TABLE ai_tasks ADD COLUMN target_kind TEXT",
92+
)?;
8093
Ok(())
8194
}
8295

@@ -86,8 +99,8 @@ impl Db {
8699
conn.execute(
87100
"INSERT OR REPLACE INTO ai_tasks
88101
(task_id, op_type, ref_id, state, result_json, cost_yuan, elapsed_ms,
89-
model, error, slices, created_at, finished_at, adopted)
90-
VALUES (?1,?2,?3,?4,?5,?6,?7,?8,?9,?10,?11,?12,?13)",
102+
model, error, slices, target_kind, created_at, finished_at, adopted)
103+
VALUES (?1,?2,?3,?4,?5,?6,?7,?8,?9,?10,?11,?12,?13,?14)",
91104
params![
92105
rec.task_id as i64,
93106
rec.op_type,
@@ -99,6 +112,7 @@ impl Db {
99112
rec.model,
100113
rec.error,
101114
rec.slices.map(|s| s as i64),
115+
rec.target_kind.as_deref(),
102116
rec.created_at,
103117
rec.finished_at,
104118
rec.adopted as i64,
@@ -188,7 +202,7 @@ impl Db {
188202
let conn = self.conn.lock().unwrap_or_else(|e| e.into_inner());
189203
let mut stmt = conn.prepare(
190204
"SELECT task_id, op_type, ref_id, state, result_json, cost_yuan, elapsed_ms,
191-
model, error, slices, created_at, finished_at, adopted
205+
model, error, slices, target_kind, created_at, finished_at, adopted
192206
FROM ai_tasks
193207
WHERE state='succeeded' AND adopted=0 AND result_json IS NOT NULL
194208
ORDER BY created_at DESC LIMIT ?1",
@@ -207,7 +221,7 @@ impl Db {
207221
let conn = self.conn.lock().unwrap_or_else(|e| e.into_inner());
208222
let mut stmt = conn.prepare(
209223
"SELECT task_id, op_type, ref_id, state, result_json, cost_yuan, elapsed_ms,
210-
model, error, slices, created_at, finished_at, adopted
224+
model, error, slices, target_kind, created_at, finished_at, adopted
211225
FROM ai_tasks
212226
WHERE op_type='refine' AND ref_id=?1 AND state='succeeded'
213227
AND adopted=0 AND result_json IS NOT NULL
@@ -225,7 +239,7 @@ impl Db {
225239
let conn = self.conn.lock().unwrap_or_else(|e| e.into_inner());
226240
let mut stmt = conn.prepare(
227241
"SELECT task_id, op_type, ref_id, state, result_json, cost_yuan, elapsed_ms,
228-
model, error, slices, created_at, finished_at, adopted
242+
model, error, slices, target_kind, created_at, finished_at, adopted
229243
FROM ai_tasks
230244
WHERE op_type=?1
231245
ORDER BY created_at DESC LIMIT ?2",
@@ -239,7 +253,7 @@ impl Db {
239253
let conn = self.conn.lock().unwrap_or_else(|e| e.into_inner());
240254
let mut stmt = conn.prepare(
241255
"SELECT task_id, op_type, ref_id, state, result_json, cost_yuan, elapsed_ms,
242-
model, error, slices, created_at, finished_at, adopted
256+
model, error, slices, target_kind, created_at, finished_at, adopted
243257
FROM ai_tasks WHERE task_id=?1",
244258
)?;
245259
let mut rows = stmt.query_map(params![task_id as i64], map_record)?;
@@ -280,9 +294,10 @@ fn map_record(row: &rusqlite::Row<'_>) -> rusqlite::Result<AiTaskRecord> {
280294
model: row.get(7)?,
281295
error: row.get(8)?,
282296
slices: row.get::<_, Option<i64>>(9)?.map(|v| v as usize),
283-
created_at: row.get(10)?,
284-
finished_at: row.get(11)?,
285-
adopted: row.get::<_, i64>(12)? != 0,
297+
target_kind: row.get(10)?,
298+
created_at: row.get(11)?,
299+
finished_at: row.get(12)?,
300+
adopted: row.get::<_, i64>(13)? != 0,
286301
})
287302
}
288303

‎app/src-tauri/src/db_ai_tasks_tests.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ fn rec(task_id: u64, op: &str, ref_id: i64, state: &str) -> AiTaskRecord {
2727
created_at: task_id as i64,
2828
finished_at: if state == "succeeded" { Some(task_id as i64) } else { None },
2929
adopted: false,
30+
target_kind: None,
3031
}
3132
}
3233

‎app/src/components/AiRefineCard.tsx‎

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ import type {
1818
AiRefineResult,
1919
AiSettingsView,
2020
AiTaskState,
21+
StrategyOverride,
2122
} from "../types";
2223
import RefineWorkbench from "./RefineWorkbench";
2324
import RefineLaunchDialog from "./RefineLaunchDialog";
25+
import { overrideFromInfo } from "../utils/refineStrategy";
2426

2527
const btn: React.CSSProperties = { padding: "5px 10px", cursor: "pointer", fontSize: 12, borderRadius: 6 };
2628

@@ -37,7 +39,7 @@ export default function AiRefineCard({
3739
onAutoTaskMissing?: () => void;
3840
}) {
3941
const [settings, setSettings] = useState<AiSettingsView | null>(null);
40-
const [phase, setPhase] = useState<"idle" | "consent" | "confirm" | "running" | "done" | "failed">("idle");
42+
const [phase, setPhase] = useState<"idle" | "running" | "done" | "failed">("idle");
4143
const [progress, setProgress] = useState<{ finished: number; total: number } | null>(null);
4244
const [result, setResult] = useState<AiRefineResult | null>(null);
4345
const [failure, setFailure] = useState<AiTaskFailureLike | null>(null);
@@ -126,8 +128,8 @@ export default function AiRefineCard({
126128
startPolling(taskId);
127129
}, [onTaskStarted, startPolling]);
128130

129-
/** ② 启动任务(工作台「重新生成」路径——沿全局默认偏好;策略选择在主发起对话框) */
130-
const start = async () => {
131+
/** ② 启动任务(重生成路径——沿用本次策略档位;主发起对话框传策略) */
132+
const start = async (strategy?: StrategyOverride) => {
131133
setMsg("");
132134
setPhase("running");
133135
// 契约修复(2026-08-21 真机"排队中"根因):Rust AiTaskHandle 为 camelCase
@@ -136,6 +138,7 @@ export default function AiRefineCard({
136138
const handle = await invoke<{ taskId: number; state: AiTaskState }>("ai_refine_start", {
137139
sessionId,
138140
authorized: true,
141+
strategy: strategy ?? null,
139142
}).catch((e) => {
140143
setMsg(`启动失败:${e}`);
141144
setPhase("idle");
@@ -184,9 +187,6 @@ export default function AiRefineCard({
184187
)}
185188
</div>
186189

187-
{/* 授权卡由 RefineLaunchDialog 承载(v0.17.0——策略/成本/授权一屏编排) */}
188-
{phase === "consent" && null}
189-
190190
{/* 任务进行中(切片进度) */}
191191
{phase === "running" && (
192192
<div style={{ fontSize: 12, color: "#4b5563" }}>
@@ -225,7 +225,10 @@ export default function AiRefineCard({
225225
// 审查修复:regenerate 旁路 onTaskStarted 导航(不离开当前页)
226226
onRegenerate={async () => {
227227
skipNavigateRef.current = true;
228-
try { await start(); } finally { skipNavigateRef.current = false; }
228+
try {
229+
// 审查修复:重生成沿用本次策略档位(首版与重生成同档位)
230+
await start(result.strategy ? overrideFromInfo(result.strategy) : undefined);
231+
} finally { skipNavigateRef.current = false; }
229232
}}
230233
onClose={() => setShowWorkbench(false)}
231234
onApplied={(id) => { reset(); onApplied?.(id); }}

0 commit comments

Comments
 (0)