chore: 修复 clippy 错误(loop never loops → if-let)并应用自动修复
This commit is contained in:
@@ -243,8 +243,8 @@ pub async fn trigger_idle_summary(
|
|||||||
|
|
||||||
/// 生成摘要:优先使用 LLM,不可用时回退到简单截断
|
/// 生成摘要:优先使用 LLM,不可用时回退到简单截断
|
||||||
async fn generate_summary(messages: &[Message], summarizer: Option<&Summarizer>) -> String {
|
async fn generate_summary(messages: &[Message], summarizer: Option<&Summarizer>) -> String {
|
||||||
if let Some(summarizer) = summarizer {
|
if let Some(summarizer) = summarizer
|
||||||
if messages.len() >= 3 {
|
&& messages.len() >= 3 {
|
||||||
let prompt = build_summary_prompt(messages);
|
let prompt = build_summary_prompt(messages);
|
||||||
match summarizer(prompt).await {
|
match summarizer(prompt).await {
|
||||||
Ok(text) if !text.is_empty() => {
|
Ok(text) if !text.is_empty() => {
|
||||||
@@ -254,7 +254,6 @@ async fn generate_summary(messages: &[Message], summarizer: Option<&Summarizer>)
|
|||||||
_ => tracing::warn!("LLM 摘要失败,回退到简单截断"),
|
_ => tracing::warn!("LLM 摘要失败,回退到简单截断"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
summarize_messages(messages)
|
summarize_messages(messages)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -363,7 +363,7 @@ async fn llm_consumer_loop(
|
|||||||
let session = session.clone();
|
let session = session.clone();
|
||||||
let n = name.to_string();
|
let n = name.to_string();
|
||||||
let args = args_json.to_string();
|
let args = args_json.to_string();
|
||||||
let is_approved = approved_tool.as_ref().map_or(false, |t| t == &n);
|
let is_approved = approved_tool.as_ref() == Some(&n);
|
||||||
|
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let ch = ChannelId::wechat(&uid);
|
let ch = ChannelId::wechat(&uid);
|
||||||
|
|||||||
@@ -291,8 +291,8 @@ impl Conversation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(calls) = tool_calls {
|
if let Some(calls) = tool_calls
|
||||||
if !calls.is_empty() {
|
&& !calls.is_empty() {
|
||||||
used_tools = true;
|
used_tools = true;
|
||||||
tracing::info!(
|
tracing::info!(
|
||||||
"🔧 LLM 请求 {} 个工具: {}",
|
"🔧 LLM 请求 {} 个工具: {}",
|
||||||
@@ -347,7 +347,6 @@ impl Conversation {
|
|||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 无工具调用:记录回复,检查是否需要溢出摘要
|
// 无工具调用:记录回复,检查是否需要溢出摘要
|
||||||
if !full_text.is_empty() {
|
if !full_text.is_empty() {
|
||||||
@@ -358,7 +357,7 @@ impl Conversation {
|
|||||||
{
|
{
|
||||||
let s = self.session.lock().await;
|
let s = self.session.lock().await;
|
||||||
let recent = s.recent_messages();
|
let recent = s.recent_messages();
|
||||||
let estimated: u32 = recent.iter().map(|m| builder::estimate_tokens(m)).sum();
|
let estimated: u32 = recent.iter().map(builder::estimate_tokens).sum();
|
||||||
if estimated > s.token_budget {
|
if estimated > s.token_budget {
|
||||||
drop(s);
|
drop(s);
|
||||||
builder::trigger_overflow_summary(&self.session, Some(&self.summarizer()))
|
builder::trigger_overflow_summary(&self.session, Some(&self.summarizer()))
|
||||||
|
|||||||
+2
-3
@@ -215,8 +215,8 @@ async fn stream_deepseek(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 检查最后的 buffer
|
// 检查最后的 buffer
|
||||||
if !buf.trim().is_empty() {
|
if !buf.trim().is_empty()
|
||||||
if let Some(parsed) = parse_chat_chunk(buf.trim()) {
|
&& let Some(parsed) = parse_chat_chunk(buf.trim()) {
|
||||||
match parsed {
|
match parsed {
|
||||||
ParsedChunk::Text(t) => full_text.push_str(&t),
|
ParsedChunk::Text(t) => full_text.push_str(&t),
|
||||||
ParsedChunk::ToolCallDelta {
|
ParsedChunk::ToolCallDelta {
|
||||||
@@ -243,7 +243,6 @@ async fn stream_deepseek(
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 构建 tool_calls
|
// 构建 tool_calls
|
||||||
let tool_calls: Option<Vec<ToolCall>> = if tool_call_builders.is_empty() {
|
let tool_calls: Option<Vec<ToolCall>> = if tool_call_builders.is_empty() {
|
||||||
|
|||||||
+12
-16
@@ -159,16 +159,16 @@ pub(crate) fn parse_chat_chunk(line: &str) -> Option<ParsedChunk> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 提取 usage(可能在最后一个 chunk)
|
// 提取 usage(可能在最后一个 chunk)
|
||||||
if let Some(ref usage) = parsed.usage {
|
if let Some(ref usage) = parsed.usage
|
||||||
if usage.total_tokens > 0 {
|
&& usage.total_tokens > 0 {
|
||||||
return Some(ParsedChunk::Usage(usage.clone()));
|
return Some(ParsedChunk::Usage(usage.clone()));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for choice in parsed.choices {
|
// SSE 流式响应中每个 chunk 只包含一个 choice 的 delta
|
||||||
|
if let Some(choice) = parsed.choices.into_iter().next() {
|
||||||
// 工具调用 delta
|
// 工具调用 delta
|
||||||
if let Some(tool_calls) = &choice.delta.tool_calls {
|
if let Some(tool_calls) = &choice.delta.tool_calls
|
||||||
for tc in tool_calls {
|
&& let Some(tc) = tool_calls.first() {
|
||||||
let idx = tc.index.unwrap_or(0);
|
let idx = tc.index.unwrap_or(0);
|
||||||
let args = tc
|
let args = tc
|
||||||
.function
|
.function
|
||||||
@@ -183,23 +183,19 @@ pub(crate) fn parse_chat_chunk(line: &str) -> Option<ParsedChunk> {
|
|||||||
arguments: args,
|
arguments: args,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(reasoning) = &choice.delta.reasoning_content {
|
if let Some(reasoning) = &choice.delta.reasoning_content
|
||||||
if !reasoning.is_empty() {
|
&& !reasoning.is_empty() {
|
||||||
return Some(ParsedChunk::Reasoning(reasoning.clone()));
|
return Some(ParsedChunk::Reasoning(reasoning.clone()));
|
||||||
}
|
}
|
||||||
}
|
if let Some(content) = &choice.delta.content
|
||||||
if let Some(content) = &choice.delta.content {
|
&& !content.is_empty() {
|
||||||
if !content.is_empty() {
|
|
||||||
return Some(ParsedChunk::Text(content.clone()));
|
return Some(ParsedChunk::Text(content.clone()));
|
||||||
}
|
}
|
||||||
}
|
if let Some(reason) = &choice.finish_reason
|
||||||
if let Some(reason) = &choice.finish_reason {
|
&& !reason.is_empty() {
|
||||||
if !reason.is_empty() {
|
|
||||||
return Some(ParsedChunk::FinishReason(reason.clone()));
|
return Some(ParsedChunk::FinishReason(reason.clone()));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
|
|||||||
+2
-3
@@ -28,8 +28,8 @@ pub fn init_logger(log_dir: Option<&str>, with_file: bool) {
|
|||||||
.with_target(false)
|
.with_target(false)
|
||||||
.with_ansi(true);
|
.with_ansi(true);
|
||||||
|
|
||||||
if with_file {
|
if with_file
|
||||||
if let Some(dir) = log_dir {
|
&& let Some(dir) = log_dir {
|
||||||
let dir_path = PathBuf::from(dir);
|
let dir_path = PathBuf::from(dir);
|
||||||
std::fs::create_dir_all(&dir_path).ok();
|
std::fs::create_dir_all(&dir_path).ok();
|
||||||
|
|
||||||
@@ -46,7 +46,6 @@ pub fn init_logger(log_dir: Option<&str>, with_file: bool) {
|
|||||||
.init();
|
.init();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
tracing_subscriber::registry()
|
tracing_subscriber::registry()
|
||||||
.with(env_filter)
|
.with(env_filter)
|
||||||
|
|||||||
+13
-22
@@ -371,7 +371,6 @@ async fn cmd_listen(
|
|||||||
.send_text(&uid, &msg, None)
|
.send_text(&uid, &msg, None)
|
||||||
.await
|
.await
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
.map_err(|e| e)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
@@ -536,8 +535,8 @@ async fn listen_loop(
|
|||||||
info!("收到消息 from={}: {}", from, text);
|
info!("收到消息 from={}: {}", from, text);
|
||||||
|
|
||||||
// === 入库:收到的消息 ===
|
// === 入库:收到的消息 ===
|
||||||
if let Some(db) = database {
|
if let Some(db) = database
|
||||||
if let Err(e) = db::models::insert_chat_record(
|
&& let Err(e) = db::models::insert_chat_record(
|
||||||
db.pool(),
|
db.pool(),
|
||||||
"inbound",
|
"inbound",
|
||||||
from,
|
from,
|
||||||
@@ -551,7 +550,6 @@ async fn listen_loop(
|
|||||||
{
|
{
|
||||||
error!("保存聊天记录失败: {}", e);
|
error!("保存聊天记录失败: {}", e);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Echo 模式
|
// Echo 模式
|
||||||
if echo {
|
if echo {
|
||||||
@@ -559,8 +557,8 @@ async fn listen_loop(
|
|||||||
Ok(sent_id) => {
|
Ok(sent_id) => {
|
||||||
info!("回显成功 msg_id={}", sent_id);
|
info!("回显成功 msg_id={}", sent_id);
|
||||||
// === 入库:发送的回显 ===
|
// === 入库:发送的回显 ===
|
||||||
if let Some(db) = database {
|
if let Some(db) = database
|
||||||
if let Err(e) = db::models::insert_chat_record(
|
&& let Err(e) = db::models::insert_chat_record(
|
||||||
db.pool(),
|
db.pool(),
|
||||||
"outbound",
|
"outbound",
|
||||||
from,
|
from,
|
||||||
@@ -574,7 +572,6 @@ async fn listen_loop(
|
|||||||
{
|
{
|
||||||
error!("保存聊天记录失败: {}", e);
|
error!("保存聊天记录失败: {}", e);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Err(e) => error!("回显失败: {}", e),
|
Err(e) => error!("回显失败: {}", e),
|
||||||
}
|
}
|
||||||
@@ -612,8 +609,8 @@ async fn listen_loop(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LLM 回复(异步执行,避免审批阻塞主循环)
|
// LLM 回复(异步执行,避免审批阻塞主循环)
|
||||||
if enable_llm {
|
if enable_llm
|
||||||
if let Some(conv) = &conversation {
|
&& let Some(conv) = &conversation {
|
||||||
let conv = conv.clone();
|
let conv = conv.clone();
|
||||||
let client = client.clone();
|
let client = client.clone();
|
||||||
let database = database.clone();
|
let database = database.clone();
|
||||||
@@ -639,8 +636,8 @@ async fn listen_loop(
|
|||||||
{
|
{
|
||||||
Ok(sent_id) => {
|
Ok(sent_id) => {
|
||||||
info!("LLM 回复成功 msg_id={}", sent_id);
|
info!("LLM 回复成功 msg_id={}", sent_id);
|
||||||
if let Some(db) = database {
|
if let Some(db) = database
|
||||||
if let Err(e) = db::models::insert_chat_record(
|
&& let Err(e) = db::models::insert_chat_record(
|
||||||
db.pool(),
|
db.pool(),
|
||||||
"outbound",
|
"outbound",
|
||||||
&from_owned,
|
&from_owned,
|
||||||
@@ -654,13 +651,11 @@ async fn listen_loop(
|
|||||||
{
|
{
|
||||||
error!("保存聊天记录失败: {}", e);
|
error!("保存聊天记录失败: {}", e);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Err(e) => error!("发送 LLM 回复失败: {}", e),
|
Err(e) => error!("发送 LLM 回复失败: {}", e),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@@ -722,8 +717,8 @@ async fn store_usage(
|
|||||||
provider: &str,
|
provider: &str,
|
||||||
u: &Usage,
|
u: &Usage,
|
||||||
) {
|
) {
|
||||||
if let Some(db) = db {
|
if let Some(db) = db
|
||||||
if let Err(e) = db::models::insert_llm_usage(
|
&& let Err(e) = db::models::insert_llm_usage(
|
||||||
db.pool(),
|
db.pool(),
|
||||||
user_id,
|
user_id,
|
||||||
model,
|
model,
|
||||||
@@ -737,7 +732,6 @@ async fn store_usage(
|
|||||||
{
|
{
|
||||||
tracing::error!("存储 LLM 用量失败: {}", e);
|
tracing::error!("存储 LLM 用量失败: {}", e);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn cmd_whoami(database: &Option<Arc<Database>>, file_state: &state::StateManager) {
|
async fn cmd_whoami(database: &Option<Arc<Database>>, file_state: &state::StateManager) {
|
||||||
@@ -863,8 +857,8 @@ async fn cmd_send(
|
|||||||
println!("✅ 消息已发送, msg_id={}", msg_id);
|
println!("✅ 消息已发送, msg_id={}", msg_id);
|
||||||
|
|
||||||
// 入库:发送的消息
|
// 入库:发送的消息
|
||||||
if let Some(db) = database {
|
if let Some(db) = database
|
||||||
if let Err(e) = db::models::insert_chat_record(
|
&& let Err(e) = db::models::insert_chat_record(
|
||||||
db.pool(),
|
db.pool(),
|
||||||
"outbound",
|
"outbound",
|
||||||
to,
|
to,
|
||||||
@@ -878,7 +872,6 @@ async fn cmd_send(
|
|||||||
{
|
{
|
||||||
error!("保存聊天记录失败: {}", e);
|
error!("保存聊天记录失败: {}", e);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Err(e) => error!("发送失败: {}", e),
|
Err(e) => error!("发送失败: {}", e),
|
||||||
}
|
}
|
||||||
@@ -898,9 +891,7 @@ async fn builtin_approve(ctx: &ExecutionContext, name: &str) -> Result<bool, Str
|
|||||||
name, code
|
name, code
|
||||||
);
|
);
|
||||||
if let Some(ref send) = ctx.send_wechat {
|
if let Some(ref send) = ctx.send_wechat {
|
||||||
if let Err(e) = send(&ctx.user_id, &msg).await {
|
send(&ctx.user_id, &msg).await?
|
||||||
return Err(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match tokio::time::timeout(std::time::Duration::from_secs(300), rx).await {
|
match tokio::time::timeout(std::time::Duration::from_secs(300), rx).await {
|
||||||
|
|||||||
@@ -265,8 +265,8 @@ impl MessageQueue {
|
|||||||
/// - 该渠道还有消息 → 放回 pending 尾部
|
/// - 该渠道还有消息 → 放回 pending 尾部
|
||||||
pub fn dequeue(&mut self) -> Option<PipelineMessage> {
|
pub fn dequeue(&mut self) -> Option<PipelineMessage> {
|
||||||
while let Some(ch) = self.pending.pop_front() {
|
while let Some(ch) = self.pending.pop_front() {
|
||||||
if let Some(q) = self.queues.get_mut(&ch) {
|
if let Some(q) = self.queues.get_mut(&ch)
|
||||||
if let Some(item) = q.pop_front() {
|
&& let Some(item) = q.pop_front() {
|
||||||
if !q.is_empty() {
|
if !q.is_empty() {
|
||||||
self.pending.push_back(ch);
|
self.pending.push_back(ch);
|
||||||
} else {
|
} else {
|
||||||
@@ -274,7 +274,6 @@ impl MessageQueue {
|
|||||||
}
|
}
|
||||||
return Some(item);
|
return Some(item);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
self.queues.remove(&ch);
|
self.queues.remove(&ch);
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
@@ -290,7 +289,7 @@ impl MessageQueue {
|
|||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn has_pending(&self, ch: &ChannelId) -> bool {
|
pub fn has_pending(&self, ch: &ChannelId) -> bool {
|
||||||
self.queues.get(ch).map_or(false, |q| !q.is_empty())
|
self.queues.get(ch).is_some_and(|q| !q.is_empty())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
|||||||
@@ -215,12 +215,11 @@ impl ApprovalManager {
|
|||||||
|
|
||||||
let mut map = self.pending.lock().await;
|
let mut map = self.pending.lock().await;
|
||||||
for (uid, i, _) in expired.iter().rev() {
|
for (uid, i, _) in expired.iter().rev() {
|
||||||
if let Some(entries) = map.get_mut(uid) {
|
if let Some(entries) = map.get_mut(uid)
|
||||||
if *i < entries.len() {
|
&& *i < entries.len() {
|
||||||
let entry = entries.remove(*i);
|
let entry = entries.remove(*i);
|
||||||
let _ = entry.sender.send(ApprovalDecision::Expired);
|
let _ = entry.sender.send(ApprovalDecision::Expired);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
map.retain(|_, v| !v.is_empty());
|
map.retain(|_, v| !v.is_empty());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -151,20 +151,18 @@ fn extract_content(document: &Html, domain: &str) -> String {
|
|||||||
let config = load_config();
|
let config = load_config();
|
||||||
if let Some(selectors) = config.get(domain) {
|
if let Some(selectors) = config.get(domain) {
|
||||||
for sel_str in selectors {
|
for sel_str in selectors {
|
||||||
if let Some(text) = try_selector(document, sel_str) {
|
if let Some(text) = try_selector(document, sel_str)
|
||||||
if text.len() > 50 {
|
&& text.len() > 50 {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 先用可读性算法
|
// 2. 先用可读性算法
|
||||||
if let Some(text) = readability_extract(document) {
|
if let Some(text) = readability_extract(document)
|
||||||
if text.len() > 50 {
|
&& text.len() > 50 {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 3. 回退到 body
|
// 3. 回退到 body
|
||||||
if let Some(text) = try_selector(document, "body") {
|
if let Some(text) = try_selector(document, "body") {
|
||||||
@@ -254,7 +252,7 @@ fn score_element(el: &ElementRef) -> f64 {
|
|||||||
score += commas * 3.0;
|
score += commas * 3.0;
|
||||||
|
|
||||||
// 句号/问号/感叹号 → 完整句子
|
// 句号/问号/感叹号 → 完整句子
|
||||||
let sentences = text.matches(|c| c == '.' || c == '。' || c == '?' || c == '?' || c == '!' || c == '!').count() as f64;
|
let sentences = text.matches(['.', '。', '?', '?', '!', '!']).count() as f64;
|
||||||
score += sentences * 2.0;
|
score += sentences * 2.0;
|
||||||
|
|
||||||
// 段落数(<p> 标签)
|
// 段落数(<p> 标签)
|
||||||
@@ -295,11 +293,10 @@ fn extract_clean_text(el: &ElementRef) -> String {
|
|||||||
|
|
||||||
for child in el.descendants() {
|
for child in el.descendants() {
|
||||||
// 跳过噪声元素
|
// 跳过噪声元素
|
||||||
if let Some(child_el) = ElementRef::wrap(child) {
|
if let Some(child_el) = ElementRef::wrap(child)
|
||||||
if is_noise(&child_el) {
|
&& is_noise(&child_el) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(t) = child.value().as_text() {
|
if let Some(t) = child.value().as_text() {
|
||||||
let t = t.trim();
|
let t = t.trim();
|
||||||
@@ -326,12 +323,11 @@ fn extract_clean_text(el: &ElementRef) -> String {
|
|||||||
// ─── 辅助 ───
|
// ─── 辅助 ───
|
||||||
|
|
||||||
fn extract_title(document: &Html) -> String {
|
fn extract_title(document: &Html) -> String {
|
||||||
if let Ok(sel) = Selector::parse("title") {
|
if let Ok(sel) = Selector::parse("title")
|
||||||
if let Some(el) = document.select(&sel).next() {
|
&& let Some(el) = document.select(&sel).next() {
|
||||||
let t: String = el.text().collect::<Vec<_>>().join(" ").trim().to_string();
|
let t: String = el.text().collect::<Vec<_>>().join(" ").trim().to_string();
|
||||||
if !t.is_empty() { return t; }
|
if !t.is_empty() { return t; }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
"无标题".to_string()
|
"无标题".to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -486,11 +486,9 @@ fn extract_days_from_prompt(prompt: &str) -> u32 {
|
|||||||
.rev()
|
.rev()
|
||||||
.collect::<String>()
|
.collect::<String>()
|
||||||
.into()
|
.into()
|
||||||
{
|
&& let Ok(n) = num_str.parse::<u32>() {
|
||||||
if let Ok(n) = num_str.parse::<u32>() {
|
|
||||||
return n.min(30).max(1);
|
return n.min(30).max(1);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
3 // 默认
|
3 // 默认
|
||||||
@@ -613,7 +611,7 @@ pub async fn execute(params: serde_json::Value) -> SkillResult {
|
|||||||
if let Some(arr) = obj.get_mut(*key).and_then(|v| v.as_array_mut()) {
|
if let Some(arr) = obj.get_mut(*key).and_then(|v| v.as_array_mut()) {
|
||||||
for item in arr.iter_mut() {
|
for item in arr.iter_mut() {
|
||||||
if let Some(m) = item.as_object_mut() {
|
if let Some(m) = item.as_object_mut() {
|
||||||
m.retain(|_, v| !v.is_null() && v.as_str().map_or(true, |s| !s.is_empty()));
|
m.retain(|_, v| !v.is_null() && v.as_str().is_none_or(|s| !s.is_empty()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -325,11 +325,10 @@ pub async fn execute(params: serde_json::Value) -> SkillResult {
|
|||||||
let mut output = String::new();
|
let mut output = String::new();
|
||||||
|
|
||||||
// AI 摘要
|
// AI 摘要
|
||||||
if let Some(ref answer) = data.answer {
|
if let Some(ref answer) = data.answer
|
||||||
if !answer.is_empty() {
|
&& !answer.is_empty() {
|
||||||
output.push_str(&format!("📝 {}\n\n", answer));
|
output.push_str(&format!("📝 {}\n\n", answer));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 搜索结果
|
// 搜索结果
|
||||||
if data.results.is_empty() {
|
if data.results.is_empty() {
|
||||||
|
|||||||
+3
-4
@@ -70,11 +70,10 @@ pub fn unpack_call_params(cp: &serde_json::Value) -> serde_json::Value {
|
|||||||
if let Some(prompt) = cp.get("prompt") {
|
if let Some(prompt) = cp.get("prompt") {
|
||||||
match prompt {
|
match prompt {
|
||||||
serde_json::Value::String(s) => {
|
serde_json::Value::String(s) => {
|
||||||
if let Ok(v) = serde_json::from_str::<serde_json::Value>(s) {
|
if let Ok(v) = serde_json::from_str::<serde_json::Value>(s)
|
||||||
if let Some(obj) = v.as_object() {
|
&& let Some(obj) = v.as_object() {
|
||||||
params.extend(obj.clone());
|
params.extend(obj.clone());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
serde_json::Value::Object(obj) => {
|
serde_json::Value::Object(obj) => {
|
||||||
params.extend(obj.clone());
|
params.extend(obj.clone());
|
||||||
@@ -192,7 +191,7 @@ fn format_spec(lines: &mut Vec<String>, spec: &SkillSpec) {
|
|||||||
.parameters
|
.parameters
|
||||||
.get("properties")
|
.get("properties")
|
||||||
.and_then(|v| v.as_object())
|
.and_then(|v| v.as_object())
|
||||||
.map_or(true, |o| o.is_empty())
|
.is_none_or(|o| o.is_empty())
|
||||||
{
|
{
|
||||||
lines.push(format!(
|
lines.push(format!(
|
||||||
" 参数: {}",
|
" 参数: {}",
|
||||||
|
|||||||
+2
-37
@@ -135,6 +135,7 @@ pub struct RefMessage {
|
|||||||
///
|
///
|
||||||
/// `text()` 便捷方法用于快速构造文本消息(发送消息时使用)。
|
/// `text()` 便捷方法用于快速构造文本消息(发送消息时使用)。
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
#[derive(Default)]
|
||||||
pub struct MessageItem {
|
pub struct MessageItem {
|
||||||
#[serde(rename = "type", skip_serializing_if = "Option::is_none")]
|
#[serde(rename = "type", skip_serializing_if = "Option::is_none")]
|
||||||
pub item_type: Option<i32>,
|
pub item_type: Option<i32>,
|
||||||
@@ -182,23 +183,6 @@ impl MessageItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for MessageItem {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
item_type: None,
|
|
||||||
create_time_ms: None,
|
|
||||||
update_time_ms: None,
|
|
||||||
is_completed: None,
|
|
||||||
msg_id: None,
|
|
||||||
ref_msg: None,
|
|
||||||
text_item: None,
|
|
||||||
image_item: None,
|
|
||||||
voice_item: None,
|
|
||||||
file_item: None,
|
|
||||||
video_item: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ## 微信消息结构
|
/// ## 微信消息结构
|
||||||
///
|
///
|
||||||
@@ -214,6 +198,7 @@ impl Default for MessageItem {
|
|||||||
/// * `group_id` — 群聊 ID(群消息时非空)
|
/// * `group_id` — 群聊 ID(群消息时非空)
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
#[derive(Default)]
|
||||||
pub struct WeixinMessage {
|
pub struct WeixinMessage {
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub seq: Option<i64>,
|
pub seq: Option<i64>,
|
||||||
@@ -245,26 +230,6 @@ pub struct WeixinMessage {
|
|||||||
pub context_token: Option<String>,
|
pub context_token: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for WeixinMessage {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
seq: None,
|
|
||||||
message_id: None,
|
|
||||||
from_user_id: None,
|
|
||||||
to_user_id: None,
|
|
||||||
client_id: None,
|
|
||||||
create_time_ms: None,
|
|
||||||
update_time_ms: None,
|
|
||||||
delete_time_ms: None,
|
|
||||||
session_id: None,
|
|
||||||
group_id: None,
|
|
||||||
msg_type: None,
|
|
||||||
message_state: None,
|
|
||||||
item_list: None,
|
|
||||||
context_token: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeixinMessage {
|
impl WeixinMessage {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
|||||||
+2
-3
@@ -276,8 +276,8 @@ fn build_worker_executor(
|
|||||||
if target_name == "manage_memos" {
|
if target_name == "manage_memos" {
|
||||||
let cp: serde_json::Value =
|
let cp: serde_json::Value =
|
||||||
serde_json::from_str(&target_args).unwrap_or_default();
|
serde_json::from_str(&target_args).unwrap_or_default();
|
||||||
if cp.get("action").and_then(|v| v.as_str()) == Some("add") {
|
if cp.get("action").and_then(|v| v.as_str()) == Some("add")
|
||||||
if let Some(content) = cp.get("content").and_then(|v| v.as_str()) {
|
&& let Some(content) = cp.get("content").and_then(|v| v.as_str()) {
|
||||||
shared
|
shared
|
||||||
.memories
|
.memories
|
||||||
.lock()
|
.lock()
|
||||||
@@ -287,7 +287,6 @@ fn build_worker_executor(
|
|||||||
.push(content.to_string());
|
.push(content.to_string());
|
||||||
shared.new_memories.lock().await.push(content.to_string());
|
shared.new_memories.lock().await.push(content.to_string());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return Ok(result.output);
|
return Ok(result.output);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user