OpenAI icon indicating copy to clipboard operation
OpenAI copied to clipboard

feat: Assistants API Beta Implemented

Open cdillard opened this issue 1 year ago • 10 comments

What

Eight new API endpoints are exposed in the APIPath to support the assistants API.

Thanks again to @bwhtmnv for his contribution to my fork assistants API PR. Functions are now supported upon assistant creation and when interacting with thread messages! All the credit goes to him for implementing the new Tool parameters for assistants and RunToolOutputsQuery for making functions useful within assistant threads.

    static let assistants = "/v1/assistants"
    static let assistantsModify = "/v1/assistants/ASST_ID"
    static let threads = "/v1/threads"
    static let runs = "/v1/threads/THREAD_ID/runs"
    static let runRetrieve = "/v1/threads/THREAD_ID/runs/RUN_ID"
    static let runRetrieveSteps = "/v1/threads/THREAD_ID/runs/RUN_ID/steps"
    static let threadsMessages = "/v1/threads/THREAD_ID/messages"
    static let files = "/v1/files"

The OpenAIProtocol is modified as follows: added

    func assistants(query: AssistantsQuery?, method: String, completion: @escaping (Result<AssistantsResult, Error>) -> Void)    

    func threads(query: ThreadsQuery, completion: @escaping (Result<ThreadsResult, Error>) -> Void)

    func runs(threadId: String, query: RunsQuery, completion: @escaping (Result<RunsResult, Error>) -> Void)

    func runRetrieve(threadId: String, runId:String, completion: @escaping (Result<RunRetreiveResult, Error>) -> Void)

    func runRetrieveSteps(threadId: String, runId: String, before: String?, completion: @escaping (Result<RunRetreiveStepsResult, Error>) -> Void)

    func threadsMessages(threadId: String, before: String?, completion: @escaping (Result<ThreadsMessagesResult, Error>) -> Void)

    func threadsAddMessage(threadId: String, query: ThreadAddMessageQuery, completion: @escaping (Result<ThreadAddMessageResult, Error>) -> Void)

    func files(query: FilesQuery, completion: @escaping (Result<FilesResult, Error>) -> Void)

Assistants:

  • [X] Create

  • [x] Modify

  • [x] Attach files of all supported OpenAI types to Assistants on creation or modify.

  • [X] List assistants

    • [x] Paging through assistants list

Tools can be passed to assistant creation/modify.

  • [X] Code Interpreter
  • [X] Retrieval
  • [x] Functions

Threads/Runs

  • [X] Create Thread
  • [X] Create Run
  • [X] Retrieve Run
  • [X] Add Message to Thread
  • [X] Retrieve Threads Messages
  • [X] Retrieve Run Steps

Files

  • [X] Upload

Example App:

A new demonstration of the assistants API and its requirements of the polling has been added to the Demo app.

  • Now you can create a new assistant on the Chats tab by selecting "+" -> New Assistant -> Fill in details -> OK. This should result in a "New Assistant" row being added to the chats, you can chat with your newly created assistant in this conversation.

  • You can now list your OpenAI API Assistants on the "Assistants" tab. Select "+" -> Get Assistants to load the assistants list.

  • For now I've implemented additional chat messages that are shown when run steps include tool calls such as code interpreter or retrieval.

Why

To support the assistant features like threads, runs, tools (such as code_interpreter and retrieval), and files with assistants API.

Affected Areas

OpenAI

cdillard avatar Dec 18 '23 21:12 cdillard

Quality Gate Passed Quality Gate passed

The SonarCloud Quality Gate passed, but some issues were introduced.

55 New issues
0 Security Hotspots
No data about Coverage
2.2% Duplication on New Code

See analysis details on SonarCloud

sonarqubecloud[bot] avatar Dec 21 '23 00:12 sonarqubecloud[bot]

Looking forward for this PR to be merged. 👁️

pblondin avatar Jan 04 '24 19:01 pblondin

Just what I need!

bryan1anderson avatar Jan 05 '24 21:01 bryan1anderson

thanks @cdillard for doing this. Please review it and get it merged guys

jerrypainter avatar Feb 04 '24 09:02 jerrypainter

Quality Gate Passed Quality Gate passed

Issues
70 New issues

Measures
0 Security Hotspots
No data about Coverage
1.7% Duplication on New Code

See analysis details on SonarCloud

sonarqubecloud[bot] avatar Feb 22 '24 00:02 sonarqubecloud[bot]

Thanks to bwhtmn and his AWESOME contribution here.

Functions are now supported!

Thanks again to @bwhtmn for adding this on my fork. All the credit goes to him for implementing the new Tool parameters for assistants and RunToolOutputsQuery for making functions useful within assistant threads.

cdillard avatar Feb 22 '24 01:02 cdillard

@cdillard have you been looking at the new Assistants Streaming functionality? Any plans to add? Thanks for the stellar work on adding this functionality for Assistants!

mrkvans avatar Mar 25 '24 18:03 mrkvans

@cdillard @bwhtmn , how can we fetch arguments from a function call response?

alelordelo avatar Apr 30 '24 18:04 alelordelo

@cdillard @bwhtmn , how can we fetch arguments from a function call response?

@alelordelo here's an example, assuming that you have started a run with threadRun(query:):

let run = try await openAI.runRetrieve(threadId: threadId, runId: runId)
switch run.status {
case .requiresAction:
    guard let toolCalls = run.requiredAction?.submitToolOutputs.toolCalls else {
        break
    }
    
    for toolCall in toolCalls where toolCall.type == "function" {
        // Arguments can be accessed like this as a string and parsed into JSON as needed.
        let arguments = toolCall.function.arguments
    }
default:
    break
}

bwhtmn avatar Apr 30 '24 19:04 bwhtmn

thank @cdillard!

I was hoping to access it in ChatBubble like:

          case .tool:
        let arguments = tool.function.arguments

The issue is that case .tool is actually incorrect, it doesn't represent a tool response (either in Assistant or Completion API)....

            switch message.role {
            case .assistant:
                Text(message.content)
                    .padding(.horizontal, 16)
                    .padding(.vertical, 12)
                    .background(assistantBackgroundColor)
                    .clipShape(RoundedRectangle(cornerRadius: 16, style: .continuous))
                Spacer(minLength: 24)
            case .user:
                Spacer(minLength: 24)
                Text(message.content)
                    .padding(.horizontal, 16)
                    .padding(.vertical, 12)
                    .foregroundColor(userForegroundColor)
                    .background(userBackgroundColor)
                    .clipShape(RoundedRectangle(cornerRadius: 16, style: .continuous))
            case .tool:
            //fetch tool arguments here
              Text(message.content)       
                  .font(.footnote.monospaced())
                  .padding(.horizontal, 16)
                  .padding(.vertical, 12)
                  .background(.green)
                  .clipShape(RoundedRectangle(cornerRadius: 16, style: .continuous))
              Spacer(minLength: 24)
            case .system:
                EmptyView()
            }

As for your suggestion, the run doesn't seem to be accessible on DetailView, and its not clear how the thread was created and how we could access in DetailView?

Maybe would make sense to create a AssistantDetailView?

let run = try await openAI.runRetrieve(threadId: threadId, runId: runId)
switch run.status {
case .requiresAction:
    guard let toolCalls = run.requiredAction?.submitToolOutputs.toolCalls else {
        break
    }
    
    for toolCall in toolCalls where toolCall.type == "function" {
        // Arguments can be accessed like this as a string and parsed into JSON as needed.
        let arguments = toolCall.function.arguments
    }
default:
    break
}

alelordelo avatar May 01 '24 10:05 alelordelo