diff --git a/rust/src/lancedb_ops.rs b/rust/src/lancedb_ops.rs index 8e98fc7..d14bd18 100644 --- a/rust/src/lancedb_ops.rs +++ b/rust/src/lancedb_ops.rs @@ -231,16 +231,71 @@ impl LanceDBOps { /// 更新记忆记录的字段(通过 SQL UPDATE) /// fields_json 格式: [{"column":"recall_count","value":"recall_count + 1"}, ...] + /// 支持算术表达式(value 包含 + 或 - 时),先查当前值再计算 pub fn update(&self, table: &str, id: &str, fields_json: &str) -> Result> { let db = rt().block_on(lancedb::connect(self.data_dir.to_str().unwrap()).execute())?; let tbl = rt().block_on(db.open_table(table).execute())?; let fields: Vec = serde_json::from_str(fields_json)?; let mut op = tbl.update().only_if(format!("id = '{}'", id.replace('\'', "''"))); + + // 如果有算术表达式,先查当前值 + let has_arith = fields.iter().any(|f| { + f["value"].as_str().map(|v| v.contains('+') || v.contains('-')).unwrap_or(false) + }); + + let mut current_values: std::collections::HashMap = std::collections::HashMap::new(); + if has_arith { + // 查询当前值 + let mut results = Box::pin(rt().block_on( + tbl.query() + .only_if(&format!("id = '{}'", id.replace('\'', "''"))) + .limit(1) + .execute(), + )?); + while let Some(Ok(batch)) = rt().block_on(results.next()) { + for i in 0..batch.num_rows() { + for f in &fields { + let col = f["column"].as_str().unwrap_or(""); + if !col.is_empty() { + let val = col_i64(&batch, i, col); + current_values.insert(col.to_string(), val); + } + } + } + } + } + for f in &fields { let col = f["column"].as_str().unwrap_or(""); let val = f["value"].as_str().unwrap_or(""); if col.is_empty() { continue; } - op = op.column(col, val); + + // 处理算术表达式: "column + N" 或 "column - N" + let final_val = if (val.contains('+') || val.contains('-')) && !val.starts_with('\'') { + let parts: Vec<&str> = val.split_whitespace().collect(); + if parts.len() == 3 { + let operand_col = parts[0]; + let op_char = parts[1].chars().next().unwrap_or('+'); + if let Ok(delta) = parts[2].parse::() { + let current = *current_values.get(operand_col).unwrap_or(&0); + let new_val = match op_char { + '+' => current.saturating_add(delta), + '-' => current.saturating_sub(delta), + _ => current, + }; + eprintln!("[lancedb] update {}: col={} expr={} current={} -> {}", id, col, val, current, new_val); + new_val.to_string() + } else { + val.to_string() + } + } else { + val.to_string() + } + } else { + val.to_string() + }; + + op = op.column(col, &final_val); } let updated = rt().block_on(op.execute())?; eprintln!("[lancedb] update {}: id={} fields={} rows={}", table, id, fields.len(), updated); diff --git a/rust/src/quality_backtrace.rs b/rust/src/quality_backtrace.rs index 3c18344..28b927f 100644 --- a/rust/src/quality_backtrace.rs +++ b/rust/src/quality_backtrace.rs @@ -147,10 +147,17 @@ impl QualityBacktracer { let text = resp.text()?; let parsed: serde_json::Value = serde_json::from_str(&text)?; - let content = parsed["choices"][0]["message"]["content"] + let mut content = parsed["choices"][0]["message"]["content"] .as_str() .unwrap_or("") .to_string(); + // MiniMax M2.7 uses reasoning_content for the actual response + if content.is_empty() { + content = parsed["choices"][0]["message"]["reasoning_content"] + .as_str() + .unwrap_or("") + .to_string(); + } Ok(content) }