Skip to content

Commit

Permalink
Merge pull request #15 from Marco-Zechner/13-tool-calls
Browse files Browse the repository at this point in the history
# 13 tool calls - 3 Commit-Merge

## 1 Refactored Project
Sorted the Files in the Project
Moved each used Class into their own File
Redefined the IntegrationTests for ToolUsage
Wrote Usage Tutorial in the IntegrationTest
Added missing Models required for ToolCalls
Added Attributes to define Tools
Added Framework to Recognize and Call Methods as Tools
Refactored the InstanceToolsManager

## 2 Cleaned up Implementation Test
Renamed Attributes to consistent Pattern
Refactored InstanceToolsManager and named the inherited Class InstanceToolsBase
removed readonly modifier in GPTModel
Complete Add/Remove Tool and ToolClass
Extracted HelperMethods. (Better naming required!)
**(disabled)** Added Experimental Implementation of Instance Management Tools 

## 3 Finished static Tool Implementation
Improved the static tool example in the Implementation Test even more.
Changed some namespaces so the user must import less
Added a Timestamp field to ChatResponse for later use in streaming
Improved PropertyAccess enum
Added possibility to disable tool-usage per completion
Reworked ToolNaming pattern and removed Enum as a valid Tool Parameter Type for now
Added additional Completion Methods to use for streaming later.
  • Loading branch information
Marco-Zechner authored Jun 23, 2024
2 parents 7c230e3 + a5e6a89 commit 4edcd53
Show file tree
Hide file tree
Showing 50 changed files with 1,932 additions and 504 deletions.
289 changes: 235 additions & 54 deletions OpenAI.ChatGPT.Net.IntegrationTests/AddTools.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,34 +1,19 @@
using OpenAI.ChatGPT.Net.DataModels;
using OpenAI.ChatGPT.Net.Tools;
using OpenAI.ChatGPT.Net.Exeptions;
using OpenAI.ChatGPT.Net.IntegrationTests.Handlers;
using OpenAI.ChatGPT.Net.Interfaces;

