Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Assistants API Beta Implemented #140

Open
wants to merge 10 commits into
base: main
Choose a base branch
from

Conversation

cdillard
Copy link

@cdillard cdillard commented Dec 18, 2023

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:

  • Create

  • Modify

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

  • List assistants

    • Paging through assistants list

Tools can be passed to assistant creation/modify.

  • Code Interpreter
  • Retrieval
  • Functions

Threads/Runs

  • Create Thread
  • Create Run
  • Retrieve Run
  • Add Message to Thread
  • Retrieve Threads Messages
  • Retrieve Run Steps

Files

  • 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

* feat: Assistants API

* Rem accidentally committed Dev team

* Demoapp syntax fix for ImageCreationView

* assistant paging, modify, fix

* demo: enhancement: Handle local message replacement, README update

* clean, runRetrieveSteps implemented, SupportedFileTypes implemented

* Handle run retrieve steps

* Assistant README, add run retrieve steps

* display run retrieve steps in updating fashion for code_interpreter
Copy link

sonarcloud bot commented Dec 21, 2023

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

@pblondin
Copy link

pblondin commented Jan 4, 2024

Looking forward for this PR to be merged. 👁️

@bryan1anderson
Copy link

Just what I need!

… thread in a single request; submit tool outputs.
@jerrypainter
Copy link

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

Copy link
Contributor

@ingvarus-bc ingvarus-bc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @cdillard! 👋
You did an amazing job! ❤️‍🔥
Thank you for your time and contribution to the project. This is a splendid addition to the library which will be loved by developers!
Appreciate how structured you made the PR with tasks and explanations! 🔥
There is one task left, to create functions, is it just for demonstration purposes or you're planning to implement that as well, should we merge the PR?
We're approving this PR and will merge it as soon as we hear from you ✅

@ingvarus-bc ingvarus-bc linked an issue Feb 14, 2024 that may be closed by this pull request
15 tasks
…api-3

# Conflicts:
#	Demo/DemoChat/Sources/ChatStore.swift
Chat -> ChatQuery.ChatCompletionMessageParam refactr
… feat/assistants-api-3

# Conflicts:
#	Demo/DemoChat/Sources/ChatStore.swift
#	Sources/OpenAI/Public/Models/ChatQuery.swift
#	Sources/OpenAI/Public/Models/ChatResult.swift
#	Sources/OpenAI/Public/Models/ImagesQuery.swift
#	Sources/OpenAI/Public/Models/ThreadsQuery.swift
#	Tests/OpenAITests/OpenAITests.swift
#	Tests/OpenAITests/OpenAITestsCombine.swift
#	Tests/OpenAITests/OpenAITestsDecoder.swift
Copy link

sonarcloud bot commented Feb 22, 2024

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

@cdillard
Copy link
Author

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.

@mrkvans
Copy link

mrkvans commented Mar 25, 2024

@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!

@alelordelo
Copy link

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

@bwhtmn
Copy link

bwhtmn commented Apr 30, 2024

@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
}

@alelordelo
Copy link

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
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

feat: WIP Assistants API, feedback requested
8 participants