Compare commits

...

4 Commits

Author SHA1 Message Date
Slavi Pantaleev
533b025f6b Release 1.1.1 2024-09-22 06:45:59 +00:00
Slavi Pantaleev
8b12bdf2b3 Combine consecutive messages by the same user when talking to the Anthropic API
Fixes https://github.com/etkecc/baibot/issues/13
2024-09-22 06:39:53 +00:00
Slavi Pantaleev
d4ddd29660 Upgrade mxlink to fix missing messages in threads
Reported here https://github.com/etkecc/baibot/issues/13#issuecomment-2365273996

Fixed in 88fabb308c
2024-09-22 09:35:15 +03:00
Slavi Pantaleev
941e5f0bc4 Use a cache-less Dockerfile for CI to try and avoid issues 2024-09-21 21:37:45 +03:00
8 changed files with 154 additions and 9 deletions

View File

@@ -53,3 +53,4 @@ jobs:
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
file: Dockerfile.ci

View File

@@ -1,6 +1,13 @@
# (2024-09-22) Version 1.1.1
- (**Bugfix**) Fix thread messages being lost due to lack of pagination support ([d4ddd29660](https://github.com/etkecc/baibot/commit/d4ddd29660d9f51d248119dd6032e68ab29e7d35)) - fixes [issue #13](https://github.com/etkecc/baibot/issues/13)
- (**Bugfix**) Fix Anthropic conversations getting stuck when being impatient and sending multiple consecutive messages ([8b12bdf2b3](https://github.com/etkecc/baibot/commit/8b12bdf2b3196abea0e8db33d7c50fff48341cb9)) - fixes [issue #13](https://github.com/etkecc/baibot/issues/13)
# (2024-09-21) Version 1.1.0
- (**Feature**) Adds support for [prompt variables](./docs/configuration/text-generation.md#️-prompt-override) (date/time, bot name, model id) ([2a5a2d6a4d](https://github.com/etkecc/baibot/commit/2a5a2d6a4dbf5fd7cb504ac07d4187fdc32ae395))
- (**Feature**) Adds support for [prompt variables](./docs/configuration/text-generation.md#️-prompt-override) (date/time, bot name, model id) ([2a5a2d6a4d](https://github.com/etkecc/baibot/commit/2a5a2d6a4dbf5fd7cb504ac07d4187fdc32ae395)) - fixes [issue #10](https://github.com/etkecc/baibot/issues/10)
- (**Improvement**) [Dockerfile](./Dockerfile) changes to produce ~20MB smaller container images ([354063abb7](https://github.com/etkecc/baibot/commit/354063abb79035069bd3b26c53214874e9cdd95d))

7
Cargo.lock generated
View File

@@ -297,7 +297,7 @@ dependencies = [
[[package]]
name = "baibot"
version = "1.1.0"
version = "1.1.1"
dependencies = [
"anthropic-rs",
"anyhow",
@@ -2132,14 +2132,13 @@ dependencies = [
[[package]]
name = "mxlink"
version = "1.2.1"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1aa513435471af3e1131dc18a1f4eb2e6fb42c11308f1be9b4f0316b3809e32"
checksum = "f5f7234edcd534b11daad1641a148b8bfcae417deb6e6bff564ae69b3d3c4678"
dependencies = [
"base64 0.22.1",
"chacha20poly1305",
"hex",
"js_int",
"matrix-sdk",
"mime",
"quick_cache",

View File

@@ -7,7 +7,7 @@ license = "AGPL-3.0-or-later"
readme = "README.md"
keywords = ["matrix", "chat", "bot", "AI", "LLM"]
include = ["/etc/assets/baibot-torso-768.png", "/src", "/README.md", "/CHANGELOG.md", "/LICENSE"]
version = "1.1.0"
version = "1.1.1"
edition = "2021"
[lib]
@@ -23,7 +23,7 @@ chrono = { version = "0.4.*", default-features = false, features = ["std", "now"
# We'd rather not depend on this, but we cannot use the ruma-events EventContent macro without it.
matrix-sdk = { version = "0.7.1", default-features = false }
mxidwc = "1.0.*"
mxlink = ">=1.2.1"
mxlink = ">=1.3.0"
etke_openai_api_rust = "0.1.*"
quick_cache = "0.6.*"
regex = "1.10.*"

35
Dockerfile.ci Normal file
View File

@@ -0,0 +1,35 @@
#######################################
# #
# Stage 1: building #
# #
#######################################
FROM docker.io/rust:1.81.0-slim-bookworm AS build
RUN apt-get update && apt-get install -y build-essential pkg-config libssl-dev libsqlite3-dev
WORKDIR /app
COPY . /app
RUN cargo build --release
#######################################
# #
# Stage 2: packaging #
# #
#######################################
FROM docker.io/debian:bookworm-slim
RUN apt-get update && apt-get install -y ca-certificates sqlite3 && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY --from=build /app/target/release/baibot .
ENTRYPOINT ["/bin/sh", "-c"]
CMD ["/app/baibot"]

View File

@@ -111,6 +111,15 @@ impl ControllerTrait for Controller {
})
};
// Avoid the situation where multiple user or assistant messages are sent consecutively,
// to avoid errors like:
// > API error: Error response: error Api error: invalid_request_error messages: roles must alternate between "user" and "assistant", but found multiple "user" roles in a row
// as reported here: https://github.com/etkecc/baibot/issues/13
//
// As https://docs.anthropic.com/en/api/messages says:
// > Our models are trained to operate on alternating user and assistant conversational turns.
let conversation = conversation.combine_consecutive_messages();
let mut conversation_messages = conversation.messages;
if params.context_management_enabled {

View File

@@ -15,3 +15,94 @@ pub struct Message {
pub struct Conversation {
pub messages: Vec<Message>,
}
impl Conversation {
/// Combine consecutive messages by the same author into a single message.
///
/// Certain models (like Anthropic) cannot tolerate consecutive messages by the same author,
/// so combining them helps avoid issues.
/// See: https://github.com/etkecc/baibot/issues/13
pub fn combine_consecutive_messages(&self) -> Conversation {
// We'll likely get fewer messages, but let's reserve the maximum we expect.
let mut new_messages = Vec::with_capacity(self.messages.len());
let mut last_seen_author: Option<Author> = None;
for message in &self.messages {
let Some(last_seen_author_clone) = last_seen_author.clone() else {
last_seen_author = Some(message.author.clone());
new_messages.push(message.clone());
continue;
};
if message.author != last_seen_author_clone {
last_seen_author = Some(message.author.clone());
new_messages.push(message.clone());
continue;
}
new_messages.last_mut().unwrap().message_text.push('\n');
new_messages
.last_mut()
.unwrap()
.message_text
.push_str(&message.message_text);
}
Conversation {
messages: new_messages,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn combine_consecutive_messages() {
let conversation = Conversation {
messages: vec![
Message {
author: Author::User,
message_text: "Hello".to_string(),
},
Message {
author: Author::User,
message_text: "How are you?".to_string(),
},
Message {
author: Author::User,
message_text: "I'm OK, btw.".to_string(),
},
Message {
author: Author::Assistant,
message_text: "Hi there!".to_string(),
},
Message {
author: Author::Assistant,
message_text: "I'm doing well, thank you.".to_string(),
},
Message {
author: Author::User,
message_text: "That's great!".to_string(),
},
],
};
let conversation = conversation.combine_consecutive_messages();
assert_eq!(conversation.messages.len(), 3);
assert_eq!(conversation.messages[0].author, Author::User);
assert_eq!(
conversation.messages[0].message_text,
"Hello\nHow are you?\nI'm OK, btw."
);
assert_eq!(conversation.messages[1].author, Author::Assistant);
assert_eq!(
conversation.messages[1].message_text,
"Hi there!\nI'm doing well, thank you."
);
assert_eq!(conversation.messages[2].author, Author::User);
assert_eq!(conversation.messages[2].message_text, "That's great!");
}
}

View File

@@ -13,7 +13,7 @@ use mxlink::matrix_sdk::{
},
Room,
};
use mxlink::{MatrixLink, ThreadInfo};
use mxlink::{MatrixLink, ThreadGetMessagesParams, ThreadInfo};
use super::{MatrixMessage, MatrixMessageProcessingParams, MatrixMessageType, RoomEventFetcher};
use crate::entity::{MessagePayload, ThreadContext, ThreadContextFirstMessage};
@@ -23,7 +23,10 @@ pub async fn get_matrix_messages_in_thread(
room: &Room,
thread_id: OwnedEventId,
) -> Result<Vec<MatrixMessage>, mxlink::matrix_sdk::Error> {
let messages_native = matrix_link.threads().get_messages(room, thread_id).await?;
let messages_native = matrix_link
.threads()
.get_messages(room, thread_id, ThreadGetMessagesParams::default())
.await?;
let mut messages: Vec<MatrixMessage> = Vec::new();