Skip to content

Commit

Permalink
feat(chat): Define initial messages on ChatScript (#34)
Browse files Browse the repository at this point in the history
  • Loading branch information
skarllot authored Jan 10, 2025
1 parent 0618b9b commit 4d78535
Show file tree
Hide file tree
Showing 8 changed files with 275 additions and 301 deletions.
10 changes: 10 additions & 0 deletions src/FlowPair/Chats/Models/ChatScript.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,20 @@ public sealed record ChatScript(
string Name,
ImmutableArray<string> Extensions,
string SystemInstruction,
ImmutableList<Message> InitialMessages,
ImmutableList<Instruction> Instructions)
{
public const string StopKeywordPlaceholder = "<NO FEEDBACK>";

public ChatScript(
string Name,
ImmutableArray<string> Extensions,
string SystemInstruction,
ImmutableList<Instruction> Instructions)
: this(Name, Extensions, SystemInstruction, [], Instructions)
{
}

public double TotalSteps => Instructions
.Aggregate(
(IEnumerable<double>) [0D],
Expand Down
91 changes: 31 additions & 60 deletions src/FlowPair/Chats/Models/ChatThread.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Collections.Immutable;
using Raiqub.LlmTools.FlowPair.Chats.Services;
using Raiqub.LlmTools.FlowPair.Common;
using Raiqub.LlmTools.FlowPair.Flow.Operations.ProxyCompleteChat;
using Spectre.Console;

Expand All @@ -24,89 +25,59 @@ public sealed record ChatThread(
LastMessage?.Role == SenderRole.Assistant &&
LastMessage.Content.Contains(StopKeyword, StringComparison.Ordinal);

public static string CreateStopKeyword() => $"<{Guid.NewGuid().ToString("N")[..8]}>";

public Result<ChatThread, string> RunStepInstruction(
Instruction.StepInstruction instruction,
IProxyCompleteChatHandler completeChatHandler)
{
try
{
if (IsInterrupted)
{
return this;
}

return AddMessages(instruction.ToMessage(StopKeyword))
.CompleteChat(completeChatHandler);
}
finally
{
Progress.Increment(1);
}
return
(IsInterrupted
? this
: AddMessages(instruction.ToMessage(StopKeyword))
.CompleteChat(completeChatHandler))
.DoBoth(_ => Progress.Increment(1));
}

public Result<ChatThread, string> RunMultiStepInstruction(
Instruction.MultiStepInstruction instruction,
int index,
IProxyCompleteChatHandler completeChatHandler)
{
try
{
if (IsInterrupted)
{
return this;
}

return AddMessages(instruction.ToMessage(index, StopKeyword))
.CompleteChat(completeChatHandler);
}
finally
{
Progress.Increment(1);
}
return
(IsInterrupted
? this
: AddMessages(instruction.ToMessage(index, StopKeyword))
.CompleteChat(completeChatHandler))
.DoBoth(_ => Progress.Increment(1));
}

public Result<ChatThread, string> RunJsonInstruction(
Instruction.JsonConvertInstruction instruction,
IProxyCompleteChatHandler completeChatHandler)
{
try
{
if (IsInterrupted)
{
return this;
}

return Enumerable.Range(0, MaxJsonRetries)
.TryAggregate(
AddMessages(instruction.ToMessage(StopKeyword)),
(chat, _) => chat.CompleteChatAndDeserialize(instruction.OutputKey, completeChatHandler));
}
finally
{
Progress.Increment(1);
}
return
(IsInterrupted
? this
: Enumerable.Range(0, MaxJsonRetries)
.TryAggregate(
AddMessages(instruction.ToMessage(StopKeyword)),
(chat, _) => chat.CompleteChatAndDeserialize(instruction.OutputKey, completeChatHandler)))
.DoBoth(_ => Progress.Increment(1));
}

public Result<ChatThread, string> RunCodeInstruction(
Instruction.CodeExtractInstruction instruction,
IProxyCompleteChatHandler completeChatHandler)
{
try
{
if (IsInterrupted)
{
return this;
}

return Enumerable.Range(0, MaxJsonRetries)
.TryAggregate(
AddMessages(instruction.ToMessage(StopKeyword)),
(chat, _) => chat.CompleteChatAndDeserialize(instruction.OutputKey, completeChatHandler));
}
finally
{
Progress.Increment(1);
}
return
(IsInterrupted
? this
: Enumerable.Range(0, MaxJsonRetries)
.TryAggregate(
AddMessages(instruction.ToMessage(StopKeyword)),
(chat, _) => chat.CompleteChatAndDeserialize(instruction.OutputKey, completeChatHandler)))
.DoBoth(_ => Progress.Increment(1));
}

private ChatThread AddMessages(params ReadOnlySpan<Message> newMessages) =>
Expand Down
5 changes: 5 additions & 0 deletions src/FlowPair/Chats/Models/ChatWorkspace.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ private Result<ChatWorkspace, string> RunMultiStepInstruction(
Instruction.MultiStepInstruction instruction,
IProxyCompleteChatHandler completeChatHandler)
{
if (ChatThreads.Count == 0)
{
return this;
}

if (ChatThreads.Count != 1)
{
return "Only one multi-step instruction is supported.";
Expand Down
15 changes: 14 additions & 1 deletion src/FlowPair/Chats/Services/ChatService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,19 @@ public sealed class ChatService(
ITempFileWriter tempFileWriter)
: IChatService
{
public Result<TResult, string> Run<TResult>(
Progress progress,
LlmModelType llmModelType,
IChatDefinition<TResult> chatDefinition)
where TResult : notnull
{
return Run(
progress,
llmModelType,
chatDefinition,
chatDefinition.ChatScript.InitialMessages);
}

public Result<TResult, string> Run<TResult>(
Progress progress,
LlmModelType llmModelType,
Expand Down Expand Up @@ -53,7 +66,7 @@ private Result<TResult, string> RunInternal<TResult>(
new ChatThread(
progress,
llmModelType,
$"<{Guid.NewGuid().ToString("N")[..8]}>",
ChatThread.CreateStopKeyword(),
[new Message(SenderRole.System, chatScript.SystemInstruction), ..initialMessages],
chatDefinition)
]);
Expand Down
30 changes: 30 additions & 0 deletions src/FlowPair/Common/FunctionalExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,36 @@ namespace Raiqub.LlmTools.FlowPair.Common;

public static class FunctionalExtensions
{
/// <summary>
/// Executes a side effect on a <see cref="Result{TOk,TErr}"/> regardless of its state and returns the original <see cref="Result{TOk,TErr}"/>.
/// </summary>
/// <typeparam name="TOk">The type of the value in case of success.</typeparam>
/// <typeparam name="TErr">The type of the error in case of failure.</typeparam>
/// <param name="result">The <see cref="Result{TOk,TErr}"/> to perform the side effect on.</param>
/// <param name="callback">The <see cref="Action{T}"/> to execute as a side effect.</param>
/// <returns>The original <see cref="Result{TOk,TErr}"/>, unmodified.</returns>
/// <remarks>
/// This method is useful for performing operations like logging or debugging without altering the <see cref="Result{TOk,TErr}"/>.
/// The <paramref name="callback"/> is executed regardless of whether the <see cref="Result{TOk,TErr}"/> is in a success or failure state.
/// </remarks>
/// <example>
/// <code>
/// var result = Ok&lt;int, string&gt;(42)
/// .DoBoth(r => Console.WriteLine($"Result state: {r.IsOk}"));
/// // Output: "Result state: True"
/// // result still contains Ok(42)
/// </code>
/// </example>
public static Result<TOk, TErr> DoBoth<TOk, TErr>(
this Result<TOk, TErr> result,
Action<Result<TOk, TErr>> callback)
where TOk : notnull
where TErr : notnull
{
callback(result);
return result;
}

/// <summary>
/// Returns a failure result if the predicate is false. Otherwise, returns a result with the specified value.
/// </summary>
Expand Down
3 changes: 3 additions & 0 deletions tests/FlowPair.Tests/Chats/Models/ChatScriptTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ public void TotalStepsShouldCalculateCorrectlyWithSingleStepInstructions()
Name: "TestScript",
Extensions: [".txt"],
SystemInstruction: "SystemInstruction",
InitialMessages: [],
Instructions:
[
new Instruction.StepInstruction("Message1"),
Expand All @@ -89,6 +90,7 @@ public void TotalStepsShouldCalculateCorrectlyWithMultiStepInstructions()
Name: "TestScript",
Extensions: [".txt"],
SystemInstruction: "SystemInstruction",
InitialMessages: [],
Instructions:
[
new Instruction.StepInstruction("Message1"),
Expand All @@ -113,6 +115,7 @@ public void TotalStepsShouldCalculateCorrectlyWithSingleAfterMultiStepInstructio
Name: "TestScript",
Extensions: [".txt"],
SystemInstruction: "SystemInstruction",
InitialMessages: [],
Instructions:
[
new Instruction.StepInstruction("Message1"),
Expand Down
Loading

0 comments on commit 4d78535

Please sign in to comment.