namespace OpenAI.ChatGPT.Net.IntegrationTests
{
public class ConversationWithCustomHandlers
{
public static async Task Run()
{
static string PrintPayloadHandler(string payload)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Payload:");
Console.WriteLine(payload);
Console.ResetColor();
return payload;
}

static string PrintResponseHandler(string response)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("Response:");
Console.WriteLine(response);
Console.ResetColor();
return response;
}

GPTModel model = new("f", APIKey.KEY)
{
PayloadHandler = PrintPayloadHandler,
ResponseHandler = PrintResponseHandler,
PayloadHandler = JsonDebugHandlers.PrintPayloadHandler,
ResponseHandler = JsonDebugHandlers.PrintResponseHandler,
Logprobs = true,
TopLogprobs = 2
};
Expand All @@ -41,11 +26,11 @@ static string PrintResponseHandler(string response)

Console.Write($"{ChatRole.User}: ");
ChatMessage initialMessage = new(ChatRole.User, Console.ReadLine());
List<ChatMessage> messageHistory = [initialMessage];
List<IMessage> messageHistory = [initialMessage];

while (true)
{
ChatResponse response = await model.Complete(messageHistory);
ChatResponse response = await model.CompletionAsync(messageHistory);
ChatMessage message;
try {
message = (ChatMessage)response; // This will throw an exception if the response is an error
Expand Down
23 changes: 23 additions & 0 deletions OpenAI.ChatGPT.Net.IntegrationTests/Handlers/JsonDebugHandlers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace OpenAI.ChatGPT.Net.IntegrationTests.Handlers
{
public class JsonDebugHandlers
{
public static string PrintPayloadHandler(string payload)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Payload:");
Console.WriteLine(payload);
Console.ResetColor();
return payload;
}

public static string PrintResponseHandler(string response)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("Response:");
Console.WriteLine(response);
Console.ResetColor();
return response;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
using OpenAI.ChatGPT.Net.Tools;
using OpenAI.ChatGPT.Net.InstanceTools;

namespace OpenAI.ChatGPT.Net.IntegrationTests.Tools
namespace OpenAI.ChatGPT.Net.IntegrationTests.InstanceTools
{
[InstanceDescription("Instance of a Car")]
public class InstanceToolCar(string carName, int horsePower, string producer) : InstanceToolsManager<InstanceToolCar>(carName)
[GPT_Description("Instance of a Car")]
public class CarInstance(string carName, int horsePower, string producer) : InstanceToolsBase<CarInstance>(carName)
{
public int horsePower = horsePower;
public string producer = producer;
public int fuel = 0;
public bool isOn = false;
public bool isOn { get; set; } = false;

public InstanceToolCar() : this("CarInstanceExample", 0, "ExampleProducer") { }
public CarInstance() : this("CarInstanceExample", 0, "ExampleProducer") { }

public CarInstance(int horsePower) : this("TestCar", horsePower, "TestProducer") { }

public int FuelUp(int fuelAmount)
{
return fuel += fuelAmount;
}
}

public int FuelUp(double fuelAmount)
{
return fuel += (int)fuelAmount;
}
}

public bool TurnOn(bool setOn)
{
return isOn = setOn;
Expand Down
6 changes: 4 additions & 2 deletions OpenAI.ChatGPT.Net.IntegrationTests/SimpleConversationTest.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using OpenAI.ChatGPT.Net.DataModels;
using OpenAI.ChatGPT.Net.Tools;
using OpenAI.ChatGPT.Net.Exeptions;
using OpenAI.ChatGPT.Net.Interfaces;

namespace OpenAI.ChatGPT.Net.IntegrationTests
{
Expand All @@ -11,13 +13,13 @@ public static async Task Run()

Console.Write($"{ChatRole.User}: ");
ChatMessage initialMessage = new(ChatRole.User, Console.ReadLine());
List<ChatMessage> messageHistory = [initialMessage];
List<IMessage> messageHistory = [initialMessage];

try
{
while (true)
{
ChatResponse response = await model.Complete(messageHistory);
ChatResponse response = await model.CompletionAsync(messageHistory);

ChatMessage message = (ChatMessage)response;
Console.WriteLine(message);
Expand Down
5 changes: 3 additions & 2 deletions OpenAI.ChatGPT.Net.IntegrationTests/SingleCompletionTest.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using OpenAI.ChatGPT.Net.DataModels;
using OpenAI.ChatGPT.Net.Tools;

namespace OpenAI.ChatGPT.Net.IntegrationTests
{
Expand All @@ -13,7 +14,7 @@ public static async Task Run()

ChatMessage initialMessage = new(ChatRole.User, "How are you?");

ChatResponse response = await model.Complete(initialMessage);
ChatResponse response = await model.CompletionAsync(initialMessage);

if (response.Error != null)
{
Expand All @@ -30,7 +31,7 @@ public static async Task TotalMin()

GPTModel model = new("gpt-4o", APIKey.KEY);
ChatMessage initialMessage = new(ChatRole.User, input);
ChatResponse response = await model.Complete(initialMessage);
ChatResponse response = await model.CompletionAsync(initialMessage);

Console.WriteLine((ChatMessage)response);
}
Expand Down
29 changes: 29 additions & 0 deletions OpenAI.ChatGPT.Net.IntegrationTests/Tools/LockedClass.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using OpenAI.ChatGPT.Net.Tools;

namespace OpenAI.ChatGPT.Net.IntegrationTests.Tools
{
/// <summary>
/// Methods of a Class locked with [<see cref="GPT_Locked"/>] can't be used by GPT even if you attempt to add them.
/// </summary>
[GPT_Locked]
internal class LockedClass
{
public static void NonToolMethods1() { }

public static void NonToolMethods2() { }

public static void NonToolMethods3() { }
}

internal class AllLockedClass
{
[GPT_Locked]
public static void NonToolMethods1() { }

[GPT_Locked]
public static void NonToolMethods2() { }

[GPT_Locked]
public static void NonToolMethods3() { }
}
}
15 changes: 13 additions & 2 deletions OpenAI.ChatGPT.Net.IntegrationTests/Tools/MyToolClass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ namespace OpenAI.ChatGPT.Net.IntegrationTests.Tools
/// </summary>
public class MyToolClass
{
public static int MyField;
[GPT_Data]
public static int MyProperty { get; set; }

[GPT_Data]
public static int MyProperty2 { get; private set; }

[GPT_Data(PropertyAccess.Getter)]
public static int MyProperty3 { get; set; }


public static string Tool1() => "Tool1";

public static string Tool2() => "Tool2";
Expand All @@ -30,10 +41,10 @@ public static string RemovedTool()
}

/// <summary>
/// Methods locked with [<see cref="GPTLcckMethod"/>] can't be used by GPT even if you attempt to add them.
/// Methods locked with [<see cref="GPT_Locked"/>] can't be used by GPT even if you attempt to add them.
/// </summary>
/// <returns></returns>
[GPTLockMethod]
[GPT_Locked]
public static string LockedMethod() => "LockedMethod executed";


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,64 +2,68 @@

namespace OpenAI.ChatGPT.Net.IntegrationTests.Tools
{
/// <summary>
/// This class has the Attribute [<see cref="GPTAttributeFiltered"/>]
/// which will filter out all methods that do not have the [<see cref="GPTTool"/>]
/// or [<see cref="GPTParemeters"/>] attribute.
/// <para/>Class containing tools must be public
/// </summary>
[GPTAttributeFiltered]
[GPT_Locked]
public class MyToolClassWithAttributes
{
/// <summary>
/// This Method will not be added by the
/// <code>.AddToolClass&lt;<see cref="MyToolClassWithAttributes"/>&gt;();</code>
/// because this class has the [<see cref="GPTAttributeFiltered"/>] Attribute which filters this method out.
/// because this class has the [<see cref="GPT_Locked"/>] Attribute which lockes all methods per default.
/// </summary>
public static string MethodWithoutAttribute() => "This shoul not be included in the tools";

/// <summary>
/// [<see cref="GPTTool"/>] Provides a Description for GPT of this method
/// [<see cref="GPT_Tool"/>] Provides a Description for GPT of this method
/// <code>
/// [GPTTool("This is the Tool1")]
/// public static string Tool1() => "Tool1";
/// </code>
/// </summary>
[GPTTool("This is the Tool1")]
[GPT_Tool]
[GPT_Description("This is the Tool1")]
public static string Tool1() => "Tool1";

/// <summary>
/// [<see cref="GPTParameters"/>] Provides a Description of the parameters for GPT of this method
/// [<see cref="GPT_Parameters"/>] Provides a Description of the parameters for GPT of this method
/// Note that this code:
/// <code>[GPTParameters(parameter1: "This is a number", parameter2: "This is a useless parameter description that will be ignored")]
/// public static string Tool2(int size) => "Tool2";
/// </code>
/// will not produce an error even tough a parameter is decribed that isn't there.
/// This description will just be ignored.
/// will not produce an error even tough a parameter is decribed, that isn't there.
/// The description of that parameter will just be ignored.
/// </summary>
[GPTParameters("This is a number", "This is a useless parameter description that will be ignored")]
[GPT_Tool]
[GPT_Parameters("This is a number", "This is a useless parameter description that will be ignored")]
public static string Tool2(int size) => "Tool2";

/// <summary>
/// Full example with [<see cref="GPTTool"/>] and [<see cref="GPTParameters"/>]
/// Full example with [<see cref="GPT_Tool"/>] and [<see cref="GPT_Parameters"/>]
/// <code>
/// [GPTTool("This is the Tool3")]
/// [GPTParameters(parameter1: "This is a number")]
/// public static string Tool3(int number) => "Tool3";
/// </code>
/// </summary>
[GPTTool("This is the Tool3")]
[GPTParameters("This is a number")]
[GPT_Tool]
[GPT_Description("This is the Tool3")]
[GPT_Parameters("This is a number")]
public static string Tool3(int number) => "Tool3";

/// <summary>
/// Non static Methods can't be used by GPT and can't have GPT Attributes
/// This Method will not be added by the
/// <code>.AddToolClass&lt;<see cref="MyToolClassWithAttributes"/>&gt;();</code>
/// because this class has the [<see cref="GPT_Locked"/>] Attribute which lockes all methods per default.
/// </summary>
public void NonStaticMethod() { }

/// <summary>
/// Non public Methods can't be used by GPT and can't have GPT Attribute
/// </summary>
private static void PrivateMethod() { }
private static void PrivateMethod1() { }

/// <summary>
/// Non public Methods can't be used by GPT and can't have GPT Attribute
/// </summary>
private void PrivateMethod2() { }
}
}
14 changes: 14 additions & 0 deletions OpenAI.ChatGPT.Net.IntegrationTests/Tools/MyTools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,20 @@ public class MyTools
/// <param name="use24h"></param>
/// <returns></returns>
public static string GetTime(int timeZoneOffset, bool use24h)
{
var time = DateTime.UtcNow.AddHours(timeZoneOffset);
return use24h ? time.ToString("HH:mm") : time.ToString("hh:mm tt");
}

// Overload with different JSON types
public static string GetTime2(float timeZoneOffset, bool use24h)
{
var time = DateTime.UtcNow.AddHours(timeZoneOffset);
return use24h ? time.ToString("HH:mm") : time.ToString("hh:mm tt");
}

// Overload with same JSON types
public static string GetTime2(double timeZoneOffset, bool use24h)
{
var time = DateTime.UtcNow.AddHours(timeZoneOffset);
return use24h ? time.ToString("HH:mm") : time.ToString("hh:mm tt");
Expand Down
17 changes: 0 additions & 17 deletions OpenAI.ChatGPT.Net.IntegrationTests/Tools/NonToolMethods.cs

This file was deleted.

8 changes: 8 additions & 0 deletions OpenAI.ChatGPT.Net/Attributes/GPT_Data.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace OpenAI.ChatGPT.Net.Tools
{
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class GPT_Data(PropertyAccess propertyAccess = PropertyAccess.Both) : Attribute
{
public PropertyAccess PropertyAccess { get; } = propertyAccess;
}
}
8 changes: 8 additions & 0 deletions OpenAI.ChatGPT.Net/Attributes/GPT_Description.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace OpenAI.ChatGPT.Net.Tools
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class GPT_Description(string descriptionForAPI) : Attribute
{
public string DescriptionForAPI { get; } = descriptionForAPI;
}
}
7 changes: 7 additions & 0 deletions OpenAI.ChatGPT.Net/Attributes/GPT_Locked.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace OpenAI.ChatGPT.Net.Tools
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public class GPT_Locked : Attribute
{
}
}
8 changes: 8 additions & 0 deletions OpenAI.ChatGPT.Net/Attributes/GPT_Parameters.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace OpenAI.ChatGPT.Net.Tools
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class GPT_Parameters(params string[] descriptionsForAPI) : Attribute
{
public string[] DescriptionsForAPI { get; } = descriptionsForAPI;
}
}
7 changes: 7 additions & 0 deletions OpenAI.ChatGPT.Net/Attributes/GPT_Tool.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace OpenAI.ChatGPT.Net.Tools
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class GPT_Tool() : Attribute
{
}
}
Loading

0 comments on commit 4edcd53

Please sign in to comment.