Feature/gpt5 by selfdocumentingcode · Pull Request #328 · selfdocumentingcode/Kattbot · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/release-v2.yml
28 changes: 19 additions & 9 deletions src/Kattbot.Common/Models/KattGpt/ChatCompletionCreateRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,22 @@ public record ChatCompletionCreateRequest
public bool? Stream { get; set; }

/// <summary>
/// Gets or sets the maximum number of tokens to generate in the chat completion.
/// The total length of input tokens and generated tokens is limited by the model's context length.
/// An upper bound for the number of tokens that can be generated for a completion,
/// including visible output tokens and reasoning tokens.
/// Defaults to inf.
/// https://platform.openai.com/docs/api-reference/chat/create#chat/create-max_tokens.
/// https://platform.openai.com/docs/api-reference/chat/create#chat_create-max_completion_tokens
/// </summary>
[JsonPropertyName("max_tokens")]
public int? MaxTokens { get; set; }
[JsonPropertyName("max_completion_tokens")]
public int? MaxCompletionTokens { get; set; }

/// <summary>
/// Constrains effort on reasoning for reasoning models.
/// Currently supported values are minimal, low, medium, and high
/// Defaults to medium.
/// https://platform.openai.com/docs/api-reference/chat/create#chat_create-reasoning_effort
/// </summary>
[JsonPropertyName("reasoning_effort")]
public string? ReasoningEffort { get; set; }

/// <summary>
/// Gets or sets number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the
Expand All @@ -130,9 +139,10 @@ public record ChatCompletionCreateRequest
public float? FrequencyPenalty { get; set; }

/// <summary>
/// Gets or sets a unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse.
/// https://platform.openai.com/docs/api-reference/chat/create#chat/create-user.
/// A stable identifier used to help detect users of your application that may be violating OpenAI's
/// usage policies. The IDs should be a string that uniquely identifies each user.
/// https://platform.openai.com/docs/api-reference/chat/create#chat_create-safety_identifier
/// </summary>
[JsonPropertyName("user")]
public string? User { get; set; }
[JsonPropertyName("safety_identifier")]
public string? SafetyIdentifier { get; set; }
}
5 changes: 5 additions & 0 deletions src/Kattbot/Helpers/DiscordExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -69,8 +70,12 @@ public static string SubstituteMentions(this DiscordMessage message)
newMessageContent = newMessageContent.Replace(role.Mention, role.Name);
}

ArgumentNullException.ThrowIfNull(message);
ArgumentNullException.ThrowIfNull(message.MentionedChannels);
foreach (DiscordChannel channel in message.MentionedChannels)
{
ArgumentNullException.ThrowIfNull(channel.Mention);
ArgumentNullException.ThrowIfNull(channel.Name);
newMessageContent = newMessageContent.Replace(channel.Mention, $"#{channel.Name}");
}

Expand Down
14 changes: 7 additions & 7 deletions src/Kattbot/Kattbot.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="9.0.9" />
<PackageReference Include="TiktokenSharp" Version="1.1.8" />
<PackageReference Include="CommandLineArgumentsParser" Version="3.0.23" />
<PackageReference Include="DSharpPlus" Version="5.0.0-nightly-02538" />
<PackageReference Include="DSharpPlus.CommandsNext" Version="5.0.0-nightly-02538" />
<PackageReference Include="DSharpPlus.Interactivity" Version="5.0.0-nightly-02538" />
<PackageReference Include="MediatR" Version="13.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.9" />
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="9.0.9" />
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.9" />
<PackageReference Include="DSharpPlus" Version="5.0.0-nightly-02542" />
<PackageReference Include="DSharpPlus.CommandsNext" Version="5.0.0-nightly-02542" />
<PackageReference Include="DSharpPlus.Interactivity" Version="5.0.0-nightly-02542" />
<PackageReference Include="MediatR" Version="[12.5.0, 13)" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.8" />
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="9.0.8" />
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.8" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.11" />
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.7" />
Expand Down
66 changes: 18 additions & 48 deletions src/Kattbot/NotificationHandlers/KattGptMessageHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ namespace Kattbot.NotificationHandlers;
public class KattGptMessageHandler : BaseNotificationHandler,
INotificationHandler<MessageCreatedNotification>
{
private const string ChatGptModel = "gpt-4o";
private const string TokenizerModel = "gpt-4o";
private const string ChatGptModel = "gpt-5";
private const string TokenizerModel = "gpt-5";
private const string DefaultReasoningEffort = "minimal";

private const float DefaultTemperature = 1.1f;
private const int MaxTotalTokens = 24_576;
private const int MaxTokensToGenerate = 960; // Roughly the limit of 2 Discord messages

private const string MessageSplitToken = "[cont.] ";
private const string RecipientMarkerToYou = "[to you]";
private const string RecipientMarkerToOthers = "[to others]";

private const string MessageToolUseTemplate = "`Kattbot used: {0}`";

private const string GptImageModel = "gpt-image-1";
Expand Down Expand Up @@ -85,26 +85,16 @@ public async Task Handle(MessageCreatedNotification notification, CancellationTo
systemPromptsMessages,
chatCompletionFunction);

bool shouldReplyToMessage = ShouldReplyToMessage(message);

string recipientMarker = shouldReplyToMessage
? RecipientMarkerToYou
: RecipientMarkerToOthers;

// Add the new message from notification
string newMessageUser = author.GetDisplayName();
string newMessageContent = message.SubstituteMentions();

ChatCompletionMessage newUserMessage =
ChatCompletionMessage.AsUser($"{newMessageUser}{recipientMarker}: {newMessageContent}");
ChatCompletionMessage.AsUser($"{newMessageUser}: {newMessageContent}");

newContextMessages.Add(newUserMessage);

if (!shouldReplyToMessage)
{
channelContext.AddMessages(newContextMessages);
return;
}
channelContext.AddMessages(newContextMessages);

await channel.TriggerTypingAsync();

Expand Down Expand Up @@ -142,8 +132,12 @@ public async Task Handle(MessageCreatedNotification notification, CancellationTo
}
catch (Exception ex)
{
await SendTextReply($"Something went wrong: {ex.Message}", message);
_discordErrorLogger.LogError(ex.Message);
if (ex is not NullReferenceException)
{
await SendTextReply($"Something went wrong: {ex.Message}", message);
}

_discordErrorLogger.LogError(ex, ex.Message);
}
}

