diff --git a/OpenAI_API/ApiResultBase.cs b/OpenAI_API/ApiResultBase.cs index 4bcba5f..fcba3b5 100644 --- a/OpenAI_API/ApiResultBase.cs +++ b/OpenAI_API/ApiResultBase.cs @@ -12,7 +12,7 @@ abstract public class ApiResultBase /// The time when the result was generated [JsonIgnore] - public DateTime? Created => CreatedUnixTime.HasValue ? (DateTime?)(DateTimeOffset.FromUnixTimeSeconds(CreatedUnixTime.Value).DateTime) : null; + public DateTime? Created => ConvertUnixTime(CreatedUnixTime); /// /// The time when the result was generated in unix epoch format @@ -55,5 +55,21 @@ abstract public class ApiResultBase /// [JsonIgnore] public string OpenaiVersion { get; internal set; } + + /// + /// Converts Unix time. + /// + /// + /// + /// The Unix time. + /// + /// + /// + /// The converted Unix time. + /// + protected static DateTime? ConvertUnixTime(long? unixTime) + { + return unixTime.HasValue ? (DateTime?) DateTimeOffset.FromUnixTimeSeconds(unixTime.Value).DateTime : null; + } } } \ No newline at end of file diff --git a/OpenAI_API/Assistants/AssistantFileRequest.cs b/OpenAI_API/Assistants/AssistantFileRequest.cs new file mode 100644 index 0000000..cdc9328 --- /dev/null +++ b/OpenAI_API/Assistants/AssistantFileRequest.cs @@ -0,0 +1,17 @@ +using Newtonsoft.Json; + +namespace OpenAI_API.Assistants +{ + /// + /// Represents a request to create an assistant file. + /// + public class AssistantFileRequest + { + /// + /// A file ID (with purpose="assistants") that the assistant should use. Useful for tools like + /// retrieval and code_interpreter that can access files. + /// + [JsonProperty("file_id")] + public string FileId { get; set; } + } +} \ No newline at end of file diff --git a/OpenAI_API/Assistants/AssistantFileResult.cs b/OpenAI_API/Assistants/AssistantFileResult.cs new file mode 100644 index 0000000..a86a675 --- /dev/null +++ b/OpenAI_API/Assistants/AssistantFileResult.cs @@ -0,0 +1,35 @@ +using System; +using Newtonsoft.Json; + +namespace OpenAI_API.Assistants +{ + /// + /// Represents a file that is attached to an assistant. + /// + public class AssistantFileResult : ApiResultBase + { + /// + /// The identifier, which can be referenced in API endpoints. + /// + [JsonProperty("id")] + public string Id { get; set; } + + /// + /// The Unix timestamp (in seconds) for when the assistant file was created. + /// + [JsonProperty("created_at")] + public long? CreatedAtUnixTime { get; set; } + + /// + /// The timestamp for when the assistant file was created. + /// + [JsonIgnore] + public DateTime? CreatedAt => ConvertUnixTime(CreatedAtUnixTime); + + /// + /// The ID of the assistant this file is attached to. + /// + [JsonProperty("assistant_id")] + public string AssistantId { get; set; } + } +} \ No newline at end of file diff --git a/OpenAI_API/Assistants/AssistantRequest.cs b/OpenAI_API/Assistants/AssistantRequest.cs new file mode 100644 index 0000000..f828aec --- /dev/null +++ b/OpenAI_API/Assistants/AssistantRequest.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; +using OpenAI_API.Common; + +namespace OpenAI_API.Assistants +{ + /// + /// Represents a request to create an assistant. + /// + public class AssistantRequest : MetadataRequest + { + /// + /// The ID of the model to use. + /// + [JsonProperty("model")] + public string Model { get; set; } + + /// + /// The name of the assistant. The maximum length is 256 characters. + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// The description of the assistant. The maximum length is 512 characters. + /// + [JsonProperty("description")] + public string Description { get; set; } + + /// + /// The system instructions that the assistant uses. The maximum length is 32768 characters. + /// + [JsonProperty("instructions")] + public string Instructions { get; set; } + + /// + /// A list of tools enabled on the assistant. There can be a maximum of 128 tools per assistant. Tools can be + /// be of types code_interpreter, retrieval or function. + /// + [JsonProperty("tools")] + public IList Tools { get; set; } = Array.Empty(); + + /// + /// A list of file IDs attached to the assistant. This can be useful for storing additional information about + /// the object in a structured format. Keys can be a maximum of 64 characters long and values can be a maximum + /// of 512 characters long. + /// + [JsonProperty("file_ids")] + public IList FileIds { get; set; } = Array.Empty(); + } +} \ No newline at end of file diff --git a/OpenAI_API/Assistants/AssistantResult.cs b/OpenAI_API/Assistants/AssistantResult.cs new file mode 100644 index 0000000..50d7312 --- /dev/null +++ b/OpenAI_API/Assistants/AssistantResult.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace OpenAI_API.Assistants +{ + /// + /// Represents an assistant that can call the model and use tools. + /// + public class AssistantResult : ApiResultBase + { + /// + /// The identifier, which can be referenced in API endpoints. + /// + [JsonProperty("id")] + public string Id { get; set; } + + /// + /// The Unix timestamp (in seconds) for when the assistant was created. + /// + [JsonProperty("created_at")] + public long? CreatedAtUnixTime { get; set; } + + /// + /// The timestamp for when the assistant was created. + /// + [JsonIgnore] + public DateTime? CreatedAt => ConvertUnixTime(CreatedAtUnixTime); + + /// + /// The name of the assistant. The maximum length is 256 characters. + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// The description of the assistant. The maximum length is 512 characters. + /// + [JsonProperty("description")] + public string Description { get; set; } + + /// + /// The system instructions that the assistant uses. The maximum length is 32768 characters. + /// + [JsonProperty("instructions")] + public string Instructions { get; set; } + + /// + /// A list of tools enabled on the assistant. There can be a maximum of 128 tools per assistant. Tools can be of + /// types code_interpreter, retrieval or function. + /// + [JsonProperty("tools")] + public IReadOnlyList Tools { get; set; } + + /// + /// A list of file IDs attached to this assistant. There can be a maximum of 20 files attached to an assistant. + /// Files are ordered by their creation date in ascending order. + /// + [JsonProperty("file_ids")] + public IReadOnlyList FileIds { get; set; } + + /// + /// Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional + /// information about the object in a structured format. Keys can be a maximum of 64 characters long and values + /// can be a maximum of 512 characters long. + /// + [JsonProperty("metadata")] + public IReadOnlyDictionary Metadata { get; set; } + } +} \ No newline at end of file diff --git a/OpenAI_API/Assistants/AssistantTool.cs b/OpenAI_API/Assistants/AssistantTool.cs new file mode 100644 index 0000000..470bf7e --- /dev/null +++ b/OpenAI_API/Assistants/AssistantTool.cs @@ -0,0 +1,65 @@ +using System.Runtime.Serialization; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Linq; + +namespace OpenAI_API.Assistants +{ + /// + /// Represents a tool that an assistant can use. + /// + public class AssistantTool + { + /// + /// The type of tool being defined. + /// + [JsonProperty("type")] + [JsonConverter(typeof(StringEnumConverter))] + public AssistantToolType Type { get; set; } + + /// + /// The function of the tool being defined. Only present if is . + /// + [JsonProperty("function")] + public AssistantToolFunction Function { get; set; } + } + + /// + /// Represents a function of a tool that an assistant can use. + /// + public class AssistantToolFunction + { + /// + /// The name of the function to be called. Must be a-z, A-Z, 0-9, or contain underscores and dashes, with a + /// minimum length of 64. + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// A description of what the function does. Used by the model to choose when and how to call the function. + /// + [JsonProperty("description")] + public string Description { get; set; } + + /// + /// The parameters the functions accepts, described as a JSON Schema object. See the guide for examples, and the + /// JSON Schema reference for documentation about the format. + /// + /// + /// Omitting parameters defines a function with an empty parameter list. + /// + [JsonProperty("parameters")] + public JObject Parameters { get; set; } + } + + /// + /// Enumerates the types of assistant tools. + /// + public enum AssistantToolType + { + [EnumMember(Value = "code_interpreter")] CodeInterpreter, + [EnumMember(Value = "retrieval")] Retrieval, + [EnumMember(Value = "function")] Function + } +} \ No newline at end of file diff --git a/OpenAI_API/Assistants/AssistantsEndpoint.cs b/OpenAI_API/Assistants/AssistantsEndpoint.cs new file mode 100644 index 0000000..341800d --- /dev/null +++ b/OpenAI_API/Assistants/AssistantsEndpoint.cs @@ -0,0 +1,107 @@ +using System.Threading.Tasks; +using Newtonsoft.Json; +using OpenAI_API.Common; + +namespace OpenAI_API.Assistants +{ + /// + /// The endpoint for the Assistants API. + /// + public class AssistantsEndpoint : EndpointBase, IAssistantsEndpoint + { + /// + /// The name of the endpoint, which is the final path segment in the API URL. + /// + protected override string Endpoint => "assistants"; + + /// + /// Constructs a new . + /// + /// + /// + /// The instance to use for making requests. + /// + public AssistantsEndpoint(OpenAIAPI api) : base(api) { } + + /// + public async Task CreateAssistant(AssistantRequest request) + { + return await HttpPost(Url, request); + } + + /// + public async Task CreateAssistantFile(string assistantId, AssistantFileRequest request) + { + var url = $"{Url}/{assistantId}/files"; + + return await HttpPost(url, request); + } + + /// + public async Task> ListAssistants(QueryParams queryParams = null) + { + queryParams ??= new QueryParams(); + + var url = $"{Url}{queryParams}"; + + var content = await HttpGetContent(url); + + return JsonConvert.DeserializeObject>(content); + } + + /// + public async Task> ListAssistantFiles( + string assistantId, + QueryParams queryParams = null + ) + { + queryParams ??= new QueryParams(); + + var url = $"{Url}/{assistantId}/files{queryParams}"; + + var content = await HttpGetContent(url); + + return JsonConvert.DeserializeObject>(content); + } + + /// + public Task RetrieveAssistant(string assistantId) + { + var url = $"{Url}/{assistantId}"; + + return HttpGet(url); + } + + /// + public Task RetrieveAssistantFile(string assistantId, string fileId) + { + var url = $"{Url}/{assistantId}/files/{fileId}"; + + return HttpGet(url); + } + + /// + public Task ModifyAssistant(string assistantId, AssistantRequest request) + { + var url = $"{Url}/{assistantId}"; + + return HttpPost(url, request); + } + + /// + public Task DeleteAssistant(string assistantId) + { + var url = $"{Url}/{assistantId}"; + + return HttpDelete(url); + } + + /// + public Task DeleteAssistantFile(string assistantId, string fileId) + { + var url = $"{Url}/{assistantId}/files/{fileId}"; + + return HttpDelete(url); + } + } +} \ No newline at end of file diff --git a/OpenAI_API/Assistants/IAssistantsEndpoint.cs b/OpenAI_API/Assistants/IAssistantsEndpoint.cs new file mode 100644 index 0000000..ff08db7 --- /dev/null +++ b/OpenAI_API/Assistants/IAssistantsEndpoint.cs @@ -0,0 +1,143 @@ +using System.Threading.Tasks; +using OpenAI_API.Common; + +namespace OpenAI_API.Assistants +{ + /// + /// An interface for the Assistants API endpoint. + /// + public interface IAssistantsEndpoint + { + /// + /// Creates an assistant with a model and instructions. + /// + /// + /// + /// The request to create an assistant. + /// + /// + /// + /// The created assistant object. + /// + Task CreateAssistant(AssistantRequest request); + + /// + /// Creates an assistant file by attaching a file to an assistant. + /// + /// + /// + /// The ID of the assistant to which to create the file. + /// + /// + /// The request to create an assistant file. + /// + /// + /// + /// The created assistant file object. + /// + Task CreateAssistantFile(string assistantId, AssistantFileRequest request); + + /// + /// Lists the assistants. + /// + /// + /// + /// The parameters to use to list the assistants. If unspecified, the default parameters are used. + /// + /// + /// + /// A list of assistant objects. + /// + Task> ListAssistants(QueryParams queryParams = null); + + /// + /// Lists the assistant files. + /// + /// + /// + /// The ID of the assistant for which to list the files. + /// + /// + /// The parameters to use to list the assistant files. If unspecified, the default parameters are used. + /// + /// + /// + /// A list of assistant file objects. + /// + Task> ListAssistantFiles(string assistantId, QueryParams queryParams = null); + + /// + /// Retrieves an assistant. + /// + /// + /// + /// The ID of the assistant to retrieve. + /// + /// + /// + /// The assistant object matching the ID. + /// + Task RetrieveAssistant(string assistantId); + + /// + /// Retrieves an assistant file. + /// + /// + /// + /// The ID of the assistant to which the file is attached. + /// + /// + /// The ID of the file to retrieve. + /// + /// + /// + /// The assistant file object matching the ID. + /// + Task RetrieveAssistantFile(string assistantId, string fileId); + + /// + /// Modifies an assistant. + /// + /// + /// + /// The ID of the assistant to modify. + /// + /// + /// The request to modify the assistant. + /// + /// + /// + /// The modified assistant object matching the specified ID. + /// + Task ModifyAssistant(string assistantId, AssistantRequest request); + + /// + /// Deletes an assistant. + /// + /// + /// + /// The ID of the assistant to delete. + /// + /// + /// + /// The status of the deletion. + /// + Task DeleteAssistant(string assistantId); + + /// + /// Deletes an assistant file. + /// + /// + /// + /// The ID of the assistant from which to delete the file. + /// + /// + /// The ID of the file to delete. + /// + /// + /// + /// The status of the deletion. + /// + Task DeleteAssistantFile(string assistantId, string fileId); + } +} \ No newline at end of file diff --git a/OpenAI_API/Common/DeletionStatus.cs b/OpenAI_API/Common/DeletionStatus.cs new file mode 100644 index 0000000..cb9477d --- /dev/null +++ b/OpenAI_API/Common/DeletionStatus.cs @@ -0,0 +1,28 @@ +using Newtonsoft.Json; + +namespace OpenAI_API.Common +{ + /// + /// Represents the status of a deletion request. + /// + public class DeletionStatus : ApiResultBase + { + /// + /// The ID of the object that was deleted. + /// + [JsonProperty("id")] + public string Id { get; set; } + + /// + /// The type of object that was deleted. + /// + [JsonProperty("object")] + public new string Object { get; set; } + + /// + /// Whether the object was deleted. + /// + [JsonProperty("deleted")] + public bool Deleted { get; set; } + } +} \ No newline at end of file diff --git a/OpenAI_API/Common/MetadataRequest.cs b/OpenAI_API/Common/MetadataRequest.cs new file mode 100644 index 0000000..52565d6 --- /dev/null +++ b/OpenAI_API/Common/MetadataRequest.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace OpenAI_API.Common +{ + /// + /// Represents a request to modify the metadata of an object. + /// + public class MetadataRequest + { + /// + /// Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional + /// information about the object in a structured format. Keys can be a maximum of 64 characters long and values + /// can be a maximum of 512 characters long. + /// + [JsonProperty("metadata")] + public IDictionary Metadata { get; set; } + } +} \ No newline at end of file diff --git a/OpenAI_API/Common/QueryParams.cs b/OpenAI_API/Common/QueryParams.cs new file mode 100644 index 0000000..118e206 --- /dev/null +++ b/OpenAI_API/Common/QueryParams.cs @@ -0,0 +1,75 @@ +using System.Runtime.Serialization; + +namespace OpenAI_API.Common +{ + /// + /// Represents the query parameters for a list request. + /// + public class QueryParams + { + /// + /// A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 20. + /// + public int Limit { get; set; } = 20; + + /// + /// Sort order by the created_at of the objects. Options are asc for ascending order and + /// desc for descending order. The default is desc. + /// + public OrderMode Order { get; set; } = OrderMode.Desc; + + /// + /// The cursor for use in pagination. after is an object ID that defines your place in the list. For + /// instance, if you make a list request and receive 100 objects, ending with obj_foo, your subsequent call can + /// include after=obj_foo in order to fetch the next page of the list. + /// + public string After { get; set; } + + /// + /// The cursor for use in pagination. before is an object ID that defines your place in the list. For + /// instance, if you make a list request and receive 100 objects, starting with obj_bar, your subsequent call can + /// include before=obj_bar in order to fetch the previous page of the list. + /// + public string Before { get; set; } + + /// + /// Converts the query parameters to a query string. + /// + /// + /// + /// The query string. + /// + public override string ToString() + { + var queryString = $"?limit={Limit}&order={Order.ToString().ToLower()}"; + + if (!string.IsNullOrEmpty(After)) + { + queryString += $"&after={After}"; + } + + if (!string.IsNullOrEmpty(Before)) + { + queryString += $"&before={Before}"; + } + + return queryString; + } + } + + /// + /// Enumerates the available sort modes. + /// + public enum OrderMode + { + /// + /// Sort in ascending order. + /// + Asc, + + /// + /// Sort in descending order. + /// + Desc + } +} \ No newline at end of file diff --git a/OpenAI_API/Common/ResultsList.cs b/OpenAI_API/Common/ResultsList.cs new file mode 100644 index 0000000..16fdcf3 --- /dev/null +++ b/OpenAI_API/Common/ResultsList.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace OpenAI_API.Common +{ + /// + /// Represents a list of results. + /// + public class ResultsList where TResult : ApiResultBase + { + /// + /// The object type. Always "list". + /// + [JsonProperty("object")] + public string Object { get; set; } + + /// + /// The list of results. + /// + [JsonProperty("data")] + public IReadOnlyList Data { get; set; } + + /// + /// The ID of the first result in the list. + /// + [JsonProperty("first_id")] + public string FirstId { get; set; } + + /// + /// The ID of the last result in the list. + /// + [JsonProperty("last_id")] + public string LastId { get; set; } + + /// + /// Whether there are more results available. + /// + [JsonProperty("has_more")] + public bool HasMore { get; set; } + } +} \ No newline at end of file diff --git a/OpenAI_API/EndpointBase.cs b/OpenAI_API/EndpointBase.cs index d981c7e..78a83eb 100644 --- a/OpenAI_API/EndpointBase.cs +++ b/OpenAI_API/EndpointBase.cs @@ -72,6 +72,7 @@ protected HttpClient GetClient() } client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", _Api.Auth.ApiKey); + client.DefaultRequestHeaders.Add("OpenAI-Beta", "assistants=v1"); // Further authentication-header used for Azure openAI service client.DefaultRequestHeaders.Add("api-key", _Api.Auth.ApiKey); client.DefaultRequestHeaders.Add("User-Agent", UserAgent); diff --git a/OpenAI_API/Messages/Annotation.cs b/OpenAI_API/Messages/Annotation.cs new file mode 100644 index 0000000..366b836 --- /dev/null +++ b/OpenAI_API/Messages/Annotation.cs @@ -0,0 +1,89 @@ +using System.Runtime.Serialization; +using Newtonsoft.Json; + +namespace OpenAI_API.Messages +{ + /// + /// Represents an annotation in a message content. + /// + public class Annotation + { + /// + /// The type of annotation. + /// + [JsonProperty("type")] + public AnnotationType Type { get; set; } + + /// + /// The text in the message content that needs to be replaced. + /// + [JsonProperty("text")] + public string Text { get; set; } + + /// + /// The file citation. + /// + /// + /// Only present if is . + /// + [JsonProperty("file_annotation")] + public FileCitation FileCitation { get; set; } + + /// + /// The file path. + /// + /// + /// Only present if is . + /// + [JsonProperty("file_path")] + public FilePath FilePath { get; set; } + + /// + /// The start index. + /// + [JsonProperty("start_index")] + public int StartIndex { get; set; } + + /// + /// The end index. + /// + [JsonProperty("end_index")] + public int EndIndex { get; set; } + } + + /// + /// Represents a citation to a file. + /// + public class FileCitation + { + /// + /// The ID of the specified file the citation is from. + /// + [JsonProperty("file_id")] + public string FileId { get; set; } + + /// + /// The specific quote in the file. + /// + [JsonProperty("quote")] + public string Quote { get; set; } + } + + /// + /// Represents a file path. + /// + public class FilePath + { + /// + /// The ID of the file that was generated. + /// + [JsonProperty("file_id")] + public string FileId { get; set; } + } + + public enum AnnotationType + { + [EnumMember(Value = "file_citation")] FileCitation, + [EnumMember(Value = "file_path")] FilePath + } +} \ No newline at end of file diff --git a/OpenAI_API/Messages/IMessagesEndpoint.cs b/OpenAI_API/Messages/IMessagesEndpoint.cs new file mode 100644 index 0000000..d765cc2 --- /dev/null +++ b/OpenAI_API/Messages/IMessagesEndpoint.cs @@ -0,0 +1,120 @@ +using System.Threading.Tasks; +using OpenAI_API.Common; + +namespace OpenAI_API.Messages +{ + /// + /// An interface for the Messages API endpoint. + /// + public interface IMessagesEndpoint + { + /// + /// Creates a message. + /// + /// + /// + /// The ID of the thread to create the message in. + /// + /// + /// The request object. + /// + /// + /// + /// The created message object. + /// + public Task CreateMessage(string threadId, MessageRequest request); + + /// + /// List the messages in a thread. + /// + /// + /// + /// The ID of the thread for which to list the messages. + /// + /// + /// The parameters to use to list the messages. If unspecified, the default parameters are used. + /// + /// + /// + /// A list of message objects. + /// + public Task> ListMessages(string threadId, QueryParams queryParams = null); + + /// + /// Lists the message files of a message. + /// + /// + /// + /// The ID of the thread the message and file belong to. + /// + /// + /// The ID of the message that the file belong to. + /// + /// + /// The parameters to use to list the message files. If unspecified, the default parameters are used. + /// + /// + /// + /// A list of message file objects. + /// + public Task> ListMessageFiles( + string threadId, + string messageId, + QueryParams queryParams = null + ); + + /// + /// Retrieves a message. + /// + /// + /// + /// The ID of the thread to retrieve the message from. + /// + /// + /// The ID of the message to retrieve. + /// + /// + /// + /// The retrieved message object. + /// + public Task RetrieveMessage(string threadId, string messageId); + + /// + /// Retrieves a message file. + /// + /// + /// + /// The ID of the thread to which the message and file belong. + /// + /// + /// The ID of the message the file belongs to. + /// + /// + /// The ID of the file being retrieved. + /// + /// + /// + /// The message file object matching the ID. + /// + public Task RetrieveMessageFile(string threadId, string messageId, string fileId); + + /// + /// Modifies a message. + /// + /// + /// + /// The ID of the thread to which the message belongs. + /// + /// + /// The ID of the message to modify. + /// + /// + /// The request object. + /// + /// + /// + /// The modified message object matching the specified ID. + /// + public Task ModifyMessage(string threadId, string messageId, MetadataRequest request); + } +} \ No newline at end of file diff --git a/OpenAI_API/Messages/MessageFileResult.cs b/OpenAI_API/Messages/MessageFileResult.cs new file mode 100644 index 0000000..f98a5ae --- /dev/null +++ b/OpenAI_API/Messages/MessageFileResult.cs @@ -0,0 +1,35 @@ +using System; +using Newtonsoft.Json; + +namespace OpenAI_API.Messages +{ + /// + /// Represents a message file attached to a message. + /// + public class MessageFileResult : ApiResultBase + { + /// + /// The identifier, which can be referenced in API endpoints. + /// + [JsonProperty("id")] + public string Id { get; set; } + + /// + /// The Unix timestamp (in seconds) for when the message file was created. + /// + [JsonProperty("created_at")] + public long? CreatedAtUnixTime { get; set; } + + /// + /// The timestamp for when the message file was created. + /// + [JsonIgnore] + public DateTime? CreatedAt => ConvertUnixTime(CreatedAtUnixTime); + + /// + /// The message ID this file belongs to. + /// + [JsonProperty("message_id")] + public string MessageId { get; set; } + } +} \ No newline at end of file diff --git a/OpenAI_API/Messages/MessageRequest.cs b/OpenAI_API/Messages/MessageRequest.cs new file mode 100644 index 0000000..baaf8ba --- /dev/null +++ b/OpenAI_API/Messages/MessageRequest.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using OpenAI_API.Common; + +namespace OpenAI_API.Messages +{ + /// + /// Represents a request to create a message. + /// + public class MessageRequest : MetadataRequest + { + + /// + /// The role of the message. Only is currently supported. + /// + [JsonProperty("role")] + [JsonConverter(typeof(StringEnumConverter))] + public MessageRole Role { get; set; } + + /// + /// The content of the message + /// + [JsonProperty("content")] + public string Content { get; set; } + + /// + /// A list of File IDs that the message should use. + /// + [JsonProperty("file_ids")] + public IList FileIds { get; set; } = Array.Empty(); + } +} \ No newline at end of file diff --git a/OpenAI_API/Messages/MessageResult.cs b/OpenAI_API/Messages/MessageResult.cs new file mode 100644 index 0000000..a3eff3f --- /dev/null +++ b/OpenAI_API/Messages/MessageResult.cs @@ -0,0 +1,143 @@ +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace OpenAI_API.Messages +{ + /// + /// Represents a message. + /// + public class MessageResult : ApiResultBase + { + /// + /// The identifier, which can be referenced in API endpoints. + /// + [JsonProperty("id")] + public string Id { get; set; } + + /// + /// The Unix timestamp (in seconds) for when the message was created. + /// + [JsonProperty("created_at")] + public long? CreatedAtUnixTime { get; set; } + + /// + /// The timestamp for when the message was created. + /// + [JsonIgnore] + public DateTime? CreatedAt => ConvertUnixTime(CreatedAtUnixTime); + + /// + /// The thread ID this message belongs to. + /// + [JsonProperty("thread_id")] + public string ThreadId { get; set; } + + /// + /// The entity that produced the message. + /// + [JsonProperty("role")] + [JsonConverter(typeof(StringEnumConverter))] + public MessageRole Role { get; set; } + + /// + /// The content of the message in an array of text and/or images. + /// + [JsonProperty("content")] + public IReadOnlyList Content { get; set; } + + /// + /// If applicable, the ID of the assistant that authored the message. + /// + [JsonProperty("assistant_id")] + public string AssistantId { get; set; } + + /// + /// If applicable, the ID of the run associated with the authoring of this message. + /// + [JsonProperty("run_id")] + public string RunId { get; set; } + + /// + /// A list of file IDs that the assistant could use. + /// + [JsonProperty("file_ids")] + public IReadOnlyList FileIds { get; set; } + + /// + /// Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional + /// information about the object in a structured format. Keys can be a maximum of 64 characters long and values + /// can be a maximum of 512 characters long. + /// + [JsonProperty("metadata")] + public IReadOnlyDictionary Metadata { get; set; } + } + + /// + /// Represents the content of a message. + /// + public class Content + { + /// + /// The type of content. + /// + [JsonProperty("type")] + public MessageContentType Type { get; set; } + + /// + /// The text content. + /// + /// + /// Only present if is . + /// + [JsonProperty("text")] + public Text Text { get; set; } + + /// + /// References an image file in the content of a message. + /// + /// + /// Only present if is . + /// + [JsonProperty("image_file")] + public ImageFile ImageFile { get; set; } + } + + /// + /// Represents a text object. + /// + public class Text + { + /// + /// The value of the text. + /// + [JsonProperty("value")] + public string Value { get; set; } + + /// + /// A list of annotations for the text. + /// + [JsonProperty("annotations")] + public IReadOnlyList Annotations { get; set; } + } + + /// + /// Represents the reference to an image. + /// + public class ImageFile + { + /// + /// The file ID of the image in the message content. + /// + [JsonProperty("file_id")] + public string FileId { get; set; } + } + + public enum MessageContentType + { + [EnumMember(Value = "test")] Text, + [EnumMember(Value = "image_file")] ImageFile + } +} \ No newline at end of file diff --git a/OpenAI_API/Messages/MessageRole.cs b/OpenAI_API/Messages/MessageRole.cs new file mode 100644 index 0000000..bf6b26a --- /dev/null +++ b/OpenAI_API/Messages/MessageRole.cs @@ -0,0 +1,20 @@ +using System.Runtime.Serialization; + +namespace OpenAI_API.Messages +{ + /// + /// Enumerates roles that a message can have. + /// + public enum MessageRole + { + /// + /// The message was created by the user. + /// + [EnumMember(Value = "user")] User, + + /// + /// The message was created by the assistant. + /// + [EnumMember(Value = "assistant")] Assistant + } +} \ No newline at end of file diff --git a/OpenAI_API/Messages/MessagesEndpoint.cs b/OpenAI_API/Messages/MessagesEndpoint.cs new file mode 100644 index 0000000..7d1d94d --- /dev/null +++ b/OpenAI_API/Messages/MessagesEndpoint.cs @@ -0,0 +1,86 @@ +using System.Threading.Tasks; +using Newtonsoft.Json; +using OpenAI_API.Common; + +namespace OpenAI_API.Messages +{ + /// + /// The endpoint for the Messages API. + /// + public class MessagesEndpoint : EndpointBase, IMessagesEndpoint + { + /// + /// The name of the endpoint, which is the final path segment in the API URL. + /// + protected override string Endpoint => "threads"; + + /// + /// Constructs a new . + /// + /// + /// + /// The instance to use for making requests. + /// + public MessagesEndpoint(OpenAIAPI api) : base(api) { } + + /// + public async Task CreateMessage(string threadId, MessageRequest request) + { + var url = $"{Url}/{threadId}/messages"; + + return await HttpPost(url, request); + } + + /// + public async Task> ListMessages(string threadId, QueryParams queryParams = null) + { + queryParams ??= new QueryParams(); + + var url = $"{Url}/{threadId}/messages{queryParams}"; + + var content = await HttpGetContent(url); + + return JsonConvert.DeserializeObject>(content); + } + + /// + public async Task> ListMessageFiles( + string threadId, + string messageId, + QueryParams queryParams = null + ) + { + queryParams ??= new QueryParams(); + + var url = $"{Url}/{threadId}/messages/{messageId}/files{queryParams}"; + + var content = await HttpGetContent(url); + + return JsonConvert.DeserializeObject>(content); + } + + /// + public async Task RetrieveMessage(string threadId, string messageId) + { + var url = $"{Url}/{threadId}/messages/{messageId}"; + + return await HttpGet(url); + } + + /// + public async Task RetrieveMessageFile(string threadId, string messageId, string fileId) + { + var url = $"{Url}/{threadId}/messages/{messageId}/files/{fileId}"; + + return await HttpGet(url); + } + + /// + public async Task ModifyMessage(string threadId, string messageId, MetadataRequest request) + { + var url = $"{Url}/{threadId}/messages/{messageId}"; + + return await HttpPost(url, request); + } + } +} \ No newline at end of file diff --git a/OpenAI_API/OpenAIAPI.cs b/OpenAI_API/OpenAIAPI.cs index 349f08f..ba2ca3e 100644 --- a/OpenAI_API/OpenAIAPI.cs +++ b/OpenAI_API/OpenAIAPI.cs @@ -7,6 +7,10 @@ using OpenAI_API.Models; using OpenAI_API.Moderation; using System.Net.Http; +using OpenAI_API.Assistants; +using OpenAI_API.Messages; +using OpenAI_API.Runs; +using OpenAI_API.Threads; namespace OpenAI_API { @@ -54,6 +58,10 @@ public OpenAIAPI(APIAuthentication apiKeys = null) TextToSpeech = new TextToSpeechEndpoint(this); Transcriptions = new TranscriptionEndpoint(this, false); Translations = new TranscriptionEndpoint(this, true); + Assistants = new AssistantsEndpoint(this); + Threads = new ThreadsEndpoint(this); + Messages = new MessagesEndpoint(this); + Runs = new RunsEndpoint(this); } /// @@ -120,5 +128,25 @@ public static OpenAIAPI ForAzure(string YourResourceName, string deploymentId, A /// The endpoint for the audio translation API. This allows you to generate English text from audio in other languages. See /// public ITranscriptionEndpoint Translations { get; } + + /// + /// The endpoint for the Assistants API. This allows you to create and manage assistants. See + /// + public IAssistantsEndpoint Assistants { get; } + + /// + /// The endpoint for the Threads API. This allows you to create and manage threads. See + /// + public IThreadsEndpoint Threads { get; } + + /// + /// The endpoint for the Messages API. This allows you to create and manage messages. See + /// + public IMessagesEndpoint Messages { get; } + + /// + /// The endpoint for the Runs API. This allows you to create and manage runs. See + /// + public IRunsEndpoint Runs { get; } } } diff --git a/OpenAI_API/Runs/IRunsEndpoint.cs b/OpenAI_API/Runs/IRunsEndpoint.cs new file mode 100644 index 0000000..cda8971 --- /dev/null +++ b/OpenAI_API/Runs/IRunsEndpoint.cs @@ -0,0 +1,170 @@ +using System.Threading.Tasks; +using OpenAI_API.Common; + +namespace OpenAI_API.Runs +{ + /// + /// An interface for the Runs API endpoint. + /// + public interface IRunsEndpoint + { + /// + /// Creates a run. + /// + /// + /// + /// The ID of the thread in which to create the run. + /// + /// + /// The request object. + /// + /// + /// + /// The created run object. + /// + public Task CreateRun(string threadId, RunRequest request); + + /// + /// Creates a thread and runs it. + /// + /// + /// + /// The request object. + /// + /// + /// + /// The created run object. + /// + public Task CreateThreadAndRun(ThreadAndRunRequest request); + + /// + /// Lists runs belonging to a thread. + /// + /// + /// + /// The ID of the thread to which the runs belong to. + /// + /// + /// The query parameters to use for the request. If unspecified, the default parameters are used. + /// + /// + /// + /// A list of runs objects belonging to the thread with the specified ID. + /// + public Task> ListRuns(string threadId, QueryParams queryParams = null); + + /// + /// Lists run steps belonging to a run. + /// + /// + /// + /// The ID of the thread to which the run and run steps belong to. + /// + /// + /// The ID of the run the run steps belong to. + /// + /// + /// The query parameters to use for the request. If unspecified, the default parameters are used. + /// + /// + /// + /// A list of run step objects belonging to the run with the specified ID. + /// + public Task> ListRunSteps( + string threadId, + string runId, + QueryParams queryParams = null + ); + + /// + /// Retrieves a run. + /// + /// + /// + /// The ID of the thread to which the run belongs to. + /// + /// + /// The ID of the run to retrieve. + /// + /// + /// + /// The run object matching the specified ID. + /// + public Task RetrieveRun(string threadId, string runId); + + /// + /// Retrieves a run step. + /// + /// + /// + /// The ID of the thread to which the run and run step belong to. + /// + /// + /// The ID of the run to which the run step belongs to. + /// + /// + /// The ID of the run step to retrieve. + /// + /// + /// + /// The run step object matching the specified ID. + /// + public Task RetrieveRunStep(string threadId, string runId, string stepId); + + /// + /// Modifies a run. + /// + /// + /// + /// The ID of the thread to which the run belongs to. + /// + /// + /// The ID of the run to modify. + /// + /// + /// The request object. + /// + /// + /// + /// The modified run object matching the specified ID. + /// + public Task ModifyRun(string threadId, string runId, MetadataRequest request); + + /// + /// When a run has the status: "requires_action" and required_action.type is submit_tool_outputs, + /// this endpoint can be used to submit the outputs from the tool calls once they're all completed. All outputs + /// must be submitted in a single request. + /// + /// + /// + /// The ID of the thread to which the run belongs to. + /// + /// + /// The ID of the run that requires the tool output submission. + /// + /// + /// The request object. + /// + /// + /// + /// The modified run object matching the specified ID. + /// + public Task SubmitToolOutputsToRun(string threadId, string runId, ToolOutputsRequest request); + + /// + /// Cancels a run. + /// + /// + /// + /// The ID of the thread to which the run belongs to. + /// + /// + /// The ID of the run to cancel. + /// + /// + /// + /// The cancelled run object matching the specified ID. + /// + public Task CancelRun(string threadId, string runId); + } +} \ No newline at end of file diff --git a/OpenAI_API/Runs/RunError.cs b/OpenAI_API/Runs/RunError.cs new file mode 100644 index 0000000..9307bbe --- /dev/null +++ b/OpenAI_API/Runs/RunError.cs @@ -0,0 +1,34 @@ +using System.Runtime.Serialization; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace OpenAI_API.Runs +{ + /// + /// Represents an error that occurred during a run. + /// + public class RunError + { + /// + /// The error code. + /// + [JsonProperty("code")] + [JsonConverter(typeof(StringEnumConverter))] + public RunErrorCode Code { get; set; } + + /// + /// A human-readable description of the error. + /// + [JsonProperty("message")] + public string Message { get; set; } + } + + /// + /// Enumerates the possible error codes. + /// + public enum RunErrorCode + { + [EnumMember(Value = "server_error")] ServerError, + [EnumMember(Value = "rate_limit_exceeded")] RateLimitExceeded, + } +} \ No newline at end of file diff --git a/OpenAI_API/Runs/RunRequest.cs b/OpenAI_API/Runs/RunRequest.cs new file mode 100644 index 0000000..91b83ad --- /dev/null +++ b/OpenAI_API/Runs/RunRequest.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using OpenAI_API.Assistants; +using OpenAI_API.Common; + +namespace OpenAI_API.Runs +{ + /// + /// Represents a request to create a run. + /// + public class RunRequest : MetadataRequest + { + /// + /// The ID of the assistant to execute this run. + /// + [JsonProperty("assistant_id")] + public string AssistantId { get; set; } + + /// + /// The ID of the Model to be used to execute this run. If a value is provided here, it will override the + /// model associated with the assistant. If not, the model associated with the assistant will be used. + /// + [JsonProperty("model")] + public string Model { get; set; } + + /// + /// Overrides the instructions of the assistant. This is useful for modifying the behavior on a per-run basis. + /// + [JsonProperty("instructions")] + public string Instructions { get; set; } + + /// + /// Appends additional instructions at the end of the of the instructions for the run. This is useful for + /// modifying the behavior on a per-run basis, without overriding other instructions. + /// + [JsonProperty("additional_instructions")] + public string AdditionalInstructions { get; set; } + + /// + /// Override the tools the assistant can use for this run. This is useful for modifying the behavior on a + /// per-run basis. + /// + [JsonProperty("tools")] + public IList Tools { get; set; } + } +} \ No newline at end of file diff --git a/OpenAI_API/Runs/RunResult.cs b/OpenAI_API/Runs/RunResult.cs new file mode 100644 index 0000000..54df886 --- /dev/null +++ b/OpenAI_API/Runs/RunResult.cs @@ -0,0 +1,238 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using OpenAI_API.Assistants; + +namespace OpenAI_API.Runs +{ + /// + /// Represents a run. + /// + public class RunResult : ApiResultBase + { + /// + /// The identifier, which can be referenced in API endpoints. + /// + [JsonProperty("id")] + public string Id { get; set; } + + /// + /// The ID of the thread that was executed as part of this run. + /// + [JsonProperty("thread_id")] + public string ThreadId { get; set; } + + /// + /// The ID of the assistant used for execution of this run. + /// + [JsonProperty("assistant_id")] + public string AssistantId { get; set; } + + /// + /// The status of the run. + /// + [JsonProperty("status")] + [JsonConverter(typeof(StringEnumConverter))] + public RunStatus Status { get; set; } + + /// + /// Details on the action required to continue the run. Will be null if no action is required. + /// + [JsonProperty("required_action")] + public RequiredAction RequiredAction { get; set; } + + /// + /// The last error associated with the run step. Will be null if there are no errors. + /// + [JsonProperty("last_error")] + public RunError LastError { get; set; } + + #region Timestamps + + /// + /// The Unix timestamp (in seconds) for when the run was created. + /// + [JsonProperty("created_at")] + public long? CreatedAtUnixTime { get; set; } + + /// + /// The timestamp for when the run was created. + /// + [JsonIgnore] + public DateTime? CreatedAt => ConvertUnixTime(CreatedAtUnixTime); + + /// + /// The Unix timestamp (in seconds) for when the run will expire. + /// + [JsonProperty("expires_at")] + public long? ExpiresAtUnixTime { get; set; } + + /// + /// The timestamp for when the run will expire. + /// + [JsonIgnore] + public DateTime? ExpiresAt => ConvertUnixTime(ExpiresAtUnixTime); + + /// + /// The Unix timestamp (in seconds) for when the run was started. + /// + [JsonProperty("started_at")] + public long? StartedAtUnixTime { get; set; } + + /// + /// The timestamp for when the run was started. + /// + [JsonIgnore] + public DateTime? StartedAt => ConvertUnixTime(StartedAtUnixTime); + + /// + /// The Unix timestamp (in seconds) for when the run was cancelled. + /// + [JsonProperty("cancelled_at")] + public long? CancelledAtUnixTime { get; set; } + + /// + /// The timestamp for when the run was cancelled. + /// + [JsonIgnore] + public DateTime? CancelledAt => ConvertUnixTime(CancelledAtUnixTime); + + /// + /// The Unix timestamp (in seconds) for when the run failed. + /// + [JsonProperty("failed_at")] + public long? FailedAtUnixTime { get; set; } + + /// + /// The timestamp for when the run failed. + /// + [JsonIgnore] + public DateTime? FailedAt => ConvertUnixTime(FailedAtUnixTime); + + /// + /// The Unix timestamp (in seconds) for when the run was completed. + /// + [JsonProperty("completed_at")] + public long? CompletedAtUnixTime { get; set; } + + /// + /// The timestamp for when the run was completed. + /// + [JsonIgnore] + public DateTime? CompletedAt => ConvertUnixTime(CompletedAtUnixTime); + + #endregion + + /// + /// The model that the assistant used for this run. + /// + [JsonProperty("model")] + public new string Model { get; set; } + + /// + /// The instructions that the assistant used for this run. + /// + [JsonProperty("instructions")] + public string Instructions { get; set; } + + /// + /// The list of tools that the assistant used for this run. + /// + [JsonProperty("tools")] + public IReadOnlyList Tools { get; set; } + + /// + /// The list of file IDs the assistant used for this run. + /// + [JsonProperty("file_ids")] + public IReadOnlyList FileIds { get; set; } + + /// + /// Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional + /// information about the object in a structured format. Keys can be a maximum of 64 characters long and values + /// can be a maximum of 512 characters long. + /// + [JsonProperty("metadata")] + public IReadOnlyDictionary Metadata { get; set; } + + /// + /// Usage statistics related to the run. Will be null if the run is not in a terminal state. + /// + [JsonProperty("usage")] + public RunUsage Usage { get; set; } + } + + /// + /// Represents the details of the action required to continue a run. + /// + public class RequiredAction + { + /// + /// For now, this is always submit_tool_outputs. + /// + [JsonProperty("type")] + public string Type { get; set; } + + /// + /// Details on the tool outputs needed for this run to continue. + /// + [JsonProperty("submit_tool_outputs")] + public SubmitToolOutputs SubmitToolOutputs { get; set; } + } + + /// + /// Represents the tool outputs needed for a run to continue. + /// + public class SubmitToolOutputs + { + /// + /// A list of the relevant tool calls. + /// + [JsonProperty("tool_calls")] + public IReadOnlyList ToolCalls { get; set; } + } + + /// + /// Represents a tool call. + /// + public class ToolCall + { + /// + /// The ID of the tool call. This ID must be referenced when you submit the tool outputs in using the + /// endpoint. + /// + [JsonProperty("id")] + public string Id { get; set; } + + /// + /// The type of tool call the output is required for. For now, this is always function. + /// + [JsonProperty("type")] + public string Type { get; set; } + + /// + /// The function definition. + /// + [JsonProperty("function")] + public FunctionDefinition Function { get; set; } + } + + /// + /// Represents a function definition. + /// + public class FunctionDefinition + { + /// + /// The name of the function. + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// The arguments that the model expects you to pass to the function. + /// + [JsonProperty("arguments")] + public IReadOnlyList Arguments { get; set; } + } +} \ No newline at end of file diff --git a/OpenAI_API/Runs/RunStatus.cs b/OpenAI_API/Runs/RunStatus.cs new file mode 100644 index 0000000..62c6e6d --- /dev/null +++ b/OpenAI_API/Runs/RunStatus.cs @@ -0,0 +1,19 @@ +using System.Runtime.Serialization; + +namespace OpenAI_API.Runs +{ + /// + /// Represents the status of a run. + /// + public enum RunStatus + { + [EnumMember(Value = "queued")] Queued, + [EnumMember(Value = "in_progress")] InProgress, + [EnumMember(Value = "requires_action")] RequiresAction, + [EnumMember(Value = "cancelling")] Cancelling, + [EnumMember(Value = "cancelled")] Cancelled, + [EnumMember(Value = "failed")] Failed, + [EnumMember(Value = "completed")] Completed, + [EnumMember(Value = "expired")] Expired + } +} \ No newline at end of file diff --git a/OpenAI_API/Runs/RunStepResult.cs b/OpenAI_API/Runs/RunStepResult.cs new file mode 100644 index 0000000..215f6d3 --- /dev/null +++ b/OpenAI_API/Runs/RunStepResult.cs @@ -0,0 +1,251 @@ +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using OpenAI_API.Assistants; + +namespace OpenAI_API.Runs +{ + /// + /// Represents a run step. + /// + public class RunStepResult : ApiResultBase + { + /// + /// The identifier, which can be referenced in API endpoints. + /// + [JsonProperty("id")] + public string Id { get; set; } + + /// + /// The ID of the assistant associated with this run step. + /// + [JsonProperty("assistant_id")] + public string AssistantId { get; set; } + + /// + /// The ID of the thread that was run. + /// + [JsonProperty("thread_id")] + public string ThreadId { get; set; } + + /// + /// The ID of the run that this run step is part of. + /// + [JsonProperty("run_id")] + public string RunId { get; set; } + + /// + /// The type of the run step. + /// + [JsonProperty("type")] + [JsonConverter(typeof(StringEnumConverter))] + public RunStepType Type { get; set; } + + /// + /// The status of the run step. + /// + [JsonProperty("status")] + [JsonConverter(typeof(StringEnumConverter))] + public RunStepStatus Status { get; set; } + + /// + /// The details of the run step. + /// + [JsonProperty("step_details")] + public RunStepDetails StepDetails { get; set; } + + /// + /// The last error associated with the run step. Will be null if there are no errors. + /// + [JsonProperty("last_error")] + public RunError LastError { get; set; } + + #region Timestamps + + /// + /// The Unix timestamp (in seconds) for when the run step was created. + /// + [JsonProperty("created_at")] + public long? CreatedAtUnixTime { get; set; } + + /// + /// The timestamp for when the run step was created. + /// + [JsonIgnore] + public DateTime? CreatedAt => ConvertUnixTime(CreatedAtUnixTime); + + /// + /// The Unix timestamp (in seconds) for when the run step expired. + /// + [JsonProperty("expired_at")] + public long? ExpiredAtUnixTime { get; set; } + + /// + /// The timestamp for when the run step expired. + /// + [JsonIgnore] + public DateTime? ExpiredAt => ConvertUnixTime(ExpiredAtUnixTime); + + /// + /// The Unix timestamp (in seconds) for when the run step was cancelled. + /// + [JsonProperty("cancelled_at")] + public long? CancelledAtUnixTime { get; set; } + + /// + /// The timestamp for when the run step was cancelled. + /// + [JsonIgnore] + public DateTime? CancelledAt => ConvertUnixTime(CancelledAtUnixTime); + + /// + /// The Unix timestamp (in seconds) for when the run step failed. + /// + [JsonProperty("failed_at")] + public long? FailedAtUnixTime { get; set; } + + /// + /// The timestamp for when the run step failed. + /// + [JsonIgnore] + public DateTime? FailedAt => ConvertUnixTime(FailedAtUnixTime); + + /// + /// The Unix timestamp (in seconds) for when the run step was completed. + /// + [JsonProperty("completed_at")] + public long? CompletedAtUnixTime { get; set; } + + /// + /// The timestamp for when the run step was completed. + /// + [JsonIgnore] + public DateTime? CompletedAt => ConvertUnixTime(CompletedAtUnixTime); + + #endregion + + /// + /// Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional + /// information about the object in a structured format. Keys can be a maximum of 64 characters long and values + /// can be a maximum of 512 characters long. + /// + [JsonProperty("metadata")] + public IReadOnlyDictionary Metadata { get; set; } + + /// + /// Usage statistics related to the run. Will be null if the run is not in a terminal state. + /// + [JsonProperty("usage")] + public RunUsage Usage { get; set; } + } + + /// + /// Represents the details of a run step. + /// + public class RunStepDetails + { + /// + /// The type of step details. + /// + [JsonProperty("type")] + [JsonConverter(typeof(StringEnumConverter))] + public RunStepDetailsType Type { get; set; } + + /// + /// Details of the message creation step. Only present if is . + /// + [JsonProperty("message_creation")] + public RunStepMessageCreation MessageCreation { get; set; } + + /// + /// An array of tool calls the run step was involved in. Only present if is . + /// + [JsonProperty("tool_calls")] + public IReadOnlyList ToolCalls { get; set; } + } + + /// + /// Represents the creation of a message by a run step. + /// + public class RunStepMessageCreation + { + /// + /// The ID of the message that was created by this run step. + /// + [JsonProperty("message_id")] + public string MessageId { get; set; } + } + + /// + /// Represents a tool call by a run step. + /// + public class RunStepToolCall + { + /// + /// The ID of the tool call. + /// + [JsonProperty("id")] + public string Id { get; set; } + + /// + /// The type of tool call. + /// + [JsonProperty("type")] + [JsonConverter(typeof(StringEnumConverter))] + public AssistantToolType Type { get; set; } + + /// + /// The code interpreter tool call definition. Only present if is . + /// + [JsonProperty("code_interpreter")] + public object CodeInterpreter { get; set; } + + /// + /// The retrieval tool call definition. For now this is going to be an empty object. + /// + [JsonProperty("retrieval")] + public object Retrieval { get; set; } + + /// + /// The definition of the function that was called. Only present if is . + /// + [JsonProperty("function")] + public object Function { get; set; } + } + + #region Enums + + /// + /// Enumerates the possible types of a run step. + /// + public enum RunStepType + { + [EnumMember(Value = "message_creation")] MessageCreation, + [EnumMember(Value = "tool_calls")] ToolCalls + } + + /// + /// Enumerates the possible statuses of a run step. + /// + public enum RunStepStatus + { + [EnumMember(Value = "in_progress")] InProgress, + [EnumMember(Value = "cancelled")] Cancelled, + [EnumMember(Value = "failed")] Failed, + [EnumMember(Value = "completed")] Completed, + [EnumMember(Value = "expired")] Expired + } + + /// + /// Enumerates the possible types of step details. + /// + public enum RunStepDetailsType + { + [EnumMember(Value = "message_creation")] MessageCreation, + [EnumMember(Value = "tool_calls")] ToolCalls + } + + #endregion +} \ No newline at end of file diff --git a/OpenAI_API/Runs/RunUsage.cs b/OpenAI_API/Runs/RunUsage.cs new file mode 100644 index 0000000..298bec6 --- /dev/null +++ b/OpenAI_API/Runs/RunUsage.cs @@ -0,0 +1,28 @@ +using Newtonsoft.Json; + +namespace OpenAI_API.Runs +{ + /// + /// Represents the usage statistics related to a run. + /// + public class RunUsage + { + /// + /// Number of completion tokens used over the course of the run. + /// + [JsonProperty("completion_tokens")] + public int CompletionTokens { get; set; } + + /// + /// Number of prompt tokens used over the course of the run. + /// + [JsonProperty("prompt_tokens")] + public int PromptTokens { get; set; } + + /// + /// Number of tokens used (prompt + completion) over the course of the run. + /// + [JsonProperty("total_tokens")] + public int TotalTokens { get; set; } + } +} \ No newline at end of file diff --git a/OpenAI_API/Runs/RunsEndpoint.cs b/OpenAI_API/Runs/RunsEndpoint.cs new file mode 100644 index 0000000..9996d5b --- /dev/null +++ b/OpenAI_API/Runs/RunsEndpoint.cs @@ -0,0 +1,110 @@ +using System.Threading.Tasks; +using Newtonsoft.Json; +using OpenAI_API.Common; + +namespace OpenAI_API.Runs +{ + /// + /// The endpoint for the Runs API. + /// + public class RunsEndpoint : EndpointBase, IRunsEndpoint + { + /// + /// The name of the endpoint, which is the final path segment in the API URL. + /// + protected override string Endpoint => "threads"; + + /// + /// Constructs a new . + /// + /// + /// + /// The instance to use for making requests. + /// + public RunsEndpoint(OpenAIAPI api) : base(api) { } + + /// + public async Task CreateRun(string threadId, RunRequest request) + { + var url = $"{Url}/{threadId}/runs"; + + return await HttpPost(url, request); + } + + /// + public async Task CreateThreadAndRun(ThreadAndRunRequest request) + { + var url = $"{Url}/runs"; + + return await HttpPost(url, request); + } + + /// + public async Task> ListRuns(string threadId, QueryParams queryParams = null) + { + queryParams ??= new QueryParams(); + + var url = $"{Url}/{threadId}/runs{queryParams}"; + + var content = await HttpGetContent(url); + + return JsonConvert.DeserializeObject>(content); + } + + /// + public async Task> ListRunSteps( + string threadId, + string runId, + QueryParams queryParams = null + ) + { + queryParams ??= new QueryParams(); + + var url = $"{Url}/{threadId}/runs/{runId}/steps{queryParams}"; + + var content = await HttpGetContent(url); + + return JsonConvert.DeserializeObject>(content); + } + + /// + public async Task RetrieveRun(string threadId, string runId) + { + var url = $"{Url}/{threadId}/runs/{runId}"; + + return await HttpGet(url); + } + + /// + public async Task RetrieveRunStep(string threadId, string runId, string stepId) + { + var url = $"{Url}/{threadId}/runs/{runId}/steps/{stepId}"; + + return await HttpGet(url); + } + + /// + public async Task ModifyRun(string threadId, string runId, MetadataRequest request) + { + var url = $"{Url}/{threadId}/runs/{runId}"; + + return await HttpPost(url, request); + } + + /// + public Task SubmitToolOutputsToRun(string threadId, string runId, ToolOutputsRequest request) + { + var url = $"{Url}/{threadId}/runs/{runId}/submit_tool_outputs"; + + return HttpPost(url, request); + } + + /// + public async Task CancelRun(string threadId, string runId) + { + var url = $"{Url}/{threadId}/runs/{runId}/cancel"; + + return await HttpPost(url); + } + } +} \ No newline at end of file diff --git a/OpenAI_API/Runs/ThreadAndRunRequest.cs b/OpenAI_API/Runs/ThreadAndRunRequest.cs new file mode 100644 index 0000000..636bd95 --- /dev/null +++ b/OpenAI_API/Runs/ThreadAndRunRequest.cs @@ -0,0 +1,17 @@ +using Newtonsoft.Json; +using OpenAI_API.Threads; + +namespace OpenAI_API.Runs +{ + /// + /// Represents a request to create a thread and run it. + /// + public class ThreadAndRunRequest : RunRequest + { + /// + /// The thread to create. + /// + [JsonProperty("thread")] + public ThreadRequest Thread { get; set; } + } +} \ No newline at end of file diff --git a/OpenAI_API/Runs/ToolOutputsRequest.cs b/OpenAI_API/Runs/ToolOutputsRequest.cs new file mode 100644 index 0000000..10a3472 --- /dev/null +++ b/OpenAI_API/Runs/ToolOutputsRequest.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace OpenAI_API.Runs +{ + /// + /// Represents a request to submit the outputs of a tool call to continue a run. + /// + public class ToolOutputsRequest + { + /// + /// A list of tools for which the outputs are being submitted. + /// + [JsonProperty("tool_outputs")] + public IList ToolOutputs { get; set; } + } + + /// + /// Represents the output of a tool call to be submitted to continue a run. + /// + public class ToolOutput + { + /// + /// The ID of the tool call in the required_action object within the run object the output is being + /// submitted for. + /// + [JsonProperty("tool_call_id")] + public string ToolCallId { get; set; } + + /// + /// The output of the tool call to be submitted to continue the run. + /// + [JsonProperty("output")] + public string Output { get; set; } + } +} \ No newline at end of file diff --git a/OpenAI_API/Threads/IThreadsEndpoint.cs b/OpenAI_API/Threads/IThreadsEndpoint.cs new file mode 100644 index 0000000..b212dba --- /dev/null +++ b/OpenAI_API/Threads/IThreadsEndpoint.cs @@ -0,0 +1,66 @@ +using System.Threading.Tasks; +using OpenAI_API.Common; + +namespace OpenAI_API.Threads +{ + /// + /// An interface for the Threads API endpoint. + /// + public interface IThreadsEndpoint + { + /// + /// Creates a thread. + /// + /// + /// + /// The request object. + /// + /// + /// + /// The created thread object. + /// + public Task CreateThread(ThreadRequest request); + + /// + /// Retrieves a thread. + /// + /// + /// + /// The ID of the thread to retrieve. + /// + /// + /// + /// The thread object matching the specified ID. + /// + public Task RetrieveThread(string threadId); + + /// + /// Modifies a thread. Only the metadata can be modified. + /// + /// + /// + /// The ID of the thread to modify. + /// + /// + /// The request object. + /// + /// + /// + /// The modified thread object matching the specified ID. + /// + public Task ModifyThread(string threadId, MetadataRequest request); + + /// + /// Deletes a thread. + /// + /// + /// + /// The ID of the thread to delete. + /// + /// + /// + /// The status of the deletion. + /// + public Task DeleteThread(string threadId); + } +} \ No newline at end of file diff --git a/OpenAI_API/Threads/ThreadRequest.cs b/OpenAI_API/Threads/ThreadRequest.cs new file mode 100644 index 0000000..cabc8e7 --- /dev/null +++ b/OpenAI_API/Threads/ThreadRequest.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using OpenAI_API.Common; +using OpenAI_API.Messages; + +namespace OpenAI_API.Threads +{ + /// + /// Represents a request to create a thread. + /// + public class ThreadRequest : MetadataRequest + { + /// + /// A list of messages to start the thread with. + /// + [JsonProperty("messages")] + public IList Messages { get; set; } + } +} \ No newline at end of file diff --git a/OpenAI_API/Threads/ThreadResult.cs b/OpenAI_API/Threads/ThreadResult.cs new file mode 100644 index 0000000..9726f3c --- /dev/null +++ b/OpenAI_API/Threads/ThreadResult.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace OpenAI_API.Threads +{ + /// + /// Represents a thread that contains messages. + /// + public class ThreadResult : ApiResultBase + { + /// + /// The identifier which can be referenced in API endpoints. + /// + [JsonProperty("id")] + public string Id { get; set; } + + /// + /// The Unix timestamp (in seconds) for when the thread was created. + /// + [JsonProperty("created_at")] + public long? CreatedAtUnixTime { get; set; } + + /// + /// The timestamp for when the thread was created. + /// + [JsonIgnore] + public DateTime? CreatedAt => ConvertUnixTime(CreatedAtUnixTime); + + /// + /// Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional + /// information about the object in a structured format. Keys can be a maximum of 64 characters long and values + /// can be a maximum of 512 characters long. + /// + [JsonProperty("metadata")] + public IReadOnlyDictionary Metadata { get; set; } + } +} \ No newline at end of file diff --git a/OpenAI_API/Threads/ThreadsEndpoint.cs b/OpenAI_API/Threads/ThreadsEndpoint.cs new file mode 100644 index 0000000..73c2d13 --- /dev/null +++ b/OpenAI_API/Threads/ThreadsEndpoint.cs @@ -0,0 +1,55 @@ +using System.Threading.Tasks; +using OpenAI_API.Common; + +namespace OpenAI_API.Threads +{ + /// + /// The endpoint for the Threads API. + /// + public class ThreadsEndpoint : EndpointBase, IThreadsEndpoint + { + /// + /// The name of the endpoint, which is the final path segment in the API URL. + /// + protected override string Endpoint => "threads"; + + /// + /// Constructs a new . + /// + /// + /// + /// The instance to use for making requests. + /// + public ThreadsEndpoint(OpenAIAPI api) : base(api) { } + + /// + public async Task CreateThread(ThreadRequest request) + { + return await HttpPost(Url, request); + } + + /// + public async Task RetrieveThread(string threadId) + { + var url = $"{Url}/{threadId}"; + + return await HttpGet(url); + } + + /// + public async Task ModifyThread(string threadId, MetadataRequest request) + { + var url = $"{Url}/{threadId}"; + + return await HttpPut(url, request); + } + + /// + public async Task DeleteThread(string threadId) + { + var url = $"{Url}/{threadId}"; + + return await HttpDelete(url); + } + } +} \ No newline at end of file