Expand Down Expand Up @@ -172,8 +166,8 @@ private static ChatCompletionCreateRequest BuildRequest(
{
Model = ChatGptModel,
Messages = requestMessages.ToArray(),
Temperature = DefaultTemperature,
MaxTokens = MaxTokensToGenerate,
MaxCompletionTokens = MaxTokensToGenerate,
ReasoningEffort = DefaultReasoningEffort,
Tools = chatCompletionTools,
ParallelToolCalls = parallelToolCalls,
};
Expand Down Expand Up @@ -343,7 +337,7 @@ private KattGptChannelContext GetOrCreateCachedContext(

int remainingTokensForContextMessages = MaxTotalTokens - MaxTokensToGenerate - reservedTokenCount;

var tokenizer = new KattGptTokenizer(ChatGptModel);
var tokenizer = new KattGptTokenizer(TokenizerModel);

channelContext = new KattGptChannelContext(remainingTokensForContextMessages, tokenizer);

Expand Down Expand Up @@ -375,31 +369,7 @@ private bool ShouldHandleMessage(DiscordMessage message)

if (channelOptions == null) return false;

// if the channel is not always on, handle the message
if (!channelOptions.AlwaysOn) return true;

// otherwise check if the message does not start with the MetaMessagePrefix
string[] metaMessagePrefixes = _kattGptOptions.AlwaysOnIgnoreMessagePrefixes;
bool messageStartsWithMetaMessagePrefix = metaMessagePrefixes.Any(messageContent.StartsWith);

// if it does, return false
return !messageStartsWithMetaMessagePrefix;
}

/// <summary>
/// Checks if KattGpt should reply to the message.
/// </summary>
/// <param name="message">The message.</param>
/// <returns>True if KattGpt should reply.</returns>
private bool ShouldReplyToMessage(DiscordMessage message)
{
DiscordChannel channel = message.Channel!;

ChannelOptions? channelOptions = _kattGptService.GetChannelOptions(channel);

if (channelOptions == null) return false;

// if the channel is not always on
// if the channel is not always on i.e. requires @mention or Reply
if (!channelOptions.AlwaysOn)
{
// check if the current message is a reply to kattbot
Expand All @@ -415,7 +385,7 @@ private bool ShouldReplyToMessage(DiscordMessage message)

// otherwise check if the message does not start with the MetaMessagePrefix
string[] metaMessagePrefixes = _kattGptOptions.AlwaysOnIgnoreMessagePrefixes;
bool messageStartsWithMetaMessagePrefix = metaMessagePrefixes.Any(message.Content.TrimStart().StartsWith);
bool messageStartsWithMetaMessagePrefix = metaMessagePrefixes.Any(messageContent.StartsWith);

// if it does, return false
return !messageStartsWithMetaMessagePrefix;
Expand Down
17 changes: 6 additions & 11 deletions src/Kattbot/appsettings.Development.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,30 +11,25 @@
"ConnectionString": "Server=host.docker.internal:5433;Database=kattbot-dev;User Id=kattbot;Password=hunter2",
"CommandPrefix": "!",
"AlternateCommandPrefix": "kd",
"ErrorLogGuildId": "753161640496857149",
"ErrorLogChannelId": "821763830577102848"
"ErrorLogGuildId": "1411437458062835809",
"ErrorLogChannelId": "1411441087997808750"
},
"KattGpt": {
"GuildOptions": [
{
"Name": "The Cozy Climber Cat Tower",
"Id": "753161640496857149",
"Id": "1411437458062835809",
"CategoryOptions": [
{
"_name": "KattGpt-dev",
"Id": "1124778131753025636",
"FallbackToChannelTopic": true
},
{
"_name": "Hobbies-Dev",
"Id": "1124778516991463464",
"Id": "1411440609046171728",
"FallbackToChannelTopic": true
}
],
"ChannelOptions": [
{
"_name": "gpt-always-on",
"Id": "1080612733222920332",
"Id": "1411440430817742888",
"Topic": "lolcat or lolspeak",
"SystemPrompts": [
"- In this channel all the users, including you, must write in lolcat.",
Expand All @@ -45,7 +40,7 @@
},
{
"_name": "norsk-test",
"Id": "1158017236070576210",
"Id": "1411440848918548541",
"Topic": "Norwegian culture and the Norwegian language",
"SystemPrompts": [
"- In this channel all the users, including you, must write in Norwegian.",
Expand Down
15 changes: 8 additions & 7 deletions src/Kattbot/appsettings.json